mirror of
https://github.com/KeygraphHQ/shannon.git
synced 2026-08-11 14:00:24 +02:00
feat(cli): support any Pi provider via generic SHANNON_AI_API_KEY (#415)
* feat(cli): support any Pi provider via generic SHANNON_AI_API_KEY * docs(cli): point users to pi.dev/models for provider and model ids * docs: document generic provider path and pi.dev catalogue
This commit is contained in:
+23
-18
@@ -6,24 +6,35 @@
|
||||
* rule are duplicated here deliberately and must stay in sync.
|
||||
*/
|
||||
|
||||
/** Providers Shannon can currently reach. Each is a pi-ai provider id. */
|
||||
export const SUPPORTED_PROVIDERS = ['anthropic', 'openai', 'xai', 'amazon-bedrock'] as const;
|
||||
/**
|
||||
* Providers Shannon curates with their own credential variables, config sections,
|
||||
* and setup flows. Any other pi provider is reachable via the generic credential
|
||||
* path. Mirrors CURATED_PROVIDERS in apps/worker/src/ai/models.ts.
|
||||
*/
|
||||
export const CURATED_PROVIDERS = ['anthropic', 'openai', 'xai', 'amazon-bedrock'] as const;
|
||||
|
||||
export type ProviderId = (typeof SUPPORTED_PROVIDERS)[number];
|
||||
export type CuratedProviderId = (typeof CURATED_PROVIDERS)[number];
|
||||
|
||||
export function isCuratedProvider(value: string): value is CuratedProviderId {
|
||||
return (CURATED_PROVIDERS as readonly string[]).includes(value);
|
||||
}
|
||||
|
||||
/** Generic API key, honored for any provider Shannon does not curate. Mirrors the worker. */
|
||||
export const GENERIC_API_KEY_ENV = 'SHANNON_AI_API_KEY';
|
||||
|
||||
/**
|
||||
* Env vars carrying each provider's API key, in precedence order. Any one of them
|
||||
* satisfies the provider. Mirrors PROVIDER_API_KEY_ENV in apps/worker/src/ai/models.ts.
|
||||
* Env vars carrying each curated provider's API key, in precedence order. Any one of
|
||||
* them satisfies the provider. Mirrors PROVIDER_API_KEY_ENV in apps/worker/src/ai/models.ts.
|
||||
*/
|
||||
export const PROVIDER_API_KEY_ENV: Readonly<Record<ProviderId, readonly string[]>> = {
|
||||
export const PROVIDER_API_KEY_ENV: Readonly<Record<CuratedProviderId, readonly string[]>> = {
|
||||
anthropic: ['ANTHROPIC_API_KEY', 'CLAUDE_CODE_OAUTH_TOKEN'],
|
||||
openai: ['OPENAI_API_KEY'],
|
||||
xai: ['XAI_API_KEY'],
|
||||
'amazon-bedrock': ['AWS_BEARER_TOKEN_BEDROCK'],
|
||||
};
|
||||
|
||||
/** Additional env vars a provider requires beyond its API key. All must be set. */
|
||||
export const PROVIDER_EXTRA_ENV: Readonly<Record<ProviderId, readonly string[]>> = {
|
||||
/** Additional env vars a curated provider requires beyond its API key. All must be set. */
|
||||
export const PROVIDER_EXTRA_ENV: Readonly<Record<CuratedProviderId, readonly string[]>> = {
|
||||
anthropic: [],
|
||||
openai: [],
|
||||
xai: [],
|
||||
@@ -31,7 +42,7 @@ export const PROVIDER_EXTRA_ENV: Readonly<Record<ProviderId, readonly string[]>>
|
||||
};
|
||||
|
||||
/** Human-readable credential requirement, used in "nothing configured" errors. */
|
||||
export const PROVIDER_CREDENTIAL_HINT: Readonly<Record<ProviderId, string>> = {
|
||||
export const PROVIDER_CREDENTIAL_HINT: Readonly<Record<CuratedProviderId, string>> = {
|
||||
anthropic: 'ANTHROPIC_API_KEY (or CLAUDE_CODE_OAUTH_TOKEN)',
|
||||
openai: 'OPENAI_API_KEY',
|
||||
xai: 'XAI_API_KEY',
|
||||
@@ -51,18 +62,15 @@ export const OPENAI_FORMATS = ['chat-completions', 'responses'] as const;
|
||||
export type OpenAiFormat = (typeof OPENAI_FORMATS)[number];
|
||||
|
||||
export interface ModelSpec {
|
||||
providerId: ProviderId;
|
||||
providerId: string;
|
||||
modelId: string;
|
||||
}
|
||||
|
||||
function isSupportedProvider(value: string): value is ProviderId {
|
||||
return (SUPPORTED_PROVIDERS as readonly string[]).includes(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a `<provider>:<model-id>` spec. Splits on the first colon only, so colons
|
||||
* inside a model ID survive (`amazon-bedrock:us.anthropic.claude-opus-4-5-20251101-v1:0`).
|
||||
* Returns an error string rather than throwing, for the CLI's validation flow.
|
||||
* The provider id is passed through as given — the worker's preflight validates it
|
||||
* against pi. Returns an error string rather than throwing, for the CLI's flow.
|
||||
*/
|
||||
export function parseModelSpec(spec: string): ModelSpec | string {
|
||||
const trimmed = spec.trim();
|
||||
@@ -74,9 +82,6 @@ export function parseModelSpec(spec: string): ModelSpec | string {
|
||||
const modelId = trimmed.slice(separator + 1).trim();
|
||||
if (!providerId || !modelId) return malformed;
|
||||
|
||||
if (!isSupportedProvider(providerId)) {
|
||||
return `Unsupported provider "${providerId}" in SHANNON_AI_MODEL. Supported providers: ${SUPPORTED_PROVIDERS.join(', ')}`;
|
||||
}
|
||||
return { providerId, modelId };
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user