@mariozechner/pi-ai 0.24.5 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +120 -10
- package/dist/agent/agent-loop.d.ts.map +1 -1
- package/dist/agent/agent-loop.js +58 -5
- package/dist/agent/agent-loop.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/models.generated.d.ts +179 -22
- package/dist/models.generated.d.ts.map +1 -1
- package/dist/models.generated.js +205 -48
- package/dist/models.generated.js.map +1 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +0 -2
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/google-gemini-cli.d.ts +16 -0
- package/dist/providers/google-gemini-cli.d.ts.map +1 -0
- package/dist/providers/google-gemini-cli.js +347 -0
- package/dist/providers/google-gemini-cli.js.map +1 -0
- package/dist/providers/google-shared.d.ts +34 -0
- package/dist/providers/google-shared.d.ts.map +1 -0
- package/dist/providers/google-shared.js +211 -0
- package/dist/providers/google-shared.js.map +1 -0
- package/dist/providers/google.d.ts.map +1 -1
- package/dist/providers/google.js +3 -162
- package/dist/providers/google.js.map +1 -1
- package/dist/providers/openai-completions.d.ts.map +1 -1
- package/dist/providers/openai-completions.js +25 -0
- package/dist/providers/openai-completions.js.map +1 -1
- package/dist/providers/openai-responses.d.ts.map +1 -1
- package/dist/providers/openai-responses.js +24 -1
- package/dist/providers/openai-responses.js.map +1 -1
- package/dist/providers/transorm-messages.d.ts.map +1 -1
- package/dist/providers/transorm-messages.js +62 -43
- package/dist/providers/transorm-messages.js.map +1 -1
- package/dist/stream.d.ts +15 -0
- package/dist/stream.d.ts.map +1 -1
- package/dist/stream.js +39 -0
- package/dist/stream.js.map +1 -1
- package/dist/types.d.ts +4 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/oauth/anthropic.d.ts +16 -0
- package/dist/utils/oauth/anthropic.d.ts.map +1 -0
- package/dist/utils/oauth/anthropic.js +102 -0
- package/dist/utils/oauth/anthropic.js.map +1 -0
- package/dist/utils/oauth/github-copilot.d.ts +43 -0
- package/dist/utils/oauth/github-copilot.d.ts.map +1 -0
- package/dist/utils/oauth/github-copilot.js +236 -0
- package/dist/utils/oauth/github-copilot.js.map +1 -0
- package/dist/utils/oauth/google-antigravity.d.ts +24 -0
- package/dist/utils/oauth/google-antigravity.d.ts.map +1 -0
- package/dist/utils/oauth/google-antigravity.js +272 -0
- package/dist/utils/oauth/google-antigravity.js.map +1 -0
- package/dist/utils/oauth/google-gemini-cli.d.ts +24 -0
- package/dist/utils/oauth/google-gemini-cli.d.ts.map +1 -0
- package/dist/utils/oauth/google-gemini-cli.js +285 -0
- package/dist/utils/oauth/google-gemini-cli.js.map +1 -0
- package/dist/utils/oauth/index.d.ts +54 -0
- package/dist/utils/oauth/index.d.ts.map +1 -0
- package/dist/utils/oauth/index.js +147 -0
- package/dist/utils/oauth/index.js.map +1 -0
- package/dist/utils/oauth/storage.d.ts +81 -0
- package/dist/utils/oauth/storage.d.ts.map +1 -0
- package/dist/utils/oauth/storage.js +119 -0
- package/dist/utils/oauth/storage.js.map +1 -0
- package/dist/utils/overflow.d.ts +2 -2
- package/dist/utils/overflow.d.ts.map +1 -1
- package/dist/utils/overflow.js +7 -4
- package/dist/utils/overflow.js.map +1 -1
- package/package.json +1 -1
package/dist/stream.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"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","sourcesContent":["import { ThinkingLevel } from \"@google/genai\";\nimport { supportsXhigh } from \"./models.js\";\nimport { type AnthropicOptions, streamAnthropic } from \"./providers/anthropic.js\";\nimport { type GoogleOptions, streamGoogle } from \"./providers/google.js\";\nimport { type OpenAICompletionsOptions, streamOpenAICompletions } from \"./providers/openai-completions.js\";\nimport { type OpenAIResponsesOptions, streamOpenAIResponses } from \"./providers/openai-responses.js\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tAssistantMessageEventStream,\n\tContext,\n\tKnownProvider,\n\tModel,\n\tOptionsForApi,\n\tReasoningEffort,\n\tSimpleStreamOptions,\n} from \"./types.js\";\n\nconst apiKeys: Map<string, string> = new Map();\n\nexport function setApiKey(provider: KnownProvider, key: string): void;\nexport function setApiKey(provider: string, key: string): void;\nexport function setApiKey(provider: any, key: string): void {\n\tapiKeys.set(provider, key);\n}\n\nexport function getApiKey(provider: KnownProvider): string | undefined;\nexport function getApiKey(provider: string): string | undefined;\nexport function getApiKey(provider: any): string | undefined {\n\t// Check explicit keys first\n\tconst key = apiKeys.get(provider);\n\tif (key) return key;\n\n\t// Fall back to environment variables\n\tif (provider === \"github-copilot\") {\n\t\treturn process.env.COPILOT_GITHUB_TOKEN || process.env.GH_TOKEN || process.env.GITHUB_TOKEN;\n\t}\n\n\tconst envMap: Record<string, string> = {\n\t\topenai: \"OPENAI_API_KEY\",\n\t\tanthropic: \"ANTHROPIC_API_KEY\",\n\t\tgoogle: \"GEMINI_API_KEY\",\n\t\tgroq: \"GROQ_API_KEY\",\n\t\tcerebras: \"CEREBRAS_API_KEY\",\n\t\txai: \"XAI_API_KEY\",\n\t\topenrouter: \"OPENROUTER_API_KEY\",\n\t\tzai: \"ZAI_API_KEY\",\n\t\tmistral: \"MISTRAL_API_KEY\",\n\t};\n\n\tconst envVar = envMap[provider];\n\treturn envVar ? process.env[envVar] : undefined;\n}\n\nexport function stream<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: OptionsForApi<TApi>,\n): AssistantMessageEventStream {\n\tconst apiKey = options?.apiKey || getApiKey(model.provider);\n\tif (!apiKey) {\n\t\tthrow new Error(`No API key for provider: ${model.provider}`);\n\t}\n\tconst providerOptions = { ...options, apiKey };\n\n\tconst api: Api = model.api;\n\tswitch (api) {\n\t\tcase \"anthropic-messages\":\n\t\t\treturn streamAnthropic(model as Model<\"anthropic-messages\">, context, providerOptions);\n\n\t\tcase \"openai-completions\":\n\t\t\treturn streamOpenAICompletions(model as Model<\"openai-completions\">, context, providerOptions as any);\n\n\t\tcase \"openai-responses\":\n\t\t\treturn streamOpenAIResponses(model as Model<\"openai-responses\">, context, providerOptions as any);\n\n\t\tcase \"google-generative-ai\":\n\t\t\treturn streamGoogle(model as Model<\"google-generative-ai\">, context, providerOptions);\n\n\t\tdefault: {\n\t\t\t// This should never be reached if all Api cases are handled\n\t\t\tconst _exhaustive: never = api;\n\t\t\tthrow new Error(`Unhandled API: ${_exhaustive}`);\n\t\t}\n\t}\n}\n\nexport async function complete<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: OptionsForApi<TApi>,\n): Promise<AssistantMessage> {\n\tconst s = stream(model, context, options);\n\treturn s.result();\n}\n\nexport function streamSimple<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream {\n\tconst apiKey = options?.apiKey || getApiKey(model.provider);\n\tif (!apiKey) {\n\t\tthrow new Error(`No API key for provider: ${model.provider}`);\n\t}\n\n\tconst providerOptions = mapOptionsForApi(model, options, apiKey);\n\treturn stream(model, context, providerOptions);\n}\n\nexport async function completeSimple<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): Promise<AssistantMessage> {\n\tconst s = streamSimple(model, context, options);\n\treturn s.result();\n}\n\nfunction mapOptionsForApi<TApi extends Api>(\n\tmodel: Model<TApi>,\n\toptions?: SimpleStreamOptions,\n\tapiKey?: string,\n): OptionsForApi<TApi> {\n\tconst base = {\n\t\ttemperature: options?.temperature,\n\t\tmaxTokens: options?.maxTokens || Math.min(model.maxTokens, 32000),\n\t\tsignal: options?.signal,\n\t\tapiKey: apiKey || options?.apiKey,\n\t};\n\n\t// Helper to clamp xhigh to high for providers that don't support it\n\tconst clampReasoning = (effort: ReasoningEffort | undefined) => (effort === \"xhigh\" ? \"high\" : effort);\n\n\tswitch (model.api) {\n\t\tcase \"anthropic-messages\": {\n\t\t\t// Explicitly disable thinking when reasoning is not specified\n\t\t\tif (!options?.reasoning) {\n\t\t\t\treturn { ...base, thinkingEnabled: false } satisfies AnthropicOptions;\n\t\t\t}\n\n\t\t\tconst anthropicBudgets = {\n\t\t\t\tminimal: 1024,\n\t\t\t\tlow: 2048,\n\t\t\t\tmedium: 8192,\n\t\t\t\thigh: 16384,\n\t\t\t};\n\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tthinkingEnabled: true,\n\t\t\t\tthinkingBudgetTokens: anthropicBudgets[clampReasoning(options.reasoning)!],\n\t\t\t} satisfies AnthropicOptions;\n\t\t}\n\n\t\tcase \"openai-completions\":\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\treasoningEffort: supportsXhigh(model) ? options?.reasoning : clampReasoning(options?.reasoning),\n\t\t\t} satisfies OpenAICompletionsOptions;\n\n\t\tcase \"openai-responses\":\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\treasoningEffort: supportsXhigh(model) ? options?.reasoning : clampReasoning(options?.reasoning),\n\t\t\t} satisfies OpenAIResponsesOptions;\n\n\t\tcase \"google-generative-ai\": {\n\t\t\t// Explicitly disable thinking when reasoning is not specified\n\t\t\t// This is needed because Gemini has \"dynamic thinking\" enabled by default\n\t\t\tif (!options?.reasoning) {\n\t\t\t\treturn { ...base, thinking: { enabled: false } } satisfies GoogleOptions;\n\t\t\t}\n\n\t\t\tconst googleModel = model as Model<\"google-generative-ai\">;\n\t\t\tconst effort = clampReasoning(options.reasoning)!;\n\n\t\t\t// Gemini 3 models use thinkingLevel exclusively instead of thinkingBudget.\n\t\t\t// https://ai.google.dev/gemini-api/docs/thinking#set-budget\n\t\t\tif (isGemini3ProModel(googleModel) || isGemini3FlashModel(googleModel)) {\n\t\t\t\treturn {\n\t\t\t\t\t...base,\n\t\t\t\t\tthinking: {\n\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t\tlevel: getGemini3ThinkingLevel(effort, googleModel),\n\t\t\t\t\t},\n\t\t\t\t} satisfies GoogleOptions;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tthinking: {\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tbudgetTokens: getGoogleBudget(googleModel, effort),\n\t\t\t\t},\n\t\t\t} satisfies GoogleOptions;\n\t\t}\n\n\t\tdefault: {\n\t\t\t// Exhaustiveness check\n\t\t\tconst _exhaustive: never = model.api;\n\t\t\tthrow new Error(`Unhandled API in mapOptionsForApi: ${_exhaustive}`);\n\t\t}\n\t}\n}\n\ntype ClampedReasoningEffort = Exclude<ReasoningEffort, \"xhigh\">;\n\nfunction isGemini3ProModel(model: Model<\"google-generative-ai\">): boolean {\n\t// Covers gemini-3-pro, gemini-3-pro-preview, and possible other prefixed ids in the future\n\treturn model.id.includes(\"3-pro\");\n}\n\nfunction isGemini3FlashModel(model: Model<\"google-generative-ai\">): boolean {\n\t// Covers gemini-3-flash, gemini-3-flash-preview, and possible other prefixed ids in the future\n\treturn model.id.includes(\"3-flash\");\n}\n\nfunction getGemini3ThinkingLevel(effort: ClampedReasoningEffort, model: Model<\"google-generative-ai\">): ThinkingLevel {\n\tif (isGemini3ProModel(model)) {\n\t\t// Gemini 3 Pro only supports LOW/HIGH (for now)\n\t\tswitch (effort) {\n\t\t\tcase \"minimal\":\n\t\t\tcase \"low\":\n\t\t\t\treturn ThinkingLevel.LOW;\n\t\t\tcase \"medium\":\n\t\t\tcase \"high\":\n\t\t\t\treturn ThinkingLevel.HIGH;\n\t\t}\n\t}\n\t// Gemini 3 Flash supports all four levels\n\tswitch (effort) {\n\t\tcase \"minimal\":\n\t\t\treturn ThinkingLevel.MINIMAL;\n\t\tcase \"low\":\n\t\t\treturn ThinkingLevel.LOW;\n\t\tcase \"medium\":\n\t\t\treturn ThinkingLevel.MEDIUM;\n\t\tcase \"high\":\n\t\t\treturn ThinkingLevel.HIGH;\n\t}\n}\n\nfunction getGoogleBudget(model: Model<\"google-generative-ai\">, effort: ClampedReasoningEffort): number {\n\t// See https://ai.google.dev/gemini-api/docs/thinking#set-budget\n\tif (model.id.includes(\"2.5-pro\")) {\n\t\tconst budgets: Record<ClampedReasoningEffort, number> = {\n\t\t\tminimal: 128,\n\t\t\tlow: 2048,\n\t\t\tmedium: 8192,\n\t\t\thigh: 32768,\n\t\t};\n\t\treturn budgets[effort];\n\t}\n\n\tif (model.id.includes(\"2.5-flash\")) {\n\t\t// Covers 2.5-flash-lite as well\n\t\tconst budgets: Record<ClampedReasoningEffort, number> = {\n\t\t\tminimal: 128,\n\t\t\tlow: 2048,\n\t\t\tmedium: 8192,\n\t\t\thigh: 24576,\n\t\t};\n\t\treturn budgets[effort];\n\t}\n\n\t// Unknown model - use dynamic\n\treturn -1;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"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","sourcesContent":["import { ThinkingLevel } from \"@google/genai\";\nimport { supportsXhigh } from \"./models.js\";\nimport { type AnthropicOptions, streamAnthropic } from \"./providers/anthropic.js\";\nimport { type GoogleOptions, streamGoogle } from \"./providers/google.js\";\nimport { type GoogleGeminiCliOptions, streamGoogleGeminiCli } from \"./providers/google-gemini-cli.js\";\nimport { type OpenAICompletionsOptions, streamOpenAICompletions } from \"./providers/openai-completions.js\";\nimport { type OpenAIResponsesOptions, streamOpenAIResponses } from \"./providers/openai-responses.js\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tAssistantMessageEventStream,\n\tContext,\n\tKnownProvider,\n\tModel,\n\tOptionsForApi,\n\tReasoningEffort,\n\tSimpleStreamOptions,\n} from \"./types.js\";\nimport { getOAuthApiKey, getOAuthProviderForModelProvider } from \"./utils/oauth/index.js\";\n\nconst apiKeys: Map<string, string> = new Map();\n\nexport function setApiKey(provider: KnownProvider, key: string): void;\nexport function setApiKey(provider: string, key: string): void;\nexport function setApiKey(provider: any, key: string): void {\n\tapiKeys.set(provider, key);\n}\n\n/**\n * Get API key from environment variables (sync).\n * Does NOT check OAuth credentials - use getApiKeyAsync for that.\n */\nexport function getApiKey(provider: KnownProvider): string | undefined;\nexport function getApiKey(provider: string): string | undefined;\nexport function getApiKey(provider: any): string | undefined {\n\t// Check explicit keys first\n\tconst key = apiKeys.get(provider);\n\tif (key) return key;\n\n\t// Fall back to environment variables\n\tif (provider === \"github-copilot\") {\n\t\treturn process.env.COPILOT_GITHUB_TOKEN || process.env.GH_TOKEN || process.env.GITHUB_TOKEN;\n\t}\n\n\tconst envMap: Record<string, string> = {\n\t\topenai: \"OPENAI_API_KEY\",\n\t\tanthropic: \"ANTHROPIC_API_KEY\",\n\t\tgoogle: \"GEMINI_API_KEY\",\n\t\tgroq: \"GROQ_API_KEY\",\n\t\tcerebras: \"CEREBRAS_API_KEY\",\n\t\txai: \"XAI_API_KEY\",\n\t\topenrouter: \"OPENROUTER_API_KEY\",\n\t\tzai: \"ZAI_API_KEY\",\n\t\tmistral: \"MISTRAL_API_KEY\",\n\t};\n\n\tconst envVar = envMap[provider];\n\treturn envVar ? process.env[envVar] : undefined;\n}\n\n/**\n * Resolve API key from OAuth credentials or environment (async).\n * Automatically refreshes expired OAuth tokens.\n *\n * Priority:\n * 1. Explicitly set keys (via setApiKey)\n * 2. OAuth credentials from ~/.pi/agent/oauth.json\n * 3. Environment variables\n */\nexport async function resolveApiKey(provider: KnownProvider): Promise<string | undefined>;\nexport async function resolveApiKey(provider: string): Promise<string | undefined>;\nexport async function resolveApiKey(provider: any): Promise<string | undefined> {\n\t// Check explicit keys first\n\tconst key = apiKeys.get(provider);\n\tif (key) return key;\n\n\t// Check OAuth credentials (auto-refresh if expired)\n\tconst oauthProvider = getOAuthProviderForModelProvider(provider);\n\tif (oauthProvider) {\n\t\tconst oauthKey = await getOAuthApiKey(oauthProvider);\n\t\tif (oauthKey) return oauthKey;\n\t}\n\n\t// Fall back to sync getApiKey for env vars\n\treturn getApiKey(provider);\n}\n\nexport function stream<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: OptionsForApi<TApi>,\n): AssistantMessageEventStream {\n\tconst apiKey = options?.apiKey || getApiKey(model.provider);\n\tif (!apiKey) {\n\t\tthrow new Error(`No API key for provider: ${model.provider}`);\n\t}\n\tconst providerOptions = { ...options, apiKey };\n\n\tconst api: Api = model.api;\n\tswitch (api) {\n\t\tcase \"anthropic-messages\":\n\t\t\treturn streamAnthropic(model as Model<\"anthropic-messages\">, context, providerOptions);\n\n\t\tcase \"openai-completions\":\n\t\t\treturn streamOpenAICompletions(model as Model<\"openai-completions\">, context, providerOptions as any);\n\n\t\tcase \"openai-responses\":\n\t\t\treturn streamOpenAIResponses(model as Model<\"openai-responses\">, context, providerOptions as any);\n\n\t\tcase \"google-generative-ai\":\n\t\t\treturn streamGoogle(model as Model<\"google-generative-ai\">, context, providerOptions);\n\n\t\tcase \"google-gemini-cli\":\n\t\t\treturn streamGoogleGeminiCli(\n\t\t\t\tmodel as Model<\"google-gemini-cli\">,\n\t\t\t\tcontext,\n\t\t\t\tproviderOptions as GoogleGeminiCliOptions,\n\t\t\t);\n\n\t\tdefault: {\n\t\t\t// This should never be reached if all Api cases are handled\n\t\t\tconst _exhaustive: never = api;\n\t\t\tthrow new Error(`Unhandled API: ${_exhaustive}`);\n\t\t}\n\t}\n}\n\nexport async function complete<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: OptionsForApi<TApi>,\n): Promise<AssistantMessage> {\n\tconst s = stream(model, context, options);\n\treturn s.result();\n}\n\nexport function streamSimple<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream {\n\tconst apiKey = options?.apiKey || getApiKey(model.provider);\n\tif (!apiKey) {\n\t\tthrow new Error(`No API key for provider: ${model.provider}`);\n\t}\n\n\tconst providerOptions = mapOptionsForApi(model, options, apiKey);\n\treturn stream(model, context, providerOptions);\n}\n\nexport async function completeSimple<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): Promise<AssistantMessage> {\n\tconst s = streamSimple(model, context, options);\n\treturn s.result();\n}\n\nfunction mapOptionsForApi<TApi extends Api>(\n\tmodel: Model<TApi>,\n\toptions?: SimpleStreamOptions,\n\tapiKey?: string,\n): OptionsForApi<TApi> {\n\tconst base = {\n\t\ttemperature: options?.temperature,\n\t\tmaxTokens: options?.maxTokens || Math.min(model.maxTokens, 32000),\n\t\tsignal: options?.signal,\n\t\tapiKey: apiKey || options?.apiKey,\n\t};\n\n\t// Helper to clamp xhigh to high for providers that don't support it\n\tconst clampReasoning = (effort: ReasoningEffort | undefined) => (effort === \"xhigh\" ? \"high\" : effort);\n\n\tswitch (model.api) {\n\t\tcase \"anthropic-messages\": {\n\t\t\t// Explicitly disable thinking when reasoning is not specified\n\t\t\tif (!options?.reasoning) {\n\t\t\t\treturn { ...base, thinkingEnabled: false } satisfies AnthropicOptions;\n\t\t\t}\n\n\t\t\tconst anthropicBudgets = {\n\t\t\t\tminimal: 1024,\n\t\t\t\tlow: 2048,\n\t\t\t\tmedium: 8192,\n\t\t\t\thigh: 16384,\n\t\t\t};\n\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tthinkingEnabled: true,\n\t\t\t\tthinkingBudgetTokens: anthropicBudgets[clampReasoning(options.reasoning)!],\n\t\t\t} satisfies AnthropicOptions;\n\t\t}\n\n\t\tcase \"openai-completions\":\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\treasoningEffort: supportsXhigh(model) ? options?.reasoning : clampReasoning(options?.reasoning),\n\t\t\t} satisfies OpenAICompletionsOptions;\n\n\t\tcase \"openai-responses\":\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\treasoningEffort: supportsXhigh(model) ? options?.reasoning : clampReasoning(options?.reasoning),\n\t\t\t} satisfies OpenAIResponsesOptions;\n\n\t\tcase \"google-generative-ai\": {\n\t\t\t// Explicitly disable thinking when reasoning is not specified\n\t\t\t// This is needed because Gemini has \"dynamic thinking\" enabled by default\n\t\t\tif (!options?.reasoning) {\n\t\t\t\treturn { ...base, thinking: { enabled: false } } satisfies GoogleOptions;\n\t\t\t}\n\n\t\t\tconst googleModel = model as Model<\"google-generative-ai\">;\n\t\t\tconst effort = clampReasoning(options.reasoning)!;\n\n\t\t\t// Gemini 3 models use thinkingLevel exclusively instead of thinkingBudget.\n\t\t\t// https://ai.google.dev/gemini-api/docs/thinking#set-budget\n\t\t\tif (isGemini3ProModel(googleModel) || isGemini3FlashModel(googleModel)) {\n\t\t\t\treturn {\n\t\t\t\t\t...base,\n\t\t\t\t\tthinking: {\n\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t\tlevel: getGemini3ThinkingLevel(effort, googleModel),\n\t\t\t\t\t},\n\t\t\t\t} satisfies GoogleOptions;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tthinking: {\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tbudgetTokens: getGoogleBudget(googleModel, effort),\n\t\t\t\t},\n\t\t\t} satisfies GoogleOptions;\n\t\t}\n\n\t\tcase \"google-gemini-cli\": {\n\t\t\t// Cloud Code Assist uses thinking budget tokens like Gemini 2.5\n\t\t\tif (!options?.reasoning) {\n\t\t\t\treturn { ...base, thinking: { enabled: false } } satisfies GoogleGeminiCliOptions;\n\t\t\t}\n\n\t\t\tconst effort = clampReasoning(options.reasoning)!;\n\t\t\tconst budgets: Record<ClampedReasoningEffort, number> = {\n\t\t\t\tminimal: 1024,\n\t\t\t\tlow: 2048,\n\t\t\t\tmedium: 8192,\n\t\t\t\thigh: 16384,\n\t\t\t};\n\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tthinking: {\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tbudgetTokens: budgets[effort],\n\t\t\t\t},\n\t\t\t} satisfies GoogleGeminiCliOptions;\n\t\t}\n\n\t\tdefault: {\n\t\t\t// Exhaustiveness check\n\t\t\tconst _exhaustive: never = model.api;\n\t\t\tthrow new Error(`Unhandled API in mapOptionsForApi: ${_exhaustive}`);\n\t\t}\n\t}\n}\n\ntype ClampedReasoningEffort = Exclude<ReasoningEffort, \"xhigh\">;\n\nfunction isGemini3ProModel(model: Model<\"google-generative-ai\">): boolean {\n\t// Covers gemini-3-pro, gemini-3-pro-preview, and possible other prefixed ids in the future\n\treturn model.id.includes(\"3-pro\");\n}\n\nfunction isGemini3FlashModel(model: Model<\"google-generative-ai\">): boolean {\n\t// Covers gemini-3-flash, gemini-3-flash-preview, and possible other prefixed ids in the future\n\treturn model.id.includes(\"3-flash\");\n}\n\nfunction getGemini3ThinkingLevel(effort: ClampedReasoningEffort, model: Model<\"google-generative-ai\">): ThinkingLevel {\n\tif (isGemini3ProModel(model)) {\n\t\t// Gemini 3 Pro only supports LOW/HIGH (for now)\n\t\tswitch (effort) {\n\t\t\tcase \"minimal\":\n\t\t\tcase \"low\":\n\t\t\t\treturn ThinkingLevel.LOW;\n\t\t\tcase \"medium\":\n\t\t\tcase \"high\":\n\t\t\t\treturn ThinkingLevel.HIGH;\n\t\t}\n\t}\n\t// Gemini 3 Flash supports all four levels\n\tswitch (effort) {\n\t\tcase \"minimal\":\n\t\t\treturn ThinkingLevel.MINIMAL;\n\t\tcase \"low\":\n\t\t\treturn ThinkingLevel.LOW;\n\t\tcase \"medium\":\n\t\t\treturn ThinkingLevel.MEDIUM;\n\t\tcase \"high\":\n\t\t\treturn ThinkingLevel.HIGH;\n\t}\n}\n\nfunction getGoogleBudget(model: Model<\"google-generative-ai\">, effort: ClampedReasoningEffort): number {\n\t// See https://ai.google.dev/gemini-api/docs/thinking#set-budget\n\tif (model.id.includes(\"2.5-pro\")) {\n\t\tconst budgets: Record<ClampedReasoningEffort, number> = {\n\t\t\tminimal: 128,\n\t\t\tlow: 2048,\n\t\t\tmedium: 8192,\n\t\t\thigh: 32768,\n\t\t};\n\t\treturn budgets[effort];\n\t}\n\n\tif (model.id.includes(\"2.5-flash\")) {\n\t\t// Covers 2.5-flash-lite as well\n\t\tconst budgets: Record<ClampedReasoningEffort, number> = {\n\t\t\tminimal: 128,\n\t\t\tlow: 2048,\n\t\t\tmedium: 8192,\n\t\t\thigh: 24576,\n\t\t};\n\t\treturn budgets[effort];\n\t}\n\n\t// Unknown model - use dynamic\n\treturn -1;\n}\n"]}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import type { AnthropicOptions } from "./providers/anthropic.js";
|
|
2
2
|
import type { GoogleOptions } from "./providers/google.js";
|
|
3
|
+
import type { GoogleGeminiCliOptions } from "./providers/google-gemini-cli.js";
|
|
3
4
|
import type { OpenAICompletionsOptions } from "./providers/openai-completions.js";
|
|
4
5
|
import type { OpenAIResponsesOptions } from "./providers/openai-responses.js";
|
|
5
6
|
import type { AssistantMessageEventStream } from "./utils/event-stream.js";
|
|
6
7
|
export type { AssistantMessageEventStream } from "./utils/event-stream.js";
|
|
7
|
-
export type Api = "openai-completions" | "openai-responses" | "anthropic-messages" | "google-generative-ai";
|
|
8
|
+
export type Api = "openai-completions" | "openai-responses" | "anthropic-messages" | "google-generative-ai" | "google-gemini-cli";
|
|
8
9
|
export interface ApiOptionsMap {
|
|
9
10
|
"anthropic-messages": AnthropicOptions;
|
|
10
11
|
"openai-completions": OpenAICompletionsOptions;
|
|
11
12
|
"openai-responses": OpenAIResponsesOptions;
|
|
12
13
|
"google-generative-ai": GoogleOptions;
|
|
14
|
+
"google-gemini-cli": GoogleGeminiCliOptions;
|
|
13
15
|
}
|
|
14
16
|
export type OptionsForApi<TApi extends Api> = ApiOptionsMap[TApi];
|
|
15
|
-
export type KnownProvider = "anthropic" | "google" | "openai" | "github-copilot" | "xai" | "groq" | "cerebras" | "openrouter" | "zai" | "mistral";
|
|
17
|
+
export type KnownProvider = "anthropic" | "google" | "google-gemini-cli" | "google-antigravity" | "openai" | "github-copilot" | "xai" | "groq" | "cerebras" | "openrouter" | "zai" | "mistral";
|
|
16
18
|
export type Provider = KnownProvider | string;
|
|
17
19
|
export type ReasoningEffort = "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
18
20
|
export interface StreamOptions {
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AnthropicOptions } from \"./providers/anthropic.js\";\nimport type { GoogleOptions } from \"./providers/google.js\";\nimport type { OpenAICompletionsOptions } from \"./providers/openai-completions.js\";\nimport type { OpenAIResponsesOptions } from \"./providers/openai-responses.js\";\nimport type { AssistantMessageEventStream } from \"./utils/event-stream.js\";\n\nexport type { AssistantMessageEventStream } from \"./utils/event-stream.js\";\n\nexport type Api = \"openai-completions\" | \"openai-responses\" | \"anthropic-messages\" | \"google-generative-ai\";\n\nexport interface ApiOptionsMap {\n\t\"anthropic-messages\": AnthropicOptions;\n\t\"openai-completions\": OpenAICompletionsOptions;\n\t\"openai-responses\": OpenAIResponsesOptions;\n\t\"google-generative-ai\": GoogleOptions;\n}\n\n// Compile-time exhaustiveness check - this will fail if ApiOptionsMap doesn't have all KnownApi keys\ntype _CheckExhaustive = ApiOptionsMap extends Record<Api, StreamOptions>\n\t? Record<Api, StreamOptions> extends ApiOptionsMap\n\t\t? true\n\t\t: [\"ApiOptionsMap is missing some KnownApi values\", Exclude<Api, keyof ApiOptionsMap>]\n\t: [\"ApiOptionsMap doesn't extend Record<KnownApi, StreamOptions>\"];\nconst _exhaustive: _CheckExhaustive = true;\n\n// Helper type to get options for a specific API\nexport type OptionsForApi<TApi extends Api> = ApiOptionsMap[TApi];\n\nexport type KnownProvider =\n\t| \"anthropic\"\n\t| \"google\"\n\t| \"openai\"\n\t| \"github-copilot\"\n\t| \"xai\"\n\t| \"groq\"\n\t| \"cerebras\"\n\t| \"openrouter\"\n\t| \"zai\"\n\t| \"mistral\";\nexport type Provider = KnownProvider | string;\n\nexport type ReasoningEffort = \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\n\n// Base options all providers share\nexport interface StreamOptions {\n\ttemperature?: number;\n\tmaxTokens?: number;\n\tsignal?: AbortSignal;\n\tapiKey?: string;\n}\n\n// Unified options with reasoning passed to streamSimple() and completeSimple()\nexport interface SimpleStreamOptions extends StreamOptions {\n\treasoning?: ReasoningEffort;\n}\n\n// Generic StreamFunction with typed options\nexport type StreamFunction<TApi extends Api> = (\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions: OptionsForApi<TApi>,\n) => AssistantMessageEventStream;\n\nexport interface TextContent {\n\ttype: \"text\";\n\ttext: string;\n\ttextSignature?: string; // e.g., for OpenAI responses, the message ID\n}\n\nexport interface ThinkingContent {\n\ttype: \"thinking\";\n\tthinking: string;\n\tthinkingSignature?: string; // e.g., for OpenAI responses, the reasoning item ID\n}\n\nexport interface ImageContent {\n\ttype: \"image\";\n\tdata: string; // base64 encoded image data\n\tmimeType: string; // e.g., \"image/jpeg\", \"image/png\"\n}\n\nexport interface ToolCall {\n\ttype: \"toolCall\";\n\tid: string;\n\tname: string;\n\targuments: Record<string, any>;\n\tthoughtSignature?: string; // Google-specific: opaque signature for reusing thought context\n}\n\nexport interface Usage {\n\tinput: number;\n\toutput: number;\n\tcacheRead: number;\n\tcacheWrite: number;\n\ttotalTokens: number;\n\tcost: {\n\t\tinput: number;\n\t\toutput: number;\n\t\tcacheRead: number;\n\t\tcacheWrite: number;\n\t\ttotal: number;\n\t};\n}\n\nexport type StopReason = \"stop\" | \"length\" | \"toolUse\" | \"error\" | \"aborted\";\n\nexport interface UserMessage {\n\trole: \"user\";\n\tcontent: string | (TextContent | ImageContent)[];\n\ttimestamp: number; // Unix timestamp in milliseconds\n}\n\nexport interface AssistantMessage {\n\trole: \"assistant\";\n\tcontent: (TextContent | ThinkingContent | ToolCall)[];\n\tapi: Api;\n\tprovider: Provider;\n\tmodel: string;\n\tusage: Usage;\n\tstopReason: StopReason;\n\terrorMessage?: string;\n\ttimestamp: number; // Unix timestamp in milliseconds\n}\n\nexport interface ToolResultMessage<TDetails = any> {\n\trole: \"toolResult\";\n\ttoolCallId: string;\n\ttoolName: string;\n\tcontent: (TextContent | ImageContent)[]; // Supports text and images\n\tdetails?: TDetails;\n\tisError: boolean;\n\ttimestamp: number; // Unix timestamp in milliseconds\n}\n\nexport type Message = UserMessage | AssistantMessage | ToolResultMessage;\n\nimport type { TSchema } from \"@sinclair/typebox\";\n\nexport interface Tool<TParameters extends TSchema = TSchema> {\n\tname: string;\n\tdescription: string;\n\tparameters: TParameters;\n}\n\nexport interface Context {\n\tsystemPrompt?: string;\n\tmessages: Message[];\n\ttools?: Tool[];\n}\n\nexport type AssistantMessageEvent =\n\t| { type: \"start\"; partial: AssistantMessage }\n\t| { type: \"text_start\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"text_delta\"; contentIndex: number; delta: string; partial: AssistantMessage }\n\t| { type: \"text_end\"; contentIndex: number; content: string; partial: AssistantMessage }\n\t| { type: \"thinking_start\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"thinking_delta\"; contentIndex: number; delta: string; partial: AssistantMessage }\n\t| { type: \"thinking_end\"; contentIndex: number; content: string; partial: AssistantMessage }\n\t| { type: \"toolcall_start\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"toolcall_delta\"; contentIndex: number; delta: string; partial: AssistantMessage }\n\t| { type: \"toolcall_end\"; contentIndex: number; toolCall: ToolCall; partial: AssistantMessage }\n\t| { type: \"done\"; reason: Extract<StopReason, \"stop\" | \"length\" | \"toolUse\">; message: AssistantMessage }\n\t| { type: \"error\"; reason: Extract<StopReason, \"aborted\" | \"error\">; error: AssistantMessage };\n\n/**\n * Compatibility settings for openai-completions API.\n * Use this to override URL-based auto-detection for custom providers.\n */\nexport interface OpenAICompat {\n\t/** Whether the provider supports the `store` field. Default: auto-detected from URL. */\n\tsupportsStore?: boolean;\n\t/** Whether the provider supports the `developer` role (vs `system`). Default: auto-detected from URL. */\n\tsupportsDeveloperRole?: boolean;\n\t/** Whether the provider supports `reasoning_effort`. Default: auto-detected from URL. */\n\tsupportsReasoningEffort?: boolean;\n\t/** Which field to use for max tokens. Default: auto-detected from URL. */\n\tmaxTokensField?: \"max_completion_tokens\" | \"max_tokens\";\n\t/** Whether tool results require the `name` field. Default: auto-detected from URL. */\n\trequiresToolResultName?: boolean;\n\t/** Whether a user message after tool results requires an assistant message in between. Default: auto-detected from URL. */\n\trequiresAssistantAfterToolResult?: boolean;\n\t/** Whether thinking blocks must be converted to text blocks with <thinking> delimiters. Default: auto-detected from URL. */\n\trequiresThinkingAsText?: boolean;\n\t/** Whether tool call IDs must be normalized to Mistral format (exactly 9 alphanumeric chars). Default: auto-detected from URL. */\n\trequiresMistralToolIds?: boolean;\n}\n\n// Model interface for the unified model system\nexport interface Model<TApi extends Api> {\n\tid: string;\n\tname: string;\n\tapi: TApi;\n\tprovider: Provider;\n\tbaseUrl: string;\n\treasoning: boolean;\n\tinput: (\"text\" | \"image\")[];\n\tcost: {\n\t\tinput: number; // $/million tokens\n\t\toutput: number; // $/million tokens\n\t\tcacheRead: number; // $/million tokens\n\t\tcacheWrite: number; // $/million tokens\n\t};\n\tcontextWindow: number;\n\tmaxTokens: number;\n\theaders?: Record<string, string>;\n\t/** Compatibility overrides for openai-completions API. If not set, auto-detected from baseUrl. */\n\tcompat?: TApi extends \"openai-completions\" ? OpenAICompat : never;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAClF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAC9E,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAE3E,YAAY,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAE3E,MAAM,MAAM,GAAG,GACZ,oBAAoB,GACpB,kBAAkB,GAClB,oBAAoB,GACpB,sBAAsB,GACtB,mBAAmB,CAAC;AAEvB,MAAM,WAAW,aAAa;IAC7B,oBAAoB,EAAE,gBAAgB,CAAC;IACvC,oBAAoB,EAAE,wBAAwB,CAAC;IAC/C,kBAAkB,EAAE,sBAAsB,CAAC;IAC3C,sBAAsB,EAAE,aAAa,CAAC;IACtC,mBAAmB,EAAE,sBAAsB,CAAC;CAC5C;AAWD,MAAM,MAAM,aAAa,CAAC,IAAI,SAAS,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC;AAElE,MAAM,MAAM,aAAa,GACtB,WAAW,GACX,QAAQ,GACR,mBAAmB,GACnB,oBAAoB,GACpB,QAAQ,GACR,gBAAgB,GAChB,KAAK,GACL,MAAM,GACN,UAAU,GACV,YAAY,GACZ,KAAK,GACL,SAAS,CAAC;AACb,MAAM,MAAM,QAAQ,GAAG,aAAa,GAAG,MAAM,CAAC;AAE9C,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;AAG9E,MAAM,WAAW,aAAa;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAGD,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACzD,SAAS,CAAC,EAAE,eAAe,CAAC;CAC5B;AAGD,MAAM,MAAM,cAAc,CAAC,IAAI,SAAS,GAAG,IAAI,CAC9C,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,KACxB,2BAA2B,CAAC;AAEjC,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACxB,IAAI,EAAE,UAAU,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC/B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,KAAK;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;KACd,CAAC;CACF;AAED,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;AAE7E,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,CAAC,WAAW,GAAG,YAAY,CAAC,EAAE,CAAC;IACjD,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,CAAC,WAAW,GAAG,eAAe,GAAG,QAAQ,CAAC,EAAE,CAAC;IACtD,GAAG,EAAE,GAAG,CAAC;IACT,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;IACb,UAAU,EAAE,UAAU,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB,CAAC,QAAQ,GAAG,GAAG;IAChD,IAAI,EAAE,YAAY,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,CAAC,WAAW,GAAG,YAAY,CAAC,EAAE,CAAC;IACxC,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,OAAO,GAAG,WAAW,GAAG,gBAAgB,GAAG,iBAAiB,CAAC;AAEzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD,MAAM,WAAW,IAAI,CAAC,WAAW,SAAS,OAAO,GAAG,OAAO;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,WAAW,CAAC;CACxB;AAED,MAAM,WAAW,OAAO;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;CACf;AAED,MAAM,MAAM,qBAAqB,GAC9B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,GACvE;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,GACtF;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,GACtF;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,GAC3E;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,GAC1F;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,GAC1F;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,GAC3E;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,GAC1F;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,GAC7F;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC,CAAC;IAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,GACvG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,SAAS,GAAG,OAAO,CAAC,CAAC;IAAC,KAAK,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAEhG;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC5B,wFAAwF;IACxF,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,yGAAyG;IACzG,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,yFAAyF;IACzF,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,0EAA0E;IAC1E,cAAc,CAAC,EAAE,uBAAuB,GAAG,YAAY,CAAC;IACxD,sFAAsF;IACtF,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,2HAA2H;IAC3H,gCAAgC,CAAC,EAAE,OAAO,CAAC;IAC3C,4HAA4H;IAC5H,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,kIAAkI;IAClI,sBAAsB,CAAC,EAAE,OAAO,CAAC;CACjC;AAGD,MAAM,WAAW,KAAK,CAAC,IAAI,SAAS,GAAG;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,IAAI,CAAC;IACV,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,CAAC,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;IAC5B,IAAI,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,kGAAkG;IAClG,MAAM,CAAC,EAAE,IAAI,SAAS,oBAAoB,GAAG,YAAY,GAAG,KAAK,CAAC;CAClE","sourcesContent":["import type { AnthropicOptions } from \"./providers/anthropic.js\";\nimport type { GoogleOptions } from \"./providers/google.js\";\nimport type { GoogleGeminiCliOptions } from \"./providers/google-gemini-cli.js\";\nimport type { OpenAICompletionsOptions } from \"./providers/openai-completions.js\";\nimport type { OpenAIResponsesOptions } from \"./providers/openai-responses.js\";\nimport type { AssistantMessageEventStream } from \"./utils/event-stream.js\";\n\nexport type { AssistantMessageEventStream } from \"./utils/event-stream.js\";\n\nexport type Api =\n\t| \"openai-completions\"\n\t| \"openai-responses\"\n\t| \"anthropic-messages\"\n\t| \"google-generative-ai\"\n\t| \"google-gemini-cli\";\n\nexport interface ApiOptionsMap {\n\t\"anthropic-messages\": AnthropicOptions;\n\t\"openai-completions\": OpenAICompletionsOptions;\n\t\"openai-responses\": OpenAIResponsesOptions;\n\t\"google-generative-ai\": GoogleOptions;\n\t\"google-gemini-cli\": GoogleGeminiCliOptions;\n}\n\n// Compile-time exhaustiveness check - this will fail if ApiOptionsMap doesn't have all KnownApi keys\ntype _CheckExhaustive = ApiOptionsMap extends Record<Api, StreamOptions>\n\t? Record<Api, StreamOptions> extends ApiOptionsMap\n\t\t? true\n\t\t: [\"ApiOptionsMap is missing some KnownApi values\", Exclude<Api, keyof ApiOptionsMap>]\n\t: [\"ApiOptionsMap doesn't extend Record<KnownApi, StreamOptions>\"];\nconst _exhaustive: _CheckExhaustive = true;\n\n// Helper type to get options for a specific API\nexport type OptionsForApi<TApi extends Api> = ApiOptionsMap[TApi];\n\nexport type KnownProvider =\n\t| \"anthropic\"\n\t| \"google\"\n\t| \"google-gemini-cli\"\n\t| \"google-antigravity\"\n\t| \"openai\"\n\t| \"github-copilot\"\n\t| \"xai\"\n\t| \"groq\"\n\t| \"cerebras\"\n\t| \"openrouter\"\n\t| \"zai\"\n\t| \"mistral\";\nexport type Provider = KnownProvider | string;\n\nexport type ReasoningEffort = \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\n\n// Base options all providers share\nexport interface StreamOptions {\n\ttemperature?: number;\n\tmaxTokens?: number;\n\tsignal?: AbortSignal;\n\tapiKey?: string;\n}\n\n// Unified options with reasoning passed to streamSimple() and completeSimple()\nexport interface SimpleStreamOptions extends StreamOptions {\n\treasoning?: ReasoningEffort;\n}\n\n// Generic StreamFunction with typed options\nexport type StreamFunction<TApi extends Api> = (\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions: OptionsForApi<TApi>,\n) => AssistantMessageEventStream;\n\nexport interface TextContent {\n\ttype: \"text\";\n\ttext: string;\n\ttextSignature?: string; // e.g., for OpenAI responses, the message ID\n}\n\nexport interface ThinkingContent {\n\ttype: \"thinking\";\n\tthinking: string;\n\tthinkingSignature?: string; // e.g., for OpenAI responses, the reasoning item ID\n}\n\nexport interface ImageContent {\n\ttype: \"image\";\n\tdata: string; // base64 encoded image data\n\tmimeType: string; // e.g., \"image/jpeg\", \"image/png\"\n}\n\nexport interface ToolCall {\n\ttype: \"toolCall\";\n\tid: string;\n\tname: string;\n\targuments: Record<string, any>;\n\tthoughtSignature?: string; // Google-specific: opaque signature for reusing thought context\n}\n\nexport interface Usage {\n\tinput: number;\n\toutput: number;\n\tcacheRead: number;\n\tcacheWrite: number;\n\ttotalTokens: number;\n\tcost: {\n\t\tinput: number;\n\t\toutput: number;\n\t\tcacheRead: number;\n\t\tcacheWrite: number;\n\t\ttotal: number;\n\t};\n}\n\nexport type StopReason = \"stop\" | \"length\" | \"toolUse\" | \"error\" | \"aborted\";\n\nexport interface UserMessage {\n\trole: \"user\";\n\tcontent: string | (TextContent | ImageContent)[];\n\ttimestamp: number; // Unix timestamp in milliseconds\n}\n\nexport interface AssistantMessage {\n\trole: \"assistant\";\n\tcontent: (TextContent | ThinkingContent | ToolCall)[];\n\tapi: Api;\n\tprovider: Provider;\n\tmodel: string;\n\tusage: Usage;\n\tstopReason: StopReason;\n\terrorMessage?: string;\n\ttimestamp: number; // Unix timestamp in milliseconds\n}\n\nexport interface ToolResultMessage<TDetails = any> {\n\trole: \"toolResult\";\n\ttoolCallId: string;\n\ttoolName: string;\n\tcontent: (TextContent | ImageContent)[]; // Supports text and images\n\tdetails?: TDetails;\n\tisError: boolean;\n\ttimestamp: number; // Unix timestamp in milliseconds\n}\n\nexport type Message = UserMessage | AssistantMessage | ToolResultMessage;\n\nimport type { TSchema } from \"@sinclair/typebox\";\n\nexport interface Tool<TParameters extends TSchema = TSchema> {\n\tname: string;\n\tdescription: string;\n\tparameters: TParameters;\n}\n\nexport interface Context {\n\tsystemPrompt?: string;\n\tmessages: Message[];\n\ttools?: Tool[];\n}\n\nexport type AssistantMessageEvent =\n\t| { type: \"start\"; partial: AssistantMessage }\n\t| { type: \"text_start\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"text_delta\"; contentIndex: number; delta: string; partial: AssistantMessage }\n\t| { type: \"text_end\"; contentIndex: number; content: string; partial: AssistantMessage }\n\t| { type: \"thinking_start\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"thinking_delta\"; contentIndex: number; delta: string; partial: AssistantMessage }\n\t| { type: \"thinking_end\"; contentIndex: number; content: string; partial: AssistantMessage }\n\t| { type: \"toolcall_start\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"toolcall_delta\"; contentIndex: number; delta: string; partial: AssistantMessage }\n\t| { type: \"toolcall_end\"; contentIndex: number; toolCall: ToolCall; partial: AssistantMessage }\n\t| { type: \"done\"; reason: Extract<StopReason, \"stop\" | \"length\" | \"toolUse\">; message: AssistantMessage }\n\t| { type: \"error\"; reason: Extract<StopReason, \"aborted\" | \"error\">; error: AssistantMessage };\n\n/**\n * Compatibility settings for openai-completions API.\n * Use this to override URL-based auto-detection for custom providers.\n */\nexport interface OpenAICompat {\n\t/** Whether the provider supports the `store` field. Default: auto-detected from URL. */\n\tsupportsStore?: boolean;\n\t/** Whether the provider supports the `developer` role (vs `system`). Default: auto-detected from URL. */\n\tsupportsDeveloperRole?: boolean;\n\t/** Whether the provider supports `reasoning_effort`. Default: auto-detected from URL. */\n\tsupportsReasoningEffort?: boolean;\n\t/** Which field to use for max tokens. Default: auto-detected from URL. */\n\tmaxTokensField?: \"max_completion_tokens\" | \"max_tokens\";\n\t/** Whether tool results require the `name` field. Default: auto-detected from URL. */\n\trequiresToolResultName?: boolean;\n\t/** Whether a user message after tool results requires an assistant message in between. Default: auto-detected from URL. */\n\trequiresAssistantAfterToolResult?: boolean;\n\t/** Whether thinking blocks must be converted to text blocks with <thinking> delimiters. Default: auto-detected from URL. */\n\trequiresThinkingAsText?: boolean;\n\t/** Whether tool call IDs must be normalized to Mistral format (exactly 9 alphanumeric chars). Default: auto-detected from URL. */\n\trequiresMistralToolIds?: boolean;\n}\n\n// Model interface for the unified model system\nexport interface Model<TApi extends Api> {\n\tid: string;\n\tname: string;\n\tapi: TApi;\n\tprovider: Provider;\n\tbaseUrl: string;\n\treasoning: boolean;\n\tinput: (\"text\" | \"image\")[];\n\tcost: {\n\t\tinput: number; // $/million tokens\n\t\toutput: number; // $/million tokens\n\t\tcacheRead: number; // $/million tokens\n\t\tcacheWrite: number; // $/million tokens\n\t};\n\tcontextWindow: number;\n\tmaxTokens: number;\n\theaders?: Record<string, string>;\n\t/** Compatibility overrides for openai-completions API. If not set, auto-detected from baseUrl. */\n\tcompat?: TApi extends \"openai-completions\" ? OpenAICompat : never;\n}\n"]}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA8BA,MAAM,WAAW,GAAqB,IAAI,CAAC","sourcesContent":["import type { AnthropicOptions } from \"./providers/anthropic.js\";\nimport type { GoogleOptions } from \"./providers/google.js\";\nimport type { GoogleGeminiCliOptions } from \"./providers/google-gemini-cli.js\";\nimport type { OpenAICompletionsOptions } from \"./providers/openai-completions.js\";\nimport type { OpenAIResponsesOptions } from \"./providers/openai-responses.js\";\nimport type { AssistantMessageEventStream } from \"./utils/event-stream.js\";\n\nexport type { AssistantMessageEventStream } from \"./utils/event-stream.js\";\n\nexport type Api =\n\t| \"openai-completions\"\n\t| \"openai-responses\"\n\t| \"anthropic-messages\"\n\t| \"google-generative-ai\"\n\t| \"google-gemini-cli\";\n\nexport interface ApiOptionsMap {\n\t\"anthropic-messages\": AnthropicOptions;\n\t\"openai-completions\": OpenAICompletionsOptions;\n\t\"openai-responses\": OpenAIResponsesOptions;\n\t\"google-generative-ai\": GoogleOptions;\n\t\"google-gemini-cli\": GoogleGeminiCliOptions;\n}\n\n// Compile-time exhaustiveness check - this will fail if ApiOptionsMap doesn't have all KnownApi keys\ntype _CheckExhaustive = ApiOptionsMap extends Record<Api, StreamOptions>\n\t? Record<Api, StreamOptions> extends ApiOptionsMap\n\t\t? true\n\t\t: [\"ApiOptionsMap is missing some KnownApi values\", Exclude<Api, keyof ApiOptionsMap>]\n\t: [\"ApiOptionsMap doesn't extend Record<KnownApi, StreamOptions>\"];\nconst _exhaustive: _CheckExhaustive = true;\n\n// Helper type to get options for a specific API\nexport type OptionsForApi<TApi extends Api> = ApiOptionsMap[TApi];\n\nexport type KnownProvider =\n\t| \"anthropic\"\n\t| \"google\"\n\t| \"google-gemini-cli\"\n\t| \"google-antigravity\"\n\t| \"openai\"\n\t| \"github-copilot\"\n\t| \"xai\"\n\t| \"groq\"\n\t| \"cerebras\"\n\t| \"openrouter\"\n\t| \"zai\"\n\t| \"mistral\";\nexport type Provider = KnownProvider | string;\n\nexport type ReasoningEffort = \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\n\n// Base options all providers share\nexport interface StreamOptions {\n\ttemperature?: number;\n\tmaxTokens?: number;\n\tsignal?: AbortSignal;\n\tapiKey?: string;\n}\n\n// Unified options with reasoning passed to streamSimple() and completeSimple()\nexport interface SimpleStreamOptions extends StreamOptions {\n\treasoning?: ReasoningEffort;\n}\n\n// Generic StreamFunction with typed options\nexport type StreamFunction<TApi extends Api> = (\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions: OptionsForApi<TApi>,\n) => AssistantMessageEventStream;\n\nexport interface TextContent {\n\ttype: \"text\";\n\ttext: string;\n\ttextSignature?: string; // e.g., for OpenAI responses, the message ID\n}\n\nexport interface ThinkingContent {\n\ttype: \"thinking\";\n\tthinking: string;\n\tthinkingSignature?: string; // e.g., for OpenAI responses, the reasoning item ID\n}\n\nexport interface ImageContent {\n\ttype: \"image\";\n\tdata: string; // base64 encoded image data\n\tmimeType: string; // e.g., \"image/jpeg\", \"image/png\"\n}\n\nexport interface ToolCall {\n\ttype: \"toolCall\";\n\tid: string;\n\tname: string;\n\targuments: Record<string, any>;\n\tthoughtSignature?: string; // Google-specific: opaque signature for reusing thought context\n}\n\nexport interface Usage {\n\tinput: number;\n\toutput: number;\n\tcacheRead: number;\n\tcacheWrite: number;\n\ttotalTokens: number;\n\tcost: {\n\t\tinput: number;\n\t\toutput: number;\n\t\tcacheRead: number;\n\t\tcacheWrite: number;\n\t\ttotal: number;\n\t};\n}\n\nexport type StopReason = \"stop\" | \"length\" | \"toolUse\" | \"error\" | \"aborted\";\n\nexport interface UserMessage {\n\trole: \"user\";\n\tcontent: string | (TextContent | ImageContent)[];\n\ttimestamp: number; // Unix timestamp in milliseconds\n}\n\nexport interface AssistantMessage {\n\trole: \"assistant\";\n\tcontent: (TextContent | ThinkingContent | ToolCall)[];\n\tapi: Api;\n\tprovider: Provider;\n\tmodel: string;\n\tusage: Usage;\n\tstopReason: StopReason;\n\terrorMessage?: string;\n\ttimestamp: number; // Unix timestamp in milliseconds\n}\n\nexport interface ToolResultMessage<TDetails = any> {\n\trole: \"toolResult\";\n\ttoolCallId: string;\n\ttoolName: string;\n\tcontent: (TextContent | ImageContent)[]; // Supports text and images\n\tdetails?: TDetails;\n\tisError: boolean;\n\ttimestamp: number; // Unix timestamp in milliseconds\n}\n\nexport type Message = UserMessage | AssistantMessage | ToolResultMessage;\n\nimport type { TSchema } from \"@sinclair/typebox\";\n\nexport interface Tool<TParameters extends TSchema = TSchema> {\n\tname: string;\n\tdescription: string;\n\tparameters: TParameters;\n}\n\nexport interface Context {\n\tsystemPrompt?: string;\n\tmessages: Message[];\n\ttools?: Tool[];\n}\n\nexport type AssistantMessageEvent =\n\t| { type: \"start\"; partial: AssistantMessage }\n\t| { type: \"text_start\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"text_delta\"; contentIndex: number; delta: string; partial: AssistantMessage }\n\t| { type: \"text_end\"; contentIndex: number; content: string; partial: AssistantMessage }\n\t| { type: \"thinking_start\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"thinking_delta\"; contentIndex: number; delta: string; partial: AssistantMessage }\n\t| { type: \"thinking_end\"; contentIndex: number; content: string; partial: AssistantMessage }\n\t| { type: \"toolcall_start\"; contentIndex: number; partial: AssistantMessage }\n\t| { type: \"toolcall_delta\"; contentIndex: number; delta: string; partial: AssistantMessage }\n\t| { type: \"toolcall_end\"; contentIndex: number; toolCall: ToolCall; partial: AssistantMessage }\n\t| { type: \"done\"; reason: Extract<StopReason, \"stop\" | \"length\" | \"toolUse\">; message: AssistantMessage }\n\t| { type: \"error\"; reason: Extract<StopReason, \"aborted\" | \"error\">; error: AssistantMessage };\n\n/**\n * Compatibility settings for openai-completions API.\n * Use this to override URL-based auto-detection for custom providers.\n */\nexport interface OpenAICompat {\n\t/** Whether the provider supports the `store` field. Default: auto-detected from URL. */\n\tsupportsStore?: boolean;\n\t/** Whether the provider supports the `developer` role (vs `system`). Default: auto-detected from URL. */\n\tsupportsDeveloperRole?: boolean;\n\t/** Whether the provider supports `reasoning_effort`. Default: auto-detected from URL. */\n\tsupportsReasoningEffort?: boolean;\n\t/** Which field to use for max tokens. Default: auto-detected from URL. */\n\tmaxTokensField?: \"max_completion_tokens\" | \"max_tokens\";\n\t/** Whether tool results require the `name` field. Default: auto-detected from URL. */\n\trequiresToolResultName?: boolean;\n\t/** Whether a user message after tool results requires an assistant message in between. Default: auto-detected from URL. */\n\trequiresAssistantAfterToolResult?: boolean;\n\t/** Whether thinking blocks must be converted to text blocks with <thinking> delimiters. Default: auto-detected from URL. */\n\trequiresThinkingAsText?: boolean;\n\t/** Whether tool call IDs must be normalized to Mistral format (exactly 9 alphanumeric chars). Default: auto-detected from URL. */\n\trequiresMistralToolIds?: boolean;\n}\n\n// Model interface for the unified model system\nexport interface Model<TApi extends Api> {\n\tid: string;\n\tname: string;\n\tapi: TApi;\n\tprovider: Provider;\n\tbaseUrl: string;\n\treasoning: boolean;\n\tinput: (\"text\" | \"image\")[];\n\tcost: {\n\t\tinput: number; // $/million tokens\n\t\toutput: number; // $/million tokens\n\t\tcacheRead: number; // $/million tokens\n\t\tcacheWrite: number; // $/million tokens\n\t};\n\tcontextWindow: number;\n\tmaxTokens: number;\n\theaders?: Record<string, string>;\n\t/** Compatibility overrides for openai-completions API. If not set, auto-detected from baseUrl. */\n\tcompat?: TApi extends \"openai-completions\" ? OpenAICompat : never;\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anthropic OAuth flow (Claude Pro/Max)
|
|
3
|
+
*/
|
|
4
|
+
import { type OAuthCredentials } from "./storage.js";
|
|
5
|
+
/**
|
|
6
|
+
* Login with Anthropic OAuth (device code flow)
|
|
7
|
+
*
|
|
8
|
+
* @param onAuthUrl - Callback to handle the authorization URL (e.g., open browser)
|
|
9
|
+
* @param onPromptCode - Callback to prompt user for the authorization code
|
|
10
|
+
*/
|
|
11
|
+
export declare function loginAnthropic(onAuthUrl: (url: string) => void, onPromptCode: () => Promise<string>): Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Refresh Anthropic OAuth token
|
|
14
|
+
*/
|
|
15
|
+
export declare function refreshAnthropicToken(refreshToken: string): Promise<OAuthCredentials>;
|
|
16
|
+
//# sourceMappingURL=anthropic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../src/utils/oauth/anthropic.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,KAAK,gBAAgB,EAAwB,MAAM,cAAc,CAAC;AAiB3E;;;;;GAKG;AACH,wBAAsB,cAAc,CACnC,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,EAChC,YAAY,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,GACjC,OAAO,CAAC,IAAI,CAAC,CAiEf;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA4B3F","sourcesContent":["/**\n * Anthropic OAuth flow (Claude Pro/Max)\n */\n\nimport { createHash, randomBytes } from \"crypto\";\nimport { type OAuthCredentials, saveOAuthCredentials } from \"./storage.js\";\n\nconst CLIENT_ID = \"9d1c250a-e61b-44d9-88ed-5944d1962f5e\";\nconst AUTHORIZE_URL = \"https://claude.ai/oauth/authorize\";\nconst TOKEN_URL = \"https://console.anthropic.com/v1/oauth/token\";\nconst REDIRECT_URI = \"https://console.anthropic.com/oauth/code/callback\";\nconst SCOPES = \"org:create_api_key user:profile user:inference\";\n\n/**\n * Generate PKCE code verifier and challenge\n */\nfunction generatePKCE(): { verifier: string; challenge: string } {\n\tconst verifier = randomBytes(32).toString(\"base64url\");\n\tconst challenge = createHash(\"sha256\").update(verifier).digest(\"base64url\");\n\treturn { verifier, challenge };\n}\n\n/**\n * Login with Anthropic OAuth (device code flow)\n *\n * @param onAuthUrl - Callback to handle the authorization URL (e.g., open browser)\n * @param onPromptCode - Callback to prompt user for the authorization code\n */\nexport async function loginAnthropic(\n\tonAuthUrl: (url: string) => void,\n\tonPromptCode: () => Promise<string>,\n): Promise<void> {\n\tconst { verifier, challenge } = generatePKCE();\n\n\t// Build authorization URL\n\tconst authParams = new URLSearchParams({\n\t\tcode: \"true\",\n\t\tclient_id: CLIENT_ID,\n\t\tresponse_type: \"code\",\n\t\tredirect_uri: REDIRECT_URI,\n\t\tscope: SCOPES,\n\t\tcode_challenge: challenge,\n\t\tcode_challenge_method: \"S256\",\n\t\tstate: verifier,\n\t});\n\n\tconst authUrl = `${AUTHORIZE_URL}?${authParams.toString()}`;\n\n\t// Notify caller with URL to open\n\tonAuthUrl(authUrl);\n\n\t// Wait for user to paste authorization code (format: code#state)\n\tconst authCode = await onPromptCode();\n\tconst splits = authCode.split(\"#\");\n\tconst code = splits[0];\n\tconst state = splits[1];\n\n\t// Exchange code for tokens\n\tconst tokenResponse = await fetch(TOKEN_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tbody: JSON.stringify({\n\t\t\tgrant_type: \"authorization_code\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tcode: code,\n\t\t\tstate: state,\n\t\t\tredirect_uri: REDIRECT_URI,\n\t\t\tcode_verifier: verifier,\n\t\t}),\n\t});\n\n\tif (!tokenResponse.ok) {\n\t\tconst error = await tokenResponse.text();\n\t\tthrow new Error(`Token exchange failed: ${error}`);\n\t}\n\n\tconst tokenData = (await tokenResponse.json()) as {\n\t\taccess_token: string;\n\t\trefresh_token: string;\n\t\texpires_in: number;\n\t};\n\n\t// Calculate expiry time (current time + expires_in seconds - 5 min buffer)\n\tconst expiresAt = Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000;\n\n\t// Save credentials\n\tconst credentials: OAuthCredentials = {\n\t\ttype: \"oauth\",\n\t\trefresh: tokenData.refresh_token,\n\t\taccess: tokenData.access_token,\n\t\texpires: expiresAt,\n\t};\n\n\tsaveOAuthCredentials(\"anthropic\", credentials);\n}\n\n/**\n * Refresh Anthropic OAuth token\n */\nexport async function refreshAnthropicToken(refreshToken: string): Promise<OAuthCredentials> {\n\tconst response = await fetch(TOKEN_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\tbody: JSON.stringify({\n\t\t\tgrant_type: \"refresh_token\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\trefresh_token: refreshToken,\n\t\t}),\n\t});\n\n\tif (!response.ok) {\n\t\tconst error = await response.text();\n\t\tthrow new Error(`Anthropic token refresh failed: ${error}`);\n\t}\n\n\tconst data = (await response.json()) as {\n\t\taccess_token: string;\n\t\trefresh_token: string;\n\t\texpires_in: number;\n\t};\n\n\treturn {\n\t\ttype: \"oauth\",\n\t\trefresh: data.refresh_token,\n\t\taccess: data.access_token,\n\t\texpires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,\n\t};\n}\n"]}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anthropic OAuth flow (Claude Pro/Max)
|
|
3
|
+
*/
|
|
4
|
+
import { createHash, randomBytes } from "crypto";
|
|
5
|
+
import { saveOAuthCredentials } from "./storage.js";
|
|
6
|
+
const CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
|
|
7
|
+
const AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
|
|
8
|
+
const TOKEN_URL = "https://console.anthropic.com/v1/oauth/token";
|
|
9
|
+
const REDIRECT_URI = "https://console.anthropic.com/oauth/code/callback";
|
|
10
|
+
const SCOPES = "org:create_api_key user:profile user:inference";
|
|
11
|
+
/**
|
|
12
|
+
* Generate PKCE code verifier and challenge
|
|
13
|
+
*/
|
|
14
|
+
function generatePKCE() {
|
|
15
|
+
const verifier = randomBytes(32).toString("base64url");
|
|
16
|
+
const challenge = createHash("sha256").update(verifier).digest("base64url");
|
|
17
|
+
return { verifier, challenge };
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Login with Anthropic OAuth (device code flow)
|
|
21
|
+
*
|
|
22
|
+
* @param onAuthUrl - Callback to handle the authorization URL (e.g., open browser)
|
|
23
|
+
* @param onPromptCode - Callback to prompt user for the authorization code
|
|
24
|
+
*/
|
|
25
|
+
export async function loginAnthropic(onAuthUrl, onPromptCode) {
|
|
26
|
+
const { verifier, challenge } = generatePKCE();
|
|
27
|
+
// Build authorization URL
|
|
28
|
+
const authParams = new URLSearchParams({
|
|
29
|
+
code: "true",
|
|
30
|
+
client_id: CLIENT_ID,
|
|
31
|
+
response_type: "code",
|
|
32
|
+
redirect_uri: REDIRECT_URI,
|
|
33
|
+
scope: SCOPES,
|
|
34
|
+
code_challenge: challenge,
|
|
35
|
+
code_challenge_method: "S256",
|
|
36
|
+
state: verifier,
|
|
37
|
+
});
|
|
38
|
+
const authUrl = `${AUTHORIZE_URL}?${authParams.toString()}`;
|
|
39
|
+
// Notify caller with URL to open
|
|
40
|
+
onAuthUrl(authUrl);
|
|
41
|
+
// Wait for user to paste authorization code (format: code#state)
|
|
42
|
+
const authCode = await onPromptCode();
|
|
43
|
+
const splits = authCode.split("#");
|
|
44
|
+
const code = splits[0];
|
|
45
|
+
const state = splits[1];
|
|
46
|
+
// Exchange code for tokens
|
|
47
|
+
const tokenResponse = await fetch(TOKEN_URL, {
|
|
48
|
+
method: "POST",
|
|
49
|
+
headers: {
|
|
50
|
+
"Content-Type": "application/json",
|
|
51
|
+
},
|
|
52
|
+
body: JSON.stringify({
|
|
53
|
+
grant_type: "authorization_code",
|
|
54
|
+
client_id: CLIENT_ID,
|
|
55
|
+
code: code,
|
|
56
|
+
state: state,
|
|
57
|
+
redirect_uri: REDIRECT_URI,
|
|
58
|
+
code_verifier: verifier,
|
|
59
|
+
}),
|
|
60
|
+
});
|
|
61
|
+
if (!tokenResponse.ok) {
|
|
62
|
+
const error = await tokenResponse.text();
|
|
63
|
+
throw new Error(`Token exchange failed: ${error}`);
|
|
64
|
+
}
|
|
65
|
+
const tokenData = (await tokenResponse.json());
|
|
66
|
+
// Calculate expiry time (current time + expires_in seconds - 5 min buffer)
|
|
67
|
+
const expiresAt = Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000;
|
|
68
|
+
// Save credentials
|
|
69
|
+
const credentials = {
|
|
70
|
+
type: "oauth",
|
|
71
|
+
refresh: tokenData.refresh_token,
|
|
72
|
+
access: tokenData.access_token,
|
|
73
|
+
expires: expiresAt,
|
|
74
|
+
};
|
|
75
|
+
saveOAuthCredentials("anthropic", credentials);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Refresh Anthropic OAuth token
|
|
79
|
+
*/
|
|
80
|
+
export async function refreshAnthropicToken(refreshToken) {
|
|
81
|
+
const response = await fetch(TOKEN_URL, {
|
|
82
|
+
method: "POST",
|
|
83
|
+
headers: { "Content-Type": "application/json" },
|
|
84
|
+
body: JSON.stringify({
|
|
85
|
+
grant_type: "refresh_token",
|
|
86
|
+
client_id: CLIENT_ID,
|
|
87
|
+
refresh_token: refreshToken,
|
|
88
|
+
}),
|
|
89
|
+
});
|
|
90
|
+
if (!response.ok) {
|
|
91
|
+
const error = await response.text();
|
|
92
|
+
throw new Error(`Anthropic token refresh failed: ${error}`);
|
|
93
|
+
}
|
|
94
|
+
const data = (await response.json());
|
|
95
|
+
return {
|
|
96
|
+
type: "oauth",
|
|
97
|
+
refresh: data.refresh_token,
|
|
98
|
+
access: data.access_token,
|
|
99
|
+
expires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=anthropic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/utils/oauth/anthropic.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Anthropic OAuth flow (Claude Pro/Max)\n */\n\nimport { createHash, randomBytes } from \"crypto\";\nimport { type OAuthCredentials, saveOAuthCredentials } from \"./storage.js\";\n\nconst CLIENT_ID = \"9d1c250a-e61b-44d9-88ed-5944d1962f5e\";\nconst AUTHORIZE_URL = \"https://claude.ai/oauth/authorize\";\nconst TOKEN_URL = \"https://console.anthropic.com/v1/oauth/token\";\nconst REDIRECT_URI = \"https://console.anthropic.com/oauth/code/callback\";\nconst SCOPES = \"org:create_api_key user:profile user:inference\";\n\n/**\n * Generate PKCE code verifier and challenge\n */\nfunction generatePKCE(): { verifier: string; challenge: string } {\n\tconst verifier = randomBytes(32).toString(\"base64url\");\n\tconst challenge = createHash(\"sha256\").update(verifier).digest(\"base64url\");\n\treturn { verifier, challenge };\n}\n\n/**\n * Login with Anthropic OAuth (device code flow)\n *\n * @param onAuthUrl - Callback to handle the authorization URL (e.g., open browser)\n * @param onPromptCode - Callback to prompt user for the authorization code\n */\nexport async function loginAnthropic(\n\tonAuthUrl: (url: string) => void,\n\tonPromptCode: () => Promise<string>,\n): Promise<void> {\n\tconst { verifier, challenge } = generatePKCE();\n\n\t// Build authorization URL\n\tconst authParams = new URLSearchParams({\n\t\tcode: \"true\",\n\t\tclient_id: CLIENT_ID,\n\t\tresponse_type: \"code\",\n\t\tredirect_uri: REDIRECT_URI,\n\t\tscope: SCOPES,\n\t\tcode_challenge: challenge,\n\t\tcode_challenge_method: \"S256\",\n\t\tstate: verifier,\n\t});\n\n\tconst authUrl = `${AUTHORIZE_URL}?${authParams.toString()}`;\n\n\t// Notify caller with URL to open\n\tonAuthUrl(authUrl);\n\n\t// Wait for user to paste authorization code (format: code#state)\n\tconst authCode = await onPromptCode();\n\tconst splits = authCode.split(\"#\");\n\tconst code = splits[0];\n\tconst state = splits[1];\n\n\t// Exchange code for tokens\n\tconst tokenResponse = await fetch(TOKEN_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tbody: JSON.stringify({\n\t\t\tgrant_type: \"authorization_code\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tcode: code,\n\t\t\tstate: state,\n\t\t\tredirect_uri: REDIRECT_URI,\n\t\t\tcode_verifier: verifier,\n\t\t}),\n\t});\n\n\tif (!tokenResponse.ok) {\n\t\tconst error = await tokenResponse.text();\n\t\tthrow new Error(`Token exchange failed: ${error}`);\n\t}\n\n\tconst tokenData = (await tokenResponse.json()) as {\n\t\taccess_token: string;\n\t\trefresh_token: string;\n\t\texpires_in: number;\n\t};\n\n\t// Calculate expiry time (current time + expires_in seconds - 5 min buffer)\n\tconst expiresAt = Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000;\n\n\t// Save credentials\n\tconst credentials: OAuthCredentials = {\n\t\ttype: \"oauth\",\n\t\trefresh: tokenData.refresh_token,\n\t\taccess: tokenData.access_token,\n\t\texpires: expiresAt,\n\t};\n\n\tsaveOAuthCredentials(\"anthropic\", credentials);\n}\n\n/**\n * Refresh Anthropic OAuth token\n */\nexport async function refreshAnthropicToken(refreshToken: string): Promise<OAuthCredentials> {\n\tconst response = await fetch(TOKEN_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\tbody: JSON.stringify({\n\t\t\tgrant_type: \"refresh_token\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\trefresh_token: refreshToken,\n\t\t}),\n\t});\n\n\tif (!response.ok) {\n\t\tconst error = await response.text();\n\t\tthrow new Error(`Anthropic token refresh failed: ${error}`);\n\t}\n\n\tconst data = (await response.json()) as {\n\t\taccess_token: string;\n\t\trefresh_token: string;\n\t\texpires_in: number;\n\t};\n\n\treturn {\n\t\ttype: \"oauth\",\n\t\trefresh: data.refresh_token,\n\t\taccess: data.access_token,\n\t\texpires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,\n\t};\n}\n"]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub Copilot OAuth flow
|
|
3
|
+
*/
|
|
4
|
+
import { type OAuthCredentials } from "./storage.js";
|
|
5
|
+
export declare function normalizeDomain(input: string): string | null;
|
|
6
|
+
/**
|
|
7
|
+
* Parse the proxy-ep from a Copilot token and convert to API base URL.
|
|
8
|
+
* Token format: tid=...;exp=...;proxy-ep=proxy.individual.githubcopilot.com;...
|
|
9
|
+
* Returns API URL like https://api.individual.githubcopilot.com
|
|
10
|
+
*/
|
|
11
|
+
export declare function getBaseUrlFromToken(token: string): string | null;
|
|
12
|
+
export declare function getGitHubCopilotBaseUrl(token?: string, enterpriseDomain?: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Refresh GitHub Copilot token
|
|
15
|
+
*/
|
|
16
|
+
export declare function refreshGitHubCopilotToken(refreshToken: string, enterpriseDomain?: string): Promise<OAuthCredentials>;
|
|
17
|
+
/**
|
|
18
|
+
* Enable a model for the user's GitHub Copilot account.
|
|
19
|
+
* This is required for some models (like Claude, Grok) before they can be used.
|
|
20
|
+
*/
|
|
21
|
+
export declare function enableGitHubCopilotModel(token: string, modelId: string, enterpriseDomain?: string): Promise<boolean>;
|
|
22
|
+
/**
|
|
23
|
+
* Enable all known GitHub Copilot models that may require policy acceptance.
|
|
24
|
+
* Called after successful login to ensure all models are available.
|
|
25
|
+
*/
|
|
26
|
+
export declare function enableAllGitHubCopilotModels(token: string, enterpriseDomain?: string, onProgress?: (model: string, success: boolean) => void): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Login with GitHub Copilot OAuth (device code flow)
|
|
29
|
+
*
|
|
30
|
+
* @param options.onAuth - Callback with URL and optional instructions (user code)
|
|
31
|
+
* @param options.onPrompt - Callback to prompt user for input
|
|
32
|
+
* @param options.onProgress - Optional progress callback
|
|
33
|
+
*/
|
|
34
|
+
export declare function loginGitHubCopilot(options: {
|
|
35
|
+
onAuth: (url: string, instructions?: string) => void;
|
|
36
|
+
onPrompt: (prompt: {
|
|
37
|
+
message: string;
|
|
38
|
+
placeholder?: string;
|
|
39
|
+
allowEmpty?: boolean;
|
|
40
|
+
}) => Promise<string>;
|
|
41
|
+
onProgress?: (message: string) => void;
|
|
42
|
+
}): Promise<OAuthCredentials>;
|
|
43
|
+
//# sourceMappingURL=github-copilot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-copilot.d.ts","sourceRoot":"","sources":["../../../src/utils/oauth/github-copilot.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,KAAK,gBAAgB,EAAwB,MAAM,cAAc,CAAC;AA+B3E,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAS5D;AAcD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOhE;AAED,wBAAgB,uBAAuB,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM,CASzF;AA0GD;;GAEG;AACH,wBAAsB,yBAAyB,CAC9C,YAAY,EAAE,MAAM,EACpB,gBAAgB,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,gBAAgB,CAAC,CA8B3B;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC7C,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,gBAAgB,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,OAAO,CAAC,CAoBlB;AAED;;;GAGG;AACH,wBAAsB,4BAA4B,CACjD,KAAK,EAAE,MAAM,EACb,gBAAgB,CAAC,EAAE,MAAM,EACzB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,GACpD,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE;IACjD,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,QAAQ,EAAE,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACvG,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACvC,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAiC5B","sourcesContent":["/**\n * GitHub Copilot OAuth flow\n */\n\nimport { getModels } from \"../../models.js\";\nimport { type OAuthCredentials, saveOAuthCredentials } from \"./storage.js\";\n\nconst CLIENT_ID = \"Iv1.b507a08c87ecfe98\";\n\nconst COPILOT_HEADERS = {\n\t\"User-Agent\": \"GitHubCopilotChat/0.35.0\",\n\t\"Editor-Version\": \"vscode/1.107.0\",\n\t\"Editor-Plugin-Version\": \"copilot-chat/0.35.0\",\n\t\"Copilot-Integration-Id\": \"vscode-chat\",\n} as const;\n\ntype DeviceCodeResponse = {\n\tdevice_code: string;\n\tuser_code: string;\n\tverification_uri: string;\n\tinterval: number;\n\texpires_in: number;\n};\n\ntype DeviceTokenSuccessResponse = {\n\taccess_token: string;\n\ttoken_type?: string;\n\tscope?: string;\n};\n\ntype DeviceTokenErrorResponse = {\n\terror: string;\n\terror_description?: string;\n\tinterval?: number;\n};\n\nexport function normalizeDomain(input: string): string | null {\n\tconst trimmed = input.trim();\n\tif (!trimmed) return null;\n\ttry {\n\t\tconst url = trimmed.includes(\"://\") ? new URL(trimmed) : new URL(`https://${trimmed}`);\n\t\treturn url.hostname;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction getUrls(domain: string): {\n\tdeviceCodeUrl: string;\n\taccessTokenUrl: string;\n\tcopilotTokenUrl: string;\n} {\n\treturn {\n\t\tdeviceCodeUrl: `https://${domain}/login/device/code`,\n\t\taccessTokenUrl: `https://${domain}/login/oauth/access_token`,\n\t\tcopilotTokenUrl: `https://api.${domain}/copilot_internal/v2/token`,\n\t};\n}\n\n/**\n * Parse the proxy-ep from a Copilot token and convert to API base URL.\n * Token format: tid=...;exp=...;proxy-ep=proxy.individual.githubcopilot.com;...\n * Returns API URL like https://api.individual.githubcopilot.com\n */\nexport function getBaseUrlFromToken(token: string): string | null {\n\tconst match = token.match(/proxy-ep=([^;]+)/);\n\tif (!match) return null;\n\tconst proxyHost = match[1];\n\t// Convert proxy.xxx to api.xxx\n\tconst apiHost = proxyHost.replace(/^proxy\\./, \"api.\");\n\treturn `https://${apiHost}`;\n}\n\nexport function getGitHubCopilotBaseUrl(token?: string, enterpriseDomain?: string): string {\n\t// If we have a token, extract the base URL from proxy-ep\n\tif (token) {\n\t\tconst urlFromToken = getBaseUrlFromToken(token);\n\t\tif (urlFromToken) return urlFromToken;\n\t}\n\t// Fallback for enterprise or if token parsing fails\n\tif (enterpriseDomain) return `https://copilot-api.${enterpriseDomain}`;\n\treturn \"https://api.individual.githubcopilot.com\";\n}\n\nasync function fetchJson(url: string, init: RequestInit): Promise<unknown> {\n\tconst response = await fetch(url, init);\n\tif (!response.ok) {\n\t\tconst text = await response.text();\n\t\tthrow new Error(`${response.status} ${response.statusText}: ${text}`);\n\t}\n\treturn response.json();\n}\n\nasync function startDeviceFlow(domain: string): Promise<DeviceCodeResponse> {\n\tconst urls = getUrls(domain);\n\tconst data = await fetchJson(urls.deviceCodeUrl, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\"User-Agent\": \"GitHubCopilotChat/0.35.0\",\n\t\t},\n\t\tbody: JSON.stringify({\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tscope: \"read:user\",\n\t\t}),\n\t});\n\n\tif (!data || typeof data !== \"object\") {\n\t\tthrow new Error(\"Invalid device code response\");\n\t}\n\n\tconst deviceCode = (data as Record<string, unknown>).device_code;\n\tconst userCode = (data as Record<string, unknown>).user_code;\n\tconst verificationUri = (data as Record<string, unknown>).verification_uri;\n\tconst interval = (data as Record<string, unknown>).interval;\n\tconst expiresIn = (data as Record<string, unknown>).expires_in;\n\n\tif (\n\t\ttypeof deviceCode !== \"string\" ||\n\t\ttypeof userCode !== \"string\" ||\n\t\ttypeof verificationUri !== \"string\" ||\n\t\ttypeof interval !== \"number\" ||\n\t\ttypeof expiresIn !== \"number\"\n\t) {\n\t\tthrow new Error(\"Invalid device code response fields\");\n\t}\n\n\treturn {\n\t\tdevice_code: deviceCode,\n\t\tuser_code: userCode,\n\t\tverification_uri: verificationUri,\n\t\tinterval,\n\t\texpires_in: expiresIn,\n\t};\n}\n\nasync function pollForGitHubAccessToken(\n\tdomain: string,\n\tdeviceCode: string,\n\tintervalSeconds: number,\n\texpiresIn: number,\n) {\n\tconst urls = getUrls(domain);\n\tconst deadline = Date.now() + expiresIn * 1000;\n\tlet intervalMs = Math.max(1000, Math.floor(intervalSeconds * 1000));\n\n\twhile (Date.now() < deadline) {\n\t\tconst raw = await fetchJson(urls.accessTokenUrl, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\"User-Agent\": \"GitHubCopilotChat/0.35.0\",\n\t\t\t},\n\t\t\tbody: JSON.stringify({\n\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\tdevice_code: deviceCode,\n\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t}),\n\t\t});\n\n\t\tif (raw && typeof raw === \"object\" && typeof (raw as DeviceTokenSuccessResponse).access_token === \"string\") {\n\t\t\treturn (raw as DeviceTokenSuccessResponse).access_token;\n\t\t}\n\n\t\tif (raw && typeof raw === \"object\" && typeof (raw as DeviceTokenErrorResponse).error === \"string\") {\n\t\t\tconst err = (raw as DeviceTokenErrorResponse).error;\n\t\t\tif (err === \"authorization_pending\") {\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, intervalMs));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (err === \"slow_down\") {\n\t\t\t\tintervalMs += 5000;\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, intervalMs));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthrow new Error(`Device flow failed: ${err}`);\n\t\t}\n\n\t\tawait new Promise((resolve) => setTimeout(resolve, intervalMs));\n\t}\n\n\tthrow new Error(\"Device flow timed out\");\n}\n\n/**\n * Refresh GitHub Copilot token\n */\nexport async function refreshGitHubCopilotToken(\n\trefreshToken: string,\n\tenterpriseDomain?: string,\n): Promise<OAuthCredentials> {\n\tconst domain = enterpriseDomain || \"github.com\";\n\tconst urls = getUrls(domain);\n\n\tconst raw = await fetchJson(urls.copilotTokenUrl, {\n\t\theaders: {\n\t\t\tAccept: \"application/json\",\n\t\t\tAuthorization: `Bearer ${refreshToken}`,\n\t\t\t...COPILOT_HEADERS,\n\t\t},\n\t});\n\n\tif (!raw || typeof raw !== \"object\") {\n\t\tthrow new Error(\"Invalid Copilot token response\");\n\t}\n\n\tconst token = (raw as Record<string, unknown>).token;\n\tconst expiresAt = (raw as Record<string, unknown>).expires_at;\n\n\tif (typeof token !== \"string\" || typeof expiresAt !== \"number\") {\n\t\tthrow new Error(\"Invalid Copilot token response fields\");\n\t}\n\n\treturn {\n\t\ttype: \"oauth\",\n\t\trefresh: refreshToken,\n\t\taccess: token,\n\t\texpires: expiresAt * 1000 - 5 * 60 * 1000,\n\t\tenterpriseUrl: enterpriseDomain,\n\t};\n}\n\n/**\n * Enable a model for the user's GitHub Copilot account.\n * This is required for some models (like Claude, Grok) before they can be used.\n */\nexport async function enableGitHubCopilotModel(\n\ttoken: string,\n\tmodelId: string,\n\tenterpriseDomain?: string,\n): Promise<boolean> {\n\tconst baseUrl = getGitHubCopilotBaseUrl(token, enterpriseDomain);\n\tconst url = `${baseUrl}/models/${modelId}/policy`;\n\n\ttry {\n\t\tconst response = await fetch(url, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\tAuthorization: `Bearer ${token}`,\n\t\t\t\t...COPILOT_HEADERS,\n\t\t\t\t\"openai-intent\": \"chat-policy\",\n\t\t\t\t\"x-interaction-type\": \"chat-policy\",\n\t\t\t},\n\t\t\tbody: JSON.stringify({ state: \"enabled\" }),\n\t\t});\n\t\treturn response.ok;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Enable all known GitHub Copilot models that may require policy acceptance.\n * Called after successful login to ensure all models are available.\n */\nexport async function enableAllGitHubCopilotModels(\n\ttoken: string,\n\tenterpriseDomain?: string,\n\tonProgress?: (model: string, success: boolean) => void,\n): Promise<void> {\n\tconst models = getModels(\"github-copilot\");\n\tawait Promise.all(\n\t\tmodels.map(async (model) => {\n\t\t\tconst success = await enableGitHubCopilotModel(token, model.id, enterpriseDomain);\n\t\t\tonProgress?.(model.id, success);\n\t\t}),\n\t);\n}\n\n/**\n * Login with GitHub Copilot OAuth (device code flow)\n *\n * @param options.onAuth - Callback with URL and optional instructions (user code)\n * @param options.onPrompt - Callback to prompt user for input\n * @param options.onProgress - Optional progress callback\n */\nexport async function loginGitHubCopilot(options: {\n\tonAuth: (url: string, instructions?: string) => void;\n\tonPrompt: (prompt: { message: string; placeholder?: string; allowEmpty?: boolean }) => Promise<string>;\n\tonProgress?: (message: string) => void;\n}): Promise<OAuthCredentials> {\n\tconst input = await options.onPrompt({\n\t\tmessage: \"GitHub Enterprise URL/domain (blank for github.com)\",\n\t\tplaceholder: \"company.ghe.com\",\n\t\tallowEmpty: true,\n\t});\n\n\tconst trimmed = input.trim();\n\tconst enterpriseDomain = normalizeDomain(input);\n\tif (trimmed && !enterpriseDomain) {\n\t\tthrow new Error(\"Invalid GitHub Enterprise URL/domain\");\n\t}\n\tconst domain = enterpriseDomain || \"github.com\";\n\n\tconst device = await startDeviceFlow(domain);\n\toptions.onAuth(device.verification_uri, `Enter code: ${device.user_code}`);\n\n\tconst githubAccessToken = await pollForGitHubAccessToken(\n\t\tdomain,\n\t\tdevice.device_code,\n\t\tdevice.interval,\n\t\tdevice.expires_in,\n\t);\n\tconst credentials = await refreshGitHubCopilotToken(githubAccessToken, enterpriseDomain ?? undefined);\n\n\t// Enable all models after successful login\n\toptions.onProgress?.(\"Enabling models...\");\n\tawait enableAllGitHubCopilotModels(credentials.access, enterpriseDomain ?? undefined);\n\n\t// Save credentials\n\tsaveOAuthCredentials(\"github-copilot\", credentials);\n\n\treturn credentials;\n}\n"]}
|