Skip to content

feat: add localStorage persistence for agent config and auth#136

Open
rubencagnie wants to merge 1 commit intoa2aproject:mainfrom
rubencagnie:local-storage
Open

feat: add localStorage persistence for agent config and auth#136
rubencagnie wants to merge 1 commit intoa2aproject:mainfrom
rubencagnie:local-storage

Conversation

@rubencagnie
Copy link

Implements automatic saving and loading of agent configuration to improve user experience by eliminating the need to re-enter settings on each visit.

Features added:

  • Agent card URL persists across sessions
  • Authentication type and credentials (Bearer, API Key, Basic Auth) are saved
  • Custom headers automatically save and restore
  • Authentication & Headers section now expanded by default
  • All settings save on input change and when connecting

Technical changes:

  • Added localStorage.getItem/setItem for agent URL, auth data, and headers
  • Implemented saveAuthInputValues() and loadAuthInputValues() functions
  • Added event listeners to save on input change and header removal
  • Auto-formatted code with gts fix (prettier/eslint)

All tests pass (74/74) and code follows project linting standards.

Description

Thank you for opening a Pull Request!
Before submitting your PR, there are a few things you can do to make sure it goes smoothly:

  • Follow the CONTRIBUTING Guide.
  • Make your Pull Request title in the https://www.conventionalcommits.org/ specification.
    • Important Prefixes for release-please:
      • fix: which represents bug fixes, and correlates to a SemVer patch.
      • feat: represents a new feature, and correlates to a SemVer minor.
      • feat!:, or fix!:, refactor!:, etc., which represent a breaking change (indicated by the !) and will result in a SemVer major.
  • Ensure the tests and linter pass (Run bash scripts/format.sh from the repository root to format)
  • Appropriate docs were updated (if necessary)

Implements automatic saving and loading of agent configuration to improve
user experience by eliminating the need to re-enter settings on each visit.

Features added:
- Agent card URL persists across sessions
- Authentication type and credentials (Bearer, API Key, Basic Auth) are saved
- Custom headers automatically save and restore
- Authentication & Headers section now expanded by default
- All settings save on input change and when connecting

Technical changes:
- Added localStorage.getItem/setItem for agent URL, auth data, and headers
- Implemented saveAuthInputValues() and loadAuthInputValues() functions
- Added event listeners to save on input change and header removal
- Auto-formatted code with gts fix (prettier/eslint)

All tests pass (74/74) and code follows project linting standards.

Co-Authored-By: Claude <noreply@anthropic.com>
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @rubencagnie, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces significant user experience improvements by implementing client-side persistence for agent configuration and authentication details. By leveraging localStorage, the application now automatically saves and loads critical user settings such as the agent URL, chosen authentication method, associated credentials, and custom headers. This enhancement streamlines the workflow by eliminating repetitive data entry, ensuring a more seamless and efficient interaction with the agent interface across browser sessions.

Highlights

  • Agent Configuration Persistence: The agent card URL, authentication type, credentials (Bearer, API Key, Basic Auth), and custom headers are now automatically saved and loaded using localStorage, eliminating the need for re-entry.
  • Improved User Experience: Users no longer need to re-enter their settings on each visit, as all configurations persist across browser sessions, streamlining the workflow.
  • Dynamic Saving Mechanism: Settings are saved automatically on input changes within the authentication and header sections, as well as when the connection button is clicked.
  • Default UI State: The Authentication & Headers section is now expanded by default, providing immediate access to these frequently used settings.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a great usability improvement by persisting agent configuration and authentication details to localStorage. The implementation is straightforward and covers agent URL, authentication data, and custom headers.

My review includes a few suggestions:

  • A high-level security consideration regarding the use of localStorage for credentials.
  • Refactoring suggestions for the data loading logic to improve robustness and readability by removing unnecessary setTimeout calls and reducing code duplication.
  • A small fix to remove another unnecessary setTimeout.

Comment on lines +343 to +362
function saveAuthInputValues() {
const authType = authTypeSelect.value;
const authData: Record<string, string> = {};

switch (authType) {
case 'bearer':
authData.token = getInputValue('bearer-token');
break;
case 'api-key':
authData.header = getInputValue('api-key-header');
authData.value = getInputValue('api-key-value');
break;
case 'basic':
authData.username = getInputValue('basic-username');
authData.password = getInputValue('basic-password');
break;
}

localStorage.setItem(`auth_${authType}`, JSON.stringify(authData));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

Storing authentication credentials like tokens and especially username/password in localStorage poses a security risk. Data in localStorage is accessible via JavaScript, making it vulnerable to Cross-Site Scripting (XSS) attacks. An attacker who manages to inject a script could steal these credentials. For a developer tool this might be an acceptable risk, but it's important to be aware of it. Consider adding a warning to the user in the UI about the risks of saving sensitive credentials in the browser.

Comment on lines +365 to +412
function loadAuthInputValues(authType: string) {
const savedData = localStorage.getItem(`auth_${authType}`);
if (!savedData) return;

try {
const authData = JSON.parse(savedData);

// Wait for inputs to be rendered
setTimeout(() => {
switch (authType) {
case 'bearer': {
const tokenInput = document.getElementById(
'bearer-token',
) as HTMLInputElement;
if (tokenInput && authData.token) tokenInput.value = authData.token;
break;
}
case 'api-key': {
const headerInput = document.getElementById(
'api-key-header',
) as HTMLInputElement;
const valueInput = document.getElementById(
'api-key-value',
) as HTMLInputElement;
if (headerInput && authData.header)
headerInput.value = authData.header;
if (valueInput && authData.value) valueInput.value = authData.value;
break;
}
case 'basic': {
const usernameInput = document.getElementById(
'basic-username',
) as HTMLInputElement;
const passwordInput = document.getElementById(
'basic-password',
) as HTMLInputElement;
if (usernameInput && authData.username)
usernameInput.value = authData.username;
if (passwordInput && authData.password)
passwordInput.value = authData.password;
break;
}
}
}, 0);
} catch (e) {
console.error('Failed to load auth data:', e);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This function can be simplified. The setTimeout is not necessary because renderAuthInputs is a synchronous function, so the DOM elements are available immediately after it runs. Additionally, the logic for setting input values is repetitive and can be extracted into a helper function to make the switch statement cleaner and more maintainable. The proposed change also fixes a bug where empty saved values (e.g., an empty token) would not be loaded back into the input field.

  function loadAuthInputValues(authType: string) {
    const savedData = localStorage.getItem(`auth_${authType}`);
    if (!savedData) return;

    try {
      const authData = JSON.parse(savedData);

      const setInputValue = (id: string, value?: string) => {
        // Only set value if it's defined in the saved data.
        // This allows clearing fields.
        if (value !== undefined) {
          const input = document.getElementById(id) as HTMLInputElement | null;
          if (input) {
            input.value = value;
          }
        }
      };

      switch (authType) {
        case 'bearer':
          setInputValue('bearer-token', authData.token);
          break;
        case 'api-key':
          setInputValue('api-key-header', authData.header);
          setInputValue('api-key-value', authData.value);
          break;
        case 'basic':
          setInputValue('basic-username', authData.username);
          setInputValue('basic-password', authData.password);
          break;
      }
    } catch (e) {
      console.error('Failed to load auth data:', e);
    }
  }

Comment on lines +813 to +814
// Wait for the DOM to update
setTimeout(saveHeadersToLocalStorage, 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The setTimeout here is unnecessary. The remove() operation on a DOM element is synchronous. Another event listener for 'click' is already registered on headersList via setupRemoveItemListener, and since it was registered first, it will execute before this one, removing the element from the DOM. Therefore, you can call saveHeadersToLocalStorage() directly without a timeout.

      saveHeadersToLocalStorage();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants