@sayknow-cli/ai 0.2.2
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/CHANGELOG.md +2788 -0
- package/README.md +1183 -0
- package/dist/types/api-registry.d.ts +30 -0
- package/dist/types/auth-broker/client.d.ts +66 -0
- package/dist/types/auth-broker/index.d.ts +5 -0
- package/dist/types/auth-broker/refresher.d.ts +25 -0
- package/dist/types/auth-broker/remote-store.d.ts +96 -0
- package/dist/types/auth-broker/server.d.ts +32 -0
- package/dist/types/auth-broker/types.d.ts +105 -0
- package/dist/types/auth-broker/wire-schemas.d.ts +412 -0
- package/dist/types/auth-gateway/http.d.ts +39 -0
- package/dist/types/auth-gateway/index.d.ts +3 -0
- package/dist/types/auth-gateway/server.d.ts +17 -0
- package/dist/types/auth-gateway/types.d.ts +115 -0
- package/dist/types/auth-storage.d.ts +660 -0
- package/dist/types/cli.d.ts +2 -0
- package/dist/types/index.d.ts +51 -0
- package/dist/types/model-cache.d.ts +17 -0
- package/dist/types/model-manager.d.ts +62 -0
- package/dist/types/model-thinking.d.ts +74 -0
- package/dist/types/models.d.ts +12 -0
- package/dist/types/provider-details.d.ts +24 -0
- package/dist/types/provider-models/bundled-references.d.ts +4 -0
- package/dist/types/provider-models/descriptors.d.ts +48 -0
- package/dist/types/provider-models/google.d.ts +20 -0
- package/dist/types/provider-models/index.d.ts +5 -0
- package/dist/types/provider-models/ollama.d.ts +7 -0
- package/dist/types/provider-models/openai-compat.d.ts +244 -0
- package/dist/types/provider-models/special.d.ts +16 -0
- package/dist/types/providers/amazon-bedrock.d.ts +60 -0
- package/dist/types/providers/anthropic-messages-server-schema.d.ts +450 -0
- package/dist/types/providers/anthropic-messages-server.d.ts +17 -0
- package/dist/types/providers/anthropic.d.ts +198 -0
- package/dist/types/providers/aws-credentials.d.ts +43 -0
- package/dist/types/providers/aws-eventstream.d.ts +38 -0
- package/dist/types/providers/aws-sigv4.d.ts +55 -0
- package/dist/types/providers/azure-openai-responses.d.ts +15 -0
- package/dist/types/providers/composer-discipline.d.ts +26 -0
- package/dist/types/providers/cursor/gen/agent_pb.d.ts +13022 -0
- package/dist/types/providers/cursor.d.ts +44 -0
- package/dist/types/providers/error-message.d.ts +27 -0
- package/dist/types/providers/github-copilot-headers.d.ts +40 -0
- package/dist/types/providers/gitlab-duo.d.ts +27 -0
- package/dist/types/providers/google-auth.d.ts +24 -0
- package/dist/types/providers/google-gemini-cli.d.ts +72 -0
- package/dist/types/providers/google-gemini-headers.d.ts +18 -0
- package/dist/types/providers/google-shared.d.ts +173 -0
- package/dist/types/providers/google-types.d.ts +138 -0
- package/dist/types/providers/google-vertex.d.ts +7 -0
- package/dist/types/providers/google.d.ts +4 -0
- package/dist/types/providers/grammar.d.ts +1 -0
- package/dist/types/providers/kimi.d.ts +27 -0
- package/dist/types/providers/mock.d.ts +175 -0
- package/dist/types/providers/ollama.d.ts +41 -0
- package/dist/types/providers/openai-anthropic-shim.d.ts +31 -0
- package/dist/types/providers/openai-chat-server-schema.d.ts +815 -0
- package/dist/types/providers/openai-chat-server.d.ts +16 -0
- package/dist/types/providers/openai-codex/constants.d.ts +26 -0
- package/dist/types/providers/openai-codex/request-transformer.d.ts +49 -0
- package/dist/types/providers/openai-codex/response-handler.d.ts +17 -0
- package/dist/types/providers/openai-codex-responses.d.ts +67 -0
- package/dist/types/providers/openai-completions-compat.d.ts +27 -0
- package/dist/types/providers/openai-completions.d.ts +33 -0
- package/dist/types/providers/openai-request-transform.d.ts +4 -0
- package/dist/types/providers/openai-responses-server-schema.d.ts +392 -0
- package/dist/types/providers/openai-responses-server.d.ts +17 -0
- package/dist/types/providers/openai-responses-shared.d.ts +89 -0
- package/dist/types/providers/openai-responses.d.ts +32 -0
- package/dist/types/providers/pi-native-client.d.ts +13 -0
- package/dist/types/providers/pi-native-server.d.ts +68 -0
- package/dist/types/providers/register-builtins.d.ts +31 -0
- package/dist/types/providers/synthetic.d.ts +26 -0
- package/dist/types/providers/transform-messages.d.ts +14 -0
- package/dist/types/providers/vision-guard.d.ts +8 -0
- package/dist/types/rate-limit-utils.d.ts +19 -0
- package/dist/types/stream.d.ts +43 -0
- package/dist/types/types.d.ts +811 -0
- package/dist/types/usage/claude.d.ts +3 -0
- package/dist/types/usage/gemini.d.ts +2 -0
- package/dist/types/usage/github-copilot.d.ts +7 -0
- package/dist/types/usage/google-antigravity.d.ts +2 -0
- package/dist/types/usage/grok-cli.d.ts +10 -0
- package/dist/types/usage/kimi.d.ts +2 -0
- package/dist/types/usage/minimax-code.d.ts +2 -0
- package/dist/types/usage/openai-codex.d.ts +3 -0
- package/dist/types/usage/shared.d.ts +1 -0
- package/dist/types/usage/zai.d.ts +2 -0
- package/dist/types/usage.d.ts +258 -0
- package/dist/types/utils/abort.d.ts +19 -0
- package/dist/types/utils/anthropic-auth.d.ts +31 -0
- package/dist/types/utils/discovery/antigravity.d.ts +61 -0
- package/dist/types/utils/discovery/codex.d.ts +38 -0
- package/dist/types/utils/discovery/cursor.d.ts +23 -0
- package/dist/types/utils/discovery/gemini.d.ts +25 -0
- package/dist/types/utils/discovery/index.d.ts +4 -0
- package/dist/types/utils/discovery/openai-compatible.d.ts +74 -0
- package/dist/types/utils/event-stream.d.ts +33 -0
- package/dist/types/utils/fireworks-model-id.d.ts +10 -0
- package/dist/types/utils/foundry.d.ts +1 -0
- package/dist/types/utils/h2-fetch.d.ts +22 -0
- package/dist/types/utils/http-inspector.d.ts +35 -0
- package/dist/types/utils/idle-iterator.d.ts +67 -0
- package/dist/types/utils/json-parse.d.ts +10 -0
- package/dist/types/utils/oauth/alibaba-coding-plan.d.ts +18 -0
- package/dist/types/utils/oauth/anthropic.d.ts +22 -0
- package/dist/types/utils/oauth/api-key-login.d.ts +35 -0
- package/dist/types/utils/oauth/api-key-validation.d.ts +27 -0
- package/dist/types/utils/oauth/callback-server.d.ts +60 -0
- package/dist/types/utils/oauth/cerebras.d.ts +1 -0
- package/dist/types/utils/oauth/cloudflare-ai-gateway.d.ts +18 -0
- package/dist/types/utils/oauth/cursor.d.ts +15 -0
- package/dist/types/utils/oauth/deepseek.d.ts +10 -0
- package/dist/types/utils/oauth/firepass.d.ts +1 -0
- package/dist/types/utils/oauth/fireworks.d.ts +1 -0
- package/dist/types/utils/oauth/github-copilot.d.ts +38 -0
- package/dist/types/utils/oauth/gitlab-duo.d.ts +3 -0
- package/dist/types/utils/oauth/google-antigravity.d.ts +11 -0
- package/dist/types/utils/oauth/google-gemini-cli.d.ts +10 -0
- package/dist/types/utils/oauth/google-oauth-shared.d.ts +28 -0
- package/dist/types/utils/oauth/huggingface.d.ts +19 -0
- package/dist/types/utils/oauth/index.d.ts +38 -0
- package/dist/types/utils/oauth/kagi.d.ts +17 -0
- package/dist/types/utils/oauth/kilo.d.ts +5 -0
- package/dist/types/utils/oauth/kimi.d.ts +21 -0
- package/dist/types/utils/oauth/litellm.d.ts +18 -0
- package/dist/types/utils/oauth/lm-studio.d.ts +17 -0
- package/dist/types/utils/oauth/minimax-code.d.ts +28 -0
- package/dist/types/utils/oauth/moonshot.d.ts +1 -0
- package/dist/types/utils/oauth/nanogpt.d.ts +1 -0
- package/dist/types/utils/oauth/nvidia.d.ts +18 -0
- package/dist/types/utils/oauth/ollama-cloud.d.ts +2 -0
- package/dist/types/utils/oauth/ollama.d.ts +18 -0
- package/dist/types/utils/oauth/openai-codex.d.ts +21 -0
- package/dist/types/utils/oauth/opencode.d.ts +18 -0
- package/dist/types/utils/oauth/parallel.d.ts +17 -0
- package/dist/types/utils/oauth/perplexity.d.ts +9 -0
- package/dist/types/utils/oauth/pkce.d.ts +8 -0
- package/dist/types/utils/oauth/qianfan.d.ts +17 -0
- package/dist/types/utils/oauth/qwen-portal.d.ts +19 -0
- package/dist/types/utils/oauth/synthetic.d.ts +1 -0
- package/dist/types/utils/oauth/tavily.d.ts +17 -0
- package/dist/types/utils/oauth/together.d.ts +1 -0
- package/dist/types/utils/oauth/types.d.ts +45 -0
- package/dist/types/utils/oauth/venice.d.ts +18 -0
- package/dist/types/utils/oauth/vercel-ai-gateway.d.ts +18 -0
- package/dist/types/utils/oauth/vllm.d.ts +16 -0
- package/dist/types/utils/oauth/xai.d.ts +30 -0
- package/dist/types/utils/oauth/xiaomi.d.ts +25 -0
- package/dist/types/utils/oauth/zai.d.ts +18 -0
- package/dist/types/utils/oauth/zenmux.d.ts +1 -0
- package/dist/types/utils/overflow.d.ts +54 -0
- package/dist/types/utils/parse-bind.d.ts +23 -0
- package/dist/types/utils/provider-response.d.ts +3 -0
- package/dist/types/utils/retry-after.d.ts +3 -0
- package/dist/types/utils/retry-budget.d.ts +1 -0
- package/dist/types/utils/retry.d.ts +26 -0
- package/dist/types/utils/schema/adapt.d.ts +24 -0
- package/dist/types/utils/schema/compatibility.d.ts +30 -0
- package/dist/types/utils/schema/dereference.d.ts +11 -0
- package/dist/types/utils/schema/draft.d.ts +10 -0
- package/dist/types/utils/schema/equality.d.ts +4 -0
- package/dist/types/utils/schema/fields.d.ts +49 -0
- package/dist/types/utils/schema/index.d.ts +13 -0
- package/dist/types/utils/schema/json-schema-validator.d.ts +12 -0
- package/dist/types/utils/schema/meta-validator.d.ts +2 -0
- package/dist/types/utils/schema/normalize.d.ts +93 -0
- package/dist/types/utils/schema/spill.d.ts +8 -0
- package/dist/types/utils/schema/stamps.d.ts +25 -0
- package/dist/types/utils/schema/types.d.ts +4 -0
- package/dist/types/utils/schema/wire.d.ts +54 -0
- package/dist/types/utils/schema/zod-decontaminate.d.ts +31 -0
- package/dist/types/utils/sse-debug.d.ts +10 -0
- package/dist/types/utils/tool-call-healing.d.ts +71 -0
- package/dist/types/utils/tool-choice-capability.d.ts +41 -0
- package/dist/types/utils/tool-choice.d.ts +50 -0
- package/dist/types/utils/validation.d.ts +17 -0
- package/dist/types/utils.d.ts +34 -0
- package/package.json +146 -0
- package/src/api-registry.ts +96 -0
- package/src/auth-broker/client.ts +358 -0
- package/src/auth-broker/index.ts +5 -0
- package/src/auth-broker/refresher.ts +127 -0
- package/src/auth-broker/remote-store.ts +623 -0
- package/src/auth-broker/server.ts +644 -0
- package/src/auth-broker/types.ts +127 -0
- package/src/auth-broker/wire-schemas.ts +200 -0
- package/src/auth-gateway/http.ts +194 -0
- package/src/auth-gateway/index.ts +3 -0
- package/src/auth-gateway/server.ts +717 -0
- package/src/auth-gateway/types.ts +134 -0
- package/src/auth-storage.ts +4179 -0
- package/src/cli.ts +263 -0
- package/src/index.ts +56 -0
- package/src/model-cache.ts +129 -0
- package/src/model-manager.ts +486 -0
- package/src/model-thinking.ts +772 -0
- package/src/models.json +75437 -0
- package/src/models.json.d.ts +9 -0
- package/src/models.ts +82 -0
- package/src/prompts/turn-aborted-guidance.md +4 -0
- package/src/provider-details.ts +90 -0
- package/src/provider-models/bundled-references.ts +38 -0
- package/src/provider-models/descriptors.ts +327 -0
- package/src/provider-models/google.ts +91 -0
- package/src/provider-models/index.ts +5 -0
- package/src/provider-models/ollama.ts +153 -0
- package/src/provider-models/openai-compat.ts +2352 -0
- package/src/provider-models/special.ts +67 -0
- package/src/providers/amazon-bedrock.ts +937 -0
- package/src/providers/anthropic-messages-server-schema.ts +229 -0
- package/src/providers/anthropic-messages-server.ts +677 -0
- package/src/providers/anthropic.ts +2940 -0
- package/src/providers/aws-credentials.ts +501 -0
- package/src/providers/aws-eventstream.ts +185 -0
- package/src/providers/aws-sigv4.ts +218 -0
- package/src/providers/azure-openai-responses.ts +379 -0
- package/src/providers/composer-discipline.ts +41 -0
- package/src/providers/cursor/gen/agent_pb.ts +15274 -0
- package/src/providers/cursor/proto/agent.proto +3526 -0
- package/src/providers/cursor/proto/buf.gen.yaml +6 -0
- package/src/providers/cursor/proto/buf.yaml +17 -0
- package/src/providers/cursor.ts +2671 -0
- package/src/providers/error-message.ts +21 -0
- package/src/providers/github-copilot-headers.ts +140 -0
- package/src/providers/gitlab-duo.ts +372 -0
- package/src/providers/google-auth.ts +252 -0
- package/src/providers/google-gemini-cli.ts +856 -0
- package/src/providers/google-gemini-headers.ts +41 -0
- package/src/providers/google-shared.ts +951 -0
- package/src/providers/google-types.ts +167 -0
- package/src/providers/google-vertex.ts +88 -0
- package/src/providers/google.ts +41 -0
- package/src/providers/grammar.ts +70 -0
- package/src/providers/kimi.ts +52 -0
- package/src/providers/mock.ts +500 -0
- package/src/providers/ollama.ts +603 -0
- package/src/providers/openai-anthropic-shim.ts +138 -0
- package/src/providers/openai-chat-server-schema.ts +243 -0
- package/src/providers/openai-chat-server.ts +635 -0
- package/src/providers/openai-codex/constants.ts +43 -0
- package/src/providers/openai-codex/request-transformer.ts +161 -0
- package/src/providers/openai-codex/response-handler.ts +81 -0
- package/src/providers/openai-codex-responses.ts +2774 -0
- package/src/providers/openai-completions-compat.ts +289 -0
- package/src/providers/openai-completions.ts +1935 -0
- package/src/providers/openai-request-transform.ts +136 -0
- package/src/providers/openai-responses-server-schema.ts +290 -0
- package/src/providers/openai-responses-server.ts +1190 -0
- package/src/providers/openai-responses-shared.ts +800 -0
- package/src/providers/openai-responses.ts +738 -0
- package/src/providers/pi-native-client.ts +227 -0
- package/src/providers/pi-native-server.ts +210 -0
- package/src/providers/register-builtins.ts +411 -0
- package/src/providers/synthetic.ts +50 -0
- package/src/providers/transform-messages.ts +319 -0
- package/src/providers/vision-guard.ts +31 -0
- package/src/rate-limit-utils.ts +93 -0
- package/src/stream.ts +960 -0
- package/src/types.ts +967 -0
- package/src/usage/claude.ts +431 -0
- package/src/usage/gemini.ts +250 -0
- package/src/usage/github-copilot.ts +421 -0
- package/src/usage/google-antigravity.ts +201 -0
- package/src/usage/grok-cli.ts +163 -0
- package/src/usage/kimi.ts +271 -0
- package/src/usage/minimax-code.ts +31 -0
- package/src/usage/openai-codex.ts +503 -0
- package/src/usage/shared.ts +10 -0
- package/src/usage/zai.ts +247 -0
- package/src/usage.ts +183 -0
- package/src/utils/abort.ts +51 -0
- package/src/utils/anthropic-auth.ts +87 -0
- package/src/utils/discovery/antigravity.ts +261 -0
- package/src/utils/discovery/codex.ts +371 -0
- package/src/utils/discovery/cursor.ts +306 -0
- package/src/utils/discovery/gemini.ts +248 -0
- package/src/utils/discovery/index.ts +4 -0
- package/src/utils/discovery/openai-compatible.ts +230 -0
- package/src/utils/event-stream.ts +172 -0
- package/src/utils/fireworks-model-id.ts +30 -0
- package/src/utils/foundry.ts +8 -0
- package/src/utils/h2-fetch.ts +60 -0
- package/src/utils/http-inspector.ts +255 -0
- package/src/utils/idle-iterator.ts +257 -0
- package/src/utils/json-parse.ts +148 -0
- package/src/utils/oauth/alibaba-coding-plan.ts +59 -0
- package/src/utils/oauth/anthropic.ts +200 -0
- package/src/utils/oauth/api-key-login.ts +87 -0
- package/src/utils/oauth/api-key-validation.ts +92 -0
- package/src/utils/oauth/callback-server.ts +281 -0
- package/src/utils/oauth/cerebras.ts +16 -0
- package/src/utils/oauth/cloudflare-ai-gateway.ts +48 -0
- package/src/utils/oauth/cursor.ts +157 -0
- package/src/utils/oauth/deepseek.ts +53 -0
- package/src/utils/oauth/firepass.ts +24 -0
- package/src/utils/oauth/fireworks.ts +15 -0
- package/src/utils/oauth/github-copilot.ts +362 -0
- package/src/utils/oauth/gitlab-duo.ts +123 -0
- package/src/utils/oauth/google-antigravity.ts +200 -0
- package/src/utils/oauth/google-gemini-cli.ts +256 -0
- package/src/utils/oauth/google-oauth-shared.ts +110 -0
- package/src/utils/oauth/huggingface.ts +62 -0
- package/src/utils/oauth/index.ts +469 -0
- package/src/utils/oauth/kagi.ts +47 -0
- package/src/utils/oauth/kilo.ts +87 -0
- package/src/utils/oauth/kimi.ts +254 -0
- package/src/utils/oauth/litellm.ts +47 -0
- package/src/utils/oauth/lm-studio.ts +38 -0
- package/src/utils/oauth/minimax-code.ts +78 -0
- package/src/utils/oauth/moonshot.ts +16 -0
- package/src/utils/oauth/nanogpt.ts +15 -0
- package/src/utils/oauth/nvidia.ts +70 -0
- package/src/utils/oauth/oauth.html +199 -0
- package/src/utils/oauth/ollama-cloud.ts +28 -0
- package/src/utils/oauth/ollama.ts +47 -0
- package/src/utils/oauth/openai-codex.ts +299 -0
- package/src/utils/oauth/opencode.ts +49 -0
- package/src/utils/oauth/parallel.ts +46 -0
- package/src/utils/oauth/perplexity.ts +206 -0
- package/src/utils/oauth/pkce.ts +18 -0
- package/src/utils/oauth/qianfan.ts +58 -0
- package/src/utils/oauth/qwen-portal.ts +60 -0
- package/src/utils/oauth/synthetic.ts +16 -0
- package/src/utils/oauth/tavily.ts +46 -0
- package/src/utils/oauth/together.ts +16 -0
- package/src/utils/oauth/types.ts +99 -0
- package/src/utils/oauth/venice.ts +59 -0
- package/src/utils/oauth/vercel-ai-gateway.ts +47 -0
- package/src/utils/oauth/vllm.ts +40 -0
- package/src/utils/oauth/xai.ts +246 -0
- package/src/utils/oauth/xiaomi.ts +199 -0
- package/src/utils/oauth/zai.ts +60 -0
- package/src/utils/oauth/zenmux.ts +15 -0
- package/src/utils/overflow.ts +137 -0
- package/src/utils/parse-bind.ts +54 -0
- package/src/utils/provider-response.ts +30 -0
- package/src/utils/retry-after.ts +110 -0
- package/src/utils/retry-budget.ts +4 -0
- package/src/utils/retry.ts +54 -0
- package/src/utils/schema/CONSTRAINTS.md +164 -0
- package/src/utils/schema/adapt.ts +36 -0
- package/src/utils/schema/compatibility.ts +435 -0
- package/src/utils/schema/dereference.ts +98 -0
- package/src/utils/schema/draft.ts +341 -0
- package/src/utils/schema/equality.ts +97 -0
- package/src/utils/schema/fields.ts +190 -0
- package/src/utils/schema/index.ts +13 -0
- package/src/utils/schema/json-schema-validator.ts +577 -0
- package/src/utils/schema/meta-validator.ts +167 -0
- package/src/utils/schema/normalize.ts +1588 -0
- package/src/utils/schema/spill.ts +43 -0
- package/src/utils/schema/stamps.ts +97 -0
- package/src/utils/schema/types.ts +11 -0
- package/src/utils/schema/wire.ts +213 -0
- package/src/utils/schema/zod-decontaminate.ts +331 -0
- package/src/utils/sse-debug.ts +289 -0
- package/src/utils/tool-call-healing.ts +271 -0
- package/src/utils/tool-choice-capability.ts +220 -0
- package/src/utils/tool-choice.ts +99 -0
- package/src/utils/validation.ts +1019 -0
- package/src/utils.ts +178 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { extractHttpStatusFromError } from "@sayknow-cli/utils/fetch-retry";
|
|
2
|
+
import * as logger from "@sayknow-cli/utils/logger";
|
|
3
|
+
import type { Api, Model, ToolChoice, ToolChoiceCompat, ToolChoiceSupport, ToolChoiceSupportSource } from "../types";
|
|
4
|
+
|
|
5
|
+
const supportRank: Record<ToolChoiceSupport, number> = {
|
|
6
|
+
none: 0,
|
|
7
|
+
auto: 1,
|
|
8
|
+
required: 2,
|
|
9
|
+
named: 3,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const registry = new Map<string, ToolChoiceSupport>();
|
|
13
|
+
const loggedRegistryKeys = new Set<string>();
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Claude Mythos accepts tools but rejects forced tool use (Anthropic 400:
|
|
17
|
+
* "tool_choice forces tool use is not compatible with this model"). Catalog
|
|
18
|
+
* generation and dynamic discovery use this to default `toolChoiceSupport`.
|
|
19
|
+
*/
|
|
20
|
+
export function isClaudeForcedToolChoiceIncapableModelId(modelId: string): boolean {
|
|
21
|
+
return /(?:^|[/.])claude-mythos(?:-|$)/i.test(modelId);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Derives the effective static tool-choice support from compatibility flags. */
|
|
25
|
+
export function deriveToolChoiceSupport(compat: ToolChoiceCompat | undefined): {
|
|
26
|
+
support: ToolChoiceSupport;
|
|
27
|
+
source: "static" | "derived";
|
|
28
|
+
} {
|
|
29
|
+
if (compat?.toolChoiceSupport) {
|
|
30
|
+
return { support: compat.toolChoiceSupport, source: "static" };
|
|
31
|
+
}
|
|
32
|
+
if (compat?.supportsToolChoice === false) {
|
|
33
|
+
return { support: "none", source: "derived" };
|
|
34
|
+
}
|
|
35
|
+
if (compat?.supportsForcedToolChoice === false) {
|
|
36
|
+
return { support: "auto", source: "derived" };
|
|
37
|
+
}
|
|
38
|
+
return { support: "named", source: "derived" };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Returns the registry key used for runtime tool-choice capability overrides. */
|
|
42
|
+
export function toolChoiceRegistryKey(model: Model<Api>): string {
|
|
43
|
+
return [model.api, model.provider, model.baseUrl, model.wireModelId ?? model.id].join("|");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Returns the current runtime tool-choice capability override for a model. */
|
|
47
|
+
export function getToolChoiceCapabilityOverride(model: Model<Api>): ToolChoiceSupport | undefined {
|
|
48
|
+
return registry.get(toolChoiceRegistryKey(model));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Clears runtime tool-choice capability overrides for tests. */
|
|
52
|
+
export function clearToolChoiceIncapabilityRegistryForTests(): void {
|
|
53
|
+
registry.clear();
|
|
54
|
+
loggedRegistryKeys.clear();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Records a discovered maximum supported tool-choice level for a model. */
|
|
58
|
+
export function markToolChoiceIncapability(model: Model<Api>, maxSupport: ToolChoiceSupport, reason?: string): void {
|
|
59
|
+
const key = toolChoiceRegistryKey(model);
|
|
60
|
+
const existing = registry.get(key);
|
|
61
|
+
const next = existing && supportRank[existing] < supportRank[maxSupport] ? existing : maxSupport;
|
|
62
|
+
registry.set(key, next);
|
|
63
|
+
|
|
64
|
+
if (!loggedRegistryKeys.has(key)) {
|
|
65
|
+
loggedRegistryKeys.add(key);
|
|
66
|
+
logger.debug("Discovered tool_choice incapability", {
|
|
67
|
+
api: model.api,
|
|
68
|
+
provider: model.provider,
|
|
69
|
+
baseUrlHost: safeHostname(model.baseUrl),
|
|
70
|
+
model: model.wireModelId ?? model.id,
|
|
71
|
+
maxSupport,
|
|
72
|
+
reason,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Resolves a requested tool_choice against static and runtime capability limits.
|
|
79
|
+
* `compat` overrides `model.compat` for transports that layer URL/provider
|
|
80
|
+
* detection on top of explicit model overrides (e.g. resolveOpenAICompat).
|
|
81
|
+
*/
|
|
82
|
+
export function resolveToolChoice(
|
|
83
|
+
model: Model<Api>,
|
|
84
|
+
requested: ToolChoice | undefined,
|
|
85
|
+
compat?: ToolChoiceCompat,
|
|
86
|
+
): ResolveToolChoiceResult {
|
|
87
|
+
const derived = deriveToolChoiceSupport(compat ?? model.compat);
|
|
88
|
+
const runtime = registry.get(toolChoiceRegistryKey(model));
|
|
89
|
+
const support = runtime && supportRank[runtime] < supportRank[derived.support] ? runtime : derived.support;
|
|
90
|
+
const supportSource: ToolChoiceSupportSource = support === derived.support ? derived.source : "runtime";
|
|
91
|
+
const requestedInfo = requestedToolChoiceLevel(requested);
|
|
92
|
+
const clampLevel = requestedInfo.requestedLevel === "none" ? "auto" : requestedInfo.requestedLevel;
|
|
93
|
+
const registryKey = toolChoiceRegistryKey(model);
|
|
94
|
+
|
|
95
|
+
if (requested === undefined) {
|
|
96
|
+
return {
|
|
97
|
+
requestedChoice: requested,
|
|
98
|
+
requestedLevel: requestedInfo.requestedLevel,
|
|
99
|
+
resolvedChoice: undefined,
|
|
100
|
+
resolvedLevel: "auto",
|
|
101
|
+
support,
|
|
102
|
+
supportSource,
|
|
103
|
+
degraded: false,
|
|
104
|
+
registryKey,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (support === "none") {
|
|
109
|
+
return {
|
|
110
|
+
requestedChoice: requested,
|
|
111
|
+
requestedLevel: requestedInfo.requestedLevel,
|
|
112
|
+
resolvedChoice: undefined,
|
|
113
|
+
resolvedLevel: "none",
|
|
114
|
+
support,
|
|
115
|
+
supportSource,
|
|
116
|
+
degraded: requestedInfo.requestedLevel !== "none",
|
|
117
|
+
reason: "tool_choice is not supported by this model",
|
|
118
|
+
registryKey,
|
|
119
|
+
targetToolName: requestedInfo.targetToolName,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (supportRank[support] >= supportRank[clampLevel]) {
|
|
124
|
+
return {
|
|
125
|
+
requestedChoice: requested,
|
|
126
|
+
requestedLevel: requestedInfo.requestedLevel,
|
|
127
|
+
resolvedChoice: requested,
|
|
128
|
+
resolvedLevel: requestedInfo.requestedLevel,
|
|
129
|
+
support,
|
|
130
|
+
supportSource,
|
|
131
|
+
degraded: false,
|
|
132
|
+
registryKey,
|
|
133
|
+
targetToolName: requestedInfo.targetToolName,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (requestedInfo.requestedLevel === "named" && support === "required") {
|
|
138
|
+
return {
|
|
139
|
+
requestedChoice: requested,
|
|
140
|
+
requestedLevel: "named",
|
|
141
|
+
resolvedChoice: "required",
|
|
142
|
+
resolvedLevel: "required",
|
|
143
|
+
support,
|
|
144
|
+
supportSource,
|
|
145
|
+
degraded: true,
|
|
146
|
+
reason: "named tool_choice degraded to required",
|
|
147
|
+
registryKey,
|
|
148
|
+
targetToolName: requestedInfo.targetToolName,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
requestedChoice: requested,
|
|
154
|
+
requestedLevel: requestedInfo.requestedLevel,
|
|
155
|
+
resolvedChoice: undefined,
|
|
156
|
+
resolvedLevel: support === "auto" ? "auto" : "none",
|
|
157
|
+
support,
|
|
158
|
+
supportSource,
|
|
159
|
+
degraded: true,
|
|
160
|
+
reason: "forced tool_choice is not supported by this model",
|
|
161
|
+
registryKey,
|
|
162
|
+
targetToolName: requestedInfo.targetToolName,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Detects provider errors indicating forced tool_choice is unsupported. */
|
|
167
|
+
export function isForcedToolChoiceUnsupportedError(error: unknown, sentForcedToolChoice: boolean): boolean {
|
|
168
|
+
if (!sentForcedToolChoice || extractHttpStatusFromError(error) !== 400) return false;
|
|
169
|
+
const message = errorMessage(error);
|
|
170
|
+
return (
|
|
171
|
+
// `by <something>` continuations ("not supported by billing") describe a
|
|
172
|
+
// different subject than the model's tool_choice capability — reject them
|
|
173
|
+
// unless the continuation names the model itself.
|
|
174
|
+
/tool[_\s-]?choices?\b.*?(not\s+compatible|incompatible|not\s+supported)(?!\s+by\s+(?!(?:this|the)\s+model\b|model\b))/is.test(
|
|
175
|
+
message,
|
|
176
|
+
) ||
|
|
177
|
+
/forces?\s+tool\s+use.*?(not\s+compatible|incompatible|not\s+supported)/is.test(message) ||
|
|
178
|
+
/does\s+not\s+support\s+forced\s+tool[_\s-]?choices?/is.test(message)
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export type { ToolChoiceCompat, ToolChoiceSupport, ToolChoiceSupportSource } from "../types";
|
|
183
|
+
|
|
184
|
+
export interface ResolveToolChoiceResult {
|
|
185
|
+
requestedChoice: ToolChoice | undefined;
|
|
186
|
+
requestedLevel: ToolChoiceSupport;
|
|
187
|
+
resolvedChoice: ToolChoice | undefined;
|
|
188
|
+
resolvedLevel: ToolChoiceSupport;
|
|
189
|
+
support: ToolChoiceSupport;
|
|
190
|
+
supportSource: ToolChoiceSupportSource;
|
|
191
|
+
degraded: boolean;
|
|
192
|
+
reason?: string;
|
|
193
|
+
registryKey: string;
|
|
194
|
+
targetToolName?: string;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function requestedToolChoiceLevel(requested: ToolChoice | undefined): {
|
|
198
|
+
requestedLevel: ToolChoiceSupport;
|
|
199
|
+
targetToolName?: string;
|
|
200
|
+
} {
|
|
201
|
+
if (requested === undefined || requested === "auto") return { requestedLevel: "auto" };
|
|
202
|
+
if (requested === "none") return { requestedLevel: "none" };
|
|
203
|
+
if (requested === "any" || requested === "required") return { requestedLevel: "required" };
|
|
204
|
+
if ("name" in requested) return { requestedLevel: "named", targetToolName: requested.name };
|
|
205
|
+
return { requestedLevel: "named", targetToolName: requested.function.name };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function errorMessage(error: unknown): string {
|
|
209
|
+
if (error instanceof Error) return error.message;
|
|
210
|
+
if (typeof error === "string") return error;
|
|
211
|
+
return String(error);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function safeHostname(baseUrl: string): string | undefined {
|
|
215
|
+
try {
|
|
216
|
+
return new URL(baseUrl).hostname;
|
|
217
|
+
} catch {
|
|
218
|
+
return undefined;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for mapping unified ToolChoice to provider-specific formats.
|
|
3
|
+
*/
|
|
4
|
+
import type { ToolChoice } from "../types";
|
|
5
|
+
|
|
6
|
+
/** OpenAI Completions API tool choice format */
|
|
7
|
+
export type OpenAICompletionsToolChoice =
|
|
8
|
+
| "auto"
|
|
9
|
+
| "none"
|
|
10
|
+
| "required"
|
|
11
|
+
| { type: "function"; function: { name: string } }
|
|
12
|
+
| undefined;
|
|
13
|
+
|
|
14
|
+
/** OpenAI Responses API tool choice format (flat structure) */
|
|
15
|
+
export type OpenAIResponsesToolChoice =
|
|
16
|
+
| "auto"
|
|
17
|
+
| "none"
|
|
18
|
+
| "required"
|
|
19
|
+
| { type: "function"; name: string }
|
|
20
|
+
| { type: "custom"; name: string }
|
|
21
|
+
| undefined;
|
|
22
|
+
|
|
23
|
+
/** Anthropic-compatible tool choice format */
|
|
24
|
+
export type AnthropicToolChoice = "auto" | "none" | "any" | { type: "tool"; name: string } | undefined;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Extract function name from unified ToolChoice.
|
|
28
|
+
*/
|
|
29
|
+
function extractFunctionName(choice: ToolChoice): string | undefined {
|
|
30
|
+
if (typeof choice === "string") return undefined;
|
|
31
|
+
if (choice.type === "tool" && "name" in choice) return choice.name;
|
|
32
|
+
if (choice.type === "function") {
|
|
33
|
+
if ("function" in choice && choice.function && typeof choice.function === "object") {
|
|
34
|
+
return (choice.function as { name?: string }).name;
|
|
35
|
+
}
|
|
36
|
+
if ("name" in choice) return choice.name;
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Map unified ToolChoice to OpenAI Completions API format.
|
|
43
|
+
* - "any" → "required"
|
|
44
|
+
* - { type: "tool", name } → { type: "function", function: { name } }
|
|
45
|
+
*/
|
|
46
|
+
export function mapToOpenAICompletionsToolChoice(choice?: ToolChoice): OpenAICompletionsToolChoice {
|
|
47
|
+
if (!choice) return undefined;
|
|
48
|
+
if (typeof choice === "string") {
|
|
49
|
+
if (choice === "any") return "required";
|
|
50
|
+
if (choice === "auto" || choice === "none" || choice === "required") return choice;
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
const name = extractFunctionName(choice);
|
|
54
|
+
return name ? { type: "function", function: { name } } : undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Returns true when an OpenAI-completions `tool_choice` value forces a tool
|
|
59
|
+
* call (`"required"` or a function-name pin), as opposed to leaving it open
|
|
60
|
+
* (`"auto"`, `"none"`, or unset). Accepts `unknown` because the param shape
|
|
61
|
+
* pulled from the OpenAI SDK (`ChatCompletionToolChoiceOption`) widens with
|
|
62
|
+
* each release; this check only needs the open/forced bit.
|
|
63
|
+
*/
|
|
64
|
+
export function isForcedToolChoice(choice: unknown): boolean {
|
|
65
|
+
if (choice === undefined || choice === "auto" || choice === "none") return false;
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Map unified ToolChoice to OpenAI Responses API format.
|
|
71
|
+
* - "any" → "required"
|
|
72
|
+
* - { type: "tool", name } → { type: "function", name } (flat structure)
|
|
73
|
+
*/
|
|
74
|
+
export function mapToOpenAIResponsesToolChoice(choice?: ToolChoice): OpenAIResponsesToolChoice {
|
|
75
|
+
if (!choice) return undefined;
|
|
76
|
+
if (typeof choice === "string") {
|
|
77
|
+
if (choice === "any") return "required";
|
|
78
|
+
if (choice === "auto" || choice === "none" || choice === "required") return choice;
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
const name = extractFunctionName(choice);
|
|
82
|
+
return name ? { type: "function", name } : undefined;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Map unified ToolChoice to Anthropic-compatible format.
|
|
87
|
+
* - "required" → "any"
|
|
88
|
+
* - { type: "function", ... } → { type: "tool", name }
|
|
89
|
+
*/
|
|
90
|
+
export function mapToAnthropicToolChoice(choice?: ToolChoice): AnthropicToolChoice {
|
|
91
|
+
if (!choice) return undefined;
|
|
92
|
+
if (typeof choice === "string") {
|
|
93
|
+
if (choice === "required") return "any";
|
|
94
|
+
if (choice === "auto" || choice === "none" || choice === "any") return choice;
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
const name = extractFunctionName(choice);
|
|
98
|
+
return name ? { type: "tool", name } : undefined;
|
|
99
|
+
}
|