Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(platform): Simplify Credentials UX #8524

Open
wants to merge 10 commits into
base: dev
Choose a base branch
from

Conversation

kcze
Copy link
Contributor

@kcze kcze commented Nov 1, 2024

Background

Current credentials system always forces users to choose correct credentials, even when they are provided by the cloud platform and should be chosen automatically (e.g. there's only one possible choice).

Changes 🏗️

  • Change provider of default credentials to actual provider names (e.g. anthropic) and not llm
  • Add discriminator and discriminator_mapping to CredentialsField that allows to filter credentials input to only allow providers for matching models in useCredentials hook (thanks @ntindle for the idea!); e.g. user chooses GPT4_TURBO so then only OpenAI credentials are allowed
  • Choose credentials automatically and hide credentials input on the node completely if there's only one possible option
  • Move getValue and parseKeys to utils
  • Add ANTHROPIC, GROQ and OLLAMA to providers in frontend types.ts
  • Add hidden field to credentials that is used for default system keys to hide them in user profile

Testing 🔍

Note

Only for the new autogpt platform, currently in autogpt_platform/

  • Create from scratch and execute an agent with at least 3 blocks
  • Import an agent from file upload, and confirm it executes correctly
  • Upload agent to marketplace
  • Import an agent from marketplace and confirm it executes correctly
  • Edit an agent from monitor, and confirm it executes correctly

@kcze kcze requested a review from a team as a code owner November 1, 2024 16:30
@github-actions github-actions bot added platform/frontend AutoGPT Platform - Front end platform/backend AutoGPT Platform - Back end platform/blocks size/l labels Nov 1, 2024
Comment on lines +318 to +345
export function parseKeys(key: string): ParsedKey[] {
const splits = key.split(/_@_|_#_|_\$_|\./);
const keys: ParsedKey[] = [];
let currentKey: string | null = null;

splits.forEach((split) => {
const isInteger = /^\d+$/.test(split);
if (!isInteger) {
if (currentKey !== null) {
keys.push({ key: currentKey });
}
currentKey = split;
} else {
if (currentKey !== null) {
keys.push({ key: currentKey, index: parseInt(split, 10) });
currentKey = null;
} else {
throw new Error("Invalid key format: array index without a key");
}
}
});

if (currentKey !== null) {
keys.push({ key: currentKey });
}

return keys;
}
Copy link
Member

Choose a reason for hiding this comment

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

we should probably add security test for this lol

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree but this code is already in the codebase I just moved it!

@ntindle
Copy link
Member

ntindle commented Nov 4, 2024

This is exactly what I was thinking! great job!

D_ID: "d_id",
DISCORD: "discord",
GITHUB: "github",
GOOGLE: "google",
GOOGLE_MAPS: "google_maps",
GROQ: "groq",
Copy link
Member

Choose a reason for hiding this comment

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

probably need logos for these too

Copy link
Member

Choose a reason for hiding this comment

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

(even if fallback)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@ntindle
Copy link
Member

ntindle commented Nov 5, 2024

I think the devx and ux of this leaves something to be desired still. I think the dev specifying the valid providers as a list would be useful and then it returns one of the credentials depending on the selected API key added.

Screen.Recording.2024-11-04.at.9.04.20.PM.mov

Also not sure how they are added to the db and filtered but I'm not seeing them after creation, and crashing anytime they're rendered. I think there's an issue somewhere. lmk if you can't replicate

Copy link
Member

@ntindle ntindle left a comment

Choose a reason for hiding this comment

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

Tested, needs addtional work

@kcze
Copy link
Contributor Author

kcze commented Nov 5, 2024

I think the dev specifying the valid providers as a list would be useful and then it returns one of the credentials depending on the selected API key added.

Constraining providers already happens in the backend by specifying discriminator_mapping. You cannot add non-matching provider and even if you manage they won't be displayed in the dropdown.

Regarding bugs and video: everything should now work, including system keys being hidden in the profile.

@kcze kcze requested a review from ntindle November 5, 2024 14:21
Copy link
Member

@ntindle ntindle left a comment

Choose a reason for hiding this comment

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

This still isn't wokring for me
image
There's nowhere to select credentials, and we're still creating llm providers which we shouldn't need

@@ -52,6 +52,10 @@ def AICredentialsField() -> AICredentials:
description="API key for the LLM provider.",
provider="llm",
Copy link
Member

Choose a reason for hiding this comment

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

imo this needs to be a structure that shows the allowable providers, not its own provider. something like

valid_providers = ['openai', 'grok', 'anthropic']
and be used in conjunction with discriminator always to have one of the providers be selected

Comment on lines +77 to +85
[...provider.savedOAuthCredentials, ...provider.savedApiKeys]
.filter((cred) => !cred.hidden)
.map((credentials) => ({
...credentials,
provider: provider.provider,
providerName: provider.providerName,
ProviderIcon: providerIcons[provider.provider],
TypeIcon: { oauth2: IconUser, api_key: IconKey }[credentials.type],
}),
),
})),
Copy link
Member

Choose a reason for hiding this comment

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

this works fine for me right now

@@ -56,6 +58,7 @@ export const providerIcons: Record<
ideogram: fallbackIcon,
llm: fallbackIcon,
Copy link
Member

Choose a reason for hiding this comment

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

we should be able to remove this once we get this right

Comment on lines -94 to -101
if (!credentials) {
if (!credentials || credentials.isLoading) {
return null;
}

if (credentials.isLoading) {
return <div>Loading...</div>;
}

Copy link
Member

Choose a reason for hiding this comment

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

why this change?

Comment on lines +259 to +283
// Only one saved credential
} else if (
savedApiKeys.length === 0 &&
savedOAuthCredentials.length === 1 &&
selectedCredentials === undefined
) {
if (selectedCredentials === undefined) {
onSelectCredentials({
id: savedOAuthCredentials[0].id,
type: "oauth2",
provider,
title: savedOAuthCredentials[0].title,
});
}
return null;
} else if (savedApiKeys.length === 1 && savedOAuthCredentials.length === 0) {
if (selectedCredentials === undefined) {
onSelectCredentials({
id: savedApiKeys[0].id,
type: "api_key",
provider,
title: savedApiKeys[0].title,
});
}
return null;
Copy link
Member

Choose a reason for hiding this comment

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

What's the purpose of this? This whole chain of logic seems questionably necessary.

@ntindle
Copy link
Member

ntindle commented Nov 5, 2024

app-index.tsx:25 
 Warning: Cannot update a component (`BatchProvider`) while rendering a different component (`CredentialsInput`). To locate the bad setState() call inside `CredentialsInput`, follow the stack trace as described in https://reactjs.org/link/setstate-in-render Error Component Stack
    at CredentialsInput (credentials-input.tsx:87:9)
    at div (<anonymous>)
    at NodeCredentialsInput (node-input-components.tsx:309:9)
    at NodeGenericInputField (

maybe this error helps

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
platform/backend AutoGPT Platform - Back end platform/blocks platform/frontend AutoGPT Platform - Front end size/l
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants