-
Notifications
You must be signed in to change notification settings - Fork 44.4k
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
base: dev
Are you sure you want to change the base?
feat(platform): Simplify Credentials UX #8524
Conversation
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; | ||
} |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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!
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", |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(even if fallback)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
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.movAlso 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 |
There was a problem hiding this 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
Constraining providers already happens in the backend by specifying Regarding bugs and video: everything should now work, including system keys being hidden in the profile. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -52,6 +52,10 @@ def AICredentialsField() -> AICredentials: | |||
description="API key for the LLM provider.", | |||
provider="llm", |
There was a problem hiding this comment.
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
[...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], | ||
}), | ||
), | ||
})), |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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
if (!credentials) { | ||
if (!credentials || credentials.isLoading) { | ||
return null; | ||
} | ||
|
||
if (credentials.isLoading) { | ||
return <div>Loading...</div>; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why this change?
// 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; |
There was a problem hiding this comment.
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.
maybe this error helps |
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 🏗️
provider
of default credentials to actual provider names (e.g.anthropic
) and notllm
discriminator
anddiscriminator_mapping
toCredentialsField
that allows to filter credentials input to only allow providers for matching models inuseCredentials
hook (thanks @ntindle for the idea!); e.g. user choosesGPT4_TURBO
so then only OpenAI credentials are allowedgetValue
andparseKeys
to utilsANTHROPIC
,GROQ
andOLLAMA
to providers in frontendtypes.ts
hidden
field to credentials that is used for default system keys to hide them in user profileTesting 🔍
Note
Only for the new autogpt platform, currently in autogpt_platform/