@linxiraos/pi-ai 1.0.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 +5066 -0
- package/README.md +1195 -0
- package/dist/types/api-registry.d.ts +30 -0
- package/dist/types/auth/sqlite-credential-store.d.ts +117 -0
- package/dist/types/auth-broker/client.d.ts +93 -0
- package/dist/types/auth-broker/discover.d.ts +39 -0
- package/dist/types/auth-broker/index.d.ts +7 -0
- package/dist/types/auth-broker/refresher.d.ts +25 -0
- package/dist/types/auth-broker/remote-store.d.ts +136 -0
- package/dist/types/auth-broker/server.d.ts +48 -0
- package/dist/types/auth-broker/snapshot-cache.d.ts +17 -0
- package/dist/types/auth-broker/types.d.ts +152 -0
- package/dist/types/auth-broker/wire-schema-resource.d.ts +53 -0
- package/dist/types/auth-broker/wire-schemas.d.ts +5 -0
- package/dist/types/auth-gateway/http.d.ts +56 -0
- package/dist/types/auth-gateway/index.d.ts +3 -0
- package/dist/types/auth-gateway/server.d.ts +36 -0
- package/dist/types/auth-gateway/types.d.ts +127 -0
- package/dist/types/auth-retry.d.ts +150 -0
- package/dist/types/auth-storage.d.ts +1258 -0
- package/dist/types/dialect/anthropic.d.ts +15 -0
- package/dist/types/dialect/catalog.d.ts +3 -0
- package/dist/types/dialect/coercion.d.ts +23 -0
- package/dist/types/dialect/deepseek.d.ts +14 -0
- package/dist/types/dialect/demotion.d.ts +30 -0
- package/dist/types/dialect/examples.d.ts +18 -0
- package/dist/types/dialect/factory.d.ts +3 -0
- package/dist/types/dialect/fenced-thinking.d.ts +53 -0
- package/dist/types/dialect/gemini.d.ts +17 -0
- package/dist/types/dialect/gemma.d.ts +15 -0
- package/dist/types/dialect/glm.d.ts +9 -0
- package/dist/types/dialect/harmony.d.ts +8 -0
- package/dist/types/dialect/hermes.d.ts +9 -0
- package/dist/types/dialect/history.d.ts +3 -0
- package/dist/types/dialect/index.d.ts +11 -0
- package/dist/types/dialect/inventory.d.ts +9 -0
- package/dist/types/dialect/kimi.d.ts +14 -0
- package/dist/types/dialect/minimax.d.ts +3 -0
- package/dist/types/dialect/owned-stream.d.ts +4 -0
- package/dist/types/dialect/qwen3.d.ts +9 -0
- package/dist/types/dialect/rendering.d.ts +54 -0
- package/dist/types/dialect/thinking.d.ts +6 -0
- package/dist/types/dialect/types.d.ts +68 -0
- package/dist/types/dialect/xml.d.ts +9 -0
- package/dist/types/error/abort.d.ts +14 -0
- package/dist/types/error/auth-classify.d.ts +20 -0
- package/dist/types/error/auth.d.ts +27 -0
- package/dist/types/error/aws.d.ts +27 -0
- package/dist/types/error/classes.d.ts +106 -0
- package/dist/types/error/finalize.d.ts +39 -0
- package/dist/types/error/flags.d.ts +94 -0
- package/dist/types/error/format.d.ts +20 -0
- package/dist/types/error/gateway.d.ts +20 -0
- package/dist/types/error/index.d.ts +14 -0
- package/dist/types/error/oauth.d.ts +43 -0
- package/dist/types/error/provider.d.ts +42 -0
- package/dist/types/error/rate-limit.d.ts +80 -0
- package/dist/types/error/retryable.d.ts +27 -0
- package/dist/types/error/validation.d.ts +32 -0
- package/dist/types/index.d.ts +51 -0
- package/dist/types/provider-details.d.ts +24 -0
- package/dist/types/providers/amazon-bedrock.d.ts +39 -0
- package/dist/types/providers/anthropic-client.d.ts +106 -0
- package/dist/types/providers/anthropic-messages-server-schema.d.ts +937 -0
- package/dist/types/providers/anthropic-messages-server.d.ts +17 -0
- package/dist/types/providers/anthropic-wire.d.ts +345 -0
- package/dist/types/providers/anthropic.d.ts +261 -0
- package/dist/types/providers/aws-credentials.d.ts +48 -0
- package/dist/types/providers/aws-eventstream.d.ts +39 -0
- package/dist/types/providers/aws-sigv4.d.ts +55 -0
- package/dist/types/providers/azure-openai-responses.d.ts +16 -0
- package/dist/types/providers/bedrock-mantle.d.ts +13 -0
- package/dist/types/providers/claude-code-fingerprint.d.ts +19 -0
- package/dist/types/providers/cowork-fetch.d.ts +3 -0
- package/dist/types/providers/cursor/exec-modern.d.ts +98 -0
- package/dist/types/providers/cursor-pi-args.d.ts +105 -0
- package/dist/types/providers/cursor.d.ts +221 -0
- package/dist/types/providers/devin.d.ts +12 -0
- package/dist/types/providers/error-message.d.ts +25 -0
- package/dist/types/providers/github-copilot-headers.d.ts +40 -0
- package/dist/types/providers/gitlab-duo-workflow.d.ts +254 -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 +120 -0
- package/dist/types/providers/google-shared.d.ts +203 -0
- package/dist/types/providers/google-types.d.ts +155 -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 +179 -0
- package/dist/types/providers/ollama.d.ts +8 -0
- package/dist/types/providers/openai-anthropic-shim.d.ts +35 -0
- package/dist/types/providers/openai-chat-server-schema.d.ts +1311 -0
- package/dist/types/providers/openai-chat-server.d.ts +16 -0
- package/dist/types/providers/openai-chat-wire.d.ts +669 -0
- package/dist/types/providers/openai-codex/request-transformer.d.ts +109 -0
- package/dist/types/providers/openai-codex/response-handler.d.ts +26 -0
- package/dist/types/providers/openai-codex-responses.d.ts +238 -0
- package/dist/types/providers/openai-completions.d.ts +48 -0
- package/dist/types/providers/openai-reasoning-fallback.d.ts +25 -0
- package/dist/types/providers/openai-responses-server-schema.d.ts +1314 -0
- package/dist/types/providers/openai-responses-server.d.ts +17 -0
- package/dist/types/providers/openai-responses-wire.d.ts +6099 -0
- package/dist/types/providers/openai-responses.d.ts +131 -0
- package/dist/types/providers/openai-shared.d.ts +624 -0
- package/dist/types/providers/pi-native-client.d.ts +13 -0
- package/dist/types/providers/pi-native-server.d.ts +69 -0
- package/dist/types/providers/register-builtins.d.ts +37 -0
- package/dist/types/providers/synthetic.d.ts +26 -0
- package/dist/types/providers/transform-messages.d.ts +32 -0
- package/dist/types/providers/vision-guard.d.ts +20 -0
- package/dist/types/registry/aiand.d.ts +7 -0
- package/dist/types/registry/aimlapi.d.ts +4 -0
- package/dist/types/registry/alibaba-coding-plan.d.ts +8 -0
- package/dist/types/registry/alibaba-token-plan.d.ts +18 -0
- package/dist/types/registry/amazon-bedrock.d.ts +5 -0
- package/dist/types/registry/anthropic.d.ts +10 -0
- package/dist/types/registry/api-key-login.d.ts +42 -0
- package/dist/types/registry/api-key-validation.d.ts +43 -0
- package/dist/types/registry/aws.d.ts +13 -0
- package/dist/types/registry/azure.d.ts +4 -0
- package/dist/types/registry/baseten.d.ts +7 -0
- package/dist/types/registry/bedrock-mantle.d.ts +22 -0
- package/dist/types/registry/cerebras.d.ts +7 -0
- package/dist/types/registry/cloudflare-ai-gateway.d.ts +13 -0
- package/dist/types/registry/coreweave.d.ts +7 -0
- package/dist/types/registry/cursor.d.ts +7 -0
- package/dist/types/registry/deepseek.d.ts +8 -0
- package/dist/types/registry/derived.d.ts +5 -0
- package/dist/types/registry/devin.d.ts +8 -0
- package/dist/types/registry/exa.d.ts +8 -0
- package/dist/types/registry/firepass.d.ts +16 -0
- package/dist/types/registry/fireworks.d.ts +7 -0
- package/dist/types/registry/github-copilot.d.ts +7 -0
- package/dist/types/registry/gitlab-duo-workflow.d.ts +10 -0
- package/dist/types/registry/gitlab-duo.d.ts +9 -0
- package/dist/types/registry/gmi-cloud.d.ts +7 -0
- package/dist/types/registry/google-antigravity.d.ts +9 -0
- package/dist/types/registry/google-gemini-cli.d.ts +9 -0
- package/dist/types/registry/google-vertex.d.ts +5 -0
- package/dist/types/registry/google.d.ts +4 -0
- package/dist/types/registry/groq.d.ts +4 -0
- package/dist/types/registry/huggingface.d.ts +7 -0
- package/dist/types/registry/index.d.ts +4 -0
- package/dist/types/registry/kagi.d.ts +14 -0
- package/dist/types/registry/kilo.d.ts +7 -0
- package/dist/types/registry/kimi-code.d.ts +7 -0
- package/dist/types/registry/litellm.d.ts +13 -0
- package/dist/types/registry/llama-cpp.d.ts +8 -0
- package/dist/types/registry/lm-studio.d.ts +8 -0
- package/dist/types/registry/meta.d.ts +7 -0
- package/dist/types/registry/minimax-code-cn.d.ts +6 -0
- package/dist/types/registry/minimax-code.d.ts +6 -0
- package/dist/types/registry/minimax.d.ts +4 -0
- package/dist/types/registry/mistral.d.ts +4 -0
- package/dist/types/registry/moonshot.d.ts +7 -0
- package/dist/types/registry/nanogpt.d.ts +7 -0
- package/dist/types/registry/novita.d.ts +6 -0
- package/dist/types/registry/nvidia.d.ts +7 -0
- package/dist/types/registry/oauth/anthropic-constants.d.ts +12 -0
- package/dist/types/registry/oauth/anthropic.d.ts +24 -0
- package/dist/types/registry/oauth/callback-server.d.ts +74 -0
- package/dist/types/registry/oauth/cursor.d.ts +16 -0
- package/dist/types/registry/oauth/device-code.d.ts +25 -0
- package/dist/types/registry/oauth/devin.d.ts +5 -0
- package/dist/types/registry/oauth/github-copilot.d.ts +30 -0
- package/dist/types/registry/oauth/gitlab-duo-workflow.d.ts +6 -0
- package/dist/types/registry/oauth/gitlab-duo.d.ts +3 -0
- package/dist/types/registry/oauth/google-antigravity.d.ts +11 -0
- package/dist/types/registry/oauth/google-gemini-cli.d.ts +22 -0
- package/dist/types/registry/oauth/google-oauth-shared.d.ts +56 -0
- package/dist/types/registry/oauth/index.d.ts +45 -0
- package/dist/types/registry/oauth/kimi.d.ts +21 -0
- package/dist/types/registry/oauth/minimax-code.d.ts +27 -0
- package/dist/types/registry/oauth/openai-codex.d.ts +33 -0
- package/dist/types/registry/oauth/opencode.d.ts +18 -0
- package/dist/types/registry/oauth/perplexity.d.ts +9 -0
- package/dist/types/registry/oauth/pkce.d.ts +8 -0
- package/dist/types/registry/oauth/types.d.ts +87 -0
- package/dist/types/registry/oauth/wafer.d.ts +1 -0
- package/dist/types/registry/oauth/xai-oauth.d.ts +46 -0
- package/dist/types/registry/oauth/xiaomi.d.ts +25 -0
- package/dist/types/registry/oauth/zai.d.ts +25 -0
- package/dist/types/registry/ollama-cloud.d.ts +7 -0
- package/dist/types/registry/ollama.d.ts +12 -0
- package/dist/types/registry/openai-codex-device.d.ts +8 -0
- package/dist/types/registry/openai-codex.d.ts +9 -0
- package/dist/types/registry/openai.d.ts +4 -0
- package/dist/types/registry/opencode-go.d.ts +6 -0
- package/dist/types/registry/opencode-zen.d.ts +6 -0
- package/dist/types/registry/openrouter.d.ts +13 -0
- package/dist/types/registry/parallel.d.ts +14 -0
- package/dist/types/registry/perplexity.d.ts +7 -0
- package/dist/types/registry/qianfan.d.ts +7 -0
- package/dist/types/registry/qwen-portal.d.ts +7 -0
- package/dist/types/registry/registry.d.ts +367 -0
- package/dist/types/registry/sakana.d.ts +7 -0
- package/dist/types/registry/siliconflow-cn.d.ts +7 -0
- package/dist/types/registry/siliconflow.d.ts +7 -0
- package/dist/types/registry/synthetic.d.ts +6 -0
- package/dist/types/registry/tavily.d.ts +14 -0
- package/dist/types/registry/together.d.ts +6 -0
- package/dist/types/registry/types.d.ts +75 -0
- package/dist/types/registry/umans.d.ts +7 -0
- package/dist/types/registry/venice.d.ts +13 -0
- package/dist/types/registry/vercel-ai-gateway.d.ts +7 -0
- package/dist/types/registry/vllm.d.ts +7 -0
- package/dist/types/registry/wafer-serverless.d.ts +6 -0
- package/dist/types/registry/xai-oauth.d.ts +7 -0
- package/dist/types/registry/xai.d.ts +7 -0
- package/dist/types/registry/xiaomi-token-plan-ams.d.ts +6 -0
- package/dist/types/registry/xiaomi-token-plan-cn.d.ts +6 -0
- package/dist/types/registry/xiaomi-token-plan-sgp.d.ts +6 -0
- package/dist/types/registry/xiaomi.d.ts +6 -0
- package/dist/types/registry/zai.d.ts +15 -0
- package/dist/types/registry/zenmux.d.ts +7 -0
- package/dist/types/registry/zhipu-coding-plan.d.ts +7 -0
- package/dist/types/stream.d.ts +46 -0
- package/dist/types/types.d.ts +1064 -0
- package/dist/types/usage/alibaba-token-plan.d.ts +3 -0
- package/dist/types/usage/claude.d.ts +4 -0
- package/dist/types/usage/cursor.d.ts +4 -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 +15 -0
- package/dist/types/usage/kimi.d.ts +2 -0
- package/dist/types/usage/minimax-code.d.ts +3 -0
- package/dist/types/usage/ollama.d.ts +5 -0
- package/dist/types/usage/openai-codex-base-url.d.ts +18 -0
- package/dist/types/usage/openai-codex-reset.d.ts +88 -0
- package/dist/types/usage/openai-codex.d.ts +10 -0
- package/dist/types/usage/opencode-go.d.ts +2 -0
- package/dist/types/usage/shared.d.ts +1 -0
- package/dist/types/usage/synthetic.d.ts +2 -0
- package/dist/types/usage/umans.d.ts +2 -0
- package/dist/types/usage/xai-oauth.d.ts +12 -0
- package/dist/types/usage/zai.d.ts +3 -0
- package/dist/types/usage.d.ts +527 -0
- package/dist/types/utils/abort.d.ts +25 -0
- package/dist/types/utils/anthropic-auth.d.ts +35 -0
- package/dist/types/utils/aws-profile.d.ts +17 -0
- package/dist/types/utils/block-symbols.d.ts +62 -0
- package/dist/types/utils/deterministic-id.d.ts +16 -0
- package/dist/types/utils/empty-completion-retry.d.ts +21 -0
- package/dist/types/utils/event-stream.d.ts +39 -0
- package/dist/types/utils/foundry.d.ts +1 -0
- package/dist/types/utils/google-validation.d.ts +2 -0
- package/dist/types/utils/harmony-leak.d.ts +135 -0
- package/dist/types/utils/http-inspector.d.ts +49 -0
- package/dist/types/utils/idle-iterator.d.ts +149 -0
- package/dist/types/utils/leaked-thinking-stream.d.ts +33 -0
- package/dist/types/utils/openai-http.d.ts +48 -0
- package/dist/types/utils/openrouter-headers.d.ts +1 -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/proxy.d.ts +39 -0
- package/dist/types/utils/request-debug.d.ts +29 -0
- package/dist/types/utils/retry-after.d.ts +4 -0
- package/dist/types/utils/retry.d.ts +14 -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 +54 -0
- package/dist/types/utils/schema/index.d.ts +14 -0
- package/dist/types/utils/schema/json-schema-validator.d.ts +20 -0
- package/dist/types/utils/schema/meta-validator.d.ts +2 -0
- package/dist/types/utils/schema/normalize.d.ts +153 -0
- package/dist/types/utils/schema/spill.d.ts +8 -0
- package/dist/types/utils/schema/stamps.d.ts +17 -0
- package/dist/types/utils/schema/strict-tool-validation.d.ts +16 -0
- package/dist/types/utils/schema/types.d.ts +4 -0
- package/dist/types/utils/schema/typescript.d.ts +24 -0
- package/dist/types/utils/schema/wire.d.ts +52 -0
- package/dist/types/utils/sdk-stream-timeout.d.ts +33 -0
- package/dist/types/utils/sse-debug.d.ts +5 -0
- package/dist/types/utils/stream-markup-healing.d.ts +87 -0
- package/dist/types/utils/thinking-loop.d.ts +102 -0
- package/dist/types/utils/tool-call-loop-guard.d.ts +26 -0
- package/dist/types/utils/tool-choice.d.ts +52 -0
- package/dist/types/utils/validation.d.ts +28 -0
- package/dist/types/utils.d.ts +57 -0
- package/package.json +138 -0
- package/src/api-registry.ts +109 -0
- package/src/auth/sqlite-credential-store.ts +2066 -0
- package/src/auth-broker/client.ts +471 -0
- package/src/auth-broker/discover.ts +310 -0
- package/src/auth-broker/index.ts +7 -0
- package/src/auth-broker/refresher.ts +117 -0
- package/src/auth-broker/remote-store.ts +1332 -0
- package/src/auth-broker/server.ts +898 -0
- package/src/auth-broker/snapshot-cache.ts +200 -0
- package/src/auth-broker/types.ts +193 -0
- package/src/auth-broker/wire-schema-resource.ts +487 -0
- package/src/auth-broker/wire-schemas.ts +43 -0
- package/src/auth-gateway/http.ts +227 -0
- package/src/auth-gateway/index.ts +3 -0
- package/src/auth-gateway/server.ts +836 -0
- package/src/auth-gateway/types.ts +153 -0
- package/src/auth-retry.ts +401 -0
- package/src/auth-storage.ts +6540 -0
- package/src/dialect/anthropic.md +31 -0
- package/src/dialect/anthropic.ts +608 -0
- package/src/dialect/catalog.ts +29 -0
- package/src/dialect/coercion.ts +136 -0
- package/src/dialect/deepseek.md +24 -0
- package/src/dialect/deepseek.ts +609 -0
- package/src/dialect/demotion.ts +40 -0
- package/src/dialect/examples.ts +71 -0
- package/src/dialect/factory.ts +34 -0
- package/src/dialect/fenced-thinking.ts +184 -0
- package/src/dialect/gemini.md +44 -0
- package/src/dialect/gemini.ts +583 -0
- package/src/dialect/gemma.md +33 -0
- package/src/dialect/gemma.ts +387 -0
- package/src/dialect/glm.md +32 -0
- package/src/dialect/glm.ts +579 -0
- package/src/dialect/harmony.md +31 -0
- package/src/dialect/harmony.ts +345 -0
- package/src/dialect/hermes.md +25 -0
- package/src/dialect/hermes.ts +206 -0
- package/src/dialect/history.ts +81 -0
- package/src/dialect/index.ts +15 -0
- package/src/dialect/inventory.ts +30 -0
- package/src/dialect/kimi.md +24 -0
- package/src/dialect/kimi.ts +340 -0
- package/src/dialect/minimax.md +31 -0
- package/src/dialect/minimax.ts +95 -0
- package/src/dialect/owned-stream.ts +481 -0
- package/src/dialect/prompt-template.md +12 -0
- package/src/dialect/qwen3.md +28 -0
- package/src/dialect/qwen3.ts +240 -0
- package/src/dialect/rendering.ts +304 -0
- package/src/dialect/thinking.ts +292 -0
- package/src/dialect/types.ts +56 -0
- package/src/dialect/xml.md +22 -0
- package/src/dialect/xml.ts +90 -0
- package/src/error/abort.ts +18 -0
- package/src/error/auth-classify.ts +47 -0
- package/src/error/auth.ts +48 -0
- package/src/error/aws.ts +35 -0
- package/src/error/classes.ts +281 -0
- package/src/error/finalize.ts +69 -0
- package/src/error/flags.ts +602 -0
- package/src/error/format.ts +45 -0
- package/src/error/gateway.ts +96 -0
- package/src/error/index.ts +14 -0
- package/src/error/oauth.ts +58 -0
- package/src/error/provider.ts +63 -0
- package/src/error/rate-limit.ts +303 -0
- package/src/error/retryable.ts +70 -0
- package/src/error/validation.ts +44 -0
- package/src/index.ts +51 -0
- package/src/provider-details.ts +90 -0
- package/src/providers/amazon-bedrock.ts +1064 -0
- package/src/providers/anthropic-client.ts +317 -0
- package/src/providers/anthropic-messages-server-schema.ts +252 -0
- package/src/providers/anthropic-messages-server.ts +818 -0
- package/src/providers/anthropic-wire.ts +359 -0
- package/src/providers/anthropic.ts +4539 -0
- package/src/providers/aws-credentials.ts +772 -0
- package/src/providers/aws-eventstream.ts +181 -0
- package/src/providers/aws-sigv4.ts +218 -0
- package/src/providers/azure-openai-responses.ts +438 -0
- package/src/providers/bedrock-mantle.ts +110 -0
- package/src/providers/claude-code-fingerprint.ts +20 -0
- package/src/providers/cowork-fetch.ts +201 -0
- package/src/providers/cursor/exec-modern.ts +496 -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.ts +165 -0
- package/src/providers/cursor.ts +4689 -0
- package/src/providers/devin/proto/buf/validate/validate.proto +468 -0
- package/src/providers/devin/proto/buf.gen.yaml +33 -0
- package/src/providers/devin/proto/buf.yaml +17 -0
- package/src/providers/devin/proto/cel/expr/checked.proto +103 -0
- package/src/providers/devin/proto/cel/expr/eval.proto +38 -0
- package/src/providers/devin/proto/cel/expr/explain.proto +15 -0
- package/src/providers/devin/proto/cel/expr/syntax.proto +113 -0
- package/src/providers/devin/proto/cel/expr/value.proto +41 -0
- package/src/providers/devin/proto/connectext/grpc/status/v1/status.proto +11 -0
- package/src/providers/devin/proto/errorspb/errors.proto +56 -0
- package/src/providers/devin/proto/errorspb/hintdetail.proto +7 -0
- package/src/providers/devin/proto/errorspb/markers.proto +10 -0
- package/src/providers/devin/proto/errorspb/tags.proto +12 -0
- package/src/providers/devin/proto/errorspb/testing.proto +6 -0
- package/src/providers/devin/proto/exa/analytics_pb/analytics.proto +188 -0
- package/src/providers/devin/proto/exa/api_server_pb/api_server.proto +2461 -0
- package/src/providers/devin/proto/exa/auth_pb/auth.proto +19 -0
- package/src/providers/devin/proto/exa/auto_cascade_common_pb/auto_cascade_common.proto +79 -0
- package/src/providers/devin/proto/exa/browser_preview_pb/browser_preview.proto +32 -0
- package/src/providers/devin/proto/exa/bug_checker_pb/bug_checker.proto +22 -0
- package/src/providers/devin/proto/exa/cascade_plugins_pb/cascade_plugins.proto +262 -0
- package/src/providers/devin/proto/exa/chat_client_server_pb/chat_client_server.proto +57 -0
- package/src/providers/devin/proto/exa/chat_pb/chat.proto +449 -0
- package/src/providers/devin/proto/exa/code_edit/code_edit_pb/code_edit.proto +186 -0
- package/src/providers/devin/proto/exa/codeium_common_pb/codeium_common.proto +4157 -0
- package/src/providers/devin/proto/exa/context_module_pb/context_module.proto +175 -0
- package/src/providers/devin/proto/exa/cortex_pb/cortex.proto +3268 -0
- package/src/providers/devin/proto/exa/dev_pb/dev.proto +26 -0
- package/src/providers/devin/proto/exa/diff_action_pb/diff_action.proto +75 -0
- package/src/providers/devin/proto/exa/eval/pr_eval/datasets_pb/datasets.proto +103 -0
- package/src/providers/devin/proto/exa/eval_pb/eval.proto +1315 -0
- package/src/providers/devin/proto/exa/extension_server_pb/extension_server.proto +556 -0
- package/src/providers/devin/proto/exa/file_system_provider_pb/file_system_provider.proto +75 -0
- package/src/providers/devin/proto/exa/index_pb/index.proto +461 -0
- package/src/providers/devin/proto/exa/knowledge_base_pb/knowledge_base.proto +144 -0
- package/src/providers/devin/proto/exa/language_server_pb/language_server.proto +2385 -0
- package/src/providers/devin/proto/exa/model_management_pb/model_management.proto +186 -0
- package/src/providers/devin/proto/exa/opensearch_clients_pb/opensearch_clients.proto +503 -0
- package/src/providers/devin/proto/exa/product_analytics_pb/product_analytics.proto +37 -0
- package/src/providers/devin/proto/exa/prompt_pb/prompt.proto +92 -0
- package/src/providers/devin/proto/exa/reactive_component_pb/reactive_component.proto +96 -0
- package/src/providers/devin/proto/exa/seat_management_pb/seat_management.proto +2680 -0
- package/src/providers/devin/proto/exa/tokenizer_pb/tokenizer.proto +37 -0
- package/src/providers/devin/proto/exa/trainer_pb/config.proto +647 -0
- package/src/providers/devin/proto/exa/tree_sitter/language_data_pb/language_data.proto +14 -0
- package/src/providers/devin/proto/exa/trust_pb/trust.proto +157 -0
- package/src/providers/devin/proto/exa/user_analytics_pb/user_analytics.proto +519 -0
- package/src/providers/devin/proto/google.golang.org/appengine/internal/base/api_base.proto +28 -0
- package/src/providers/devin/proto/google.golang.org/appengine/internal/datastore/datastore_v3.proto +484 -0
- package/src/providers/devin/proto/google.golang.org/appengine/internal/log/log_service.proto +136 -0
- package/src/providers/devin/proto/google.golang.org/appengine/internal/remote_api/remote_api.proto +42 -0
- package/src/providers/devin/proto/google.golang.org/appengine/internal/urlfetch/urlfetch_service.proto +61 -0
- package/src/providers/devin/proto/grpc/binlog/v1/binarylog.proto +84 -0
- package/src/providers/devin/proto/io/prometheus/client/metrics.proto +98 -0
- package/src/providers/devin.ts +679 -0
- package/src/providers/error-message.ts +23 -0
- package/src/providers/github-copilot-headers.ts +141 -0
- package/src/providers/gitlab-duo-workflow-chatml-note.md +1 -0
- package/src/providers/gitlab-duo-workflow.ts +3135 -0
- package/src/providers/gitlab-duo.ts +399 -0
- package/src/providers/google-auth.ts +330 -0
- package/src/providers/google-gemini-cli.ts +1370 -0
- package/src/providers/google-shared.ts +1122 -0
- package/src/providers/google-types.ts +180 -0
- package/src/providers/google-vertex.ts +135 -0
- package/src/providers/google.ts +47 -0
- package/src/providers/grammar.ts +70 -0
- package/src/providers/kimi.ts +51 -0
- package/src/providers/mock.ts +514 -0
- package/src/providers/ollama.ts +776 -0
- package/src/providers/openai-anthropic-shim.ts +166 -0
- package/src/providers/openai-chat-server-schema.ts +243 -0
- package/src/providers/openai-chat-server.ts +752 -0
- package/src/providers/openai-chat-wire.ts +859 -0
- package/src/providers/openai-codex/request-transformer.ts +491 -0
- package/src/providers/openai-codex/response-handler.ts +102 -0
- package/src/providers/openai-codex-responses.ts +4716 -0
- package/src/providers/openai-completions.ts +2389 -0
- package/src/providers/openai-reasoning-fallback.ts +269 -0
- package/src/providers/openai-responses-server-schema.ts +397 -0
- package/src/providers/openai-responses-server.ts +1466 -0
- package/src/providers/openai-responses-wire.ts +6416 -0
- package/src/providers/openai-responses.ts +1393 -0
- package/src/providers/openai-shared.ts +3500 -0
- package/src/providers/pi-native-client.ts +275 -0
- package/src/providers/pi-native-server.ts +245 -0
- package/src/providers/register-builtins.ts +503 -0
- package/src/providers/synthetic.ts +50 -0
- package/src/providers/transform-messages.ts +1083 -0
- package/src/providers/vision-guard.ts +54 -0
- package/src/registry/aiand.ts +22 -0
- package/src/registry/aimlapi.ts +6 -0
- package/src/registry/alibaba-coding-plan.ts +104 -0
- package/src/registry/alibaba-token-plan.ts +125 -0
- package/src/registry/amazon-bedrock.ts +22 -0
- package/src/registry/anthropic.ts +26 -0
- package/src/registry/api-key-login.ts +115 -0
- package/src/registry/api-key-validation.ts +145 -0
- package/src/registry/aws.ts +57 -0
- package/src/registry/azure.ts +6 -0
- package/src/registry/baseten.ts +22 -0
- package/src/registry/bedrock-mantle.ts +34 -0
- package/src/registry/cerebras.ts +23 -0
- package/src/registry/cloudflare-ai-gateway.ts +45 -0
- package/src/registry/coreweave.ts +40 -0
- package/src/registry/cursor.ts +20 -0
- package/src/registry/deepseek.ts +46 -0
- package/src/registry/derived.ts +9 -0
- package/src/registry/devin.ts +15 -0
- package/src/registry/exa.ts +19 -0
- package/src/registry/firepass.ts +32 -0
- package/src/registry/fireworks.ts +28 -0
- package/src/registry/github-copilot.ts +22 -0
- package/src/registry/gitlab-duo-workflow.ts +20 -0
- package/src/registry/gitlab-duo.ts +19 -0
- package/src/registry/gmi-cloud.ts +22 -0
- package/src/registry/google-antigravity.ts +22 -0
- package/src/registry/google-gemini-cli.ts +22 -0
- package/src/registry/google-vertex.ts +38 -0
- package/src/registry/google.ts +6 -0
- package/src/registry/groq.ts +6 -0
- package/src/registry/huggingface.ts +29 -0
- package/src/registry/index.ts +4 -0
- package/src/registry/kagi.ts +46 -0
- package/src/registry/kilo.ts +114 -0
- package/src/registry/kimi-code.ts +17 -0
- package/src/registry/litellm.ts +45 -0
- package/src/registry/llama-cpp.ts +35 -0
- package/src/registry/lm-studio.ts +31 -0
- package/src/registry/meta.ts +22 -0
- package/src/registry/minimax-code-cn.ts +12 -0
- package/src/registry/minimax-code.ts +12 -0
- package/src/registry/minimax.ts +6 -0
- package/src/registry/mistral.ts +6 -0
- package/src/registry/moonshot.ts +28 -0
- package/src/registry/nanogpt.ts +22 -0
- package/src/registry/novita.ts +25 -0
- package/src/registry/nvidia.ts +61 -0
- package/src/registry/oauth/anthropic-constants.ts +12 -0
- package/src/registry/oauth/anthropic.ts +346 -0
- package/src/registry/oauth/callback-server.ts +438 -0
- package/src/registry/oauth/cursor.ts +187 -0
- package/src/registry/oauth/device-code.ts +92 -0
- package/src/registry/oauth/devin.ts +124 -0
- package/src/registry/oauth/github-copilot.ts +369 -0
- package/src/registry/oauth/gitlab-duo-workflow.ts +146 -0
- package/src/registry/oauth/gitlab-duo.ts +222 -0
- package/src/registry/oauth/google-antigravity.ts +225 -0
- package/src/registry/oauth/google-gemini-cli.ts +297 -0
- package/src/registry/oauth/google-oauth-shared.ts +211 -0
- package/src/registry/oauth/index.ts +187 -0
- package/src/registry/oauth/kimi.ts +297 -0
- package/src/registry/oauth/minimax-code.ts +53 -0
- package/src/registry/oauth/oauth.html +317 -0
- package/src/registry/oauth/openai-codex.ts +384 -0
- package/src/registry/oauth/opencode.ts +50 -0
- package/src/registry/oauth/perplexity.ts +228 -0
- package/src/registry/oauth/pkce.ts +18 -0
- package/src/registry/oauth/types.ts +96 -0
- package/src/registry/oauth/wafer.ts +24 -0
- package/src/registry/oauth/xai-oauth.ts +559 -0
- package/src/registry/oauth/xiaomi.ts +211 -0
- package/src/registry/oauth/zai.ts +285 -0
- package/src/registry/ollama-cloud.ts +36 -0
- package/src/registry/ollama.ts +43 -0
- package/src/registry/openai-codex-device.ts +18 -0
- package/src/registry/openai-codex.ts +19 -0
- package/src/registry/openai.ts +6 -0
- package/src/registry/opencode-go.ts +12 -0
- package/src/registry/opencode-zen.ts +12 -0
- package/src/registry/openrouter.ts +28 -0
- package/src/registry/parallel.ts +45 -0
- package/src/registry/perplexity.ts +13 -0
- package/src/registry/qianfan.ts +27 -0
- package/src/registry/qwen-portal.ts +50 -0
- package/src/registry/registry.ts +182 -0
- package/src/registry/sakana.ts +22 -0
- package/src/registry/siliconflow-cn.ts +22 -0
- package/src/registry/siliconflow.ts +22 -0
- package/src/registry/synthetic.ts +21 -0
- package/src/registry/tavily.ts +45 -0
- package/src/registry/together.ts +22 -0
- package/src/registry/types.ts +86 -0
- package/src/registry/umans.ts +23 -0
- package/src/registry/venice.ts +33 -0
- package/src/registry/vercel-ai-gateway.ts +38 -0
- package/src/registry/vllm.ts +34 -0
- package/src/registry/wafer-serverless.ts +12 -0
- package/src/registry/xai-oauth.ts +17 -0
- package/src/registry/xai.ts +22 -0
- package/src/registry/xiaomi-token-plan-ams.ts +12 -0
- package/src/registry/xiaomi-token-plan-cn.ts +12 -0
- package/src/registry/xiaomi-token-plan-sgp.ts +12 -0
- package/src/registry/xiaomi.ts +12 -0
- package/src/registry/zai.ts +41 -0
- package/src/registry/zenmux.ts +22 -0
- package/src/registry/zhipu-coding-plan.ts +27 -0
- package/src/stream.ts +1944 -0
- package/src/types.ts +1243 -0
- package/src/usage/alibaba-token-plan.ts +230 -0
- package/src/usage/claude.ts +830 -0
- package/src/usage/cursor.ts +335 -0
- package/src/usage/gemini.ts +258 -0
- package/src/usage/github-copilot.ts +424 -0
- package/src/usage/google-antigravity.ts +497 -0
- package/src/usage/kimi.ts +277 -0
- package/src/usage/minimax-code.ts +291 -0
- package/src/usage/ollama.ts +41 -0
- package/src/usage/openai-codex-base-url.ts +35 -0
- package/src/usage/openai-codex-reset.ts +205 -0
- package/src/usage/openai-codex.ts +627 -0
- package/src/usage/opencode-go.ts +89 -0
- package/src/usage/shared.ts +10 -0
- package/src/usage/synthetic.ts +180 -0
- package/src/usage/umans.ts +192 -0
- package/src/usage/xai-oauth.ts +414 -0
- package/src/usage/zai.ts +370 -0
- package/src/usage.ts +411 -0
- package/src/utils/abort.ts +67 -0
- package/src/utils/anthropic-auth.ts +93 -0
- package/src/utils/aws-profile.ts +88 -0
- package/src/utils/block-symbols.ts +78 -0
- package/src/utils/deterministic-id.ts +20 -0
- package/src/utils/empty-completion-retry.ts +161 -0
- package/src/utils/event-stream.ts +202 -0
- package/src/utils/foundry.ts +8 -0
- package/src/utils/google-validation.ts +25 -0
- package/src/utils/harmony-leak.ts +500 -0
- package/src/utils/http-inspector.ts +196 -0
- package/src/utils/idle-iterator.ts +531 -0
- package/src/utils/leaked-thinking-stream.ts +483 -0
- package/src/utils/openai-http.ts +119 -0
- package/src/utils/openrouter-headers.ts +12 -0
- package/src/utils/parse-bind.ts +56 -0
- package/src/utils/provider-response.ts +30 -0
- package/src/utils/proxy.ts +314 -0
- package/src/utils/request-debug.ts +351 -0
- package/src/utils/retry-after.ts +121 -0
- package/src/utils/retry.ts +77 -0
- package/src/utils/schema/CONSTRAINTS.md +168 -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 +210 -0
- package/src/utils/schema/index.ts +14 -0
- package/src/utils/schema/json-schema-validator.ts +595 -0
- package/src/utils/schema/meta-validator.ts +167 -0
- package/src/utils/schema/normalize.ts +2314 -0
- package/src/utils/schema/spill.ts +43 -0
- package/src/utils/schema/stamps.ts +109 -0
- package/src/utils/schema/strict-tool-validation.ts +117 -0
- package/src/utils/schema/types.ts +10 -0
- package/src/utils/schema/typescript.ts +212 -0
- package/src/utils/schema/wire.ts +662 -0
- package/src/utils/sdk-stream-timeout.ts +43 -0
- package/src/utils/sse-debug.ts +18 -0
- package/src/utils/stream-markup-healing.ts +247 -0
- package/src/utils/thinking-loop.ts +552 -0
- package/src/utils/tool-call-loop-guard.ts +107 -0
- package/src/utils/tool-choice.ts +101 -0
- package/src/utils/validation.ts +1932 -0
- package/src/utils.ts +492 -0
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Central live healing for leaked reasoning markup in the visible text channel.
|
|
3
|
+
*
|
|
4
|
+
* Some providers emit their canonical reasoning idioms (` ```thinking `,
|
|
5
|
+
* `<think>`, Gemma/Harmony channels, …) into the *visible* text stream instead
|
|
6
|
+
* of a structured thinking part. {@link wrapLeakedThinkingStream} re-projects a
|
|
7
|
+
* provider stream into a fresh {@link AssistantMessageEventStream}, splitting the
|
|
8
|
+
* leaked fences out into proper `thinking` blocks *live* as deltas arrive.
|
|
9
|
+
*
|
|
10
|
+
* Applied to every provider stream *except* official first-party endpoints
|
|
11
|
+
* (the official Anthropic API and the official OpenAI / OpenAI-Codex endpoints),
|
|
12
|
+
* which return structured thinking and never leak — `healLeakedThinking` in
|
|
13
|
+
* `../stream.ts` gates the wrap so the healer cannot misfire on legitimate
|
|
14
|
+
* fenced content those models emit as visible text.
|
|
15
|
+
*
|
|
16
|
+
* The healing is idempotent: a second pass over already-clean text finds no
|
|
17
|
+
* fences, so wrapping a provider that already heals (or wrapping twice) is a
|
|
18
|
+
* harmless pass-through. Signatures are load-bearing for Google/Gemini/Vertex
|
|
19
|
+
* thought round-tripping, so text sub-blocks carry the source `textSignature`,
|
|
20
|
+
* forwarded thinking blocks their `thinkingSignature`, and forwarded tool calls
|
|
21
|
+
* their `thoughtSignature`.
|
|
22
|
+
*
|
|
23
|
+
* Modeled on {@link wrapInbandToolStream} / `InbandStreamProjector` in
|
|
24
|
+
* `../dialect/owned-stream.ts`, minus all in-band tool-call grammar: tool-call
|
|
25
|
+
* events are forwarded verbatim.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { isAnthropicWebSearchHistoryBlock } from "../providers/anthropic-wire";
|
|
29
|
+
import type {
|
|
30
|
+
AnthropicServerToolContent,
|
|
31
|
+
AssistantMessage,
|
|
32
|
+
ImageContent,
|
|
33
|
+
TextContent,
|
|
34
|
+
ThinkingContent,
|
|
35
|
+
ToolCall,
|
|
36
|
+
} from "../types";
|
|
37
|
+
import {
|
|
38
|
+
clearStreamingPartialJson,
|
|
39
|
+
getStreamingPartialJson,
|
|
40
|
+
type StreamingPartialJsonCarrier,
|
|
41
|
+
setStreamingPartialJson,
|
|
42
|
+
} from "./block-symbols";
|
|
43
|
+
import { AssistantMessageEventStream } from "./event-stream";
|
|
44
|
+
import { StreamMarkupHealing, type StreamMarkupHealingEvent } from "./stream-markup-healing";
|
|
45
|
+
|
|
46
|
+
type StreamingToolCall = ToolCall & StreamingPartialJsonCarrier;
|
|
47
|
+
|
|
48
|
+
function cloneToolCall(source: StreamingToolCall): StreamingToolCall {
|
|
49
|
+
const block: StreamingToolCall = { ...source, arguments: source.arguments };
|
|
50
|
+
const partialJson = getStreamingPartialJson(source);
|
|
51
|
+
if (partialJson !== undefined) setStreamingPartialJson(block, partialJson);
|
|
52
|
+
return block;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function syncToolCall(target: StreamingToolCall, source: StreamingToolCall): void {
|
|
56
|
+
Object.assign(target, source);
|
|
57
|
+
const partialJson = getStreamingPartialJson(source);
|
|
58
|
+
if (partialJson === undefined) clearStreamingPartialJson(target);
|
|
59
|
+
else setStreamingPartialJson(target, partialJson);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Wrap a provider stream so leaked reasoning fences are healed into thinking
|
|
64
|
+
* blocks live, for every provider. Returns a new stream that re-projects the
|
|
65
|
+
* inner one; the inner stream is fully consumed.
|
|
66
|
+
*/
|
|
67
|
+
export function wrapLeakedThinkingStream(inner: AssistantMessageEventStream): AssistantMessageEventStream {
|
|
68
|
+
const out = new AssistantMessageEventStream();
|
|
69
|
+
void (async () => {
|
|
70
|
+
try {
|
|
71
|
+
let projector: LeakedThinkingProjector | undefined;
|
|
72
|
+
for await (const event of inner) {
|
|
73
|
+
switch (event.type) {
|
|
74
|
+
case "start":
|
|
75
|
+
projector = new LeakedThinkingProjector(out, event.partial);
|
|
76
|
+
break;
|
|
77
|
+
case "text_delta": {
|
|
78
|
+
projector ??= new LeakedThinkingProjector(out, event.partial);
|
|
79
|
+
const block = event.partial.content[event.contentIndex];
|
|
80
|
+
projector.text(
|
|
81
|
+
event.contentIndex,
|
|
82
|
+
event.delta,
|
|
83
|
+
block?.type === "text" ? block.textSignature : undefined,
|
|
84
|
+
);
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
case "thinking_delta": {
|
|
88
|
+
projector ??= new LeakedThinkingProjector(out, event.partial);
|
|
89
|
+
const block = event.partial.content[event.contentIndex];
|
|
90
|
+
projector.thinking(
|
|
91
|
+
event.contentIndex,
|
|
92
|
+
event.delta,
|
|
93
|
+
block?.type === "thinking" ? block.thinkingSignature : undefined,
|
|
94
|
+
);
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
case "thinking_end": {
|
|
98
|
+
const block = event.partial.content[event.contentIndex];
|
|
99
|
+
projector?.thinkingEnd(
|
|
100
|
+
event.contentIndex,
|
|
101
|
+
block?.type === "thinking" ? block.thinkingSignature : undefined,
|
|
102
|
+
);
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
case "image_end":
|
|
106
|
+
projector ??= new LeakedThinkingProjector(out, event.partial);
|
|
107
|
+
projector.image(event.contentIndex, event.content);
|
|
108
|
+
break;
|
|
109
|
+
case "toolcall_start": {
|
|
110
|
+
projector ??= new LeakedThinkingProjector(out, event.partial);
|
|
111
|
+
const block = event.partial.content[event.contentIndex];
|
|
112
|
+
projector.toolStart(event.contentIndex, block?.type === "toolCall" ? block : undefined);
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
case "toolcall_delta": {
|
|
116
|
+
const block = event.partial.content[event.contentIndex];
|
|
117
|
+
projector?.toolDelta(event.contentIndex, event.delta, block?.type === "toolCall" ? block : undefined);
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
case "toolcall_end":
|
|
121
|
+
projector?.toolEnd(event.contentIndex, event.toolCall);
|
|
122
|
+
break;
|
|
123
|
+
case "done": {
|
|
124
|
+
projector ??= new LeakedThinkingProjector(out, event.message);
|
|
125
|
+
const content = projector.finish(event.message);
|
|
126
|
+
out.push({ type: "done", reason: event.reason, message: { ...event.message, content } });
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
case "error": {
|
|
130
|
+
projector ??= new LeakedThinkingProjector(out, event.error);
|
|
131
|
+
const content = projector.finish(event.error);
|
|
132
|
+
out.push({ type: "error", reason: event.reason, error: { ...event.error, content } });
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
// text_start/text_end/thinking_start are ignored: the projector owns
|
|
136
|
+
// block boundaries (matches wrapInbandToolStream). thinking_end is
|
|
137
|
+
// handled to capture the signature Anthropic delivers at block close.
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Inner ended via end(result) without a terminal event.
|
|
141
|
+
if (!out.done) {
|
|
142
|
+
const result = await inner.result();
|
|
143
|
+
projector ??= new LeakedThinkingProjector(out, result);
|
|
144
|
+
const content = projector.finish(result);
|
|
145
|
+
out.end({ ...result, content });
|
|
146
|
+
}
|
|
147
|
+
} catch (err) {
|
|
148
|
+
if (!out.done) out.fail(err);
|
|
149
|
+
}
|
|
150
|
+
})();
|
|
151
|
+
return out;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
type OpenBlock = { index: number } | undefined;
|
|
155
|
+
type ProjectedContent = AssistantMessage["content"][number];
|
|
156
|
+
type AnchoredContent = { block: ProjectedContent; sourceIndex: number; order: number };
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Re-projects an inner stream's events into `out`, healing leaked reasoning out
|
|
160
|
+
* of the visible text channel while forwarding native thinking and tool calls.
|
|
161
|
+
*/
|
|
162
|
+
class LeakedThinkingProjector {
|
|
163
|
+
readonly #out: AssistantMessageEventStream;
|
|
164
|
+
readonly #healer = new StreamMarkupHealing({ pattern: "thinking" });
|
|
165
|
+
#partial: AssistantMessage;
|
|
166
|
+
#text: OpenBlock;
|
|
167
|
+
#thinking: OpenBlock;
|
|
168
|
+
/** Visible text consumed per source block, used to recover terminal-only tails. */
|
|
169
|
+
#fedTextLengths = new Map<number, number>();
|
|
170
|
+
/** Source text block whose held healer output has not crossed a content boundary. */
|
|
171
|
+
#activeTextSourceIndex: number | undefined;
|
|
172
|
+
/** Original terminal content index for every projected block. */
|
|
173
|
+
#sourceAnchors = new Map<ProjectedContent, number>();
|
|
174
|
+
/** Latest non-undefined text signature seen, stamped onto held-back text flushed later. */
|
|
175
|
+
#lastTextSignature: string | undefined;
|
|
176
|
+
/** Forwarded native tool calls, keyed by the inner stream's `contentIndex`. */
|
|
177
|
+
#toolBlocks = new Map<number, { index: number; block: StreamingToolCall }>();
|
|
178
|
+
/** Projected native thinking blocks, keyed by the inner stream's `contentIndex`. */
|
|
179
|
+
#thinkingBlocks = new Map<number, number>();
|
|
180
|
+
/** Native thinking blocks whose projected `thinking_end` awaits the source end event. */
|
|
181
|
+
#pendingThinkingEnds = new Set<number>();
|
|
182
|
+
|
|
183
|
+
constructor(out: AssistantMessageEventStream, seed: AssistantMessage) {
|
|
184
|
+
this.#out = out;
|
|
185
|
+
this.#partial = { ...seed, content: [] };
|
|
186
|
+
this.#out.push({ type: "start", partial: this.#partial });
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** Feed a visible-text delta through the healer, splitting leaked fences live. */
|
|
190
|
+
text(srcIndex: number, delta: string, signature: string | undefined): void {
|
|
191
|
+
const startsSource = this.#activeTextSourceIndex !== srcIndex;
|
|
192
|
+
if (this.#activeTextSourceIndex !== undefined && startsSource) {
|
|
193
|
+
this.#flushHealer();
|
|
194
|
+
this.#closeText();
|
|
195
|
+
this.#closeThinking();
|
|
196
|
+
}
|
|
197
|
+
this.#activeTextSourceIndex = srcIndex;
|
|
198
|
+
this.#fedTextLengths.set(srcIndex, (this.#fedTextLengths.get(srcIndex) ?? 0) + delta.length);
|
|
199
|
+
if (startsSource || signature !== undefined) this.#lastTextSignature = signature;
|
|
200
|
+
this.#apply(this.#healer.feedEvents(delta), this.#lastTextSignature, srcIndex);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** Forward a native thinking delta, preserving its source block identity and signature. */
|
|
204
|
+
thinking(srcIndex: number, delta: string, signature: string | undefined): void {
|
|
205
|
+
let index = this.#thinkingBlocks.get(srcIndex);
|
|
206
|
+
if (index === undefined) {
|
|
207
|
+
if (this.#thinking && this.#pendingThinkingEnds.has(this.#thinking.index)) this.#closeThinking();
|
|
208
|
+
index = this.#openThinking(srcIndex);
|
|
209
|
+
this.#thinkingBlocks.set(srcIndex, index);
|
|
210
|
+
this.#pendingThinkingEnds.add(index);
|
|
211
|
+
}
|
|
212
|
+
const block = this.#partial.content[index] as ThinkingContent;
|
|
213
|
+
block.thinking += delta;
|
|
214
|
+
if (signature !== undefined) block.thinkingSignature = signature;
|
|
215
|
+
this.#out.push({ type: "thinking_delta", contentIndex: index, delta, partial: this.#partial });
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Finalize a native thinking block by source identity. Its projected end is
|
|
220
|
+
* deferred until this event so stream consumers observe the completed
|
|
221
|
+
* signature before the block closes, even when later blocks started first.
|
|
222
|
+
*
|
|
223
|
+
* A block that never streamed a delta but closes with a signature is
|
|
224
|
+
* projected here instead of dropped: Gemini thought signatures arrive via
|
|
225
|
+
* OpenRouter's Responses translation as a text-less reasoning item whose id
|
|
226
|
+
* is the following function call's `call_id`. Losing that signature makes
|
|
227
|
+
* every current-turn function-call replay unsigned, which Gemini 3 punishes
|
|
228
|
+
* with empty stops and `server_error: stream closed with reason: error`.
|
|
229
|
+
*/
|
|
230
|
+
thinkingEnd(srcIndex: number, signature: string | undefined): void {
|
|
231
|
+
const index = this.#thinkingBlocks.get(srcIndex);
|
|
232
|
+
if (index === undefined) {
|
|
233
|
+
if (signature) this.#projectSignedThinking(srcIndex, "", signature);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (signature !== undefined) {
|
|
237
|
+
(this.#partial.content[index] as ThinkingContent).thinkingSignature = signature;
|
|
238
|
+
}
|
|
239
|
+
if (!this.#pendingThinkingEnds.delete(index)) return;
|
|
240
|
+
if (this.#thinking?.index === index) this.#thinking = undefined;
|
|
241
|
+
this.#emitThinkingEnd(index);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Project a completed signature-bearing thinking block whose deltas never
|
|
246
|
+
* reached the projector. Releases held-back text first (same boundary
|
|
247
|
+
* semantics as {@link toolStart}) so block order survives for replay —
|
|
248
|
+
* the signature item must precede the function call it signs.
|
|
249
|
+
*/
|
|
250
|
+
#projectSignedThinking(srcIndex: number, thinking: string, signature: string): void {
|
|
251
|
+
this.#flushHealer();
|
|
252
|
+
this.#closeText();
|
|
253
|
+
this.#closeThinking();
|
|
254
|
+
this.#partial.content.push({ type: "thinking", thinking, thinkingSignature: signature });
|
|
255
|
+
const index = this.#partial.content.length - 1;
|
|
256
|
+
this.#anchor(index, srcIndex);
|
|
257
|
+
this.#thinkingBlocks.set(srcIndex, index);
|
|
258
|
+
this.#out.push({ type: "thinking_start", contentIndex: index, partial: this.#partial });
|
|
259
|
+
this.#emitThinkingEnd(index);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** Forward a completed native image after releasing held text. */
|
|
263
|
+
image(srcIndex: number, content: ImageContent): void {
|
|
264
|
+
this.#flushHealer();
|
|
265
|
+
this.#closeText();
|
|
266
|
+
this.#closeThinking();
|
|
267
|
+
this.#partial.content.push(content);
|
|
268
|
+
const index = this.#partial.content.length - 1;
|
|
269
|
+
this.#anchor(index, srcIndex);
|
|
270
|
+
this.#out.push({
|
|
271
|
+
type: "image_end",
|
|
272
|
+
contentIndex: index,
|
|
273
|
+
content,
|
|
274
|
+
partial: this.#partial,
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** Forward a native tool call's start, releasing any held-back text first. */
|
|
279
|
+
toolStart(srcIndex: number, source: StreamingToolCall | undefined): void {
|
|
280
|
+
if (!source) return;
|
|
281
|
+
this.#flushHealer();
|
|
282
|
+
this.#closeText();
|
|
283
|
+
this.#closeThinking();
|
|
284
|
+
const block = cloneToolCall(source);
|
|
285
|
+
this.#partial.content.push(block);
|
|
286
|
+
const index = this.#partial.content.length - 1;
|
|
287
|
+
this.#anchor(index, srcIndex);
|
|
288
|
+
this.#toolBlocks.set(srcIndex, { index, block });
|
|
289
|
+
this.#out.push({ type: "toolcall_start", contentIndex: index, partial: this.#partial });
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
toolDelta(srcIndex: number, delta: string, source: StreamingToolCall | undefined): void {
|
|
293
|
+
let entry = this.#toolBlocks.get(srcIndex);
|
|
294
|
+
if (!entry && source) {
|
|
295
|
+
this.toolStart(srcIndex, source);
|
|
296
|
+
entry = this.#toolBlocks.get(srcIndex);
|
|
297
|
+
}
|
|
298
|
+
if (!entry) return;
|
|
299
|
+
if (source) syncToolCall(entry.block, source);
|
|
300
|
+
this.#out.push({ type: "toolcall_delta", contentIndex: entry.index, delta, partial: this.#partial });
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
toolEnd(srcIndex: number, toolCall: ToolCall): void {
|
|
304
|
+
const entry = this.#toolBlocks.get(srcIndex);
|
|
305
|
+
if (entry) {
|
|
306
|
+
syncToolCall(entry.block, toolCall);
|
|
307
|
+
this.#out.push({
|
|
308
|
+
type: "toolcall_end",
|
|
309
|
+
contentIndex: entry.index,
|
|
310
|
+
toolCall: entry.block,
|
|
311
|
+
partial: this.#partial,
|
|
312
|
+
});
|
|
313
|
+
this.#toolBlocks.delete(srcIndex);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
// `end` without a matching `start` — release held text, then forward whole.
|
|
317
|
+
this.#flushHealer();
|
|
318
|
+
this.#closeText();
|
|
319
|
+
this.#closeThinking();
|
|
320
|
+
const block = cloneToolCall(toolCall);
|
|
321
|
+
this.#partial.content.push(block);
|
|
322
|
+
const index = this.#partial.content.length - 1;
|
|
323
|
+
this.#anchor(index, srcIndex);
|
|
324
|
+
this.#out.push({ type: "toolcall_start", contentIndex: index, partial: this.#partial });
|
|
325
|
+
this.#out.push({ type: "toolcall_end", contentIndex: index, toolCall: block, partial: this.#partial });
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Finalize: replay any un-streamed visible-text tail from `message.content`,
|
|
330
|
+
* flush held-back fragments, close open blocks, and return the healed content.
|
|
331
|
+
*/
|
|
332
|
+
finish(message: AssistantMessage): AssistantMessage["content"] {
|
|
333
|
+
for (const [srcIndex] of this.#thinkingBlocks) {
|
|
334
|
+
const block = message.content[srcIndex];
|
|
335
|
+
this.thinkingEnd(srcIndex, block?.type === "thinking" ? block.thinkingSignature : undefined);
|
|
336
|
+
}
|
|
337
|
+
// Safety net: signature-bearing thinking blocks whose events never
|
|
338
|
+
// reached the projector at all (e.g. a terminal message assembled from
|
|
339
|
+
// blocks that skipped per-item events) must still survive with their
|
|
340
|
+
// text and signature intact.
|
|
341
|
+
for (let srcIndex = 0; srcIndex < message.content.length; srcIndex++) {
|
|
342
|
+
const block = message.content[srcIndex];
|
|
343
|
+
if (block?.type !== "thinking" || !block.thinkingSignature) continue;
|
|
344
|
+
if (this.#thinkingBlocks.has(srcIndex)) continue;
|
|
345
|
+
this.#projectSignedThinking(srcIndex, block.thinking, block.thinkingSignature);
|
|
346
|
+
}
|
|
347
|
+
for (let srcIndex = 0; srcIndex < message.content.length; srcIndex++) {
|
|
348
|
+
const block = message.content[srcIndex];
|
|
349
|
+
if (block?.type !== "text") continue;
|
|
350
|
+
const fedLength = this.#fedTextLengths.get(srcIndex) ?? 0;
|
|
351
|
+
if (block.text.length <= fedLength) continue;
|
|
352
|
+
if (this.#activeTextSourceIndex !== undefined && this.#activeTextSourceIndex !== srcIndex) {
|
|
353
|
+
this.#flushHealer();
|
|
354
|
+
this.#closeText();
|
|
355
|
+
this.#closeThinking();
|
|
356
|
+
}
|
|
357
|
+
this.#activeTextSourceIndex = srcIndex;
|
|
358
|
+
this.#lastTextSignature = block.textSignature;
|
|
359
|
+
this.#apply(this.#healer.feedEvents(block.text.slice(fedLength)), this.#lastTextSignature, srcIndex);
|
|
360
|
+
}
|
|
361
|
+
this.#flushHealer();
|
|
362
|
+
this.#closeText();
|
|
363
|
+
this.#closeThinking();
|
|
364
|
+
return this.#mergeServerToolHistory(message);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
#apply(events: readonly StreamMarkupHealingEvent[], signature: string | undefined, srcIndex: number): void {
|
|
368
|
+
for (const event of events) {
|
|
369
|
+
if (event.type === "text") this.#emitText(event.text, signature, srcIndex);
|
|
370
|
+
else if (event.type === "thinking") this.#emitHealedThinking(event.thinking, srcIndex);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
#emitText(text: string, signature: string | undefined, srcIndex: number): void {
|
|
375
|
+
if (text.length === 0) return;
|
|
376
|
+
this.#closeThinking();
|
|
377
|
+
if (!this.#text) {
|
|
378
|
+
const block: TextContent =
|
|
379
|
+
signature === undefined ? { type: "text", text: "" } : { type: "text", text: "", textSignature: signature };
|
|
380
|
+
this.#partial.content.push(block);
|
|
381
|
+
this.#text = { index: this.#partial.content.length - 1 };
|
|
382
|
+
this.#anchor(this.#text.index, srcIndex);
|
|
383
|
+
this.#out.push({ type: "text_start", contentIndex: this.#text.index, partial: this.#partial });
|
|
384
|
+
} else if (signature !== undefined) {
|
|
385
|
+
(this.#partial.content[this.#text.index] as TextContent).textSignature = signature;
|
|
386
|
+
}
|
|
387
|
+
const block = this.#partial.content[this.#text.index] as TextContent;
|
|
388
|
+
block.text += text;
|
|
389
|
+
this.#out.push({ type: "text_delta", contentIndex: this.#text.index, delta: text, partial: this.#partial });
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/** Healed (leaked) thinking carries no signature, matching the source fence. */
|
|
393
|
+
#emitHealedThinking(text: string, srcIndex: number): void {
|
|
394
|
+
if (text.length === 0) return;
|
|
395
|
+
const index = this.#openThinking(srcIndex);
|
|
396
|
+
const block = this.#partial.content[index] as ThinkingContent;
|
|
397
|
+
block.thinking += text;
|
|
398
|
+
this.#out.push({ type: "thinking_delta", contentIndex: index, delta: text, partial: this.#partial });
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
#openThinking(srcIndex: number): number {
|
|
402
|
+
this.#closeText();
|
|
403
|
+
if (!this.#thinking) {
|
|
404
|
+
this.#partial.content.push({ type: "thinking", thinking: "" });
|
|
405
|
+
this.#thinking = { index: this.#partial.content.length - 1 };
|
|
406
|
+
this.#anchor(this.#thinking.index, srcIndex);
|
|
407
|
+
this.#out.push({ type: "thinking_start", contentIndex: this.#thinking.index, partial: this.#partial });
|
|
408
|
+
}
|
|
409
|
+
return this.#thinking.index;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
#flushHealer(): void {
|
|
413
|
+
const srcIndex = this.#activeTextSourceIndex;
|
|
414
|
+
if (srcIndex !== undefined) {
|
|
415
|
+
this.#apply(this.#healer.flushEvents(), this.#lastTextSignature, srcIndex);
|
|
416
|
+
}
|
|
417
|
+
this.#activeTextSourceIndex = undefined;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
#anchor(index: number, srcIndex: number): void {
|
|
421
|
+
const block = this.#partial.content[index];
|
|
422
|
+
if (block) this.#sourceAnchors.set(block, srcIndex);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
#mergeServerToolHistory(message: AssistantMessage): AssistantMessage["content"] {
|
|
426
|
+
const pendingCalls = new Map<string, number>();
|
|
427
|
+
const pairedIndexes = new Set<number>();
|
|
428
|
+
for (let srcIndex = 0; srcIndex < message.content.length; srcIndex++) {
|
|
429
|
+
const content = message.content[srcIndex];
|
|
430
|
+
if (content?.type !== "anthropicServerTool" || !isAnthropicWebSearchHistoryBlock(content.block)) continue;
|
|
431
|
+
if (content.block.type === "server_tool_use") {
|
|
432
|
+
pendingCalls.set(content.block.id, srcIndex);
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
const callIndex = pendingCalls.get(content.block.tool_use_id);
|
|
436
|
+
if (callIndex === undefined) continue;
|
|
437
|
+
pairedIndexes.add(callIndex);
|
|
438
|
+
pairedIndexes.add(srcIndex);
|
|
439
|
+
pendingCalls.delete(content.block.tool_use_id);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const anchored: AnchoredContent[] = this.#partial.content.map((block, order) => ({
|
|
443
|
+
block,
|
|
444
|
+
sourceIndex: this.#sourceAnchors.get(block) ?? message.content.length + order,
|
|
445
|
+
order,
|
|
446
|
+
}));
|
|
447
|
+
for (const srcIndex of pairedIndexes) {
|
|
448
|
+
const content = message.content[srcIndex];
|
|
449
|
+
if (content?.type !== "anthropicServerTool") continue;
|
|
450
|
+
const cloned: AnthropicServerToolContent = {
|
|
451
|
+
type: "anthropicServerTool",
|
|
452
|
+
block: structuredClone(content.block),
|
|
453
|
+
};
|
|
454
|
+
anchored.push({ block: cloned, sourceIndex: srcIndex, order: srcIndex });
|
|
455
|
+
}
|
|
456
|
+
anchored.sort((left, right) => left.sourceIndex - right.sourceIndex || left.order - right.order);
|
|
457
|
+
return anchored.map(({ block }) => block);
|
|
458
|
+
}
|
|
459
|
+
#closeText(): void {
|
|
460
|
+
if (!this.#text) return;
|
|
461
|
+
const block = this.#partial.content[this.#text.index] as TextContent;
|
|
462
|
+
this.#out.push({ type: "text_end", contentIndex: this.#text.index, content: block.text, partial: this.#partial });
|
|
463
|
+
this.#text = undefined;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
#closeThinking(): void {
|
|
467
|
+
if (!this.#thinking) return;
|
|
468
|
+
const index = this.#thinking.index;
|
|
469
|
+
this.#thinking = undefined;
|
|
470
|
+
if (this.#pendingThinkingEnds.has(index)) return;
|
|
471
|
+
this.#emitThinkingEnd(index);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
#emitThinkingEnd(index: number): void {
|
|
475
|
+
const block = this.#partial.content[index] as ThinkingContent;
|
|
476
|
+
this.#out.push({
|
|
477
|
+
type: "thinking_end",
|
|
478
|
+
contentIndex: index,
|
|
479
|
+
content: block.thinking,
|
|
480
|
+
partial: this.#partial,
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-POST → SSE transport for OpenAI-wire streaming endpoints (chat
|
|
3
|
+
* completions, responses, azure responses). Replaces the `openai` SDK client:
|
|
4
|
+
*
|
|
5
|
+
* - Retries: `fetchWithRetry` (Retry-After/quota-hint aware; 5xx/408/429 and
|
|
6
|
+
* transient network errors). Default 6 total attempts — parity with the
|
|
7
|
+
* SDK's former `maxRetries: 5`.
|
|
8
|
+
* - SSE decode: `readSseJson` (spec-compliant framing, `[DONE]`-aware).
|
|
9
|
+
* `onSseEvent` observers now receive real wire frames instead of events
|
|
10
|
+
* re-synthesized from decoded SDK objects.
|
|
11
|
+
* - Errors: {@link OpenAIHttpError} exposes `status`/`headers`/`code`
|
|
12
|
+
* structurally (ProviderHttpError contract — `extractHttpStatusFromError`,
|
|
13
|
+
* retry-after extraction, copilot transient classification) and carries the
|
|
14
|
+
* captured response body for the strict-tools fallback and the responses
|
|
15
|
+
* chain-state detectors, which regex over `error.message`.
|
|
16
|
+
*/
|
|
17
|
+
import { fetchWithRetry, readSseJson, type SseEventObserver } from "@linxiraos/pi-utils";
|
|
18
|
+
import * as AIError from "../error";
|
|
19
|
+
import { OpenAIHttpError } from "../error";
|
|
20
|
+
|
|
21
|
+
export { OpenAIHttpError };
|
|
22
|
+
|
|
23
|
+
import type { FetchImpl } from "../types";
|
|
24
|
+
import type { CapturedHttpErrorResponse } from "./http-inspector";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Total attempts (initial + retries). Parity with the removed SDK clients'
|
|
28
|
+
* `maxRetries: 5`, i.e. 6 requests. Callers arming a first-event watchdog
|
|
29
|
+
* stay bounded: the watchdog aborts the request `signal`, which
|
|
30
|
+
* `fetchWithRetry` races on every attempt and every backoff sleep, so
|
|
31
|
+
* transient 408/429/5xx retries can never extend the caller's deadline.
|
|
32
|
+
*/
|
|
33
|
+
const DEFAULT_MAX_ATTEMPTS = 6;
|
|
34
|
+
|
|
35
|
+
/** Bound the `Error.message` allocation for proxy HTML error pages and the like. */
|
|
36
|
+
const MAX_DETAIL_CHARS = 4096;
|
|
37
|
+
|
|
38
|
+
export interface OpenAIStreamRequestInit {
|
|
39
|
+
url: string;
|
|
40
|
+
headers: Record<string, string>;
|
|
41
|
+
/** JSON request body; serialized once per call (retries resend the same bytes). */
|
|
42
|
+
body: unknown;
|
|
43
|
+
signal: AbortSignal;
|
|
44
|
+
fetch?: FetchImpl;
|
|
45
|
+
/** Raw wire-frame observer (`onSseEvent` debug pipeline). */
|
|
46
|
+
onSseEvent?: SseEventObserver;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface OpenAIStreamHandle<TEvent> {
|
|
50
|
+
/** Decoded `data:` payloads; terminates on `[DONE]` or stream end. */
|
|
51
|
+
events: AsyncGenerator<TEvent>;
|
|
52
|
+
response: Response;
|
|
53
|
+
/** `x-request-id` response header (the SDK's former `request_id`). */
|
|
54
|
+
requestId: string | null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* POST a JSON body and stream back decoded SSE events.
|
|
59
|
+
*
|
|
60
|
+
* Throws {@link OpenAIHttpError} on a non-2xx terminal response. Aborts on
|
|
61
|
+
* `signal` propagate from `fetchWithRetry`/`readSseJson`; callers own the
|
|
62
|
+
* watchdog timers and abort-reason bookkeeping.
|
|
63
|
+
*/
|
|
64
|
+
export async function postOpenAIStream<TEvent>(init: OpenAIStreamRequestInit): Promise<OpenAIStreamHandle<TEvent>> {
|
|
65
|
+
const response = await fetchWithRetry(init.url, {
|
|
66
|
+
method: "POST",
|
|
67
|
+
headers: { "Content-Type": "application/json", Accept: "text/event-stream", ...init.headers },
|
|
68
|
+
body: JSON.stringify(init.body),
|
|
69
|
+
signal: init.signal,
|
|
70
|
+
fetch: init.fetch,
|
|
71
|
+
maxAttempts: DEFAULT_MAX_ATTEMPTS,
|
|
72
|
+
// Bun's native fetch enforces a hard ~300s pre-response timeout (issue #2422).
|
|
73
|
+
// Cold large-context streams legitimately exceed it; the caller's
|
|
74
|
+
// `firstEventTimeoutMs`/`AbortSignal` already govern stuck requests.
|
|
75
|
+
timeout: false,
|
|
76
|
+
});
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
throw await captureOpenAIHttpError(response);
|
|
79
|
+
}
|
|
80
|
+
if (!response.body) {
|
|
81
|
+
throw new AIError.ProviderResponseError(`OpenAI stream response has no body (status ${response.status})`, {
|
|
82
|
+
kind: "envelope",
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
events: readSseJson<TEvent>(response.body, init.signal, init.onSseEvent),
|
|
87
|
+
response,
|
|
88
|
+
requestId: response.headers.get("x-request-id"),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Decode a non-2xx response into an {@link OpenAIHttpError} without consuming it twice. */
|
|
93
|
+
export async function captureOpenAIHttpError(response: Response): Promise<AIError.OpenAIHttpError> {
|
|
94
|
+
let bodyText: string | undefined;
|
|
95
|
+
let bodyJson: unknown;
|
|
96
|
+
try {
|
|
97
|
+
bodyText = await response.text();
|
|
98
|
+
if (bodyText.trim().length > 0) {
|
|
99
|
+
try {
|
|
100
|
+
bodyJson = JSON.parse(bodyText);
|
|
101
|
+
} catch {}
|
|
102
|
+
} else {
|
|
103
|
+
bodyText = undefined;
|
|
104
|
+
}
|
|
105
|
+
} catch {}
|
|
106
|
+
const captured: CapturedHttpErrorResponse = {
|
|
107
|
+
status: response.status,
|
|
108
|
+
headers: response.headers,
|
|
109
|
+
bodyText,
|
|
110
|
+
bodyJson,
|
|
111
|
+
};
|
|
112
|
+
const { detail, code } = OpenAIHttpError.parseEnvelope(bodyJson, bodyText);
|
|
113
|
+
// "status code (no body)" matches the SDK's former APIError phrasing;
|
|
114
|
+
// `finalizeErrorMessage` keys a repair path on that exact wording.
|
|
115
|
+
const message = detail
|
|
116
|
+
? `${response.status} ${detail.length > MAX_DETAIL_CHARS ? detail.slice(0, MAX_DETAIL_CHARS) : detail}`
|
|
117
|
+
: `${response.status} status code (no body)`;
|
|
118
|
+
return new AIError.OpenAIHttpError(message, captured, code);
|
|
119
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import packageJson from "../../package.json" with { type: "json" };
|
|
2
|
+
|
|
3
|
+
export function getOpenRouterHeaders(): Record<string, string> {
|
|
4
|
+
return {
|
|
5
|
+
"User-Agent": `Zeta/${packageJson.version}`,
|
|
6
|
+
"HTTP-Referer": "https://linxira-os.github.io/",
|
|
7
|
+
"X-OpenRouter-Title": "Zeta",
|
|
8
|
+
"X-OpenRouter-Categories": "cli-agent",
|
|
9
|
+
"X-OpenRouter-Cache": "true",
|
|
10
|
+
"X-OpenRouter-Cache-TTL": "3600",
|
|
11
|
+
};
|
|
12
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared `host:port` parser used by the auth-broker and auth-gateway boot
|
|
3
|
+
* paths. Centralized so the two servers can't drift on what they accept (the
|
|
4
|
+
* gateway used to silently allow empty hostnames; this fixes it).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as AIError from "../error";
|
|
8
|
+
|
|
9
|
+
export interface ParsedBind {
|
|
10
|
+
hostname: string;
|
|
11
|
+
port: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function parsePort(raw: string, bind: string): number {
|
|
15
|
+
if (!/^\d+$/.test(raw)) {
|
|
16
|
+
throw new AIError.ConfigurationError(`Invalid bind '${bind}'; port must be an integer.`);
|
|
17
|
+
}
|
|
18
|
+
const port = Number.parseInt(raw, 10);
|
|
19
|
+
if (!Number.isFinite(port) || port < 0 || port > 65535) {
|
|
20
|
+
throw new AIError.ConfigurationError(`Invalid bind '${bind}'; port out of range.`);
|
|
21
|
+
}
|
|
22
|
+
return port;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Parse a `host:port` (or bare `port`, which assumes loopback) string.
|
|
27
|
+
*
|
|
28
|
+
* Accepts:
|
|
29
|
+
* - `"4000"` → `127.0.0.1:4000`
|
|
30
|
+
* - `"0.0.0.0:4000"` → as written
|
|
31
|
+
* - `"[::1]:4000"` → as written (brackets retained, Bun handles them)
|
|
32
|
+
*
|
|
33
|
+
* Rejects:
|
|
34
|
+
* - empty input
|
|
35
|
+
* - empty hostname (`":4000"`)
|
|
36
|
+
* - non-integer / out-of-range port
|
|
37
|
+
*/
|
|
38
|
+
export function parseBind(raw: string): ParsedBind {
|
|
39
|
+
const trimmed = raw.trim();
|
|
40
|
+
if (trimmed.length === 0) {
|
|
41
|
+
throw new AIError.ConfigurationError("Invalid bind; expected 'host:port' or 'port'.");
|
|
42
|
+
}
|
|
43
|
+
if (/^\d+$/.test(trimmed)) {
|
|
44
|
+
return { hostname: "127.0.0.1", port: parsePort(trimmed, raw) };
|
|
45
|
+
}
|
|
46
|
+
const lastColon = trimmed.lastIndexOf(":");
|
|
47
|
+
if (lastColon < 0) {
|
|
48
|
+
throw new AIError.ConfigurationError(`Invalid bind '${raw}'; expected 'host:port' or 'port'.`);
|
|
49
|
+
}
|
|
50
|
+
const hostPart = trimmed.slice(0, lastColon);
|
|
51
|
+
const portPart = trimmed.slice(lastColon + 1);
|
|
52
|
+
if (hostPart.length === 0) {
|
|
53
|
+
throw new AIError.ConfigurationError(`Invalid bind '${raw}'; host must not be empty.`);
|
|
54
|
+
}
|
|
55
|
+
return { hostname: hostPart, port: parsePort(portPart, raw) };
|
|
56
|
+
}
|