@vib-rato/ai 0.16.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/CHANGELOG.md +3354 -0
- package/README.md +1194 -0
- package/dist/types/adapter-internals/provider-safety-stop.d.ts +45 -0
- package/dist/types/api-registry.d.ts +30 -0
- package/dist/types/auth-broker/client.d.ts +80 -0
- package/dist/types/auth-broker/index.d.ts +5 -0
- package/dist/types/auth-broker/redact.d.ts +7 -0
- package/dist/types/auth-broker/refresher.d.ts +25 -0
- package/dist/types/auth-broker/remote-store.d.ts +153 -0
- package/dist/types/auth-broker/server.d.ts +32 -0
- package/dist/types/auth-broker/types.d.ts +132 -0
- package/dist/types/auth-broker/wire-schemas.d.ts +555 -0
- package/dist/types/auth-gateway/http.d.ts +40 -0
- package/dist/types/auth-gateway/index.d.ts +3 -0
- package/dist/types/auth-gateway/server.d.ts +70 -0
- package/dist/types/auth-gateway/types.d.ts +129 -0
- package/dist/types/auth-storage.d.ts +1074 -0
- package/dist/types/cli.d.ts +2 -0
- package/dist/types/codex-tools.d.ts +4 -0
- package/dist/types/context-cap-policy.d.ts +68 -0
- package/dist/types/core.d.ts +35 -0
- package/dist/types/index.d.ts +55 -0
- package/dist/types/model-cache.d.ts +24 -0
- package/dist/types/model-manager.d.ts +77 -0
- package/dist/types/model-pricing.d.ts +3 -0
- package/dist/types/model-retirements.d.ts +6 -0
- package/dist/types/model-thinking.d.ts +100 -0
- package/dist/types/models.d.ts +21 -0
- package/dist/types/openai-completions-compat.d.ts +34 -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 +293 -0
- package/dist/types/provider-models/special.d.ts +29 -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 +280 -0
- package/dist/types/providers/aws-credential-config.d.ts +19 -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 +22 -0
- package/dist/types/providers/composer-discipline.d.ts +32 -0
- package/dist/types/providers/cursor/client-version.d.ts +10 -0
- package/dist/types/providers/cursor/exec-modern.d.ts +98 -0
- package/dist/types/providers/cursor/gen/agent_pb.d.ts +16769 -0
- package/dist/types/providers/cursor-pi-args.d.ts +119 -0
- package/dist/types/providers/cursor.d.ts +72 -0
- package/dist/types/providers/dashscope-token-plan-headers.d.ts +57 -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 +26 -0
- package/dist/types/providers/google-gemini-cli.d.ts +75 -0
- package/dist/types/providers/google-gemini-headers.d.ts +43 -0
- package/dist/types/providers/google-shared.d.ts +183 -0
- package/dist/types/providers/google-types.d.ts +138 -0
- package/dist/types/providers/google-vertex.d.ts +11 -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/kiro-api-key.d.ts +50 -0
- package/dist/types/providers/kiro-codewhisperer.d.ts +11 -0
- package/dist/types/providers/mock.d.ts +189 -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-bounded-rate-limits.d.ts +3 -0
- package/dist/types/providers/openai-chat-server-schema.d.ts +1733 -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 +50 -0
- package/dist/types/providers/openai-codex/response-handler.d.ts +18 -0
- package/dist/types/providers/openai-codex-responses.d.ts +71 -0
- package/dist/types/providers/openai-completions-compat.d.ts +6 -0
- package/dist/types/providers/openai-completions.d.ts +35 -0
- package/dist/types/providers/openai-opencodex-responses.d.ts +10 -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 +106 -0
- package/dist/types/providers/openai-responses.d.ts +37 -0
- package/dist/types/providers/pi-native-client.d.ts +29 -0
- package/dist/types/providers/pi-native-server.d.ts +60 -0
- package/dist/types/providers/register-builtins.d.ts +59 -0
- package/dist/types/providers/synthetic.d.ts +26 -0
- package/dist/types/providers/transform-messages.d.ts +33 -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 +45 -0
- package/dist/types/types.d.ts +1073 -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 +17 -0
- package/dist/types/usage/kimi.d.ts +4 -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 +264 -0
- package/dist/types/utils/abort.d.ts +19 -0
- package/dist/types/utils/anthropic-auth.d.ts +39 -0
- package/dist/types/utils/block-symbols.d.ts +6 -0
- package/dist/types/utils/discovery/antigravity.d.ts +67 -0
- package/dist/types/utils/discovery/codex.d.ts +38 -0
- package/dist/types/utils/discovery/cursor.d.ts +49 -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 +81 -0
- package/dist/types/utils/event-stream.d.ts +41 -0
- package/dist/types/utils/fallback-transport.d.ts +110 -0
- package/dist/types/utils/fireworks-model-id.d.ts +10 -0
- package/dist/types/utils/foundry.d.ts +11 -0
- package/dist/types/utils/h2-fetch.d.ts +22 -0
- package/dist/types/utils/http-inspector.d.ts +59 -0
- package/dist/types/utils/idle-iterator.d.ts +122 -0
- package/dist/types/utils/json-parse.d.ts +98 -0
- package/dist/types/utils/oauth/alibaba-token-plan.d.ts +19 -0
- package/dist/types/utils/oauth/anthropic.d.ts +41 -0
- package/dist/types/utils/oauth/api-key-login.d.ts +38 -0
- package/dist/types/utils/oauth/api-key-validation.d.ts +39 -0
- package/dist/types/utils/oauth/bizrouter.d.ts +1 -0
- package/dist/types/utils/oauth/callback-server.d.ts +80 -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/commandcode.d.ts +1 -0
- package/dist/types/utils/oauth/cursor.d.ts +15 -0
- package/dist/types/utils/oauth/deepinfra.d.ts +1 -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/fugu.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/glm-zcode.d.ts +71 -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 +39 -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 +17 -0
- package/dist/types/utils/oauth/kiro.d.ts +71 -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/mara.d.ts +1 -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/opengateway.d.ts +1 -0
- package/dist/types/utils/oauth/openrouter.d.ts +1 -0
- package/dist/types/utils/oauth/parallel.d.ts +17 -0
- package/dist/types/utils/oauth/perplexity.d.ts +4 -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/sglang.d.ts +16 -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 +56 -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 +14 -0
- package/dist/types/utils/parse-bind.d.ts +26 -0
- package/dist/types/utils/provider-response.d.ts +6 -0
- package/dist/types/utils/provider-safety-stop.d.ts +8 -0
- package/dist/types/utils/proxy.d.ts +7 -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 +29 -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 +14 -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/root-combinator.d.ts +12 -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 +80 -0
- package/dist/types/utils/tool-choice-capability.d.ts +57 -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 +117 -0
- package/package.json +152 -0
- package/src/adapter-internals/provider-safety-stop.d.ts +45 -0
- package/src/adapter-internals/provider-safety-stop.ts +156 -0
- package/src/api-registry.d.ts +30 -0
- package/src/api-registry.ts +96 -0
- package/src/auth-broker/client.ts +444 -0
- package/src/auth-broker/index.ts +5 -0
- package/src/auth-broker/redact.ts +39 -0
- package/src/auth-broker/refresher.ts +130 -0
- package/src/auth-broker/remote-store.ts +1576 -0
- package/src/auth-broker/server.ts +764 -0
- package/src/auth-broker/types.ts +164 -0
- package/src/auth-broker/wire-schemas.ts +261 -0
- package/src/auth-gateway/http.ts +198 -0
- package/src/auth-gateway/index.ts +3 -0
- package/src/auth-gateway/server.ts +1315 -0
- package/src/auth-gateway/types.ts +160 -0
- package/src/auth-storage.ts +7312 -0
- package/src/cli.ts +269 -0
- package/src/codex-tools.d.ts +4 -0
- package/src/codex-tools.ts +24 -0
- package/src/context-cap-policy.d.ts +68 -0
- package/src/context-cap-policy.ts +123 -0
- package/src/core.ts +44 -0
- package/src/index.ts +61 -0
- package/src/model-cache.ts +236 -0
- package/src/model-manager.ts +744 -0
- package/src/model-pricing.d.ts +3 -0
- package/src/model-pricing.ts +68 -0
- package/src/model-retirements.d.ts +6 -0
- package/src/model-retirements.ts +19 -0
- package/src/model-thinking.d.ts +100 -0
- package/src/model-thinking.ts +1054 -0
- package/src/models.d.ts +21 -0
- package/src/models.json +94672 -0
- package/src/models.json.d.ts +9 -0
- package/src/models.ts +126 -0
- package/src/openai-completions-compat.d.ts +34 -0
- package/src/openai-completions-compat.ts +383 -0
- package/src/prompts/composer-bash-policy-recovery.md +1 -0
- package/src/prompts/cursor-composer-bash-policy-recovery.md +1 -0
- package/src/prompts/cursor-composer-edit-discipline.md +7 -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 +392 -0
- package/src/provider-models/google.ts +92 -0
- package/src/provider-models/index.ts +5 -0
- package/src/provider-models/ollama.ts +159 -0
- package/src/provider-models/openai-compat.ts +2920 -0
- package/src/provider-models/special.ts +185 -0
- package/src/providers/amazon-bedrock.d.ts +60 -0
- package/src/providers/amazon-bedrock.ts +939 -0
- package/src/providers/anthropic-messages-server-schema.ts +229 -0
- package/src/providers/anthropic-messages-server.ts +839 -0
- package/src/providers/anthropic.d.ts +280 -0
- package/src/providers/anthropic.ts +4421 -0
- package/src/providers/aws-credential-config.d.ts +19 -0
- package/src/providers/aws-credential-config.ts +179 -0
- package/src/providers/aws-credentials.d.ts +43 -0
- package/src/providers/aws-credentials.ts +457 -0
- package/src/providers/aws-eventstream.d.ts +38 -0
- package/src/providers/aws-eventstream.ts +185 -0
- package/src/providers/aws-sigv4.d.ts +55 -0
- package/src/providers/aws-sigv4.ts +218 -0
- package/src/providers/azure-openai-responses.d.ts +22 -0
- package/src/providers/azure-openai-responses.ts +447 -0
- package/src/providers/composer-discipline.d.ts +32 -0
- package/src/providers/composer-discipline.ts +95 -0
- package/src/providers/cursor/client-version.d.ts +10 -0
- package/src/providers/cursor/client-version.ts +10 -0
- package/src/providers/cursor/exec-modern.d.ts +98 -0
- package/src/providers/cursor/exec-modern.ts +497 -0
- package/src/providers/cursor/gen/agent_pb.d.ts +16769 -0
- package/src/providers/cursor/gen/agent_pb.ts +19780 -0
- package/src/providers/cursor/proto/agent.proto +4533 -0
- package/src/providers/cursor/proto/buf.gen.yaml +6 -0
- package/src/providers/cursor/proto/buf.yaml +17 -0
- package/src/providers/cursor-pi-args.d.ts +119 -0
- package/src/providers/cursor-pi-args.ts +187 -0
- package/src/providers/cursor.d.ts +72 -0
- package/src/providers/cursor.ts +3396 -0
- package/src/providers/dashscope-token-plan-headers.d.ts +57 -0
- package/src/providers/dashscope-token-plan-headers.ts +84 -0
- package/src/providers/error-message.d.ts +27 -0
- package/src/providers/error-message.ts +21 -0
- package/src/providers/github-copilot-headers.d.ts +40 -0
- package/src/providers/github-copilot-headers.ts +140 -0
- package/src/providers/gitlab-duo.d.ts +27 -0
- package/src/providers/gitlab-duo.ts +393 -0
- package/src/providers/google-auth.d.ts +26 -0
- package/src/providers/google-auth.ts +262 -0
- package/src/providers/google-gemini-cli.d.ts +75 -0
- package/src/providers/google-gemini-cli.ts +969 -0
- package/src/providers/google-gemini-headers.d.ts +43 -0
- package/src/providers/google-gemini-headers.ts +100 -0
- package/src/providers/google-shared.d.ts +183 -0
- package/src/providers/google-shared.ts +1105 -0
- package/src/providers/google-types.d.ts +138 -0
- package/src/providers/google-types.ts +167 -0
- package/src/providers/google-vertex.d.ts +11 -0
- package/src/providers/google-vertex.ts +124 -0
- package/src/providers/google.d.ts +4 -0
- package/src/providers/google.ts +41 -0
- package/src/providers/grammar.d.ts +1 -0
- package/src/providers/grammar.ts +70 -0
- package/src/providers/kimi.d.ts +27 -0
- package/src/providers/kimi.ts +52 -0
- package/src/providers/kiro-api-key.d.ts +50 -0
- package/src/providers/kiro-api-key.ts +786 -0
- package/src/providers/kiro-codewhisperer.d.ts +11 -0
- package/src/providers/kiro-codewhisperer.ts +600 -0
- package/src/providers/mock.ts +526 -0
- package/src/providers/ollama.d.ts +41 -0
- package/src/providers/ollama.ts +645 -0
- package/src/providers/openai-anthropic-shim.d.ts +31 -0
- package/src/providers/openai-anthropic-shim.ts +156 -0
- package/src/providers/openai-bounded-rate-limits.d.ts +3 -0
- package/src/providers/openai-bounded-rate-limits.ts +57 -0
- package/src/providers/openai-chat-server-schema.ts +254 -0
- package/src/providers/openai-chat-server.ts +724 -0
- package/src/providers/openai-codex/constants.d.ts +26 -0
- package/src/providers/openai-codex/constants.ts +43 -0
- package/src/providers/openai-codex/request-transformer.d.ts +50 -0
- package/src/providers/openai-codex/request-transformer.ts +219 -0
- package/src/providers/openai-codex/response-handler.d.ts +18 -0
- package/src/providers/openai-codex/response-handler.ts +111 -0
- package/src/providers/openai-codex-responses.d.ts +71 -0
- package/src/providers/openai-codex-responses.ts +3288 -0
- package/src/providers/openai-completions-compat.d.ts +6 -0
- package/src/providers/openai-completions-compat.ts +6 -0
- package/src/providers/openai-completions.d.ts +35 -0
- package/src/providers/openai-completions.ts +2294 -0
- package/src/providers/openai-opencodex-responses.ts +174 -0
- package/src/providers/openai-request-transform.d.ts +4 -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 +1268 -0
- package/src/providers/openai-responses-shared.d.ts +106 -0
- package/src/providers/openai-responses-shared.ts +1253 -0
- package/src/providers/openai-responses.d.ts +37 -0
- package/src/providers/openai-responses.ts +989 -0
- package/src/providers/pi-native-client.d.ts +29 -0
- package/src/providers/pi-native-client.ts +243 -0
- package/src/providers/pi-native-server.ts +488 -0
- package/src/providers/register-builtins.d.ts +59 -0
- package/src/providers/register-builtins.ts +544 -0
- package/src/providers/synthetic.d.ts +26 -0
- package/src/providers/synthetic.ts +50 -0
- package/src/providers/transform-messages.d.ts +33 -0
- package/src/providers/transform-messages.ts +408 -0
- package/src/providers/vision-guard.d.ts +8 -0
- package/src/providers/vision-guard.ts +31 -0
- package/src/rate-limit-utils.d.ts +19 -0
- package/src/rate-limit-utils.ts +102 -0
- package/src/stream.d.ts +45 -0
- package/src/stream.ts +1306 -0
- package/src/types.d.ts +1073 -0
- package/src/types.ts +1305 -0
- package/src/usage/claude.ts +449 -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 +259 -0
- package/src/usage/kimi.ts +285 -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 +190 -0
- package/src/utils/abort.d.ts +19 -0
- package/src/utils/abort.ts +51 -0
- package/src/utils/anthropic-auth.ts +95 -0
- package/src/utils/block-symbols.d.ts +6 -0
- package/src/utils/block-symbols.ts +11 -0
- package/src/utils/discovery/antigravity.ts +275 -0
- package/src/utils/discovery/codex.ts +362 -0
- package/src/utils/discovery/cursor.ts +388 -0
- package/src/utils/discovery/gemini.ts +248 -0
- package/src/utils/discovery/index.ts +4 -0
- package/src/utils/discovery/openai-compatible.ts +379 -0
- package/src/utils/event-stream.d.ts +41 -0
- package/src/utils/event-stream.ts +269 -0
- package/src/utils/fallback-transport.d.ts +110 -0
- package/src/utils/fallback-transport.ts +411 -0
- package/src/utils/fireworks-model-id.d.ts +10 -0
- package/src/utils/fireworks-model-id.ts +30 -0
- package/src/utils/foundry.d.ts +11 -0
- package/src/utils/foundry.ts +18 -0
- package/src/utils/h2-fetch.ts +60 -0
- package/src/utils/http-inspector.d.ts +59 -0
- package/src/utils/http-inspector.ts +380 -0
- package/src/utils/idle-iterator.d.ts +122 -0
- package/src/utils/idle-iterator.ts +410 -0
- package/src/utils/json-parse.d.ts +98 -0
- package/src/utils/json-parse.ts +607 -0
- package/src/utils/oauth/alibaba-token-plan.ts +60 -0
- package/src/utils/oauth/anthropic.ts +233 -0
- package/src/utils/oauth/api-key-login.ts +98 -0
- package/src/utils/oauth/api-key-validation.ts +344 -0
- package/src/utils/oauth/bizrouter.ts +15 -0
- package/src/utils/oauth/callback-server.d.ts +80 -0
- package/src/utils/oauth/callback-server.ts +359 -0
- package/src/utils/oauth/cerebras.ts +16 -0
- package/src/utils/oauth/cloudflare-ai-gateway.ts +48 -0
- package/src/utils/oauth/commandcode.ts +17 -0
- package/src/utils/oauth/cursor.ts +157 -0
- package/src/utils/oauth/deepinfra.ts +15 -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/fugu.ts +15 -0
- package/src/utils/oauth/github-copilot.d.ts +38 -0
- package/src/utils/oauth/github-copilot.ts +362 -0
- package/src/utils/oauth/gitlab-duo.ts +123 -0
- package/src/utils/oauth/glm-zcode.d.ts +71 -0
- package/src/utils/oauth/glm-zcode.ts +433 -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 +558 -0
- package/src/utils/oauth/kagi.ts +47 -0
- package/src/utils/oauth/kilo.ts +87 -0
- package/src/utils/oauth/kimi.d.ts +17 -0
- package/src/utils/oauth/kimi.ts +275 -0
- package/src/utils/oauth/kiro.ts +448 -0
- package/src/utils/oauth/litellm.ts +47 -0
- package/src/utils/oauth/lm-studio.ts +38 -0
- package/src/utils/oauth/mara.ts +16 -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/opengateway.ts +15 -0
- package/src/utils/oauth/openrouter.ts +16 -0
- package/src/utils/oauth/parallel.ts +46 -0
- package/src/utils/oauth/perplexity.ts +225 -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/sglang.ts +42 -0
- package/src/utils/oauth/synthetic.ts +15 -0
- package/src/utils/oauth/tavily.ts +46 -0
- package/src/utils/oauth/together.ts +16 -0
- package/src/utils/oauth/types.d.ts +56 -0
- package/src/utils/oauth/types.ts +122 -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 +42 -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 +275 -0
- package/src/utils/parse-bind.ts +81 -0
- package/src/utils/provider-response.d.ts +6 -0
- package/src/utils/provider-response.ts +30 -0
- package/src/utils/provider-safety-stop.ts +8 -0
- package/src/utils/proxy.d.ts +7 -0
- package/src/utils/proxy.ts +652 -0
- package/src/utils/retry-after.d.ts +3 -0
- package/src/utils/retry-after.ts +110 -0
- package/src/utils/retry-budget.d.ts +1 -0
- package/src/utils/retry-budget.ts +4 -0
- package/src/utils/retry.d.ts +29 -0
- package/src/utils/retry.ts +67 -0
- package/src/utils/schema/CONSTRAINTS.md +164 -0
- package/src/utils/schema/adapt.d.ts +24 -0
- package/src/utils/schema/adapt.ts +36 -0
- package/src/utils/schema/compatibility.d.ts +30 -0
- package/src/utils/schema/compatibility.ts +435 -0
- package/src/utils/schema/dereference.d.ts +11 -0
- package/src/utils/schema/dereference.ts +98 -0
- package/src/utils/schema/draft.d.ts +10 -0
- package/src/utils/schema/draft.ts +341 -0
- package/src/utils/schema/equality.d.ts +4 -0
- package/src/utils/schema/equality.ts +97 -0
- package/src/utils/schema/fields.d.ts +49 -0
- package/src/utils/schema/fields.ts +190 -0
- package/src/utils/schema/index.d.ts +14 -0
- package/src/utils/schema/index.ts +14 -0
- package/src/utils/schema/json-schema-validator.d.ts +12 -0
- package/src/utils/schema/json-schema-validator.ts +577 -0
- package/src/utils/schema/meta-validator.d.ts +2 -0
- package/src/utils/schema/meta-validator.ts +167 -0
- package/src/utils/schema/normalize.d.ts +93 -0
- package/src/utils/schema/normalize.ts +1588 -0
- package/src/utils/schema/root-combinator.d.ts +12 -0
- package/src/utils/schema/root-combinator.ts +143 -0
- package/src/utils/schema/spill.d.ts +8 -0
- package/src/utils/schema/spill.ts +43 -0
- package/src/utils/schema/stamps.d.ts +25 -0
- package/src/utils/schema/stamps.ts +97 -0
- package/src/utils/schema/types.d.ts +4 -0
- package/src/utils/schema/types.ts +11 -0
- package/src/utils/schema/wire.d.ts +54 -0
- package/src/utils/schema/wire.ts +213 -0
- package/src/utils/schema/zod-decontaminate.d.ts +31 -0
- package/src/utils/schema/zod-decontaminate.ts +331 -0
- package/src/utils/sse-debug.d.ts +10 -0
- package/src/utils/sse-debug.ts +289 -0
- package/src/utils/tool-call-healing.d.ts +80 -0
- package/src/utils/tool-call-healing.ts +298 -0
- package/src/utils/tool-choice-capability.d.ts +57 -0
- package/src/utils/tool-choice-capability.ts +633 -0
- package/src/utils/tool-choice.d.ts +50 -0
- package/src/utils/tool-choice.ts +99 -0
- package/src/utils/validation.ts +1080 -0
- package/src/utils.d.ts +117 -0
- package/src/utils.ts +523 -0
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import * as net from "node:net";
|
|
2
|
+
import { UNK_CONTEXT_WINDOW, UNK_MAX_TOKENS } from "@vib-rato/ai";
|
|
3
|
+
import * as z from "zod/v4";
|
|
4
|
+
import type { Api, FetchImpl, Model, Provider } from "../../types";
|
|
5
|
+
import { toNumber } from "../../utils";
|
|
6
|
+
|
|
7
|
+
const MODELS_PATH = "/models";
|
|
8
|
+
const MAX_MODELS_RESPONSE_BYTES = 1_000_000;
|
|
9
|
+
const MAX_CATALOG_MODEL_ID_LENGTH = 200;
|
|
10
|
+
|
|
11
|
+
function parseIpv6Hextets(host: string): number[] | undefined {
|
|
12
|
+
if (net.isIP(host) !== 6) return undefined;
|
|
13
|
+
const doubleColon = host.indexOf("::");
|
|
14
|
+
if (doubleColon !== host.lastIndexOf("::")) return undefined;
|
|
15
|
+
const parseSide = (value: string): number[] | undefined => {
|
|
16
|
+
if (!value) return [];
|
|
17
|
+
const parts = value.split(":");
|
|
18
|
+
if (parts.some(part => !/^[0-9a-f]{1,4}$/i.test(part))) return undefined;
|
|
19
|
+
return parts.map(part => Number.parseInt(part, 16));
|
|
20
|
+
};
|
|
21
|
+
if (doubleColon < 0) {
|
|
22
|
+
const hextets = parseSide(host);
|
|
23
|
+
return hextets?.length === 8 ? hextets : undefined;
|
|
24
|
+
}
|
|
25
|
+
const left = parseSide(host.slice(0, doubleColon));
|
|
26
|
+
const right = parseSide(host.slice(doubleColon + 2));
|
|
27
|
+
if (!left || !right) return undefined;
|
|
28
|
+
const missing = 8 - left.length - right.length;
|
|
29
|
+
if (missing < 1) return undefined;
|
|
30
|
+
return [...left, ...new Array<number>(missing).fill(0), ...right];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function isLoopbackHost(hostname: string): boolean {
|
|
34
|
+
const host = hostname.toLowerCase().replace(/^\[|\]$/g, "");
|
|
35
|
+
if (host === "localhost") return true;
|
|
36
|
+
if (net.isIP(host) === 4) return host.split(".", 1)[0] === "127";
|
|
37
|
+
const hextets = parseIpv6Hextets(host);
|
|
38
|
+
if (!hextets) return false;
|
|
39
|
+
const isIpv6Loopback = hextets.slice(0, 7).every(part => part === 0) && hextets[7] === 1;
|
|
40
|
+
const isIpv4MappedLoopback =
|
|
41
|
+
hextets.slice(0, 5).every(part => part === 0) && hextets[5] === 0xffff && hextets[6]! >> 8 === 0x7f;
|
|
42
|
+
return isIpv6Loopback || isIpv4MappedLoopback;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Catalog identities are rendered and used for routing; unsafe values are dropped, never rewritten. */
|
|
46
|
+
export function isSafeCatalogModelId(value: unknown): value is string {
|
|
47
|
+
return (
|
|
48
|
+
typeof value === "string" &&
|
|
49
|
+
value.trim().length > 0 &&
|
|
50
|
+
value.length <= MAX_CATALOG_MODEL_ID_LENGTH &&
|
|
51
|
+
!/[\u0000-\u001f\u007f-\u009f]/u.test(value)
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Minimal OpenAI-style model entry shape consumed by discovery.
|
|
57
|
+
*
|
|
58
|
+
* Providers may return additional fields; this type only captures
|
|
59
|
+
* fields that are useful for generic normalization.
|
|
60
|
+
*/
|
|
61
|
+
export interface OpenAICompatibleModelRecord {
|
|
62
|
+
id?: unknown;
|
|
63
|
+
name?: unknown;
|
|
64
|
+
object?: unknown;
|
|
65
|
+
owned_by?: unknown;
|
|
66
|
+
[key: string]: unknown;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Tolerant envelope for OpenAI-compatible `/models` responses.
|
|
71
|
+
*
|
|
72
|
+
* Common providers return `{ data: [...] }`, but variants such as
|
|
73
|
+
* `{ models: [...] }`, `{ result: [...] }`, or direct arrays are also
|
|
74
|
+
* accepted during extraction.
|
|
75
|
+
*/
|
|
76
|
+
export interface OpenAICompatibleModelsEnvelope {
|
|
77
|
+
data?: unknown;
|
|
78
|
+
models?: unknown;
|
|
79
|
+
result?: unknown;
|
|
80
|
+
items?: unknown;
|
|
81
|
+
[key: string]: unknown;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const openAICompatibleModelRecordSchema = z
|
|
85
|
+
.object({
|
|
86
|
+
id: z.string().min(1),
|
|
87
|
+
name: z.string().optional().nullable(),
|
|
88
|
+
object: z.unknown().optional(),
|
|
89
|
+
owned_by: z.unknown().optional(),
|
|
90
|
+
})
|
|
91
|
+
.loose();
|
|
92
|
+
|
|
93
|
+
const openAICompatibleModelsEnvelopeSchema = z
|
|
94
|
+
.object({
|
|
95
|
+
data: z.unknown().optional(),
|
|
96
|
+
models: z.unknown().optional(),
|
|
97
|
+
result: z.unknown().optional(),
|
|
98
|
+
items: z.unknown().optional(),
|
|
99
|
+
})
|
|
100
|
+
.loose();
|
|
101
|
+
|
|
102
|
+
const openAICompatibleModelsPayloadSchema = z.union([z.array(z.unknown()), openAICompatibleModelsEnvelopeSchema]);
|
|
103
|
+
|
|
104
|
+
type ParsedOpenAICompatibleModelRecord = z.infer<typeof openAICompatibleModelRecordSchema>;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Context passed to custom OpenAI-compatible model mappers.
|
|
108
|
+
*/
|
|
109
|
+
export interface OpenAICompatibleModelMapperContext<TApi extends Api> {
|
|
110
|
+
api: TApi;
|
|
111
|
+
provider: Provider;
|
|
112
|
+
baseUrl: string;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Options for fetching and normalizing OpenAI-compatible `/models` catalogs.
|
|
117
|
+
*/
|
|
118
|
+
export interface FetchOpenAICompatibleModelsOptions<TApi extends Api> {
|
|
119
|
+
/** API type assigned to normalized models. */
|
|
120
|
+
api: TApi;
|
|
121
|
+
/** Provider id assigned to normalized models. */
|
|
122
|
+
provider: Provider;
|
|
123
|
+
/** Provider base URL used for both fetch and normalized model records. */
|
|
124
|
+
baseUrl: string;
|
|
125
|
+
/** Optional bearer token for Authorization header. */
|
|
126
|
+
apiKey?: string;
|
|
127
|
+
/** Additional request headers. */
|
|
128
|
+
headers?: Record<string, string>;
|
|
129
|
+
/** Optional AbortSignal for request cancellation. */
|
|
130
|
+
signal?: AbortSignal;
|
|
131
|
+
/** Optional fetch implementation override for testing/custom runtimes. */
|
|
132
|
+
fetch?: FetchImpl;
|
|
133
|
+
/** Optional HTTP status predicate for provider-specific hard failures. */
|
|
134
|
+
throwOnStatus?: (response: Response) => Error | undefined;
|
|
135
|
+
/**
|
|
136
|
+
* Optional post-normalization filter.
|
|
137
|
+
* Return false to skip a model.
|
|
138
|
+
*/
|
|
139
|
+
filterModel?: (entry: OpenAICompatibleModelRecord, model: Model<TApi>) => boolean;
|
|
140
|
+
/**
|
|
141
|
+
* Optional mapper override for provider-specific quirks.
|
|
142
|
+
* Return null to skip a model.
|
|
143
|
+
*/
|
|
144
|
+
mapModel?: (
|
|
145
|
+
entry: OpenAICompatibleModelRecord,
|
|
146
|
+
defaults: Model<TApi>,
|
|
147
|
+
context: OpenAICompatibleModelMapperContext<TApi>,
|
|
148
|
+
) => Model<TApi> | null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Resolves an endpoint for an implicit local provider without allowing an
|
|
153
|
+
* environment override to turn its keyless discovery into a remote request.
|
|
154
|
+
*/
|
|
155
|
+
export function resolveLoopbackOpenAIBaseUrl(value: string | undefined, fallback: string): string {
|
|
156
|
+
const candidate = value?.trim();
|
|
157
|
+
if (!candidate) return fallback;
|
|
158
|
+
try {
|
|
159
|
+
const parsed = new URL(candidate);
|
|
160
|
+
if ((parsed.protocol === "http:" || parsed.protocol === "https:") && isLoopbackHost(parsed.hostname)) {
|
|
161
|
+
return candidate;
|
|
162
|
+
}
|
|
163
|
+
} catch {
|
|
164
|
+
// Fall back to the fixed loopback endpoint below.
|
|
165
|
+
}
|
|
166
|
+
return fallback;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Fetches and normalizes an OpenAI-compatible `/models` catalog.
|
|
171
|
+
*
|
|
172
|
+
* Returns `null` on transport/protocol failures.
|
|
173
|
+
* Returns `[]` only when the endpoint responds successfully with no usable models.
|
|
174
|
+
*/
|
|
175
|
+
export async function fetchOpenAICompatibleModels<TApi extends Api>(
|
|
176
|
+
options: FetchOpenAICompatibleModelsOptions<TApi>,
|
|
177
|
+
): Promise<Model<TApi>[] | null> {
|
|
178
|
+
const baseUrl = normalizeBaseUrl(options.baseUrl);
|
|
179
|
+
if (!baseUrl) {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const requestHeaders: Record<string, string> = {
|
|
184
|
+
Accept: "application/json",
|
|
185
|
+
...options.headers,
|
|
186
|
+
};
|
|
187
|
+
if (options.apiKey) {
|
|
188
|
+
requestHeaders.Authorization = `Bearer ${options.apiKey}`;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
192
|
+
let response: Response;
|
|
193
|
+
try {
|
|
194
|
+
response = await fetchImpl(buildModelsUrl(baseUrl), {
|
|
195
|
+
method: "GET",
|
|
196
|
+
headers: requestHeaders,
|
|
197
|
+
signal: options.signal
|
|
198
|
+
? AbortSignal.any([options.signal, AbortSignal.timeout(5_000)])
|
|
199
|
+
: AbortSignal.timeout(5_000),
|
|
200
|
+
});
|
|
201
|
+
} catch {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (!response.ok) {
|
|
206
|
+
const hardFailure = options.throwOnStatus?.(response);
|
|
207
|
+
if (hardFailure) {
|
|
208
|
+
throw hardFailure;
|
|
209
|
+
}
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
let payload: unknown;
|
|
214
|
+
try {
|
|
215
|
+
payload = JSON.parse(await readModelsResponse(response));
|
|
216
|
+
} catch {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const entries = extractModelEntries(payload);
|
|
221
|
+
if (entries === null) {
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const context: OpenAICompatibleModelMapperContext<TApi> = {
|
|
226
|
+
api: options.api,
|
|
227
|
+
provider: options.provider,
|
|
228
|
+
baseUrl,
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const deduped = new Map<string, Model<TApi>>();
|
|
232
|
+
for (const entry of entries) {
|
|
233
|
+
if (!isSafeCatalogModelId(entry.id)) {
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
const rawContextWindow = firstPositiveModelNumber(
|
|
237
|
+
UNK_CONTEXT_WINDOW,
|
|
238
|
+
entry.max_model_len,
|
|
239
|
+
entry.context_length,
|
|
240
|
+
entry.context_window,
|
|
241
|
+
entry.max_context_length,
|
|
242
|
+
entry.max_position_embeddings,
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
const rawMaxTokens = firstPositiveModelNumber(UNK_MAX_TOKENS, entry.max_tokens, entry.max_output_tokens);
|
|
246
|
+
|
|
247
|
+
const defaults: Model<TApi> = {
|
|
248
|
+
id: entry.id,
|
|
249
|
+
name: typeof entry.name === "string" && entry.name.length > 0 ? entry.name : entry.id,
|
|
250
|
+
api: options.api,
|
|
251
|
+
provider: options.provider,
|
|
252
|
+
baseUrl,
|
|
253
|
+
reasoning: false,
|
|
254
|
+
input: ["text"],
|
|
255
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
256
|
+
contextWindow: rawContextWindow,
|
|
257
|
+
maxTokens: rawMaxTokens,
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const mapped = options.mapModel?.(entry, defaults, context) ?? defaults;
|
|
261
|
+
if (!mapped || !isSafeCatalogModelId(mapped.id)) {
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
if (options.filterModel && !options.filterModel(entry, mapped)) {
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
deduped.set(mapped.id, mapped);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return Array.from(deduped.values()).sort((left, right) => left.id.localeCompare(right.id));
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
async function readModelsResponse(response: Response): Promise<string> {
|
|
274
|
+
const contentLength = Number(response.headers.get("content-length"));
|
|
275
|
+
if (Number.isFinite(contentLength) && contentLength > MAX_MODELS_RESPONSE_BYTES) {
|
|
276
|
+
throw new Error("OpenAI-compatible models response exceeds the size limit");
|
|
277
|
+
}
|
|
278
|
+
if (!response.body) return "";
|
|
279
|
+
const reader = response.body.getReader();
|
|
280
|
+
const chunks: Uint8Array[] = [];
|
|
281
|
+
let total = 0;
|
|
282
|
+
try {
|
|
283
|
+
while (true) {
|
|
284
|
+
const { done, value } = await reader.read();
|
|
285
|
+
if (done) break;
|
|
286
|
+
if (!value) continue;
|
|
287
|
+
total += value.byteLength;
|
|
288
|
+
if (total > MAX_MODELS_RESPONSE_BYTES) {
|
|
289
|
+
await reader.cancel();
|
|
290
|
+
throw new Error("OpenAI-compatible models response exceeds the size limit");
|
|
291
|
+
}
|
|
292
|
+
chunks.push(value);
|
|
293
|
+
}
|
|
294
|
+
} finally {
|
|
295
|
+
reader.releaseLock();
|
|
296
|
+
}
|
|
297
|
+
const body = new Uint8Array(total);
|
|
298
|
+
let offset = 0;
|
|
299
|
+
for (const chunk of chunks) {
|
|
300
|
+
body.set(chunk, offset);
|
|
301
|
+
offset += chunk.byteLength;
|
|
302
|
+
}
|
|
303
|
+
return new TextDecoder().decode(body);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function normalizeBaseUrl(baseUrl: string): string {
|
|
307
|
+
const trimmed = baseUrl.trim();
|
|
308
|
+
if (!trimmed) {
|
|
309
|
+
return "";
|
|
310
|
+
}
|
|
311
|
+
try {
|
|
312
|
+
const parsed = new URL(trimmed);
|
|
313
|
+
parsed.pathname = parsed.pathname.replace(/\/+$/g, "");
|
|
314
|
+
return parsed.toString();
|
|
315
|
+
} catch {
|
|
316
|
+
return trimmed.endsWith("/") ? trimmed.slice(0, -1) : trimmed;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function buildModelsUrl(baseUrl: string): string {
|
|
321
|
+
try {
|
|
322
|
+
const parsed = new URL(baseUrl);
|
|
323
|
+
parsed.pathname = `${parsed.pathname.replace(/\/+$/g, "")}${MODELS_PATH}`;
|
|
324
|
+
return parsed.toString();
|
|
325
|
+
} catch {
|
|
326
|
+
return `${baseUrl}${MODELS_PATH}`;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function extractModelEntries(payload: unknown): ParsedOpenAICompatibleModelRecord[] | null {
|
|
331
|
+
return extractModelEntriesFromNode(payload);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function extractModelEntriesFromNode(node: unknown): ParsedOpenAICompatibleModelRecord[] | null {
|
|
335
|
+
const parsedPayload = openAICompatibleModelsPayloadSchema.safeParse(node);
|
|
336
|
+
if (!parsedPayload.success) {
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
if (Array.isArray(parsedPayload.data)) {
|
|
340
|
+
const parsedEntries = parsedPayload.data
|
|
341
|
+
.map(entry => openAICompatibleModelRecordSchema.safeParse(entry))
|
|
342
|
+
.flatMap(entry => (entry.success ? [entry.data] : []));
|
|
343
|
+
return parsedEntries;
|
|
344
|
+
}
|
|
345
|
+
for (const candidate of [
|
|
346
|
+
parsedPayload.data.data,
|
|
347
|
+
parsedPayload.data.models,
|
|
348
|
+
parsedPayload.data.result,
|
|
349
|
+
parsedPayload.data.items,
|
|
350
|
+
]) {
|
|
351
|
+
if (candidate === undefined) {
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
const nested = extractModelEntriesFromNode(candidate);
|
|
355
|
+
if (nested !== null) {
|
|
356
|
+
return nested;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* First positive safe integer among candidates, else the fallback.
|
|
365
|
+
*
|
|
366
|
+
* Rejects non-numbers, non-finite values (JSON `1e400` parses to `Infinity`),
|
|
367
|
+
* fractions, values outside the safe integer range, zero, and negatives so a
|
|
368
|
+
* malformed catalog field can never poison compaction thresholds or output
|
|
369
|
+
* budgets.
|
|
370
|
+
*/
|
|
371
|
+
function firstPositiveModelNumber(fallback: number, ...candidates: readonly unknown[]): number {
|
|
372
|
+
for (const candidate of candidates) {
|
|
373
|
+
const value = toNumber(candidate);
|
|
374
|
+
if (value !== undefined && Number.isSafeInteger(value) && value > 0) {
|
|
375
|
+
return value;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return fallback;
|
|
379
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { AssistantMessage, AssistantMessageEvent } from "../types";
|
|
2
|
+
export declare class EventStream<T, R = T> implements AsyncIterable<T> {
|
|
3
|
+
#private;
|
|
4
|
+
waiting: Array<{
|
|
5
|
+
resolve: (value: IteratorResult<T>) => void;
|
|
6
|
+
reject: (err: unknown) => void;
|
|
7
|
+
}>;
|
|
8
|
+
done: boolean;
|
|
9
|
+
finalResultPromise: Promise<R>;
|
|
10
|
+
resolveFinalResult: (result: R) => void;
|
|
11
|
+
rejectFinalResult: (err: unknown) => void;
|
|
12
|
+
isComplete: (event: T) => boolean;
|
|
13
|
+
extractResult: (event: T) => R;
|
|
14
|
+
constructor(isComplete: (event: T) => boolean, extractResult: (event: T) => R, onConsumerClose?: () => void);
|
|
15
|
+
/**
|
|
16
|
+
* Read-only snapshot of the not-yet-consumed events. Always a fresh copy:
|
|
17
|
+
* external code can never mutate internal queue state or observe head-index
|
|
18
|
+
* tombstones or private consumer-drain sentinels, so the deque cannot desynchronize.
|
|
19
|
+
*/
|
|
20
|
+
get queue(): T[];
|
|
21
|
+
/** Read-only test seam for outstanding consumer-drain waiters. */
|
|
22
|
+
get pendingConsumerDrainCountForTests(): number;
|
|
23
|
+
/** Whether an async iterator is currently consuming this stream. */
|
|
24
|
+
get hasActiveConsumer(): boolean;
|
|
25
|
+
push(event: T): void;
|
|
26
|
+
deliver(event: T): void;
|
|
27
|
+
/**
|
|
28
|
+
* Resolves after every event enqueued before this call has been yielded and
|
|
29
|
+
* the consumer asks the iterator for its next node. The private sentinel is
|
|
30
|
+
* never exposed through the async iterator.
|
|
31
|
+
*/
|
|
32
|
+
waitForConsumerDrain(signal: AbortSignal): Promise<void>;
|
|
33
|
+
end(result?: R): void;
|
|
34
|
+
endWaiting(): void;
|
|
35
|
+
fail(err: unknown): void;
|
|
36
|
+
[Symbol.asyncIterator](): AsyncIterator<T>;
|
|
37
|
+
result(): Promise<R>;
|
|
38
|
+
}
|
|
39
|
+
export declare class AssistantMessageEventStream extends EventStream<AssistantMessageEvent, AssistantMessage> {
|
|
40
|
+
constructor(onConsumerClose?: () => void);
|
|
41
|
+
}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import type { AssistantMessage, AssistantMessageEvent } from "../types";
|
|
2
|
+
|
|
3
|
+
interface EventQueueNode<T> {
|
|
4
|
+
type: "event";
|
|
5
|
+
event: T;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
type QueueNode<T> = EventQueueNode<T> | { type: "consumer-drain"; drain: ConsumerDrain };
|
|
9
|
+
|
|
10
|
+
interface ConsumerDrain {
|
|
11
|
+
settled: boolean;
|
|
12
|
+
signal: AbortSignal;
|
|
13
|
+
abortListener: () => void;
|
|
14
|
+
resolve: () => void;
|
|
15
|
+
reject: (reason: unknown) => void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function abortReason(signal: AbortSignal): unknown {
|
|
19
|
+
return signal.reason ?? new DOMException("The operation was aborted.", "AbortError");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Generic event stream class for async iteration
|
|
23
|
+
|
|
24
|
+
export class EventStream<T, R = T> implements AsyncIterable<T> {
|
|
25
|
+
#queue: QueueNode<T>[] = [];
|
|
26
|
+
#queueHead = 0;
|
|
27
|
+
waiting: Array<{ resolve: (value: IteratorResult<T>) => void; reject: (err: unknown) => void }> = [];
|
|
28
|
+
#pendingConsumerDrains = new Set<ConsumerDrain>();
|
|
29
|
+
#activeConsumerCount = 0;
|
|
30
|
+
done = false;
|
|
31
|
+
#failed = false;
|
|
32
|
+
#error: unknown = undefined;
|
|
33
|
+
finalResultPromise: Promise<R>;
|
|
34
|
+
resolveFinalResult!: (result: R) => void;
|
|
35
|
+
rejectFinalResult!: (err: unknown) => void;
|
|
36
|
+
isComplete: (event: T) => boolean;
|
|
37
|
+
extractResult: (event: T) => R;
|
|
38
|
+
#onConsumerClose?: () => void;
|
|
39
|
+
|
|
40
|
+
constructor(isComplete: (event: T) => boolean, extractResult: (event: T) => R, onConsumerClose?: () => void) {
|
|
41
|
+
const { promise, resolve, reject } = Promise.withResolvers<R>();
|
|
42
|
+
// Prevent an unhandled rejection when fail() is called but nobody awaits result().
|
|
43
|
+
// Callers who do await result() still receive the rejection normally.
|
|
44
|
+
promise.catch(() => {});
|
|
45
|
+
this.finalResultPromise = promise;
|
|
46
|
+
this.resolveFinalResult = resolve;
|
|
47
|
+
this.rejectFinalResult = reject;
|
|
48
|
+
this.isComplete = isComplete;
|
|
49
|
+
this.extractResult = extractResult;
|
|
50
|
+
this.#onConsumerClose = onConsumerClose;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
#enqueue(node: QueueNode<T>): void {
|
|
54
|
+
this.#queue.push(node);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
#dequeue(): QueueNode<T> | undefined {
|
|
58
|
+
if (this.#queueHead >= this.#queue.length) return undefined;
|
|
59
|
+
const node = this.#queue[this.#queueHead]!;
|
|
60
|
+
this.#queue[this.#queueHead] = undefined as unknown as QueueNode<T>;
|
|
61
|
+
this.#queueHead++;
|
|
62
|
+
if (this.#queueHead > 1024 && this.#queueHead * 2 >= this.#queue.length) {
|
|
63
|
+
this.#queue = this.#queue.slice(this.#queueHead);
|
|
64
|
+
this.#queueHead = 0;
|
|
65
|
+
}
|
|
66
|
+
return node;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
get #queueLength(): number {
|
|
70
|
+
return this.#queue.length - this.#queueHead;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Read-only snapshot of the not-yet-consumed events. Always a fresh copy:
|
|
75
|
+
* external code can never mutate internal queue state or observe head-index
|
|
76
|
+
* tombstones or private consumer-drain sentinels, so the deque cannot desynchronize.
|
|
77
|
+
*/
|
|
78
|
+
get queue(): T[] {
|
|
79
|
+
return this.#queue.slice(this.#queueHead).flatMap(node => (node.type === "event" ? [node.event] : []));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Read-only test seam for outstanding consumer-drain waiters. */
|
|
83
|
+
get pendingConsumerDrainCountForTests(): number {
|
|
84
|
+
return this.#pendingConsumerDrains.size;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Whether an async iterator is currently consuming this stream. */
|
|
88
|
+
get hasActiveConsumer(): boolean {
|
|
89
|
+
return this.#activeConsumerCount > 0;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
#settleConsumerDrain(drain: ConsumerDrain, status: "resolve" | "reject", reason?: unknown): void {
|
|
93
|
+
if (drain.settled) return;
|
|
94
|
+
drain.settled = true;
|
|
95
|
+
this.#pendingConsumerDrains.delete(drain);
|
|
96
|
+
drain.signal.removeEventListener("abort", drain.abortListener);
|
|
97
|
+
if (status === "resolve") {
|
|
98
|
+
drain.resolve();
|
|
99
|
+
} else {
|
|
100
|
+
drain.reject(reason);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
#settleAllConsumerDrains(status: "resolve" | "reject", reason?: unknown): void {
|
|
105
|
+
for (const drain of this.#pendingConsumerDrains) {
|
|
106
|
+
this.#settleConsumerDrain(drain, status, reason);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
#drainQueuedNodesToWaitingConsumers(): void {
|
|
111
|
+
while (this.waiting.length > 0 && this.#queueLength > 0) {
|
|
112
|
+
const node = this.#dequeue()!;
|
|
113
|
+
if (node.type === "consumer-drain") {
|
|
114
|
+
this.#settleConsumerDrain(node.drain, "resolve");
|
|
115
|
+
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
this.waiting.shift()!.resolve({ value: node.event, done: false });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
#dequeueEvent(): EventQueueNode<T> | undefined {
|
|
123
|
+
while (this.#queueLength > 0) {
|
|
124
|
+
const node = this.#dequeue()!;
|
|
125
|
+
if (node.type === "event") return node;
|
|
126
|
+
this.#settleConsumerDrain(node.drain, "resolve");
|
|
127
|
+
}
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
push(event: T): void {
|
|
132
|
+
if (this.done) return;
|
|
133
|
+
try {
|
|
134
|
+
if (this.isComplete(event)) {
|
|
135
|
+
const result = this.extractResult(event);
|
|
136
|
+
this.done = true;
|
|
137
|
+
this.resolveFinalResult(result);
|
|
138
|
+
}
|
|
139
|
+
} catch (error) {
|
|
140
|
+
this.fail(error);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
this.deliver(event);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
deliver(event: T): void {
|
|
147
|
+
if (this.#queueLength === 0) {
|
|
148
|
+
const waiter = this.waiting.shift();
|
|
149
|
+
if (waiter) {
|
|
150
|
+
waiter.resolve({ value: event, done: false });
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
this.#enqueue({ type: "event", event });
|
|
155
|
+
this.#drainQueuedNodesToWaitingConsumers();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Resolves after every event enqueued before this call has been yielded and
|
|
160
|
+
* the consumer asks the iterator for its next node. The private sentinel is
|
|
161
|
+
* never exposed through the async iterator.
|
|
162
|
+
*/
|
|
163
|
+
waitForConsumerDrain(signal: AbortSignal): Promise<void> {
|
|
164
|
+
if (signal.aborted) return Promise.reject(abortReason(signal));
|
|
165
|
+
if (this.#failed) return Promise.reject(this.#error);
|
|
166
|
+
if (this.done && this.#activeConsumerCount === 0) {
|
|
167
|
+
if (this.#queueLength === 0) return Promise.resolve();
|
|
168
|
+
return Promise.reject(new Error("Event stream ended before queued events could be drained"));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const { promise, resolve, reject } = Promise.withResolvers<void>();
|
|
172
|
+
let drain!: ConsumerDrain;
|
|
173
|
+
const abortListener = () => this.#settleConsumerDrain(drain, "reject", abortReason(signal));
|
|
174
|
+
|
|
175
|
+
drain = { settled: false, signal, abortListener, resolve, reject };
|
|
176
|
+
this.#pendingConsumerDrains.add(drain);
|
|
177
|
+
signal.addEventListener("abort", abortListener, { once: true });
|
|
178
|
+
this.#enqueue({ type: "consumer-drain", drain });
|
|
179
|
+
this.#drainQueuedNodesToWaitingConsumers();
|
|
180
|
+
return promise;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
end(result?: R): void {
|
|
184
|
+
this.done = true;
|
|
185
|
+
if (this.#activeConsumerCount === 0) {
|
|
186
|
+
this.#settleAllConsumerDrains("reject", new Error("Event stream ended before consumer drain completed"));
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (result !== undefined) {
|
|
190
|
+
this.resolveFinalResult(result);
|
|
191
|
+
}
|
|
192
|
+
// Notify all waiting consumers that we're done
|
|
193
|
+
while (this.waiting.length > 0) {
|
|
194
|
+
const waiter = this.waiting.shift()!;
|
|
195
|
+
waiter.resolve({ value: undefined as any, done: true });
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
endWaiting(): void {
|
|
200
|
+
if (this.#activeConsumerCount === 0) {
|
|
201
|
+
this.#settleAllConsumerDrains("reject", new Error("Event stream ended before consumer drain completed"));
|
|
202
|
+
}
|
|
203
|
+
while (this.waiting.length > 0) {
|
|
204
|
+
const waiter = this.waiting.shift()!;
|
|
205
|
+
waiter.resolve({ value: undefined as any, done: true });
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
fail(err: unknown): void {
|
|
210
|
+
if (this.done) return;
|
|
211
|
+
this.done = true;
|
|
212
|
+
this.#failed = true;
|
|
213
|
+
this.#error = err;
|
|
214
|
+
this.#settleAllConsumerDrains("reject", err);
|
|
215
|
+
|
|
216
|
+
this.rejectFinalResult(err);
|
|
217
|
+
while (this.waiting.length > 0) {
|
|
218
|
+
const waiter = this.waiting.shift()!;
|
|
219
|
+
waiter.reject(err);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
async *[Symbol.asyncIterator](): AsyncIterator<T> {
|
|
224
|
+
this.#activeConsumerCount += 1;
|
|
225
|
+
try {
|
|
226
|
+
while (true) {
|
|
227
|
+
const node = this.#dequeueEvent();
|
|
228
|
+
if (node !== undefined) {
|
|
229
|
+
yield node.event;
|
|
230
|
+
} else if (this.#failed) {
|
|
231
|
+
throw this.#error;
|
|
232
|
+
} else if (this.done) {
|
|
233
|
+
return;
|
|
234
|
+
} else {
|
|
235
|
+
const result = await new Promise<IteratorResult<T>>((resolve, reject) =>
|
|
236
|
+
this.waiting.push({ resolve, reject }),
|
|
237
|
+
);
|
|
238
|
+
if (result.done) return;
|
|
239
|
+
yield result.value;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
} finally {
|
|
243
|
+
this.#activeConsumerCount -= 1;
|
|
244
|
+
this.#settleAllConsumerDrains("reject", new Error("Event stream consumer stopped before drain completed"));
|
|
245
|
+
if (!this.done) this.#onConsumerClose?.();
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
result(): Promise<R> {
|
|
250
|
+
return this.finalResultPromise;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export class AssistantMessageEventStream extends EventStream<AssistantMessageEvent, AssistantMessage> {
|
|
255
|
+
constructor(onConsumerClose?: () => void) {
|
|
256
|
+
super(
|
|
257
|
+
event => event.type === "done" || event.type === "error",
|
|
258
|
+
event => {
|
|
259
|
+
if (event.type === "done") {
|
|
260
|
+
return event.message;
|
|
261
|
+
} else if (event.type === "error") {
|
|
262
|
+
return event.error;
|
|
263
|
+
}
|
|
264
|
+
throw new Error("Unexpected event type for final result");
|
|
265
|
+
},
|
|
266
|
+
onConsumerClose,
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
}
|