@prometheus-ai/ai 0.5.3 → 0.5.8
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/dist/types/auth-broker/remote-store.d.ts +2 -1
- package/dist/types/auth-broker/wire-schemas.d.ts +4 -1
- package/dist/types/auth-gateway/server.d.ts +19 -0
- package/dist/types/auth-gateway/types.d.ts +9 -3
- package/dist/types/auth-retry.d.ts +119 -0
- package/dist/types/auth-storage.d.ts +217 -8
- package/dist/types/errors.d.ts +24 -0
- package/dist/types/index.d.ts +5 -9
- package/dist/types/provider-details.d.ts +1 -1
- package/dist/types/providers/amazon-bedrock.d.ts +12 -6
- package/dist/types/providers/anthropic-client.d.ts +10 -3
- package/dist/types/providers/anthropic-messages-server-schema.d.ts +2 -2
- package/dist/types/providers/anthropic-messages-server.d.ts +3 -3
- package/dist/types/providers/anthropic-wire.d.ts +3 -3
- package/dist/types/providers/anthropic.d.ts +41 -34
- package/dist/types/providers/aws-credentials.d.ts +8 -0
- package/dist/types/providers/azure-openai-responses.d.ts +1 -0
- package/dist/types/providers/google-gemini-cli.d.ts +22 -1
- package/dist/types/providers/google-shared.d.ts +22 -0
- package/dist/types/providers/google-types.d.ts +13 -1
- package/dist/types/providers/mock.d.ts +8 -3
- package/dist/types/providers/ollama.d.ts +6 -0
- package/dist/types/providers/openai-chat-server-schema.d.ts +6 -3
- package/dist/types/providers/openai-chat-server.d.ts +3 -3
- package/dist/types/providers/openai-chat-wire.d.ts +644 -0
- package/dist/types/providers/openai-codex/request-transformer.d.ts +8 -0
- package/dist/types/providers/openai-codex/response-handler.d.ts +9 -0
- package/dist/types/providers/openai-codex-responses.d.ts +31 -2
- package/dist/types/providers/openai-completions-compat.d.ts +2 -25
- package/dist/types/providers/openai-completions.d.ts +2 -10
- package/dist/types/providers/openai-responses-server-schema.d.ts +4 -4
- package/dist/types/providers/openai-responses-server.d.ts +2 -2
- package/dist/types/providers/openai-responses-shared.d.ts +49 -9
- package/dist/types/providers/openai-responses-wire.d.ts +6065 -0
- package/dist/types/providers/openai-responses.d.ts +13 -4
- package/dist/types/providers/prometheus-native-client.d.ts +9 -0
- package/dist/types/providers/prometheus-native-server.d.ts +4 -3
- package/dist/types/providers/transform-messages.d.ts +1 -2
- package/dist/types/rate-limit-utils.d.ts +3 -2
- package/dist/types/registry/aimlapi.d.ts +4 -0
- package/dist/types/registry/alibaba-coding-plan.d.ts +7 -0
- package/dist/types/registry/amazon-bedrock.d.ts +5 -0
- package/dist/types/registry/anthropic.d.ts +10 -0
- package/dist/types/{utils/oauth → registry}/api-key-login.d.ts +8 -2
- package/dist/types/{utils/oauth → registry}/api-key-validation.d.ts +15 -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/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/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.d.ts +9 -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/lm-studio.d.ts +8 -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/nvidia.d.ts +7 -0
- package/dist/types/registry/oauth/__tests__/xai-oauth.test.d.ts +1 -0
- package/dist/types/{utils → registry}/oauth/anthropic.d.ts +2 -1
- package/dist/types/{utils → registry}/oauth/github-copilot.d.ts +15 -23
- package/dist/types/{utils → registry}/oauth/index.d.ts +1 -0
- package/dist/types/{utils → registry}/oauth/minimax-code.d.ts +5 -5
- package/dist/types/{utils → registry}/oauth/types.d.ts +6 -1
- package/dist/types/{utils → registry}/oauth/xai-oauth.d.ts +2 -1
- 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 +272 -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 +51 -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-pass.d.ts +6 -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 +4 -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 +7 -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 +9 -1
- package/dist/types/types.d.ts +56 -295
- package/dist/types/usage/google-antigravity.d.ts +15 -1
- package/dist/types/usage/openai-codex-reset.d.ts +79 -0
- package/dist/types/usage/openai-codex.d.ts +1 -0
- package/dist/types/usage.d.ts +77 -4
- package/dist/types/utils/abort.d.ts +6 -0
- package/dist/types/utils/event-stream.d.ts +2 -0
- package/dist/types/utils/http-inspector.d.ts +0 -1
- package/dist/types/utils/idle-iterator.d.ts +35 -0
- package/dist/types/utils/openai-http.d.ts +58 -0
- package/dist/types/utils/request-debug.d.ts +3 -0
- package/dist/types/utils/retry-after.d.ts +1 -0
- package/dist/types/utils/schema/fields.d.ts +5 -0
- package/dist/types/utils/schema/json-schema-validator.d.ts +8 -0
- package/dist/types/utils/schema/stamps.d.ts +7 -15
- package/dist/types/utils/sse-debug.d.ts +0 -5
- package/dist/types/utils/stream-markup-healing.d.ts +2 -0
- package/dist/types/utils.d.ts +1 -5
- package/package.json +17 -29
- package/src/auth-broker/remote-store.ts +10 -1
- package/src/auth-broker/snapshot-cache.ts +1 -1
- package/src/auth-broker/wire-schemas.ts +1 -1
- package/src/auth-gateway/http.ts +1 -1
- package/src/auth-gateway/server.ts +95 -30
- package/src/auth-gateway/types.ts +10 -2
- package/src/auth-retry.ts +238 -0
- package/src/auth-storage.ts +935 -430
- package/src/errors.ts +32 -0
- package/src/index.ts +9 -14
- package/src/provider-details.ts +1 -1
- package/src/providers/__tests__/google-auth.test.ts +144 -0
- package/src/providers/amazon-bedrock.ts +70 -40
- package/src/providers/anthropic-client.ts +15 -13
- package/src/providers/anthropic-messages-server-schema.ts +17 -7
- package/src/providers/anthropic-messages-server.ts +88 -20
- package/src/providers/anthropic-wire.ts +4 -3
- package/src/providers/anthropic.ts +1234 -621
- package/src/providers/aws-credentials.ts +47 -5
- package/src/providers/aws-eventstream.ts +5 -0
- package/src/providers/azure-openai-responses.ts +117 -67
- package/src/providers/cursor.ts +30 -30
- package/src/providers/github-copilot-headers.ts +1 -1
- package/src/providers/gitlab-duo.ts +36 -29
- package/src/providers/google-auth.ts +71 -8
- package/src/providers/google-gemini-cli.ts +118 -22
- package/src/providers/google-shared.ts +163 -43
- package/src/providers/google-types.ts +10 -1
- package/src/providers/kimi.ts +1 -1
- package/src/providers/mock.ts +11 -3
- package/src/providers/ollama.ts +64 -7
- package/src/providers/openai-anthropic-shim.ts +17 -8
- package/src/providers/openai-chat-server-schema.ts +9 -3
- package/src/providers/openai-chat-server.ts +82 -16
- package/src/providers/openai-chat-wire.ts +847 -0
- package/src/providers/openai-codex/request-transformer.ts +129 -34
- package/src/providers/openai-codex/response-handler.ts +22 -1
- package/src/providers/openai-codex-responses.ts +699 -247
- package/src/providers/openai-completions-compat.ts +8 -308
- package/src/providers/openai-completions.ts +416 -267
- package/src/providers/openai-responses-server-schema.ts +15 -9
- package/src/providers/openai-responses-server.ts +162 -114
- package/src/providers/openai-responses-shared.ts +320 -82
- package/src/providers/openai-responses-wire.ts +6391 -0
- package/src/providers/openai-responses.ts +382 -176
- package/src/providers/prometheus-native-client.ts +27 -11
- package/src/providers/prometheus-native-server.ts +44 -17
- package/src/providers/transform-messages.ts +311 -120
- package/src/providers/vision-guard.ts +5 -3
- package/src/rate-limit-utils.ts +13 -3
- package/src/registry/aimlapi.ts +6 -0
- package/src/{utils/oauth → registry}/alibaba-coding-plan.ts +8 -18
- package/src/registry/amazon-bedrock.ts +22 -0
- package/src/registry/anthropic.ts +26 -0
- package/src/{utils/oauth → registry}/api-key-login.ts +25 -3
- package/src/{utils/oauth → registry}/api-key-validation.ts +62 -2
- package/src/{utils/oauth → registry}/cerebras.ts +8 -1
- package/src/{utils/oauth → registry}/cloudflare-ai-gateway.ts +8 -12
- package/src/registry/cursor.ts +20 -0
- package/src/{utils/oauth → registry}/deepseek.ts +9 -17
- package/src/registry/derived.ts +9 -0
- package/src/{utils/oauth → registry}/firepass.ts +10 -2
- package/src/{utils/oauth → registry}/fireworks.ts +8 -1
- package/src/registry/github-copilot.ts +22 -0
- package/src/registry/gitlab-duo.ts +19 -0
- package/src/registry/google-antigravity.ts +21 -0
- package/src/registry/google-gemini-cli.ts +21 -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/{utils/oauth → registry}/huggingface.ts +8 -19
- package/src/registry/index.ts +4 -0
- package/src/{utils/oauth → registry}/kagi.ts +9 -11
- package/src/{utils/oauth → registry}/kilo.ts +11 -6
- package/src/registry/kimi-code.ts +17 -0
- package/src/{utils/oauth → registry}/litellm.ts +8 -12
- package/src/{utils/oauth → registry}/lm-studio.ts +9 -17
- 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/{utils/oauth → registry}/moonshot.ts +8 -9
- package/src/{utils/oauth → registry}/nanogpt.ts +8 -1
- package/src/{utils/oauth → registry}/nvidia.ts +8 -18
- package/src/{utils → registry}/oauth/__tests__/xai-oauth.test.ts +4 -7
- package/src/{utils → registry}/oauth/anthropic.ts +38 -17
- package/src/{utils → registry}/oauth/github-copilot.ts +79 -115
- package/src/registry/oauth/gitlab-duo.ts +198 -0
- package/src/{utils → registry}/oauth/google-antigravity.ts +1 -4
- package/src/{utils → registry}/oauth/google-gemini-cli.ts +1 -4
- package/src/registry/oauth/index.ts +164 -0
- package/src/{utils → registry}/oauth/minimax-code.ts +16 -14
- package/src/{utils → registry}/oauth/types.ts +7 -51
- package/src/{utils → registry}/oauth/wafer.ts +1 -1
- package/src/{utils → registry}/oauth/xai-oauth.ts +16 -8
- package/src/{utils → registry}/oauth/xiaomi.ts +9 -4
- package/src/{utils/oauth → registry}/ollama-cloud.ts +8 -1
- package/src/{utils/oauth → registry}/ollama.ts +8 -13
- 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/{utils/oauth → registry}/openrouter.ts +10 -2
- package/src/{utils/oauth → registry}/parallel.ts +9 -11
- package/src/registry/perplexity.ts +13 -0
- package/src/{utils/oauth → registry}/qianfan.ts +8 -17
- package/src/{utils/oauth → registry}/qwen-portal.ts +8 -19
- package/src/registry/registry.ts +149 -0
- package/src/{utils/oauth → registry}/synthetic.ts +7 -1
- package/src/{utils/oauth → registry}/tavily.ts +10 -12
- package/src/{utils/oauth → registry}/together.ts +7 -1
- package/src/registry/types.ts +56 -0
- package/src/{utils/oauth → registry}/venice.ts +8 -12
- package/src/{utils/oauth → registry}/vercel-ai-gateway.ts +8 -18
- package/src/{utils/oauth → registry}/vllm.ts +9 -16
- package/src/registry/wafer-pass.ts +12 -0
- package/src/registry/wafer-serverless.ts +12 -0
- package/src/registry/xai-oauth.ts +17 -0
- package/src/registry/xai.ts +6 -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/{utils/oauth → registry}/zai.ts +10 -22
- package/src/{utils/oauth → registry}/zenmux.ts +8 -1
- package/src/{utils/oauth/zhipu.ts → registry/zhipu-coding-plan.ts} +9 -21
- package/src/stream.ts +229 -199
- package/src/types.ts +63 -384
- package/src/usage/claude.ts +4 -2
- package/src/usage/github-copilot.ts +4 -2
- package/src/usage/google-antigravity.ts +196 -28
- package/src/usage/kimi.ts +1 -1
- package/src/usage/minimax-code.ts +5 -6
- package/src/usage/openai-codex-reset.ts +174 -0
- package/src/usage/openai-codex.ts +19 -2
- package/src/usage/zai.ts +2 -1
- package/src/usage.ts +93 -4
- package/src/utils/abort.ts +14 -0
- package/src/utils/event-stream.ts +17 -0
- package/src/utils/http-inspector.ts +4 -12
- package/src/utils/idle-iterator.ts +250 -79
- package/src/utils/openai-http.ts +157 -0
- package/src/utils/request-debug.ts +67 -19
- package/src/utils/retry-after.ts +1 -1
- package/src/utils/retry.ts +23 -2
- package/src/utils/schema/CONSTRAINTS.md +4 -2
- package/src/utils/schema/fields.ts +16 -0
- package/src/utils/schema/json-schema-validator.ts +19 -1
- package/src/utils/schema/normalize.ts +80 -8
- package/src/utils/schema/stamps.ts +22 -10
- package/src/utils/schema/wire.ts +2 -2
- package/src/utils/sse-debug.ts +0 -271
- package/src/utils/stream-markup-healing.ts +50 -8
- package/src/utils/validation.ts +49 -13
- package/src/utils.ts +2 -26
- package/dist/types/model-cache.d.ts +0 -17
- package/dist/types/model-manager.d.ts +0 -64
- package/dist/types/model-thinking.d.ts +0 -100
- package/dist/types/models.d.ts +0 -12
- package/dist/types/provider-models/bundled-references.d.ts +0 -4
- package/dist/types/provider-models/descriptors.d.ts +0 -50
- package/dist/types/provider-models/google.d.ts +0 -24
- package/dist/types/provider-models/index.d.ts +0 -5
- package/dist/types/provider-models/ollama.d.ts +0 -7
- package/dist/types/provider-models/openai-compat.d.ts +0 -323
- package/dist/types/provider-models/special.d.ts +0 -16
- package/dist/types/utils/discovery/antigravity.d.ts +0 -61
- package/dist/types/utils/discovery/codex.d.ts +0 -38
- package/dist/types/utils/discovery/cursor.d.ts +0 -23
- package/dist/types/utils/discovery/gemini.d.ts +0 -25
- package/dist/types/utils/discovery/index.d.ts +0 -4
- package/dist/types/utils/discovery/openai-compatible.d.ts +0 -72
- package/dist/types/utils/oauth/alibaba-coding-plan.d.ts +0 -18
- package/dist/types/utils/oauth/cerebras.d.ts +0 -1
- package/dist/types/utils/oauth/cloudflare-ai-gateway.d.ts +0 -18
- package/dist/types/utils/oauth/deepseek.d.ts +0 -10
- package/dist/types/utils/oauth/firepass.d.ts +0 -1
- package/dist/types/utils/oauth/fireworks.d.ts +0 -1
- package/dist/types/utils/oauth/huggingface.d.ts +0 -19
- package/dist/types/utils/oauth/kagi.d.ts +0 -17
- package/dist/types/utils/oauth/kilo.d.ts +0 -5
- package/dist/types/utils/oauth/litellm.d.ts +0 -18
- package/dist/types/utils/oauth/lm-studio.d.ts +0 -17
- package/dist/types/utils/oauth/moonshot.d.ts +0 -1
- package/dist/types/utils/oauth/nanogpt.d.ts +0 -1
- package/dist/types/utils/oauth/nvidia.d.ts +0 -18
- package/dist/types/utils/oauth/ollama-cloud.d.ts +0 -2
- package/dist/types/utils/oauth/ollama.d.ts +0 -18
- package/dist/types/utils/oauth/openrouter.d.ts +0 -1
- package/dist/types/utils/oauth/parallel.d.ts +0 -17
- package/dist/types/utils/oauth/qianfan.d.ts +0 -17
- package/dist/types/utils/oauth/qwen-portal.d.ts +0 -19
- package/dist/types/utils/oauth/synthetic.d.ts +0 -1
- package/dist/types/utils/oauth/tavily.d.ts +0 -17
- package/dist/types/utils/oauth/together.d.ts +0 -1
- package/dist/types/utils/oauth/venice.d.ts +0 -18
- package/dist/types/utils/oauth/vercel-ai-gateway.d.ts +0 -18
- package/dist/types/utils/oauth/vllm.d.ts +0 -16
- package/dist/types/utils/oauth/zai.d.ts +0 -18
- package/dist/types/utils/oauth/zenmux.d.ts +0 -1
- package/dist/types/utils/oauth/zhipu.d.ts +0 -18
- package/src/model-cache.ts +0 -129
- package/src/model-manager.ts +0 -469
- package/src/model-thinking.ts +0 -756
- package/src/models.json +0 -60287
- package/src/models.json.d.ts +0 -9
- package/src/models.ts +0 -56
- package/src/provider-models/bundled-references.ts +0 -38
- package/src/provider-models/descriptors.ts +0 -364
- package/src/provider-models/google.ts +0 -88
- package/src/provider-models/index.ts +0 -5
- package/src/provider-models/ollama.ts +0 -153
- package/src/provider-models/openai-compat.ts +0 -2904
- package/src/provider-models/special.ts +0 -67
- package/src/utils/discovery/antigravity.ts +0 -261
- package/src/utils/discovery/codex.ts +0 -371
- package/src/utils/discovery/cursor.ts +0 -306
- package/src/utils/discovery/gemini.ts +0 -248
- package/src/utils/discovery/index.ts +0 -4
- package/src/utils/discovery/openai-compatible.ts +0 -224
- package/src/utils/oauth/gitlab-duo.ts +0 -123
- package/src/utils/oauth/index.ts +0 -502
- /package/dist/types/{utils/oauth/__tests__/xai-oauth.test.d.ts → providers/__tests__/google-auth.test.d.ts} +0 -0
- /package/dist/types/{utils → registry}/oauth/callback-server.d.ts +0 -0
- /package/dist/types/{utils → registry}/oauth/cursor.d.ts +0 -0
- /package/dist/types/{utils → registry}/oauth/gitlab-duo.d.ts +0 -0
- /package/dist/types/{utils → registry}/oauth/google-antigravity.d.ts +0 -0
- /package/dist/types/{utils → registry}/oauth/google-gemini-cli.d.ts +0 -0
- /package/dist/types/{utils → registry}/oauth/google-oauth-shared.d.ts +0 -0
- /package/dist/types/{utils → registry}/oauth/kimi.d.ts +0 -0
- /package/dist/types/{utils → registry}/oauth/openai-codex.d.ts +0 -0
- /package/dist/types/{utils → registry}/oauth/opencode.d.ts +0 -0
- /package/dist/types/{utils → registry}/oauth/perplexity.d.ts +0 -0
- /package/dist/types/{utils → registry}/oauth/pkce.d.ts +0 -0
- /package/dist/types/{utils → registry}/oauth/wafer.d.ts +0 -0
- /package/dist/types/{utils → registry}/oauth/xiaomi.d.ts +0 -0
- /package/src/{utils → registry}/oauth/callback-server.ts +0 -0
- /package/src/{utils → registry}/oauth/cursor.ts +0 -0
- /package/src/{utils → registry}/oauth/google-oauth-shared.ts +0 -0
- /package/src/{utils → registry}/oauth/kimi.ts +0 -0
- /package/src/{utils → registry}/oauth/oauth.html +0 -0
- /package/src/{utils → registry}/oauth/openai-codex.ts +0 -0
- /package/src/{utils → registry}/oauth/opencode.ts +0 -0
- /package/src/{utils → registry}/oauth/perplexity.ts +0 -0
- /package/src/{utils → registry}/oauth/pkce.ts +0 -0
package/src/utils/schema/wire.ts
CHANGED
|
@@ -50,8 +50,8 @@ export function isZodSchema(value: unknown): value is ZodType {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/** Symbol-stamped caches keyed by schema object identity. */
|
|
53
|
-
const kZodWireSchema = Symbol("
|
|
54
|
-
const kJsonWireSchema = Symbol("
|
|
53
|
+
const kZodWireSchema = Symbol("prometheus.schema.zod.wire");
|
|
54
|
+
const kJsonWireSchema = Symbol("prometheus.schema.json.wire");
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
57
|
* Post-process Zod-emitted JSON Schema so it matches the wire shape providers
|
package/src/utils/sse-debug.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import type { ServerSentEvent } from "@prometheus-ai/utils";
|
|
2
2
|
import type { RawSseEvent } from "../types";
|
|
3
3
|
|
|
4
|
-
type FetchFunction = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
5
|
-
type FetchWithPreconnect = FetchFunction & { preconnect?: typeof fetch.preconnect };
|
|
6
|
-
|
|
7
4
|
type RawSseObserver = (event: RawSseEvent) => void;
|
|
8
5
|
|
|
9
6
|
export function notifyRawSseEvent(observer: RawSseObserver | undefined, event: ServerSentEvent | RawSseEvent): void {
|
|
@@ -19,271 +16,3 @@ export function notifyRawSseEvent(observer: RawSseObserver | undefined, event: S
|
|
|
19
16
|
// Raw stream observers are diagnostic only and must not affect generation.
|
|
20
17
|
}
|
|
21
18
|
}
|
|
22
|
-
|
|
23
|
-
function isSseResponse(response: Response): boolean {
|
|
24
|
-
// `response.body` is non-null for any fetch Response with a body, but we
|
|
25
|
-
// still guard because user-supplied `fetch` mocks may return `{ body: null }`
|
|
26
|
-
// for empty responses and we don't want to wrap those.
|
|
27
|
-
if (!response.ok || !response.body) return false;
|
|
28
|
-
const contentType = response.headers.get("content-type");
|
|
29
|
-
// All providers in this repo emit lowercase `text/event-stream` (verified
|
|
30
|
-
// against anthropic, openai-completions, openai-responses, azure-openai-responses,
|
|
31
|
-
// google-shared, google-gemini-cli, openai-codex-responses, prometheus-native-client,
|
|
32
|
-
// and the auth-gateway server). A canonical `includes` check is sufficient;
|
|
33
|
-
// if a future provider sends mixed case it will fall back to the unwrapped
|
|
34
|
-
// fetch — observably safe, just no debug tee for that response.
|
|
35
|
-
return contentType?.includes("text/event-stream") ?? false;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Reused for every UTF-8 line decode. Safe because lines are split on LF
|
|
39
|
-
// (0x0a), which is single-byte ASCII and never appears inside a UTF-8
|
|
40
|
-
// multi-byte sequence — each line is a complete UTF-8 run, so the decoder
|
|
41
|
-
// carries no state across calls.
|
|
42
|
-
const SSE_LINE_DECODER = new TextDecoder("utf-8");
|
|
43
|
-
|
|
44
|
-
// Decode bytes [start, end) of an SSE line.
|
|
45
|
-
//
|
|
46
|
-
// A previous revision added an ASCII fast-path using `String.fromCharCode.apply`
|
|
47
|
-
// over chunked subarrays, on the theory that skipping `TextDecoder` would save
|
|
48
|
-
// the ~9.7% `decode` self-time the profile reported. In practice the swap
|
|
49
|
-
// *regressed* total wall time: `fromCharCode` became a new 7.8% hotspot,
|
|
50
|
-
// `Uint8Array` allocations grew 5.3%, and `subarray` rose from 11.5% to 18.3%
|
|
51
|
-
// — net loss of ~10pp. Bun's `TextDecoder.decode` has a fast C++ ASCII path
|
|
52
|
-
// that beats chunked `fromCharCode.apply` for the typical sub-1KB SSE line,
|
|
53
|
-
// so we keep the decoder. The line is bounded by LF (0x0a, single-byte
|
|
54
|
-
// ASCII), so each [start, end) slice is a complete UTF-8 run and the shared
|
|
55
|
-
// stateless decoder is safe to reuse.
|
|
56
|
-
function decodeSseLine(buf: Uint8Array, start: number, end: number): string {
|
|
57
|
-
if (start === 0 && end === buf.length) return SSE_LINE_DECODER.decode(buf);
|
|
58
|
-
return SSE_LINE_DECODER.decode(buf.subarray(start, end));
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Inline SSE event splitter. Walks the byte stream as it flows through a
|
|
63
|
-
* `TransformStream`, dispatching parsed events to the debug observer while
|
|
64
|
-
* the bytes are forwarded unchanged to the response consumer. Replaces the
|
|
65
|
-
* previous `body.tee()` + `readSseEvents` re-parse pipeline so the byte
|
|
66
|
-
* stream is parsed exactly once when a debug observer is attached.
|
|
67
|
-
*
|
|
68
|
-
* Field parsing intentionally mirrors `readSseEvents` in `@prometheus-ai/utils`
|
|
69
|
-
* (only `event` and `data` are observed; `id`/`retry` ignored; CR stripped
|
|
70
|
-
* before LF dispatch; leading space after `:` trimmed; `data:` lines join
|
|
71
|
-
* with `\n`). Reusing `readSseEvents` directly would require a second stream
|
|
72
|
-
* pipeline, which is exactly what this class avoids.
|
|
73
|
-
*/
|
|
74
|
-
class SseTeeParser {
|
|
75
|
-
#observer: RawSseObserver;
|
|
76
|
-
// Trailing bytes from the previous chunk that did not end with LF.
|
|
77
|
-
#partial: Uint8Array | null = null;
|
|
78
|
-
#event: string | null = null;
|
|
79
|
-
#data: string | null = null;
|
|
80
|
-
#raw: string[] = [];
|
|
81
|
-
|
|
82
|
-
constructor(observer: RawSseObserver) {
|
|
83
|
-
this.#observer = observer;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
push(chunk: Uint8Array): void {
|
|
87
|
-
// Carry-forward path: concat the partial line with the new chunk so the
|
|
88
|
-
// LF scan walks a single contiguous buffer. The common case (partial is
|
|
89
|
-
// null) skips the allocation entirely.
|
|
90
|
-
let buf: Uint8Array;
|
|
91
|
-
if (this.#partial) {
|
|
92
|
-
buf = new Uint8Array(this.#partial.length + chunk.length);
|
|
93
|
-
buf.set(this.#partial, 0);
|
|
94
|
-
buf.set(chunk, this.#partial.length);
|
|
95
|
-
this.#partial = null;
|
|
96
|
-
} else {
|
|
97
|
-
buf = chunk;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const len = buf.length;
|
|
101
|
-
let i = 0;
|
|
102
|
-
while (i < len) {
|
|
103
|
-
const lf = buf.indexOf(0x0a, i);
|
|
104
|
-
if (lf === -1) {
|
|
105
|
-
// Retain the tail as a partial line for the next chunk. Copy
|
|
106
|
-
// because the source `chunk` buffer may be reused upstream.
|
|
107
|
-
this.#partial = buf.subarray(i).slice();
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
let end = lf;
|
|
111
|
-
if (end > i && buf[end - 1] === 0x0d) end--;
|
|
112
|
-
this.#consumeLine(buf, i, end);
|
|
113
|
-
i = lf + 1;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
flush(): void {
|
|
118
|
-
// Treat any trailing partial line (no terminating LF) as a complete line.
|
|
119
|
-
if (this.#partial) {
|
|
120
|
-
const tail = this.#partial;
|
|
121
|
-
this.#partial = null;
|
|
122
|
-
let end = tail.length;
|
|
123
|
-
if (end > 0 && tail[end - 1] === 0x0d) end--;
|
|
124
|
-
if (end > 0) this.#consumeLine(tail, 0, end);
|
|
125
|
-
}
|
|
126
|
-
// Real services don't always close on a blank line — flush any pending event.
|
|
127
|
-
this.#dispatch();
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
#consumeLine(buf: Uint8Array, start: number, end: number): void {
|
|
131
|
-
if (end === start) {
|
|
132
|
-
this.#dispatch();
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
// Comment line: keep verbatim in `raw` for diagnostic context, skip parsing.
|
|
136
|
-
// SSE spec § 9.2.6: lines beginning with ':' are heartbeats/comments and
|
|
137
|
-
// MUST NOT contribute to the event dispatch state. Heartbeats are the
|
|
138
|
-
// single most common line type on long-poll provider streams, so the
|
|
139
|
-
// early-return here directly avoids ~half the field-parse work.
|
|
140
|
-
if (buf[start] === 0x3a /* ':' */) {
|
|
141
|
-
this.#raw.push(decodeSseLine(buf, start, end));
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
// Byte-level field parse. We avoid `text.indexOf(':')` + two `String.slice`
|
|
145
|
-
// calls (~6% of CPU pre-optimization) by scanning bytes for the field
|
|
146
|
-
// delimiter and matching the field name byte-for-byte. Field-name bytes
|
|
147
|
-
// are ASCII per SSE spec, so byte offsets equal char offsets in the
|
|
148
|
-
// decoded string and we can `slice` the value directly off `text` without
|
|
149
|
-
// re-decoding.
|
|
150
|
-
//
|
|
151
|
-
// ASCII signatures (verified against SSE spec):
|
|
152
|
-
// "event" = 0x65 0x76 0x65 0x6e 0x74 (5 bytes)
|
|
153
|
-
// "data" = 0x64 0x61 0x74 0x61 (4 bytes)
|
|
154
|
-
let colon = -1;
|
|
155
|
-
for (let k = start; k < end; k++) {
|
|
156
|
-
if (buf[k] === 0x3a) {
|
|
157
|
-
colon = k;
|
|
158
|
-
break;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
const fieldEnd = colon === -1 ? end : colon;
|
|
162
|
-
let valueStart = colon === -1 ? end : colon + 1;
|
|
163
|
-
// Per SSE spec, a single leading SP after the colon is stripped.
|
|
164
|
-
if (valueStart < end && buf[valueStart] === 0x20 /* ' ' */) valueStart++;
|
|
165
|
-
const fieldLen = fieldEnd - start;
|
|
166
|
-
const isEvent =
|
|
167
|
-
fieldLen === 5 &&
|
|
168
|
-
buf[start] === 0x65 &&
|
|
169
|
-
buf[start + 1] === 0x76 &&
|
|
170
|
-
buf[start + 2] === 0x65 &&
|
|
171
|
-
buf[start + 3] === 0x6e &&
|
|
172
|
-
buf[start + 4] === 0x74;
|
|
173
|
-
const isData =
|
|
174
|
-
!isEvent &&
|
|
175
|
-
fieldLen === 4 &&
|
|
176
|
-
buf[start] === 0x64 &&
|
|
177
|
-
buf[start + 1] === 0x61 &&
|
|
178
|
-
buf[start + 2] === 0x74 &&
|
|
179
|
-
buf[start + 3] === 0x61;
|
|
180
|
-
// Decode the line exactly once. Raw observers (debug buffer) want it
|
|
181
|
-
// regardless of field kind; `id`/`retry`/unknown lines pay only the
|
|
182
|
-
// decode cost, not any extra slicing.
|
|
183
|
-
const text = decodeSseLine(buf, start, end);
|
|
184
|
-
this.#raw.push(text);
|
|
185
|
-
if (isEvent) {
|
|
186
|
-
// `valueStart - start` is a byte offset into the line; since the
|
|
187
|
-
// "event:" prefix (and the optional SP) are pure ASCII, that byte
|
|
188
|
-
// offset equals the char offset in the decoded `text`.
|
|
189
|
-
this.#event = valueStart === end ? "" : text.slice(valueStart - start);
|
|
190
|
-
} else if (isData) {
|
|
191
|
-
const value = valueStart === end ? "" : text.slice(valueStart - start);
|
|
192
|
-
if (this.#data === null) this.#data = value;
|
|
193
|
-
else this.#data = `${this.#data}\n${value}`;
|
|
194
|
-
}
|
|
195
|
-
// `id` and `retry` are intentionally ignored — providers don't use them
|
|
196
|
-
// and reconnects are handled by the underlying transport.
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Hands ownership of the accumulated `raw` array to the observer. The
|
|
200
|
-
// observer (currently only `RawSseDebugBuffer.recordEvent`) MAY retain the
|
|
201
|
-
// array; we install a fresh `#raw = []` for the next event before invoking
|
|
202
|
-
// the observer so there is no aliasing across dispatches. This contract is
|
|
203
|
-
// mirrored in `notifyRawSseEvent` (no defensive clone) — see its comment.
|
|
204
|
-
//
|
|
205
|
-
// TODO(BufferOpt): once the buffer-side audit confirms it never mutates
|
|
206
|
-
// `event.raw`, the defensive `[...event.raw]` clone in older call paths
|
|
207
|
-
// (search for `notifyRawSseEvent`) can be dropped repository-wide.
|
|
208
|
-
#dispatch(): void {
|
|
209
|
-
if (this.#event === null && this.#data === null) return;
|
|
210
|
-
const event: RawSseEvent = {
|
|
211
|
-
event: this.#event,
|
|
212
|
-
data: this.#data ?? "",
|
|
213
|
-
raw: this.#raw,
|
|
214
|
-
};
|
|
215
|
-
this.#event = null;
|
|
216
|
-
this.#data = null;
|
|
217
|
-
this.#raw = [];
|
|
218
|
-
try {
|
|
219
|
-
this.#observer(event);
|
|
220
|
-
} catch {
|
|
221
|
-
// Raw stream observers are diagnostic only and must not affect generation.
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
export function wrapFetchForSseDebug(
|
|
227
|
-
fetchImpl: FetchWithPreconnect,
|
|
228
|
-
observer: RawSseObserver | undefined,
|
|
229
|
-
): FetchWithPreconnect {
|
|
230
|
-
if (!observer) return fetchImpl;
|
|
231
|
-
|
|
232
|
-
const wrapped = Object.assign(
|
|
233
|
-
async (input: string | URL | Request, init?: RequestInit): Promise<Response> => {
|
|
234
|
-
const response = await fetchImpl(input, init);
|
|
235
|
-
if (!isSseResponse(response)) {
|
|
236
|
-
return response;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const body = response.body;
|
|
240
|
-
if (!body) return response;
|
|
241
|
-
|
|
242
|
-
// Single-pass interception. Previously implemented as
|
|
243
|
-
// `body.pipeThrough(new TransformStream({...}))`, but the WHATWG
|
|
244
|
-
// TransformStream machinery imposes a per-chunk Promise boundary
|
|
245
|
-
// (`#handleNumberResult` showed at 8.8% self-time in CPU profile).
|
|
246
|
-
// A manual ReadableStream pulling directly from `body.getReader()`
|
|
247
|
-
// skips that hop: every `read()` immediately feeds both the parser
|
|
248
|
-
// and the controller in the same microtask.
|
|
249
|
-
const parser = new SseTeeParser(observer);
|
|
250
|
-
const reader = body.getReader();
|
|
251
|
-
const teed = new ReadableStream<Uint8Array>({
|
|
252
|
-
async pull(controller) {
|
|
253
|
-
try {
|
|
254
|
-
const { done, value } = await reader.read();
|
|
255
|
-
if (done) {
|
|
256
|
-
parser.flush();
|
|
257
|
-
controller.close();
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
260
|
-
// Enqueue first so the consumer sees bytes ASAP; parser
|
|
261
|
-
// dispatch is best-effort diagnostic and runs after.
|
|
262
|
-
controller.enqueue(value);
|
|
263
|
-
parser.push(value);
|
|
264
|
-
} catch (err) {
|
|
265
|
-
// Mirror TransformStream semantics: surface upstream
|
|
266
|
-
// errors to the consumer; do not flush a partial event.
|
|
267
|
-
controller.error(err);
|
|
268
|
-
}
|
|
269
|
-
},
|
|
270
|
-
cancel(reason) {
|
|
271
|
-
// Propagate downstream cancellation to the source body so the
|
|
272
|
-
// underlying connection is released. Matches `pipeThrough`'s
|
|
273
|
-
// cancel-propagation behavior; `flush()` is intentionally NOT
|
|
274
|
-
// called (TransformStream skips `flush` on abort too).
|
|
275
|
-
return reader.cancel(reason);
|
|
276
|
-
},
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
return new Response(teed, {
|
|
280
|
-
status: response.status,
|
|
281
|
-
statusText: response.statusText,
|
|
282
|
-
headers: response.headers,
|
|
283
|
-
});
|
|
284
|
-
},
|
|
285
|
-
fetchImpl.preconnect ? { preconnect: fetchImpl.preconnect } : {},
|
|
286
|
-
);
|
|
287
|
-
|
|
288
|
-
return wrapped;
|
|
289
|
-
}
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
* deltas for thinking blocks, and holds partial tags across chunk boundaries.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
+
import { isDeepseekModelIdOrName } from "@prometheus-ai/catalog/identity";
|
|
17
|
+
|
|
16
18
|
import { parseJsonWithRepair } from "./json-parse";
|
|
17
19
|
|
|
18
20
|
const KIMI_SECTION_BEGIN = "<|tool_calls_section_begin|>";
|
|
@@ -36,6 +38,8 @@ const DSML_PARAMETER_OPEN_RE = new RegExp(
|
|
|
36
38
|
"y",
|
|
37
39
|
);
|
|
38
40
|
const DSML_PARAMETER_CLOSE_RE = new RegExp(`</${DSML_PIPE}DSML${DSML_PIPE}parameter>`, "y");
|
|
41
|
+
/** Canonical DSML section-open shape; `|` positions accept either pipe variant. */
|
|
42
|
+
const DSML_SECTION_OPEN_TEMPLATE = "<|DSML|tool_calls>";
|
|
39
43
|
|
|
40
44
|
const THINK_OPEN = "<think>";
|
|
41
45
|
const THINK_CLOSE = "</think>";
|
|
@@ -81,6 +85,7 @@ type XmlToolState =
|
|
|
81
85
|
readonly paramName: string;
|
|
82
86
|
readonly isString: boolean;
|
|
83
87
|
value: string;
|
|
88
|
+
truncated?: boolean;
|
|
84
89
|
};
|
|
85
90
|
|
|
86
91
|
type ThinkingTag = { readonly open: string; readonly close: string };
|
|
@@ -429,12 +434,25 @@ export class StreamMarkupHealing {
|
|
|
429
434
|
continue;
|
|
430
435
|
}
|
|
431
436
|
} else if (this.#tryMatch(config.parameterClose)) {
|
|
432
|
-
|
|
437
|
+
// A capped value executes with silently corrupted input unless the
|
|
438
|
+
// truncation is made explicit — the marker fails JSON params loudly
|
|
439
|
+
// and tells the model/tool what happened to string params.
|
|
440
|
+
const paramValue = state.truncated
|
|
441
|
+
? `${state.value}\n…[parameter truncated: exceeded ${MAX_XML_PARAM_VALUE_LENGTH} bytes]`
|
|
442
|
+
: state.value;
|
|
443
|
+
state.args[state.paramName] = coerceXmlParamValue(paramValue, state.isString);
|
|
433
444
|
config.setState({ kind: "invoke", name: state.invokeName, args: state.args });
|
|
434
445
|
continue;
|
|
435
446
|
}
|
|
436
447
|
|
|
437
|
-
if (
|
|
448
|
+
if (state.kind === "idle") {
|
|
449
|
+
// In idle, a bare `<` is legitimate output (`a < b`, generics, JSX).
|
|
450
|
+
// Only hold back tails that could still grow into the DSML
|
|
451
|
+
// section-open tag; everything else flows through immediately.
|
|
452
|
+
if (this.#startsWithPartialDsmlSectionOpen()) break;
|
|
453
|
+
} else if (this.#startsWithPartialXmlTag()) {
|
|
454
|
+
break;
|
|
455
|
+
}
|
|
438
456
|
|
|
439
457
|
const ch = this.#buffer[this.#offset]!;
|
|
440
458
|
this.#offset += 1;
|
|
@@ -443,11 +461,15 @@ export class StreamMarkupHealing {
|
|
|
443
461
|
continue;
|
|
444
462
|
}
|
|
445
463
|
if (state.kind === "parameter") {
|
|
446
|
-
if (state.value.length
|
|
447
|
-
|
|
448
|
-
|
|
464
|
+
if (state.value.length < MAX_XML_PARAM_VALUE_LENGTH) {
|
|
465
|
+
state.value += ch;
|
|
466
|
+
} else {
|
|
467
|
+
// Beyond the cap the value stops growing, but we stay in
|
|
468
|
+
// `parameter` state so the rest of the envelope — including its
|
|
469
|
+
// close tags — is still swallowed instead of leaking into
|
|
470
|
+
// visible text. The close handler appends an explicit marker.
|
|
471
|
+
state.truncated = true;
|
|
449
472
|
}
|
|
450
|
-
state.value += ch;
|
|
451
473
|
}
|
|
452
474
|
}
|
|
453
475
|
|
|
@@ -511,6 +533,21 @@ export class StreamMarkupHealing {
|
|
|
511
533
|
return true;
|
|
512
534
|
}
|
|
513
535
|
|
|
536
|
+
#startsWithPartialDsmlSectionOpen(): boolean {
|
|
537
|
+
const tailLength = this.#buffer.length - this.#offset;
|
|
538
|
+
if (tailLength === 0 || tailLength >= DSML_SECTION_OPEN_TEMPLATE.length) return false;
|
|
539
|
+
for (let i = 0; i < tailLength; i++) {
|
|
540
|
+
const ch = this.#buffer[this.#offset + i]!;
|
|
541
|
+
const expected = DSML_SECTION_OPEN_TEMPLATE[i]!;
|
|
542
|
+
if (expected === "|") {
|
|
543
|
+
if (ch !== "|" && ch !== "|") return false;
|
|
544
|
+
} else if (ch !== expected) {
|
|
545
|
+
return false;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
return true;
|
|
549
|
+
}
|
|
550
|
+
|
|
514
551
|
#bufferIsPrefixOf(token: string, remainingLength: number): boolean {
|
|
515
552
|
for (let i = 0; i < remainingLength; i++) {
|
|
516
553
|
if (this.#buffer[this.#offset + i] !== token[i]) return false;
|
|
@@ -587,7 +624,7 @@ export function modelMayLeakKimiToolCalls(provider: string, modelId: string): bo
|
|
|
587
624
|
|
|
588
625
|
/** Cheap model/provider gate for DeepSeek DSML envelope leaks. */
|
|
589
626
|
export function modelMayLeakDsmlToolCalls(provider: string, modelId: string): boolean {
|
|
590
|
-
if (
|
|
627
|
+
if (!isDeepseekModelIdOrName(modelId)) return false;
|
|
591
628
|
return (
|
|
592
629
|
provider === "ollama" ||
|
|
593
630
|
provider === "ollama-cloud" ||
|
|
@@ -600,12 +637,17 @@ export function modelMayLeakDsmlToolCalls(provider: string, modelId: string): bo
|
|
|
600
637
|
);
|
|
601
638
|
}
|
|
602
639
|
|
|
640
|
+
/** Cheap model/provider gate for MiniMax plain thinking tag leaks. */
|
|
641
|
+
export function modelMayLeakThinkingTags(provider: string, modelId: string): boolean {
|
|
642
|
+
return /minimax/i.test(provider) || /minimax/i.test(modelId);
|
|
643
|
+
}
|
|
644
|
+
|
|
603
645
|
export function getStreamMarkupHealingPattern(
|
|
604
646
|
provider: string,
|
|
605
647
|
modelId: string,
|
|
606
648
|
options?: { readonly parseThinkingTags?: boolean },
|
|
607
649
|
): StreamMarkupHealingPattern | undefined {
|
|
608
|
-
if (options?.parseThinkingTags) return "thinking";
|
|
650
|
+
if (options?.parseThinkingTags || modelMayLeakThinkingTags(provider, modelId)) return "thinking";
|
|
609
651
|
if (modelMayLeakKimiToolCalls(provider, modelId)) return "kimi";
|
|
610
652
|
if (modelMayLeakDsmlToolCalls(provider, modelId)) return "dsml";
|
|
611
653
|
return undefined;
|
package/src/utils/validation.ts
CHANGED
|
@@ -724,6 +724,7 @@ interface FlatIssue {
|
|
|
724
724
|
keyword: "type" | "unrecognized" | "other";
|
|
725
725
|
instancePath: string;
|
|
726
726
|
expectedTypes: string[];
|
|
727
|
+
unionBranch: boolean;
|
|
727
728
|
}
|
|
728
729
|
|
|
729
730
|
/**
|
|
@@ -759,12 +760,12 @@ function mapZodExpectedToJsonSchemaType(expected: unknown): string | null {
|
|
|
759
760
|
*/
|
|
760
761
|
function flattenIssues(issues: ReadonlyArray<ZodIssue>): FlatIssue[] {
|
|
761
762
|
const out: FlatIssue[] = [];
|
|
762
|
-
const walk = (issue: ZodIssue, prefix: ReadonlyArray<PropertyKey
|
|
763
|
+
const walk = (issue: ZodIssue, prefix: ReadonlyArray<PropertyKey>, unionBranch: boolean): void => {
|
|
763
764
|
const fullPath = prefix.length === 0 ? issue.path : [...prefix, ...issue.path];
|
|
764
765
|
if (issue.code === "invalid_type") {
|
|
765
766
|
const mapped = mapZodExpectedToJsonSchemaType((issue as { expected?: unknown }).expected);
|
|
766
767
|
if (mapped) {
|
|
767
|
-
out.push({ keyword: "type", instancePath: pathToPointer(fullPath), expectedTypes: [mapped] });
|
|
768
|
+
out.push({ keyword: "type", instancePath: pathToPointer(fullPath), expectedTypes: [mapped], unionBranch });
|
|
768
769
|
return;
|
|
769
770
|
}
|
|
770
771
|
}
|
|
@@ -775,6 +776,7 @@ function flattenIssues(issues: ReadonlyArray<ZodIssue>): FlatIssue[] {
|
|
|
775
776
|
keyword: "unrecognized",
|
|
776
777
|
instancePath: pathToPointer([...fullPath, key]),
|
|
777
778
|
expectedTypes: [],
|
|
779
|
+
unionBranch,
|
|
778
780
|
});
|
|
779
781
|
}
|
|
780
782
|
return;
|
|
@@ -782,17 +784,21 @@ function flattenIssues(issues: ReadonlyArray<ZodIssue>): FlatIssue[] {
|
|
|
782
784
|
if (issue.code === "invalid_union") {
|
|
783
785
|
const inner = (issue as unknown as { errors?: ReadonlyArray<ReadonlyArray<ZodIssue>> }).errors;
|
|
784
786
|
if (inner) {
|
|
787
|
+
// A union-branch issue only competes with a sibling branch when it
|
|
788
|
+
// sits at the union node's own path. Issues whose own path is
|
|
789
|
+
// non-empty live on a deeper field that an already-identified
|
|
790
|
+
// branch owns, so the singleton-array repair should still apply.
|
|
785
791
|
for (const branch of inner) {
|
|
786
792
|
for (const child of branch) {
|
|
787
|
-
walk(child, fullPath);
|
|
793
|
+
walk(child, fullPath, child.path.length === 0);
|
|
788
794
|
}
|
|
789
795
|
}
|
|
790
796
|
}
|
|
791
797
|
return;
|
|
792
798
|
}
|
|
793
|
-
out.push({ keyword: "other", instancePath: pathToPointer(fullPath), expectedTypes: [] });
|
|
799
|
+
out.push({ keyword: "other", instancePath: pathToPointer(fullPath), expectedTypes: [], unionBranch });
|
|
794
800
|
};
|
|
795
|
-
for (const issue of issues) walk(issue, []);
|
|
801
|
+
for (const issue of issues) walk(issue, [], false);
|
|
796
802
|
return out;
|
|
797
803
|
}
|
|
798
804
|
|
|
@@ -801,7 +807,9 @@ function flattenIssues(issues: ReadonlyArray<ZodIssue>): FlatIssue[] {
|
|
|
801
807
|
*
|
|
802
808
|
* Two kinds of repair are applied:
|
|
803
809
|
* - **type**: when a value is a JSON-encoded string and the schema wants
|
|
804
|
-
* something else, parse it and substitute the parsed value.
|
|
810
|
+
* something else, parse it and substitute the parsed value. When a
|
|
811
|
+
* non-union schema wants an array but receives a singleton value, wrap that
|
|
812
|
+
* value in a one-element array.
|
|
805
813
|
* - **unrecognized**: when a strict object received an extra key (Zod's
|
|
806
814
|
* `unrecognized_keys` or JSON Schema's `additionalProperties: false`),
|
|
807
815
|
* drop that key so re-validation succeeds. This effectively coerces every
|
|
@@ -811,6 +819,7 @@ function flattenIssues(issues: ReadonlyArray<ZodIssue>): FlatIssue[] {
|
|
|
811
819
|
* The function is safe and conservative:
|
|
812
820
|
* - Only processes "type" and "unrecognized" issues
|
|
813
821
|
* - Only attempts JSON coercion on string values
|
|
822
|
+
* - Only wraps singleton array values for non-union type expectations
|
|
814
823
|
* - Only accepts parsed results that match the expected type
|
|
815
824
|
* - Clones the args object before mutation (copy-on-write)
|
|
816
825
|
*/
|
|
@@ -836,12 +845,16 @@ function coerceArgsFromIssues(args: unknown, issues: FlatIssue[]): { value: unkn
|
|
|
836
845
|
if (issue.expectedTypes.length === 0) continue;
|
|
837
846
|
|
|
838
847
|
const currentValue = getValueAtPointer(nextArgs, issue.instancePath);
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
848
|
+
const result =
|
|
849
|
+
typeof currentValue === "string"
|
|
850
|
+
? tryParseJsonForTypes(currentValue, issue.expectedTypes)
|
|
851
|
+
: { value: currentValue, changed: false };
|
|
842
852
|
const coercedValue = result.changed
|
|
843
853
|
? result.value
|
|
844
|
-
: issue.expectedTypes.includes("array")
|
|
854
|
+
: issue.expectedTypes.includes("array") &&
|
|
855
|
+
!issue.unionBranch &&
|
|
856
|
+
currentValue !== undefined &&
|
|
857
|
+
!Array.isArray(currentValue)
|
|
845
858
|
? [currentValue]
|
|
846
859
|
: undefined;
|
|
847
860
|
if (coercedValue === undefined) continue;
|
|
@@ -905,17 +918,20 @@ function preserveUnknownRootFields(input: unknown, parsed: unknown): unknown {
|
|
|
905
918
|
|
|
906
919
|
function flattenJsonSchemaIssues(issues: ReadonlyArray<JsonSchemaValidationIssue>): FlatIssue[] {
|
|
907
920
|
return issues.map(issue => {
|
|
921
|
+
const unionBranch = issue.fromUnionBranch === true;
|
|
908
922
|
if (issue.keyword === "additionalProperties") {
|
|
909
923
|
return {
|
|
910
924
|
keyword: "unrecognized",
|
|
911
925
|
instancePath: pathToPointer(issue.path),
|
|
912
926
|
expectedTypes: [],
|
|
927
|
+
unionBranch,
|
|
913
928
|
};
|
|
914
929
|
}
|
|
915
930
|
return {
|
|
916
931
|
keyword: issue.keyword === "type" ? "type" : "other",
|
|
917
932
|
instancePath: pathToPointer(issue.path),
|
|
918
933
|
expectedTypes: issue.expectedTypes ?? [],
|
|
934
|
+
unionBranch,
|
|
919
935
|
};
|
|
920
936
|
});
|
|
921
937
|
}
|
|
@@ -963,6 +979,23 @@ export function validateToolCall(tools: Tool[], toolCall: ToolCall): ToolCall["a
|
|
|
963
979
|
return validateToolArguments(tool, toolCall);
|
|
964
980
|
}
|
|
965
981
|
|
|
982
|
+
/** Cap per-field string lengths when embedding received args in an error message. */
|
|
983
|
+
const MAX_ERROR_ARG_STRING_LENGTH = 256;
|
|
984
|
+
|
|
985
|
+
function truncateArgsForError(value: unknown): unknown {
|
|
986
|
+
if (typeof value === "string") {
|
|
987
|
+
if (value.length <= MAX_ERROR_ARG_STRING_LENGTH) return value;
|
|
988
|
+
return `${value.slice(0, MAX_ERROR_ARG_STRING_LENGTH)}… [truncated ${value.length - MAX_ERROR_ARG_STRING_LENGTH} chars]`;
|
|
989
|
+
}
|
|
990
|
+
if (Array.isArray(value)) return value.map(truncateArgsForError);
|
|
991
|
+
if (value !== null && typeof value === "object") {
|
|
992
|
+
const out: Record<string, unknown> = {};
|
|
993
|
+
for (const [key, entry] of Object.entries(value)) out[key] = truncateArgsForError(entry);
|
|
994
|
+
return out;
|
|
995
|
+
}
|
|
996
|
+
return value;
|
|
997
|
+
}
|
|
998
|
+
|
|
966
999
|
/**
|
|
967
1000
|
* Validates tool call arguments against the tool's schema (Zod or plain JSON
|
|
968
1001
|
* Schema). Applies LLM-quirk coercions (numeric strings, JSON-string
|
|
@@ -1009,12 +1042,15 @@ export function validateToolArguments(tool: Tool, toolCall: ToolCall): ToolCall[
|
|
|
1009
1042
|
// existing tests; the detailed body is informational.
|
|
1010
1043
|
const errors = result.messages.join("\n") || "Unknown validation error";
|
|
1011
1044
|
|
|
1045
|
+
// Truncate long per-field strings: the full payload (potentially hundreds
|
|
1046
|
+
// of KB for write/edit-class calls) would otherwise round-trip back to the
|
|
1047
|
+
// model inside the tool error.
|
|
1012
1048
|
const receivedArgs = changed
|
|
1013
1049
|
? {
|
|
1014
|
-
original: originalArgs,
|
|
1015
|
-
normalized: normalizedArgs,
|
|
1050
|
+
original: truncateArgsForError(originalArgs),
|
|
1051
|
+
normalized: truncateArgsForError(normalizedArgs),
|
|
1016
1052
|
}
|
|
1017
|
-
: originalArgs;
|
|
1053
|
+
: truncateArgsForError(originalArgs);
|
|
1018
1054
|
|
|
1019
1055
|
const errorMessage = `Validation failed for tool "${
|
|
1020
1056
|
toolCall.name
|
package/src/utils.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { $env } from "@prometheus-ai/utils";
|
|
2
|
-
import type { ResponseInput } from "openai
|
|
2
|
+
import type { ResponseInput } from "./providers/openai-responses-wire";
|
|
3
3
|
import type { CacheRetention, OpenAIResponsesHistoryPayload, ProviderPayload } from "./types";
|
|
4
4
|
|
|
5
5
|
type OpenAIResponsesReplayItem = ResponseInput[number];
|
|
@@ -8,27 +8,7 @@ export { isRecord } from "@prometheus-ai/utils";
|
|
|
8
8
|
export function normalizeSystemPrompts(systemPrompt: readonly string[] | string | undefined | null): string[] {
|
|
9
9
|
if (systemPrompt === undefined || systemPrompt === null) return [];
|
|
10
10
|
const prompts = Array.isArray(systemPrompt) ? systemPrompt : typeof systemPrompt === "string" ? [systemPrompt] : [];
|
|
11
|
-
return prompts.map(prompt => prompt.toWellFormed()).filter(prompt => prompt.length > 0);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function toNumber(value: unknown): number | undefined {
|
|
15
|
-
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
16
|
-
if (typeof value === "string" && value.trim()) {
|
|
17
|
-
const parsed = Number(value);
|
|
18
|
-
return Number.isFinite(parsed) ? parsed : undefined;
|
|
19
|
-
}
|
|
20
|
-
return undefined;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function toPositiveNumber(value: unknown, fallback: number): number {
|
|
24
|
-
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
25
|
-
return fallback;
|
|
26
|
-
}
|
|
27
|
-
return value;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function toBoolean(value: unknown): boolean | undefined {
|
|
31
|
-
return typeof value === "boolean" ? value : undefined;
|
|
11
|
+
return prompts.map(prompt => prompt.toWellFormed()).filter(prompt => prompt.trim().length > 0);
|
|
32
12
|
}
|
|
33
13
|
|
|
34
14
|
export function normalizeToolCallId(id: string): string {
|
|
@@ -160,7 +140,3 @@ export function resolveCacheRetention(cacheRetention?: CacheRetention): CacheRet
|
|
|
160
140
|
if ($env.PROMETHEUS_CACHE_RETENTION === "long") return "long";
|
|
161
141
|
return "short";
|
|
162
142
|
}
|
|
163
|
-
|
|
164
|
-
export function isAnthropicOAuthToken(key: string): boolean {
|
|
165
|
-
return key.includes("sk-ant-oat");
|
|
166
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { Api, Model } from "./types";
|
|
2
|
-
interface CacheEntry<TApi extends Api = Api> {
|
|
3
|
-
models: Model<TApi>[];
|
|
4
|
-
fresh: boolean;
|
|
5
|
-
authoritative: boolean;
|
|
6
|
-
updatedAt: number;
|
|
7
|
-
/**
|
|
8
|
-
* Hash of the static catalog slice that was merged into `models` when this
|
|
9
|
-
* row was written. `resolveProviderModels` compares against the current
|
|
10
|
-
* static fingerprint and bypasses the static+cache re-merge when they
|
|
11
|
-
* match — the cache already incorporates the same static state.
|
|
12
|
-
*/
|
|
13
|
-
staticFingerprint: string;
|
|
14
|
-
}
|
|
15
|
-
export declare function readModelCache<TApi extends Api>(providerId: string, ttlMs: number, now: () => number, dbPath?: string): CacheEntry<TApi> | null;
|
|
16
|
-
export declare function writeModelCache<TApi extends Api>(providerId: string, updatedAt: number, models: Model<TApi>[], authoritative: boolean, staticFingerprint: string, dbPath?: string): void;
|
|
17
|
-
export {};
|