@bastani/pi-ai 0.9.20 → 0.9.21-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -1
- package/NOTICE.md +1 -1
- package/dist/api/anthropic-messages.d.ts.map +1 -1
- package/dist/api/anthropic-messages.js.map +1 -1
- package/dist/api/anthropic-messages.lazy.d.ts.map +1 -1
- package/dist/api/azure-openai-responses.d.ts.map +1 -1
- package/dist/api/azure-openai-responses.js +2 -4
- package/dist/api/azure-openai-responses.js.map +1 -1
- package/dist/api/azure-openai-responses.lazy.d.ts.map +1 -1
- package/dist/api/bedrock-converse-stream.d.ts.map +1 -1
- package/dist/api/bedrock-converse-stream.js.map +1 -1
- package/dist/api/bedrock-converse-stream.lazy.d.ts.map +1 -1
- package/dist/api/bedrock-converse-stream.lazy.js.map +1 -1
- package/dist/api/cloudflare-gateway-binding.d.ts.map +1 -1
- package/dist/api/cloudflare-gateway-binding.js.map +1 -1
- package/dist/api/cloudflare-workers-ai-system-one.d.ts.map +1 -1
- package/dist/api/cloudflare-workers-ai-system-one.js.map +1 -1
- package/dist/api/cloudflare-workers-ai-system-one.lazy.d.ts.map +1 -1
- package/dist/api/cloudflare.d.ts.map +1 -1
- package/dist/api/cloudflare.js.map +1 -1
- package/dist/api/constrained-sampling.d.ts.map +1 -1
- package/dist/api/constrained-sampling.js.map +1 -1
- package/dist/api/github-copilot-headers.d.ts.map +1 -1
- package/dist/api/github-copilot-headers.js.map +1 -1
- package/dist/api/google-generative-ai.d.ts.map +1 -1
- package/dist/api/google-generative-ai.js.map +1 -1
- package/dist/api/google-generative-ai.lazy.d.ts.map +1 -1
- package/dist/api/google-shared.d.ts.map +1 -1
- package/dist/api/google-shared.js.map +1 -1
- package/dist/api/google-vertex.d.ts.map +1 -1
- package/dist/api/google-vertex.js.map +1 -1
- package/dist/api/google-vertex.lazy.d.ts.map +1 -1
- package/dist/api/lazy.d.ts.map +1 -1
- package/dist/api/lazy.js.map +1 -1
- package/dist/api/mistral-conversations.d.ts.map +1 -1
- package/dist/api/mistral-conversations.js +6 -0
- package/dist/api/mistral-conversations.js.map +1 -1
- package/dist/api/mistral-conversations.lazy.d.ts.map +1 -1
- package/dist/api/openai-codex-responses.d.ts.map +1 -1
- package/dist/api/openai-codex-responses.js.map +1 -1
- package/dist/api/openai-codex-responses.lazy.d.ts.map +1 -1
- package/dist/api/openai-completions.d.ts.map +1 -1
- package/dist/api/openai-completions.js +5 -6
- package/dist/api/openai-completions.js.map +1 -1
- package/dist/api/openai-completions.lazy.d.ts.map +1 -1
- package/dist/api/openai-prompt-cache.d.ts.map +1 -1
- package/dist/api/openai-prompt-cache.js.map +1 -1
- package/dist/api/openai-responses-shared.d.ts.map +1 -1
- package/dist/api/openai-responses-shared.js.map +1 -1
- package/dist/api/openai-responses.d.ts.map +1 -1
- package/dist/api/openai-responses.js +3 -4
- package/dist/api/openai-responses.js.map +1 -1
- package/dist/api/openai-responses.lazy.d.ts.map +1 -1
- package/dist/api/openrouter-images.d.ts.map +1 -1
- package/dist/api/openrouter-images.js.map +1 -1
- package/dist/api/openrouter-images.lazy.d.ts.map +1 -1
- package/dist/api/pi-messages.d.ts.map +1 -1
- package/dist/api/pi-messages.js.map +1 -1
- package/dist/api/pi-messages.lazy.d.ts.map +1 -1
- package/dist/api/simple-options.d.ts.map +1 -1
- package/dist/api/simple-options.js +1 -4
- package/dist/api/simple-options.js.map +1 -1
- package/dist/api/system-one-shared.d.ts.map +1 -1
- package/dist/api/system-one-shared.js.map +1 -1
- package/dist/api/transform-messages.d.ts.map +1 -1
- package/dist/api/transform-messages.js.map +1 -1
- package/dist/api/typesafe-system-one.d.ts.map +1 -1
- package/dist/api/typesafe-system-one.js.map +1 -1
- package/dist/api/typesafe-system-one.lazy.d.ts.map +1 -1
- package/dist/auth/context.d.ts.map +1 -1
- package/dist/auth/context.js.map +1 -1
- package/dist/auth/credential-store.d.ts.map +1 -1
- package/dist/auth/credential-store.js.map +1 -1
- package/dist/auth/helpers.d.ts.map +1 -1
- package/dist/auth/helpers.js.map +1 -1
- package/dist/auth/oauth/anthropic.d.ts.map +1 -1
- package/dist/auth/oauth/anthropic.js.map +1 -1
- package/dist/auth/oauth/device-code.d.ts.map +1 -1
- package/dist/auth/oauth/device-code.js.map +1 -1
- package/dist/auth/oauth/github-copilot.d.ts.map +1 -1
- package/dist/auth/oauth/github-copilot.js.map +1 -1
- package/dist/auth/oauth/kimi-coding.d.ts.map +1 -1
- package/dist/auth/oauth/kimi-coding.js.map +1 -1
- package/dist/auth/oauth/load.d.ts.map +1 -1
- package/dist/auth/oauth/load.js.map +1 -1
- package/dist/auth/oauth/meta.d.ts.map +1 -1
- package/dist/auth/oauth/meta.js.map +1 -1
- package/dist/auth/oauth/oauth-page.d.ts.map +1 -1
- package/dist/auth/oauth/oauth-page.js.map +1 -1
- package/dist/auth/oauth/openai-codex.d.ts.map +1 -1
- package/dist/auth/oauth/openai-codex.js.map +1 -1
- package/dist/auth/oauth/openrouter.d.ts.map +1 -1
- package/dist/auth/oauth/openrouter.js.map +1 -1
- package/dist/auth/oauth/pkce.d.ts.map +1 -1
- package/dist/auth/oauth/pkce.js.map +1 -1
- package/dist/auth/oauth/radius.d.ts.map +1 -1
- package/dist/auth/oauth/radius.js.map +1 -1
- package/dist/auth/oauth/xai.d.ts.map +1 -1
- package/dist/auth/oauth/xai.js.map +1 -1
- package/dist/auth/resolve.d.ts.map +1 -1
- package/dist/auth/resolve.js.map +1 -1
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/bedrock-provider.d.ts.map +1 -1
- package/dist/bun-oauth.d.ts.map +1 -1
- package/dist/bun-oauth.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/compat/extension-oauth-types.d.ts.map +1 -1
- package/dist/compat.d.ts.map +1 -1
- package/dist/compat.js.map +1 -1
- package/dist/decision-models.d.ts.map +1 -1
- package/dist/decision-models.generated.d.ts.map +1 -1
- package/dist/decision-models.js.map +1 -1
- package/dist/env-api-keys.d.ts.map +1 -1
- package/dist/env-api-keys.js.map +1 -1
- package/dist/image-models.d.ts.map +1 -1
- package/dist/image-models.js.map +1 -1
- package/dist/images-api-registry.d.ts.map +1 -1
- package/dist/images-api-registry.js.map +1 -1
- package/dist/images.d.ts.map +1 -1
- package/dist/images.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/legacy-api-aliases.d.ts.map +1 -1
- package/dist/model-catalog.d.ts.map +1 -1
- package/dist/model-catalog.js.map +1 -1
- package/dist/models-store.d.ts.map +1 -1
- package/dist/models-store.js.map +1 -1
- package/dist/models.d.ts.map +1 -1
- package/dist/models.generated.d.ts.map +1 -1
- package/dist/models.js.map +1 -1
- package/dist/oauth.d.ts.map +1 -1
- package/dist/providers/all.d.ts.map +1 -1
- package/dist/providers/all.js.map +1 -1
- package/dist/providers/amazon-bedrock.d.ts.map +1 -1
- package/dist/providers/amazon-bedrock.js.map +1 -1
- package/dist/providers/amazon-bedrock.models.d.ts.map +1 -1
- package/dist/providers/ant-ling.d.ts.map +1 -1
- package/dist/providers/ant-ling.js.map +1 -1
- package/dist/providers/ant-ling.models.d.ts.map +1 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/anthropic.models.d.ts.map +1 -1
- package/dist/providers/azure-openai-responses.d.ts.map +1 -1
- package/dist/providers/azure-openai-responses.js.map +1 -1
- package/dist/providers/azure-openai-responses.models.d.ts.map +1 -1
- package/dist/providers/baseten.d.ts.map +1 -1
- package/dist/providers/baseten.js.map +1 -1
- package/dist/providers/baseten.models.d.ts.map +1 -1
- package/dist/providers/cerebras.d.ts.map +1 -1
- package/dist/providers/cerebras.js.map +1 -1
- package/dist/providers/cerebras.models.d.ts.map +1 -1
- package/dist/providers/cloudflare-ai-gateway.d.ts.map +1 -1
- package/dist/providers/cloudflare-ai-gateway.js.map +1 -1
- package/dist/providers/cloudflare-ai-gateway.models.d.ts.map +1 -1
- package/dist/providers/cloudflare-auth.d.ts.map +1 -1
- package/dist/providers/cloudflare-auth.js.map +1 -1
- package/dist/providers/cloudflare-stream.d.ts.map +1 -1
- package/dist/providers/cloudflare-stream.js.map +1 -1
- package/dist/providers/cloudflare-workers-ai.d.ts.map +1 -1
- package/dist/providers/cloudflare-workers-ai.js.map +1 -1
- package/dist/providers/cloudflare-workers-ai.models.d.ts.map +1 -1
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/providers/data/fireworks.json +1 -1
- package/dist/providers/data/opencode-go.json +1 -1
- package/dist/providers/data/opencode.json +1 -1
- package/dist/providers/data/openrouter.json +1 -1
- package/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/dist/providers/deepseek.d.ts.map +1 -1
- package/dist/providers/deepseek.js.map +1 -1
- package/dist/providers/deepseek.models.d.ts.map +1 -1
- package/dist/providers/faux.d.ts +2 -2
- package/dist/providers/faux.d.ts.map +1 -1
- package/dist/providers/faux.js.map +1 -1
- package/dist/providers/fireworks.d.ts.map +1 -1
- package/dist/providers/fireworks.js.map +1 -1
- package/dist/providers/fireworks.models.d.ts.map +1 -1
- package/dist/providers/github-copilot-env.d.ts.map +1 -1
- package/dist/providers/github-copilot-env.js.map +1 -1
- package/dist/providers/github-copilot.d.ts.map +1 -1
- package/dist/providers/github-copilot.js.map +1 -1
- package/dist/providers/github-copilot.models.d.ts.map +1 -1
- package/dist/providers/google-vertex.d.ts.map +1 -1
- package/dist/providers/google-vertex.js.map +1 -1
- package/dist/providers/google-vertex.models.d.ts.map +1 -1
- package/dist/providers/google.d.ts.map +1 -1
- package/dist/providers/google.js.map +1 -1
- package/dist/providers/google.models.d.ts.map +1 -1
- package/dist/providers/groq.d.ts.map +1 -1
- package/dist/providers/groq.js.map +1 -1
- package/dist/providers/groq.models.d.ts.map +1 -1
- package/dist/providers/huggingface.d.ts.map +1 -1
- package/dist/providers/huggingface.js.map +1 -1
- package/dist/providers/huggingface.models.d.ts.map +1 -1
- package/dist/providers/images/register-builtins.d.ts.map +1 -1
- package/dist/providers/images/register-builtins.js.map +1 -1
- package/dist/providers/kimi-coding.d.ts.map +1 -1
- package/dist/providers/kimi-coding.js.map +1 -1
- package/dist/providers/kimi-coding.models.d.ts.map +1 -1
- package/dist/providers/meta.d.ts.map +1 -1
- package/dist/providers/meta.js.map +1 -1
- package/dist/providers/meta.models.d.ts.map +1 -1
- package/dist/providers/minimax-cn.d.ts.map +1 -1
- package/dist/providers/minimax-cn.js.map +1 -1
- package/dist/providers/minimax-cn.models.d.ts.map +1 -1
- package/dist/providers/minimax.d.ts.map +1 -1
- package/dist/providers/minimax.js.map +1 -1
- package/dist/providers/minimax.models.d.ts.map +1 -1
- package/dist/providers/mistral.d.ts.map +1 -1
- package/dist/providers/mistral.js.map +1 -1
- package/dist/providers/mistral.models.d.ts.map +1 -1
- package/dist/providers/moonshotai-cn.d.ts.map +1 -1
- package/dist/providers/moonshotai-cn.js.map +1 -1
- package/dist/providers/moonshotai-cn.models.d.ts.map +1 -1
- package/dist/providers/moonshotai.d.ts.map +1 -1
- package/dist/providers/moonshotai.js.map +1 -1
- package/dist/providers/moonshotai.models.d.ts.map +1 -1
- package/dist/providers/nvidia.d.ts.map +1 -1
- package/dist/providers/nvidia.js.map +1 -1
- package/dist/providers/nvidia.models.d.ts.map +1 -1
- package/dist/providers/openai-codex.d.ts.map +1 -1
- package/dist/providers/openai-codex.js.map +1 -1
- package/dist/providers/openai-codex.models.d.ts.map +1 -1
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/openai.models.d.ts.map +1 -1
- package/dist/providers/opencode-go.d.ts.map +1 -1
- package/dist/providers/opencode-go.js.map +1 -1
- package/dist/providers/opencode-go.models.d.ts.map +1 -1
- package/dist/providers/opencode.d.ts.map +1 -1
- package/dist/providers/opencode.js.map +1 -1
- package/dist/providers/opencode.models.d.ts.map +1 -1
- package/dist/providers/openrouter.d.ts.map +1 -1
- package/dist/providers/openrouter.js.map +1 -1
- package/dist/providers/openrouter.models.d.ts.map +1 -1
- package/dist/providers/qwen-token-plan-cn.d.ts.map +1 -1
- package/dist/providers/qwen-token-plan-cn.js.map +1 -1
- package/dist/providers/qwen-token-plan-cn.models.d.ts.map +1 -1
- package/dist/providers/qwen-token-plan-individual.d.ts.map +1 -1
- package/dist/providers/qwen-token-plan-individual.js.map +1 -1
- package/dist/providers/qwen-token-plan-individual.models.d.ts.map +1 -1
- package/dist/providers/qwen-token-plan.d.ts.map +1 -1
- package/dist/providers/qwen-token-plan.js.map +1 -1
- package/dist/providers/qwen-token-plan.models.d.ts.map +1 -1
- package/dist/providers/radius-config.d.ts.map +1 -1
- package/dist/providers/radius-config.js.map +1 -1
- package/dist/providers/radius.d.ts.map +1 -1
- package/dist/providers/radius.js.map +1 -1
- package/dist/providers/radius.models.d.ts.map +1 -1
- package/dist/providers/together.d.ts.map +1 -1
- package/dist/providers/together.js.map +1 -1
- package/dist/providers/together.models.d.ts.map +1 -1
- package/dist/providers/typesafe.d.ts.map +1 -1
- package/dist/providers/typesafe.js.map +1 -1
- package/dist/providers/typesafe.models.d.ts.map +1 -1
- package/dist/providers/vercel-ai-gateway.d.ts.map +1 -1
- package/dist/providers/vercel-ai-gateway.js.map +1 -1
- package/dist/providers/vercel-ai-gateway.models.d.ts.map +1 -1
- package/dist/providers/xai.d.ts.map +1 -1
- package/dist/providers/xai.js.map +1 -1
- package/dist/providers/xai.models.d.ts.map +1 -1
- package/dist/providers/xiaomi-token-plan-ams.d.ts.map +1 -1
- package/dist/providers/xiaomi-token-plan-ams.js.map +1 -1
- package/dist/providers/xiaomi-token-plan-ams.models.d.ts.map +1 -1
- package/dist/providers/xiaomi-token-plan-cn.d.ts.map +1 -1
- package/dist/providers/xiaomi-token-plan-cn.js.map +1 -1
- package/dist/providers/xiaomi-token-plan-cn.models.d.ts.map +1 -1
- package/dist/providers/xiaomi-token-plan-sgp.d.ts.map +1 -1
- package/dist/providers/xiaomi-token-plan-sgp.js.map +1 -1
- package/dist/providers/xiaomi-token-plan-sgp.models.d.ts.map +1 -1
- package/dist/providers/xiaomi.d.ts.map +1 -1
- package/dist/providers/xiaomi.js.map +1 -1
- package/dist/providers/xiaomi.models.d.ts.map +1 -1
- package/dist/providers/zai-coding-cn.d.ts.map +1 -1
- package/dist/providers/zai-coding-cn.js.map +1 -1
- package/dist/providers/zai-coding-cn.models.d.ts.map +1 -1
- package/dist/providers/zai.d.ts.map +1 -1
- package/dist/providers/zai.js.map +1 -1
- package/dist/providers/zai.models.d.ts.map +1 -1
- package/dist/session-resources.d.ts.map +1 -1
- package/dist/session-resources.js.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/abort-signals.d.ts.map +1 -1
- package/dist/utils/abort-signals.js.map +1 -1
- package/dist/utils/abort.d.ts.map +1 -1
- package/dist/utils/abort.js.map +1 -1
- package/dist/utils/assistant-message-frame.d.ts.map +1 -1
- package/dist/utils/assistant-message-frame.js.map +1 -1
- package/dist/utils/diagnostics.d.ts.map +1 -1
- package/dist/utils/diagnostics.js.map +1 -1
- package/dist/utils/document-input.d.ts.map +1 -1
- package/dist/utils/document-input.js.map +1 -1
- package/dist/utils/error-body.d.ts.map +1 -1
- package/dist/utils/error-body.js.map +1 -1
- package/dist/utils/estimate.d.ts.map +1 -1
- package/dist/utils/estimate.js.map +1 -1
- package/dist/utils/event-stream.d.ts.map +1 -1
- package/dist/utils/event-stream.js.map +1 -1
- package/dist/utils/hash.d.ts.map +1 -1
- package/dist/utils/hash.js.map +1 -1
- package/dist/utils/headers.d.ts.map +1 -1
- package/dist/utils/headers.js.map +1 -1
- package/dist/utils/json-parse.d.ts.map +1 -1
- package/dist/utils/json-parse.js.map +1 -1
- package/dist/utils/model-operations.d.ts.map +1 -1
- package/dist/utils/model-operations.js.map +1 -1
- package/dist/utils/models-error.d.ts.map +1 -1
- package/dist/utils/models-error.js.map +1 -1
- package/dist/utils/node-http-proxy.d.ts.map +1 -1
- package/dist/utils/node-http-proxy.js.map +1 -1
- package/dist/utils/overflow.d.ts.map +1 -1
- package/dist/utils/overflow.js.map +1 -1
- package/dist/utils/pi-user-agent.d.ts.map +1 -1
- package/dist/utils/pi-user-agent.js.map +1 -1
- package/dist/utils/provider-env.d.ts.map +1 -1
- package/dist/utils/provider-env.js.map +1 -1
- package/dist/utils/provider-retry.d.ts.map +1 -1
- package/dist/utils/provider-retry.js.map +1 -1
- package/dist/utils/retry.d.ts.map +1 -1
- package/dist/utils/retry.js.map +1 -1
- package/dist/utils/sanitize-unicode.d.ts.map +1 -1
- package/dist/utils/sanitize-unicode.js.map +1 -1
- package/dist/utils/sleep.d.ts.map +1 -1
- package/dist/utils/sleep.js.map +1 -1
- package/dist/utils/stream-deadline.d.ts.map +1 -1
- package/dist/utils/stream-deadline.js.map +1 -1
- package/dist/utils/text.d.ts.map +1 -1
- package/dist/utils/text.js.map +1 -1
- package/dist/utils/transcript.d.ts.map +1 -1
- package/dist/utils/transcript.js.map +1 -1
- package/dist/utils/typebox-helpers.d.ts.map +1 -1
- package/dist/utils/typebox-helpers.js.map +1 -1
- package/dist/utils/uuid.d.ts.map +1 -1
- package/dist/utils/uuid.js.map +1 -1
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js.map +1 -1
- package/package.json +5 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pi-user-agent.js","sourceRoot":"","sources":["../../src/utils/pi-user-agent.ts"],"names":[],"mappings":"AAMA,SAAS,UAAU
|
|
1
|
+
{"version":3,"file":"pi-user-agent.js","sourceRoot":"","sources":["../../src/utils/pi-user-agent.ts"],"names":[],"mappings":"AAMA,SAAS,UAAU;IAClB,IAAI,OAAO,OAAO,KAAK,WAAW,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,IAAI,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC;QAC1F,OAAO,IAAI,CAAC;IACb,CAAC;IACD,OAAQ,OAAsC,CAAC,gBAAgB,EAAE,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;AACtF,CAAC;AAED,0GAA0G;AAC1G,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;AAE5B,MAAM,UAAU,cAAc;IAC7B,OAAO,MAAM,CAAC,CAAC,CAAC,OAAO,MAAM,CAAC,QAAQ,EAAE,IAAI,MAAM,CAAC,OAAO,EAAE,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC;AACpG,CAAC","sourcesContent":["import type * as NodeOs from \"node:os\";\n\ntype ProcessWithOsBuiltinModule = typeof process & {\n\tgetBuiltinModule?: (id: \"node:os\") => typeof NodeOs;\n};\n\nfunction loadNodeOs(): typeof NodeOs | null {\n\tif (typeof process === \"undefined\" || !(process.versions?.node || process.versions?.bun)) {\n\t\treturn null;\n\t}\n\treturn (process as ProcessWithOsBuiltinModule).getBuiltinModule?.(\"node:os\") ?? null;\n}\n\n// Keep runtime OS loading browser-safe. A top-level runtime import of node:os breaks browser/Vite builds.\nconst nodeOs = loadNodeOs();\n\nexport function getPiUserAgent(): string {\n\treturn nodeOs ? `pi (${nodeOs.platform()} ${nodeOs.release()}; ${nodeOs.arch()})` : \"pi (browser)\";\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-env.d.ts","sourceRoot":"","sources":["../../src/utils/provider-env.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAwC/C;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAOvF"
|
|
1
|
+
{"version":3,"file":"provider-env.d.ts","sourceRoot":"","sources":["../../src/utils/provider-env.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAwC/C;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAOvF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-env.js","sourceRoot":"","sources":["../../src/utils/provider-env.ts"],"names":[],"mappings":"AAEA,IAAI,YAAY,GAA+B,IAAI,CAAC;AAEpD;;;;;;;;;GASG;AACH,SAAS,qBAAqB,CAAC,IAAY
|
|
1
|
+
{"version":3,"file":"provider-env.js","sourceRoot":"","sources":["../../src/utils/provider-env.ts"],"names":[],"mappings":"AAEA,IAAI,YAAY,GAA+B,IAAI,CAAC;AAEpD;;;;;;;;;GASG;AACH,SAAS,qBAAqB,CAAC,IAAY;IAC1C,IAAI,OAAO,OAAO,KAAK,WAAW,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrG,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;QAC3B,YAAY,GAAG,IAAI,GAAG,EAAE,CAAC;QACzB,IAAI,CAAC;YACJ,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,SAAS,CAEzC,CAAC;YACF,MAAM,IAAI,GAAG,YAAY,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC;YACzD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACtC,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAC/B,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;oBACb,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;gBAC7D,CAAC;YACF,CAAC;QACF,CAAC;QAAC,MAAM,CAAC;YACR,2DAA2D;QAC5D,CAAC;IACF,CAAC;IAED,OAAO,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,GAAiB;IAClE,OAAO,CACN,GAAG,EAAE,CAAC,IAAI,CAAC;QACX,CAAC,OAAO,OAAO,KAAK,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAChE,qBAAqB,CAAC,IAAI,CAAC;QAC3B,SAAS,CACT,CAAC;AACH,CAAC","sourcesContent":["import type { ProviderEnv } from \"../types.ts\";\n\nlet procEnvCache: Map<string, string> | null = null;\n\n/**\n * Fallback for https://github.com/oven-sh/bun/issues/27802.\n * Bun compiled binaries can expose an empty process.env inside Linux sandboxes\n * even though /proc/self/environ contains the environment.\n *\n * This intentionally duplicates restoreSandboxEnv() in\n * packages/coding-agent/src/bun/restore-sandbox-env.ts. The ai package can be\n * used directly, without going through that entrypoint, so provider env lookup\n * must not depend on process.env having been patched.\n */\nfunction getBunSandboxEnvValue(name: string): string | undefined {\n\tif (typeof process === \"undefined\" || !process.versions?.bun || Object.keys(process.env).length > 0) {\n\t\treturn undefined;\n\t}\n\n\tif (procEnvCache === null) {\n\t\tprocEnvCache = new Map();\n\t\ttry {\n\t\t\tconst { readFileSync } = require(\"node:fs\") as {\n\t\t\t\treadFileSync(path: string, encoding: BufferEncoding): string;\n\t\t\t};\n\t\t\tconst data = readFileSync(\"/proc/self/environ\", \"utf-8\");\n\t\t\tfor (const entry of data.split(\"\\0\")) {\n\t\t\t\tconst idx = entry.indexOf(\"=\");\n\t\t\t\tif (idx > 0) {\n\t\t\t\t\tprocEnvCache.set(entry.slice(0, idx), entry.slice(idx + 1));\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// /proc/self/environ may not exist or may not be readable.\n\t\t}\n\t}\n\n\treturn procEnvCache.get(name);\n}\n\n/**\n * Resolve a provider env value from scoped overrides, normal process.env, then\n * the duplicated Bun sandbox fallback for direct pi-ai consumers.\n */\nexport function getProviderEnvValue(name: string, env?: ProviderEnv): string | undefined {\n\treturn (\n\t\tenv?.[name] ||\n\t\t(typeof process !== \"undefined\" ? process.env[name] : undefined) ||\n\t\tgetBunSandboxEnvValue(name) ||\n\t\tundefined\n\t);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-retry.d.ts","sourceRoot":"","sources":["../../src/utils/provider-retry.ts"],"names":[],"mappings":"AAEA,UAAU,oBAAoB;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AA0FD;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CAAC,CAAC,EAC3C,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACzB,OAAO,GAAE,oBAAyB,GAChC,OAAO,CAAC,CAAC,CAAC,CAiBZ"
|
|
1
|
+
{"version":3,"file":"provider-retry.d.ts","sourceRoot":"","sources":["../../src/utils/provider-retry.ts"],"names":[],"mappings":"AAEA,UAAU,oBAAoB;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AA0FD;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CAAC,CAAC,EAC3C,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACzB,OAAO,GAAE,oBAAyB,GAChC,OAAO,CAAC,CAAC,CAAC,CAiBZ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-retry.js","sourceRoot":"","sources":["../../src/utils/provider-retry.ts"],"names":[],"mappings":"AAAA,MAAM,0BAA0B,GAAG,MAAM,CAAC;AAa1C,SAAS,eAAe,CAAC,KAAc
|
|
1
|
+
{"version":3,"file":"provider-retry.js","sourceRoot":"","sources":["../../src/utils/provider-retry.ts"],"names":[],"mappings":"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","sourcesContent":["const DEFAULT_MAX_RETRY_DELAY_MS = 60_000;\n\ninterface ProviderRetryOptions {\n\tmaxRetries?: number;\n\tmaxRetryDelayMs?: number;\n\tsignal?: AbortSignal;\n}\n\ninterface ProviderError extends Error {\n\tstatus: number | undefined;\n\theaders: Headers | undefined;\n}\n\nfunction isProviderError(error: unknown): error is ProviderError {\n\tif (!(error instanceof Error) || !(\"status\" in error) || !(\"headers\" in error)) return false;\n\treturn (\n\t\t(error.status === undefined || typeof error.status === \"number\") &&\n\t\t(error.headers === undefined || error.headers instanceof Headers)\n\t);\n}\n\n/** Mirrors the pinned OpenAI/Anthropic SDK retry policy; review when either SDK is upgraded. */\nfunction isRetryableProviderError(error: ProviderError): boolean {\n\tconst shouldRetry = error.headers?.get(\"x-should-retry\");\n\tif (shouldRetry === \"true\") return true;\n\tif (shouldRetry === \"false\") return false;\n\n\tif (error.status === undefined) return true;\n\treturn (\n\t\terror.status === 408 ||\n\t\terror.status === 409 ||\n\t\terror.status === 429 ||\n\t\t(typeof error.status === \"number\" && error.status >= 500)\n\t);\n}\n\nfunction validateServerRetryDelayMs(\n\tdelayMs: number,\n\tmaxRetryDelayMs: number | undefined,\n\tproviderErrorMessage: string,\n): number {\n\tconst maxDelayMs = maxRetryDelayMs ?? DEFAULT_MAX_RETRY_DELAY_MS;\n\tif (maxDelayMs > 0 && delayMs > maxDelayMs) {\n\t\tthrow new Error(\n\t\t\t`Server requested ${Math.ceil(delayMs / 1000)}s retry delay (max: ${Math.ceil(maxDelayMs / 1000)}s). ${providerErrorMessage}`,\n\t\t);\n\t}\n\treturn delayMs;\n}\n\nfunction getRetryDelayMs(error: ProviderError, retryIndex: number, maxRetryDelayMs: number | undefined): number {\n\tconst retryAfterMs = error.headers?.get(\"retry-after-ms\");\n\tif (retryAfterMs) {\n\t\tconst value = Number.parseFloat(retryAfterMs);\n\t\tif (!Number.isNaN(value)) return validateServerRetryDelayMs(value, maxRetryDelayMs, error.message);\n\t}\n\n\tconst retryAfter = error.headers?.get(\"retry-after\");\n\tif (retryAfter) {\n\t\tconst seconds = Number.parseFloat(retryAfter);\n\t\tconst delayMs = Number.isNaN(seconds) ? Date.parse(retryAfter) - Date.now() : seconds * 1000;\n\t\treturn validateServerRetryDelayMs(delayMs, maxRetryDelayMs, error.message);\n\t}\n\n\tconst exponentialDelay = Math.min(0.5 * 2 ** retryIndex, 8) * 1000;\n\treturn exponentialDelay * (1 - Math.random() * 0.25);\n}\n\nfunction createAbortError(): Error {\n\tconst error = new Error(\"Request aborted\");\n\terror.name = \"AbortError\";\n\treturn error;\n}\n\nfunction abortableSleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(createAbortError());\n\t\t\treturn;\n\t\t}\n\n\t\tconst onAbort = () => {\n\t\t\tclearTimeout(timeout);\n\t\t\treject(createAbortError());\n\t\t};\n\t\tconst timeout = setTimeout(\n\t\t\t() => {\n\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\tresolve();\n\t\t\t},\n\t\t\tMath.max(0, ms),\n\t\t);\n\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t});\n}\n\n/**\n * Reproduce the retry behavior used by the OpenAI and Anthropic SDKs while making\n * their backoff sleep interruptible. Their built-in retry timers ignore the\n * request AbortSignal, so callers must invoke the SDK with `maxRetries: 0` and\n * wrap the request with this helper. Provider-requested delays above\n * `maxRetryDelayMs` fail immediately (60 seconds by default); set it to zero to\n * disable the limit.\n */\nexport async function retryProviderRequest<T>(\n\trequest: () => Promise<T>,\n\toptions: ProviderRetryOptions = {},\n): Promise<T> {\n\tconst maxRetries = options.maxRetries ?? 0;\n\tlet retriesRemaining = maxRetries;\n\n\tfor (;;) {\n\t\ttry {\n\t\t\t// Each retry is a fresh SDK request, so X-Stainless-Retry-Count remains zero.\n\t\t\treturn await request();\n\t\t} catch (error) {\n\t\t\tif (options.signal?.aborted) throw createAbortError();\n\t\t\tif (retriesRemaining <= 0 || !isProviderError(error) || !isRetryableProviderError(error)) throw error;\n\n\t\t\tconst retryIndex = maxRetries - retriesRemaining;\n\t\t\tretriesRemaining--;\n\t\t\tawait abortableSleep(getRetryDelayMs(error, retryIndex, options.maxRetryDelayMs), options.signal);\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AA6GpD;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,qFAAqF;IACrF,UAAU,EAAE,MAAM,CAAC;IACnB,0FAA0F;IAC1F,WAAW,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,eAAO,MAAM,gCAAgC,QAAS,CAAC;AAEvD,wBAAgB,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,aAAa,GAAG,iBAAiB,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAIlH;AAED,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC9B,0EAA0E;IAC1E,gBAAgB,CAAC,EAAE,CAClB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,KAChB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,mFAAmF;IACnF,mBAAmB,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,mFAAmF;IACnF,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnG;AA0BD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,kBAAkB,CACvC,OAAO,EAAE,MAAM,OAAO,CAAC,gBAAgB,CAAC,EACxC,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,SAAS,CAAC,EAAE,cAAc,GACxB,OAAO,CAAC,gBAAgB,CAAC,CA4C3B;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAK5E","sourcesContent":["import type { AssistantMessage } from \"../types.ts\";\n\nfunction buildProviderErrorPattern(patterns: readonly string[]): RegExp {\n\treturn new RegExp(patterns.join(\"|\"), \"i\");\n}\n\nconst NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN = buildProviderErrorPattern([\n\t// OpenCode Go/free-tier limits returned as 429 JSON error types by OpenCode's\n\t// Zen API. These are subscription/account limits, not transient throttles.\n\t\"GoUsageLimitError\",\n\t\"FreeUsageLimitError\",\n\n\t// OpenCode Go subscription-limit text asks users to enable available-balance\n\t// usage after rolling/weekly/monthly limits are reached.\n\t\"Monthly usage limit reached\",\n\t\"available balance\",\n\n\t// Generic quota/budget/billing exhaustion. `insufficient_quota` is OpenAI's\n\t// quota/billing error code; the other strings cover common gateway wording.\n\t\"insufficient_quota\",\n\t\"out of budget\",\n\t\"quota exceeded\",\n\t\"billing\",\n]);\n\nconst RETRYABLE_PROVIDER_ERROR_PATTERN = buildProviderErrorPattern([\n\t// Generic provider load, HTTP status, and server-side transient failures.\n\t\"overloaded\",\n\t\"currently experiencing high demand\",\n\t\"rate.?limit\",\n\t\"too many requests\",\n\t\"429\",\n\t\"500\",\n\t\"502\",\n\t\"503\",\n\t\"504\",\n\t\"520\",\n\t\"524\",\n\t\"service.?unavailable\",\n\t\"server.?error\",\n\t\"internal.?error\",\n\n\t// Wrapper/provider text for transient upstream failures, including OpenRouter\n\t// \"Provider returned error\" responses (#2264).\n\t\"provider.?returned.?error\",\n\t\"exceeded request buffer limit while retrying upstream\",\n\n\t// Network, proxy, and fetch transport failures. This includes OpenAI Codex\n\t// raw-fetch failures such as \"upstream connect\", \"connection refused\", and\n\t// \"reset before headers\" (#733), plus OpenRouter connection drops (#3317).\n\t\"network.?error\",\n\t\"connection.?error\",\n\t\"connection.?refused\",\n\t\"connection.?lost\",\n\t\"other side closed\",\n\t\"fetch failed\",\n\t\"getaddrinfo\",\n\t\"ENOTFOUND\",\n\t\"EAI_AGAIN\",\n\t\"upstream.?connect\",\n\t\"reset before headers\",\n\t\"socket hang up\",\n\t\"socket connection was closed\",\n\t\"timed? out\",\n\t\"timeout\",\n\t\"terminated\",\n\n\t// WebSocket transports can report close/error text instead of HTTP/fetch text.\n\t\"websocket.?closed\",\n\t\"websocket.?error\",\n\n\t// Response-body decompression failures. Node/Bun zlib rejects a body whose\n\t// Content-Encoding lied or whose compressed bytes were corrupted, and the\n\t// fetch/WebSocket layer wraps it with a \"Library error:\" prefix. GitHub\n\t// Copilot on the default `transport: \"auto\"` reports this as\n\t// \"Library error: zlib error: incorrect header check\" (#2553). The transfer\n\t// is already unusable, and a fresh attempt normally succeeds, so treat every\n\t// variant as a transient transport failure rather than a deterministic error.\n\t\"zlib\",\n\t\"incorrect header check\",\n\t\"decompress\",\n\t\"library error\",\n\n\t// Idle-stream deadline enforced below the HTTP layer by `withStreamDeadline`\n\t// so a stream that never settles cannot hang an attempt forever (#2553).\n\t\"stream deadline exceeded\",\n\n\t// Premature stream endings from SDKs and transports. Anthropic can throw\n\t// \"stream ended without ...\" and \"Anthropic stream ended before message_stop\"\n\t// (#4433); Bedrock/Smithy can throw an HTTP/2 no-response error (#3594).\n\t\"ended without\",\n\t\"stream ended before message_stop\",\n\t\"stream ended before a terminal response event\",\n\t\"http2 request did not get a response\",\n\n\t// Provider-requested retry delay cap failures should flow through the outer\n\t// retry policy so callers can surface/abort the backoff (#1123).\n\t\"retry delay\",\n\n\t// Explicit retry guidance emitted mid-stream by OpenAI Responses and Bedrock\n\t// stream exceptions (#6019).\n\t\"you can retry your request\",\n\t\"try your request again\",\n\t\"please retry your request\",\n\n\t// gRPC based providers (e.g. NVIDIA NIM)\n\t\"ResourceExhausted\",\n]);\n\n/**\n * Retry policy: bounded attempts with exponential backoff (`baseDelayMs * 2^(attempt-1)`).\n * Each delay is capped by `maxAgentDelayMs` (60 seconds by default).\n * Matches `settings.retry` (`enabled`, `maxRetries`, `baseDelayMs`) in coding-agent; kept\n * here so the classifier and the policy-driven retry loop live together and stay reusable\n * by the SDK and other callers.\n */\nexport interface RetryPolicy {\n\tenabled: boolean;\n\t/** Max retry attempts (0 = no retries). The initial call never counts as a retry. */\n\tmaxRetries: number;\n\t/** Base delay in ms. Per-attempt delay is `baseDelayMs * 2^(attempt-1)` before jitter. */\n\tbaseDelayMs: number;\n\t/** Cap for agent-level retry delays in ms. Defaults to 60 seconds. */\n\tmaxAgentDelayMs?: number;\n}\n\nexport const DEFAULT_MAX_AGENT_RETRY_DELAY_MS = 60_000;\n\nexport function retryDelayMs(policy: Pick<RetryPolicy, \"baseDelayMs\" | \"maxAgentDelayMs\">, attempt: number): number {\n\tconst delay = policy.baseDelayMs * 2 ** Math.max(0, attempt - 1);\n\tconst safeDelay = Number.isSafeInteger(delay) ? delay : Number.MAX_SAFE_INTEGER;\n\treturn Math.min(safeDelay, policy.maxAgentDelayMs ?? DEFAULT_MAX_AGENT_RETRY_DELAY_MS);\n}\n\n/** Optional callbacks emitted by {@link retryAssistantCall} around each retry. */\nexport interface RetryCallbacks {\n\t/** Emitted before the backoff sleep of each retry attempt (1-indexed). */\n\tonRetryScheduled?: (\n\t\tattempt: number,\n\t\tmaxAttempts: number,\n\t\tdelayMs: number,\n\t\terrorMessage: string,\n\t) => void | Promise<void>;\n\t/** Emitted after the backoff sleep, immediately before the retried call starts. */\n\tonRetryAttemptStart?: () => void | Promise<void>;\n\t/** Emitted once when the loop ends: success if a later call completed normally. */\n\tonRetryFinished?: (success: boolean, attempt: number, finalError?: string) => void | Promise<void>;\n}\n\nclass RetrySleepAbortError extends Error {\n\tconstructor() {\n\t\tsuper(\"Aborted\");\n\t}\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(new RetrySleepAbortError());\n\t\t\treturn;\n\t\t}\n\t\tconst timeout = setTimeout(resolve, ms);\n\t\tsignal?.addEventListener(\n\t\t\t\"abort\",\n\t\t\t() => {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\treject(new RetrySleepAbortError());\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t});\n}\n\n/**\n * Run a single assistant-producing call with bounded retry on transient errors.\n *\n * Behavior:\n * - A successful response is returned immediately. Aborts are terminal and never\n * retried, but reported as unsuccessful if they happen after a retry was scheduled.\n * Aborts during the backoff sleep are normalized to an aborted `AssistantMessage`\n * too, so callers do not need to care when cancellation happened.\n * - A non-retryable error (per {@link isRetryableAssistantError}, including quota/\n * billing exhaustion) is returned immediately so deterministic errors fail fast.\n * - Otherwise retries up to `maxRetries` times with exponential backoff, emitting\n * `onRetryScheduled` before each sleep, `onRetryAttemptStart` after each sleep before\n * the retried call starts, and `onRetryFinished` once at the end (whether the loop\n * ends in success, exhausted retries, or an aborted backoff).\n *\n * When `policy` is undefined or disabled, the first response is returned unchanged\n * (equivalent to calling `produce()` directly).\n */\nexport async function retryAssistantCall(\n\tproduce: () => Promise<AssistantMessage>,\n\tpolicy: RetryPolicy | undefined,\n\tsignal: AbortSignal | undefined,\n\tcallbacks?: RetryCallbacks,\n): Promise<AssistantMessage> {\n\tconst maxAttempts = policy?.enabled ? policy.maxRetries : 0;\n\n\tlet attempt = 0;\n\tlet lastRetry: { attempt: number; errorMessage: string } | undefined;\n\tfor (;;) {\n\t\tconst response = await produce();\n\n\t\t// Abort: terminal but not successful. Never retry an aborted message.\n\t\tif (response.stopReason === \"aborted\") {\n\t\t\tif (lastRetry) await callbacks?.onRetryFinished?.(false, lastRetry.attempt);\n\t\t\treturn response;\n\t\t}\n\n\t\t// Success: non-error, non-abort responses return as-is.\n\t\tif (response.stopReason !== \"error\") {\n\t\t\tif (lastRetry) await callbacks?.onRetryFinished?.(true, lastRetry.attempt);\n\t\t\treturn response;\n\t\t}\n\n\t\t// Non-retryable, or budget exhausted: return the final error message.\n\t\tif (attempt >= maxAttempts || !isRetryableAssistantError(response)) {\n\t\t\tif (lastRetry) await callbacks?.onRetryFinished?.(false, lastRetry.attempt, response.errorMessage);\n\t\t\treturn response;\n\t\t}\n\n\t\tattempt++;\n\t\tlastRetry = { attempt, errorMessage: response.errorMessage || \"Unknown error\" };\n\t\tconst delayMs = retryDelayMs(policy!, attempt);\n\t\tawait callbacks?.onRetryScheduled?.(attempt, maxAttempts, delayMs, lastRetry.errorMessage);\n\n\t\t// Normalize aborts during retry backoff to the same AssistantMessage shape as\n\t\t// provider stream aborts, so callers do not need to care when cancellation happened.\n\t\ttry {\n\t\t\tawait sleep(delayMs, signal);\n\t\t} catch (error) {\n\t\t\tawait callbacks?.onRetryFinished?.(false, attempt, lastRetry.errorMessage);\n\t\t\tif (error instanceof RetrySleepAbortError) {\n\t\t\t\treturn { ...response, stopReason: \"aborted\", errorMessage: undefined };\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tawait callbacks?.onRetryAttemptStart?.();\n\t}\n}\n\n/**\n * Classifies whether a failed assistant message looks like a transient provider\n * or transport error, so callers can decide if the last assistant turn should be\n * restarted.\n *\n * This does not implement retry policy. Callers should first handle context\n * overflow separately, then apply their own retry budget, backoff, and reporting\n * before restarting the assistant turn.\n */\nexport function isRetryableAssistantError(message: AssistantMessage): boolean {\n\tif (message.stopReason !== \"error\" || !message.errorMessage) return false;\n\tconst errorMessage = message.errorMessage;\n\tif (NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN.test(errorMessage)) return false;\n\treturn RETRYABLE_PROVIDER_ERROR_PATTERN.test(errorMessage);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AA6GpD;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,qFAAqF;IACrF,UAAU,EAAE,MAAM,CAAC;IACnB,0FAA0F;IAC1F,WAAW,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,eAAO,MAAM,gCAAgC,QAAS,CAAC;AAEvD,wBAAgB,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,aAAa,GAAG,iBAAiB,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAIlH;AAED,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC9B,0EAA0E;IAC1E,gBAAgB,CAAC,EAAE,CAClB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,KAChB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,mFAAmF;IACnF,mBAAmB,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,mFAAmF;IACnF,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnG;AA0BD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,kBAAkB,CACvC,OAAO,EAAE,MAAM,OAAO,CAAC,gBAAgB,CAAC,EACxC,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,SAAS,CAAC,EAAE,cAAc,GACxB,OAAO,CAAC,gBAAgB,CAAC,CA4C3B;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAK5E"}
|
package/dist/utils/retry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AssistantMessage } from \"../types.ts\";\n\nfunction buildProviderErrorPattern(patterns: readonly string[]): RegExp {\n\treturn new RegExp(patterns.join(\"|\"), \"i\");\n}\n\nconst NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN = buildProviderErrorPattern([\n\t// OpenCode Go/free-tier limits returned as 429 JSON error types by OpenCode's\n\t// Zen API. These are subscription/account limits, not transient throttles.\n\t\"GoUsageLimitError\",\n\t\"FreeUsageLimitError\",\n\n\t// OpenCode Go subscription-limit text asks users to enable available-balance\n\t// usage after rolling/weekly/monthly limits are reached.\n\t\"Monthly usage limit reached\",\n\t\"available balance\",\n\n\t// Generic quota/budget/billing exhaustion. `insufficient_quota` is OpenAI's\n\t// quota/billing error code; the other strings cover common gateway wording.\n\t\"insufficient_quota\",\n\t\"out of budget\",\n\t\"quota exceeded\",\n\t\"billing\",\n]);\n\nconst RETRYABLE_PROVIDER_ERROR_PATTERN = buildProviderErrorPattern([\n\t// Generic provider load, HTTP status, and server-side transient failures.\n\t\"overloaded\",\n\t\"currently experiencing high demand\",\n\t\"rate.?limit\",\n\t\"too many requests\",\n\t\"429\",\n\t\"500\",\n\t\"502\",\n\t\"503\",\n\t\"504\",\n\t\"520\",\n\t\"524\",\n\t\"service.?unavailable\",\n\t\"server.?error\",\n\t\"internal.?error\",\n\n\t// Wrapper/provider text for transient upstream failures, including OpenRouter\n\t// \"Provider returned error\" responses (#2264).\n\t\"provider.?returned.?error\",\n\t\"exceeded request buffer limit while retrying upstream\",\n\n\t// Network, proxy, and fetch transport failures. This includes OpenAI Codex\n\t// raw-fetch failures such as \"upstream connect\", \"connection refused\", and\n\t// \"reset before headers\" (#733), plus OpenRouter connection drops (#3317).\n\t\"network.?error\",\n\t\"connection.?error\",\n\t\"connection.?refused\",\n\t\"connection.?lost\",\n\t\"other side closed\",\n\t\"fetch failed\",\n\t\"getaddrinfo\",\n\t\"ENOTFOUND\",\n\t\"EAI_AGAIN\",\n\t\"upstream.?connect\",\n\t\"reset before headers\",\n\t\"socket hang up\",\n\t\"socket connection was closed\",\n\t\"timed? out\",\n\t\"timeout\",\n\t\"terminated\",\n\n\t// WebSocket transports can report close/error text instead of HTTP/fetch text.\n\t\"websocket.?closed\",\n\t\"websocket.?error\",\n\n\t// Response-body decompression failures. Node/Bun zlib rejects a body whose\n\t// Content-Encoding lied or whose compressed bytes were corrupted, and the\n\t// fetch/WebSocket layer wraps it with a \"Library error:\" prefix. GitHub\n\t// Copilot on the default `transport: \"auto\"` reports this as\n\t// \"Library error: zlib error: incorrect header check\" (#2553). The transfer\n\t// is already unusable, and a fresh attempt normally succeeds, so treat every\n\t// variant as a transient transport failure rather than a deterministic error.\n\t\"zlib\",\n\t\"incorrect header check\",\n\t\"decompress\",\n\t\"library error\",\n\n\t// Idle-stream deadline enforced below the HTTP layer by `withStreamDeadline`\n\t// so a stream that never settles cannot hang an attempt forever (#2553).\n\t\"stream deadline exceeded\",\n\n\t// Premature stream endings from SDKs and transports. Anthropic can throw\n\t// \"stream ended without ...\" and \"Anthropic stream ended before message_stop\"\n\t// (#4433); Bedrock/Smithy can throw an HTTP/2 no-response error (#3594).\n\t\"ended without\",\n\t\"stream ended before message_stop\",\n\t\"stream ended before a terminal response event\",\n\t\"http2 request did not get a response\",\n\n\t// Provider-requested retry delay cap failures should flow through the outer\n\t// retry policy so callers can surface/abort the backoff (#1123).\n\t\"retry delay\",\n\n\t// Explicit retry guidance emitted mid-stream by OpenAI Responses and Bedrock\n\t// stream exceptions (#6019).\n\t\"you can retry your request\",\n\t\"try your request again\",\n\t\"please retry your request\",\n\n\t// gRPC based providers (e.g. NVIDIA NIM)\n\t\"ResourceExhausted\",\n]);\n\n/**\n * Retry policy: bounded attempts with exponential backoff (`baseDelayMs * 2^(attempt-1)`).\n * Each delay is capped by `maxAgentDelayMs` (60 seconds by default).\n * Matches `settings.retry` (`enabled`, `maxRetries`, `baseDelayMs`) in coding-agent; kept\n * here so the classifier and the policy-driven retry loop live together and stay reusable\n * by the SDK and other callers.\n */\nexport interface RetryPolicy {\n\tenabled: boolean;\n\t/** Max retry attempts (0 = no retries). The initial call never counts as a retry. */\n\tmaxRetries: number;\n\t/** Base delay in ms. Per-attempt delay is `baseDelayMs * 2^(attempt-1)` before jitter. */\n\tbaseDelayMs: number;\n\t/** Cap for agent-level retry delays in ms. Defaults to 60 seconds. */\n\tmaxAgentDelayMs?: number;\n}\n\nexport const DEFAULT_MAX_AGENT_RETRY_DELAY_MS = 60_000;\n\nexport function retryDelayMs(policy: Pick<RetryPolicy, \"baseDelayMs\" | \"maxAgentDelayMs\">, attempt: number): number {\n\tconst delay = policy.baseDelayMs * 2 ** Math.max(0, attempt - 1);\n\tconst safeDelay = Number.isSafeInteger(delay) ? delay : Number.MAX_SAFE_INTEGER;\n\treturn Math.min(safeDelay, policy.maxAgentDelayMs ?? DEFAULT_MAX_AGENT_RETRY_DELAY_MS);\n}\n\n/** Optional callbacks emitted by {@link retryAssistantCall} around each retry. */\nexport interface RetryCallbacks {\n\t/** Emitted before the backoff sleep of each retry attempt (1-indexed). */\n\tonRetryScheduled?: (\n\t\tattempt: number,\n\t\tmaxAttempts: number,\n\t\tdelayMs: number,\n\t\terrorMessage: string,\n\t) => void | Promise<void>;\n\t/** Emitted after the backoff sleep, immediately before the retried call starts. */\n\tonRetryAttemptStart?: () => void | Promise<void>;\n\t/** Emitted once when the loop ends: success if a later call completed normally. */\n\tonRetryFinished?: (success: boolean, attempt: number, finalError?: string) => void | Promise<void>;\n}\n\nclass RetrySleepAbortError extends Error {\n\tconstructor() {\n\t\tsuper(\"Aborted\");\n\t}\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(new RetrySleepAbortError());\n\t\t\treturn;\n\t\t}\n\t\tconst timeout = setTimeout(resolve, ms);\n\t\tsignal?.addEventListener(\n\t\t\t\"abort\",\n\t\t\t() => {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\treject(new RetrySleepAbortError());\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t});\n}\n\n/**\n * Run a single assistant-producing call with bounded retry on transient errors.\n *\n * Behavior:\n * - A successful response is returned immediately. Aborts are terminal and never\n * retried, but reported as unsuccessful if they happen after a retry was scheduled.\n * Aborts during the backoff sleep are normalized to an aborted `AssistantMessage`\n * too, so callers do not need to care when cancellation happened.\n * - A non-retryable error (per {@link isRetryableAssistantError}, including quota/\n * billing exhaustion) is returned immediately so deterministic errors fail fast.\n * - Otherwise retries up to `maxRetries` times with exponential backoff, emitting\n * `onRetryScheduled` before each sleep, `onRetryAttemptStart` after each sleep before\n * the retried call starts, and `onRetryFinished` once at the end (whether the loop\n * ends in success, exhausted retries, or an aborted backoff).\n *\n * When `policy` is undefined or disabled, the first response is returned unchanged\n * (equivalent to calling `produce()` directly).\n */\nexport async function retryAssistantCall(\n\tproduce: () => Promise<AssistantMessage>,\n\tpolicy: RetryPolicy | undefined,\n\tsignal: AbortSignal | undefined,\n\tcallbacks?: RetryCallbacks,\n): Promise<AssistantMessage> {\n\tconst maxAttempts = policy?.enabled ? policy.maxRetries : 0;\n\n\tlet attempt = 0;\n\tlet lastRetry: { attempt: number; errorMessage: string } | undefined;\n\tfor (;;) {\n\t\tconst response = await produce();\n\n\t\t// Abort: terminal but not successful. Never retry an aborted message.\n\t\tif (response.stopReason === \"aborted\") {\n\t\t\tif (lastRetry) await callbacks?.onRetryFinished?.(false, lastRetry.attempt);\n\t\t\treturn response;\n\t\t}\n\n\t\t// Success: non-error, non-abort responses return as-is.\n\t\tif (response.stopReason !== \"error\") {\n\t\t\tif (lastRetry) await callbacks?.onRetryFinished?.(true, lastRetry.attempt);\n\t\t\treturn response;\n\t\t}\n\n\t\t// Non-retryable, or budget exhausted: return the final error message.\n\t\tif (attempt >= maxAttempts || !isRetryableAssistantError(response)) {\n\t\t\tif (lastRetry) await callbacks?.onRetryFinished?.(false, lastRetry.attempt, response.errorMessage);\n\t\t\treturn response;\n\t\t}\n\n\t\tattempt++;\n\t\tlastRetry = { attempt, errorMessage: response.errorMessage || \"Unknown error\" };\n\t\tconst delayMs = retryDelayMs(policy!, attempt);\n\t\tawait callbacks?.onRetryScheduled?.(attempt, maxAttempts, delayMs, lastRetry.errorMessage);\n\n\t\t// Normalize aborts during retry backoff to the same AssistantMessage shape as\n\t\t// provider stream aborts, so callers do not need to care when cancellation happened.\n\t\ttry {\n\t\t\tawait sleep(delayMs, signal);\n\t\t} catch (error) {\n\t\t\tawait callbacks?.onRetryFinished?.(false, attempt, lastRetry.errorMessage);\n\t\t\tif (error instanceof RetrySleepAbortError) {\n\t\t\t\treturn { ...response, stopReason: \"aborted\", errorMessage: undefined };\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tawait callbacks?.onRetryAttemptStart?.();\n\t}\n}\n\n/**\n * Classifies whether a failed assistant message looks like a transient provider\n * or transport error, so callers can decide if the last assistant turn should be\n * restarted.\n *\n * This does not implement retry policy. Callers should first handle context\n * overflow separately, then apply their own retry budget, backoff, and reporting\n * before restarting the assistant turn.\n */\nexport function isRetryableAssistantError(message: AssistantMessage): boolean {\n\tif (message.stopReason !== \"error\" || !message.errorMessage) return false;\n\tconst errorMessage = message.errorMessage;\n\tif (NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN.test(errorMessage)) return false;\n\treturn RETRYABLE_PROVIDER_ERROR_PATTERN.test(errorMessage);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AssistantMessage } from \"../types.ts\";\n\nfunction buildProviderErrorPattern(patterns: readonly string[]): RegExp {\n\treturn new RegExp(patterns.join(\"|\"), \"i\");\n}\n\nconst NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN = buildProviderErrorPattern([\n\t// OpenCode Go/free-tier limits returned as 429 JSON error types by OpenCode's\n\t// Zen API. These are subscription/account limits, not transient throttles.\n\t\"GoUsageLimitError\",\n\t\"FreeUsageLimitError\",\n\n\t// OpenCode Go subscription-limit text asks users to enable available-balance\n\t// usage after rolling/weekly/monthly limits are reached.\n\t\"Monthly usage limit reached\",\n\t\"available balance\",\n\n\t// Generic quota/budget/billing exhaustion. `insufficient_quota` is OpenAI's\n\t// quota/billing error code; the other strings cover common gateway wording.\n\t\"insufficient_quota\",\n\t\"out of budget\",\n\t\"quota exceeded\",\n\t\"billing\",\n]);\n\nconst RETRYABLE_PROVIDER_ERROR_PATTERN = buildProviderErrorPattern([\n\t// Generic provider load, HTTP status, and server-side transient failures.\n\t\"overloaded\",\n\t\"currently experiencing high demand\",\n\t\"rate.?limit\",\n\t\"too many requests\",\n\t\"429\",\n\t\"500\",\n\t\"502\",\n\t\"503\",\n\t\"504\",\n\t\"520\",\n\t\"524\",\n\t\"service.?unavailable\",\n\t\"server.?error\",\n\t\"internal.?error\",\n\n\t// Wrapper/provider text for transient upstream failures, including OpenRouter\n\t// \"Provider returned error\" responses (#2264).\n\t\"provider.?returned.?error\",\n\t\"exceeded request buffer limit while retrying upstream\",\n\n\t// Network, proxy, and fetch transport failures. This includes OpenAI Codex\n\t// raw-fetch failures such as \"upstream connect\", \"connection refused\", and\n\t// \"reset before headers\" (#733), plus OpenRouter connection drops (#3317).\n\t\"network.?error\",\n\t\"connection.?error\",\n\t\"connection.?refused\",\n\t\"connection.?lost\",\n\t\"other side closed\",\n\t\"fetch failed\",\n\t\"getaddrinfo\",\n\t\"ENOTFOUND\",\n\t\"EAI_AGAIN\",\n\t\"upstream.?connect\",\n\t\"reset before headers\",\n\t\"socket hang up\",\n\t\"socket connection was closed\",\n\t\"timed? out\",\n\t\"timeout\",\n\t\"terminated\",\n\n\t// WebSocket transports can report close/error text instead of HTTP/fetch text.\n\t\"websocket.?closed\",\n\t\"websocket.?error\",\n\n\t// Response-body decompression failures. Node/Bun zlib rejects a body whose\n\t// Content-Encoding lied or whose compressed bytes were corrupted, and the\n\t// fetch/WebSocket layer wraps it with a \"Library error:\" prefix. GitHub\n\t// Copilot on the default `transport: \"auto\"` reports this as\n\t// \"Library error: zlib error: incorrect header check\" (#2553). The transfer\n\t// is already unusable, and a fresh attempt normally succeeds, so treat every\n\t// variant as a transient transport failure rather than a deterministic error.\n\t\"zlib\",\n\t\"incorrect header check\",\n\t\"decompress\",\n\t\"library error\",\n\n\t// Idle-stream deadline enforced below the HTTP layer by `withStreamDeadline`\n\t// so a stream that never settles cannot hang an attempt forever (#2553).\n\t\"stream deadline exceeded\",\n\n\t// Premature stream endings from SDKs and transports. Anthropic can throw\n\t// \"stream ended without ...\" and \"Anthropic stream ended before message_stop\"\n\t// (#4433); Bedrock/Smithy can throw an HTTP/2 no-response error (#3594).\n\t\"ended without\",\n\t\"stream ended before message_stop\",\n\t\"stream ended before a terminal response event\",\n\t\"http2 request did not get a response\",\n\n\t// Provider-requested retry delay cap failures should flow through the outer\n\t// retry policy so callers can surface/abort the backoff (#1123).\n\t\"retry delay\",\n\n\t// Explicit retry guidance emitted mid-stream by OpenAI Responses and Bedrock\n\t// stream exceptions (#6019).\n\t\"you can retry your request\",\n\t\"try your request again\",\n\t\"please retry your request\",\n\n\t// gRPC based providers (e.g. NVIDIA NIM)\n\t\"ResourceExhausted\",\n]);\n\n/**\n * Retry policy: bounded attempts with exponential backoff (`baseDelayMs * 2^(attempt-1)`).\n * Each delay is capped by `maxAgentDelayMs` (60 seconds by default).\n * Matches `settings.retry` (`enabled`, `maxRetries`, `baseDelayMs`) in coding-agent; kept\n * here so the classifier and the policy-driven retry loop live together and stay reusable\n * by the SDK and other callers.\n */\nexport interface RetryPolicy {\n\tenabled: boolean;\n\t/** Max retry attempts (0 = no retries). The initial call never counts as a retry. */\n\tmaxRetries: number;\n\t/** Base delay in ms. Per-attempt delay is `baseDelayMs * 2^(attempt-1)` before jitter. */\n\tbaseDelayMs: number;\n\t/** Cap for agent-level retry delays in ms. Defaults to 60 seconds. */\n\tmaxAgentDelayMs?: number;\n}\n\nexport const DEFAULT_MAX_AGENT_RETRY_DELAY_MS = 60_000;\n\nexport function retryDelayMs(policy: Pick<RetryPolicy, \"baseDelayMs\" | \"maxAgentDelayMs\">, attempt: number): number {\n\tconst delay = policy.baseDelayMs * 2 ** Math.max(0, attempt - 1);\n\tconst safeDelay = Number.isSafeInteger(delay) ? delay : Number.MAX_SAFE_INTEGER;\n\treturn Math.min(safeDelay, policy.maxAgentDelayMs ?? DEFAULT_MAX_AGENT_RETRY_DELAY_MS);\n}\n\n/** Optional callbacks emitted by {@link retryAssistantCall} around each retry. */\nexport interface RetryCallbacks {\n\t/** Emitted before the backoff sleep of each retry attempt (1-indexed). */\n\tonRetryScheduled?: (\n\t\tattempt: number,\n\t\tmaxAttempts: number,\n\t\tdelayMs: number,\n\t\terrorMessage: string,\n\t) => void | Promise<void>;\n\t/** Emitted after the backoff sleep, immediately before the retried call starts. */\n\tonRetryAttemptStart?: () => void | Promise<void>;\n\t/** Emitted once when the loop ends: success if a later call completed normally. */\n\tonRetryFinished?: (success: boolean, attempt: number, finalError?: string) => void | Promise<void>;\n}\n\nclass RetrySleepAbortError extends Error {\n\tconstructor() {\n\t\tsuper(\"Aborted\");\n\t}\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(new RetrySleepAbortError());\n\t\t\treturn;\n\t\t}\n\t\tconst timeout = setTimeout(resolve, ms);\n\t\tsignal?.addEventListener(\n\t\t\t\"abort\",\n\t\t\t() => {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\treject(new RetrySleepAbortError());\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t});\n}\n\n/**\n * Run a single assistant-producing call with bounded retry on transient errors.\n *\n * Behavior:\n * - A successful response is returned immediately. Aborts are terminal and never\n * retried, but reported as unsuccessful if they happen after a retry was scheduled.\n * Aborts during the backoff sleep are normalized to an aborted `AssistantMessage`\n * too, so callers do not need to care when cancellation happened.\n * - A non-retryable error (per {@link isRetryableAssistantError}, including quota/\n * billing exhaustion) is returned immediately so deterministic errors fail fast.\n * - Otherwise retries up to `maxRetries` times with exponential backoff, emitting\n * `onRetryScheduled` before each sleep, `onRetryAttemptStart` after each sleep before\n * the retried call starts, and `onRetryFinished` once at the end (whether the loop\n * ends in success, exhausted retries, or an aborted backoff).\n *\n * When `policy` is undefined or disabled, the first response is returned unchanged\n * (equivalent to calling `produce()` directly).\n */\nexport async function retryAssistantCall(\n\tproduce: () => Promise<AssistantMessage>,\n\tpolicy: RetryPolicy | undefined,\n\tsignal: AbortSignal | undefined,\n\tcallbacks?: RetryCallbacks,\n): Promise<AssistantMessage> {\n\tconst maxAttempts = policy?.enabled ? policy.maxRetries : 0;\n\n\tlet attempt = 0;\n\tlet lastRetry: { attempt: number; errorMessage: string } | undefined;\n\tfor (;;) {\n\t\tconst response = await produce();\n\n\t\t// Abort: terminal but not successful. Never retry an aborted message.\n\t\tif (response.stopReason === \"aborted\") {\n\t\t\tif (lastRetry) await callbacks?.onRetryFinished?.(false, lastRetry.attempt);\n\t\t\treturn response;\n\t\t}\n\n\t\t// Success: non-error, non-abort responses return as-is.\n\t\tif (response.stopReason !== \"error\") {\n\t\t\tif (lastRetry) await callbacks?.onRetryFinished?.(true, lastRetry.attempt);\n\t\t\treturn response;\n\t\t}\n\n\t\t// Non-retryable, or budget exhausted: return the final error message.\n\t\tif (attempt >= maxAttempts || !isRetryableAssistantError(response)) {\n\t\t\tif (lastRetry) await callbacks?.onRetryFinished?.(false, lastRetry.attempt, response.errorMessage);\n\t\t\treturn response;\n\t\t}\n\n\t\tattempt++;\n\t\tlastRetry = { attempt, errorMessage: response.errorMessage || \"Unknown error\" };\n\t\tconst delayMs = retryDelayMs(policy!, attempt);\n\t\tawait callbacks?.onRetryScheduled?.(attempt, maxAttempts, delayMs, lastRetry.errorMessage);\n\n\t\t// Normalize aborts during retry backoff to the same AssistantMessage shape as\n\t\t// provider stream aborts, so callers do not need to care when cancellation happened.\n\t\ttry {\n\t\t\tawait sleep(delayMs, signal);\n\t\t} catch (error) {\n\t\t\tawait callbacks?.onRetryFinished?.(false, attempt, lastRetry.errorMessage);\n\t\t\tif (error instanceof RetrySleepAbortError) {\n\t\t\t\treturn { ...response, stopReason: \"aborted\", errorMessage: undefined };\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tawait callbacks?.onRetryAttemptStart?.();\n\t}\n}\n\n/**\n * Classifies whether a failed assistant message looks like a transient provider\n * or transport error, so callers can decide if the last assistant turn should be\n * restarted.\n *\n * This does not implement retry policy. Callers should first handle context\n * overflow separately, then apply their own retry budget, backoff, and reporting\n * before restarting the assistant turn.\n */\nexport function isRetryableAssistantError(message: AssistantMessage): boolean {\n\tif (message.stopReason !== \"error\" || !message.errorMessage) return false;\n\tconst errorMessage = message.errorMessage;\n\tif (NON_RETRYABLE_PROVIDER_LIMIT_ERROR_PATTERN.test(errorMessage)) return false;\n\treturn RETRYABLE_PROVIDER_ERROR_PATTERN.test(errorMessage);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitize-unicode.d.ts","sourceRoot":"","sources":["../../src/utils/sanitize-unicode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIvD"
|
|
1
|
+
{"version":3,"file":"sanitize-unicode.d.ts","sourceRoot":"","sources":["../../src/utils/sanitize-unicode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIvD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitize-unicode.js","sourceRoot":"","sources":["../../src/utils/sanitize-unicode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY
|
|
1
|
+
{"version":3,"file":"sanitize-unicode.js","sourceRoot":"","sources":["../../src/utils/sanitize-unicode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC9C,iFAAiF;IACjF,iFAAiF;IACjF,OAAO,IAAI,CAAC,OAAO,CAAC,yEAAyE,EAAE,EAAE,CAAC,CAAC;AACpG,CAAC","sourcesContent":["/**\n * Removes unpaired Unicode surrogate characters from a string.\n *\n * Unpaired surrogates (high surrogates 0xD800-0xDBFF without matching low surrogates 0xDC00-0xDFFF,\n * or vice versa) cause JSON serialization errors in many API providers.\n *\n * Valid emoji and other characters outside the Basic Multilingual Plane use properly paired\n * surrogates and will NOT be affected by this function.\n *\n * @param text - The text to sanitize\n * @returns The sanitized text with unpaired surrogates removed\n *\n * @example\n * // Valid emoji (properly paired surrogates) are preserved\n * sanitizeSurrogates(\"Hello 🙈 World\") // => \"Hello 🙈 World\"\n *\n * // Unpaired high surrogate is removed\n * const unpaired = String.fromCharCode(0xD83D); // high surrogate without low\n * sanitizeSurrogates(`Text ${unpaired} here`) // => \"Text here\"\n */\nexport function sanitizeSurrogates(text: string): string {\n\t// Replace unpaired high surrogates (0xD800-0xDBFF not followed by low surrogate)\n\t// Replace unpaired low surrogates (0xDC00-0xDFFF not preceded by high surrogate)\n\treturn text.replace(/[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|(?<![\\uD800-\\uDBFF])[\\uDC00-\\uDFFF]/g, \"\");\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sleep.d.ts","sourceRoot":"","sources":["../../src/utils/sleep.ts"],"names":[],"mappings":"AAAA,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAapE"
|
|
1
|
+
{"version":3,"file":"sleep.d.ts","sourceRoot":"","sources":["../../src/utils/sleep.ts"],"names":[],"mappings":"AAAA,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAapE"}
|
package/dist/utils/sleep.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sleep.js","sourceRoot":"","sources":["../../src/utils/sleep.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,KAAK,CAAC,EAAU,EAAE,MAAmB
|
|
1
|
+
{"version":3,"file":"sleep.js","sourceRoot":"","sources":["../../src/utils/sleep.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,KAAK,CAAC,EAAU,EAAE,MAAmB;IACpD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACtC,MAAM,CAAC,cAAc,EAAE,CAAC;QACxB,MAAM,OAAO,GAAG,GAAG,EAAE;YACpB,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC,CAAC;QACF,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC/B,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC7C,OAAO,EAAE,CAAC;QACX,CAAC,EAAE,EAAE,CAAC,CAAC;QACP,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;AACJ,CAAC","sourcesContent":["export function sleep(ms: number, signal: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tsignal.throwIfAborted();\n\t\tconst onAbort = () => {\n\t\t\tclearTimeout(timeout);\n\t\t\treject(signal.reason);\n\t\t};\n\t\tconst timeout = setTimeout(() => {\n\t\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\t\tresolve();\n\t\t}, ms);\n\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t});\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream-deadline.d.ts","sourceRoot":"","sources":["../../src/utils/stream-deadline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,SAAU,CAAC;AAKlD,iEAAiE;AACjE,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAErE;AAED;;;;;GAKG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B,YAAY,UAAU,EAAE,MAAM,EAI7B;CACD;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC,KAAK,IAAI,IAAI,CAAC;IACd,OAAO,IAAI,IAAI,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAIrF;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,YAAY,CAAC,EAAE,WAAW,GAAG,oBAAoB,CA6BhH;AAgCD;;;;;;;;;;GAUG;AACH,wBAAuB,kBAAkB,CAAC,CAAC,EAC1C,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,EACxB,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,UAAU,CAAC,EAAE,MAAM,IAAI,GACrB,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CA0DpC"
|
|
1
|
+
{"version":3,"file":"stream-deadline.d.ts","sourceRoot":"","sources":["../../src/utils/stream-deadline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,SAAU,CAAC;AAKlD,iEAAiE;AACjE,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAErE;AAED;;;;;GAKG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B,YAAY,UAAU,EAAE,MAAM,EAI7B;CACD;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC,KAAK,IAAI,IAAI,CAAC;IACd,OAAO,IAAI,IAAI,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAIrF;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,YAAY,CAAC,EAAE,WAAW,GAAG,oBAAoB,CA6BhH;AAgCD;;;;;;;;;;GAUG;AACH,wBAAuB,kBAAkB,CAAC,CAAC,EAC1C,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,EACxB,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,UAAU,CAAC,EAAE,MAAM,IAAI,GACrB,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CA0DpC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream-deadline.js","sourceRoot":"","sources":["../../src/utils/stream-deadline.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Idle deadline for provider response streams (#2553).\n *\n * The HTTP layer only bounds the request/response handshake and, for SDK clients,\n * the socket idle timeout its dispatcher enforces. A body that decodes into a\n * decompression failure can destroy the underlying stream without ever rejecting\n * the async iterator the adapter is awaiting, so `for await (...)` stays pending\n * forever, the adapter's promise never settles, and retry/model-fallback logic\n * never advances. GitHub Copilot with the default `transport: \"auto\"` reproduces\n * this as a repeated `Library error: zlib error: incorrect header check`.\n *\n * {@link withStreamDeadline} bounds the gap *between* stream events, below the\n * HTTP layer, so a stalled stream always settles as a transient transport error\n * that {@link isRetryableAssistantError} classifies as retryable.\n */\n\nimport { type CombinedAbortSignal, combineAbortSignals } from \"./abort-signals.ts\";\n\n/**\n * Default idle gap allowed between two provider stream events, in milliseconds.\n *\n * Deliberately below the 600000 ms default HTTP idle timeout so a stalled stream\n * is cut by this deadline rather than waiting on the transport, while staying\n * generous enough for slow reasoning models that go quiet between events.\n */\nexport const DEFAULT_STREAM_DEADLINE_MS = 300_000;\n\n/** The largest delay accepted by a platform timer without overflow. */\nconst MAX_TIMER_DELAY_MS = 2_147_483_647;\n\n/** Message text used when a stream exceeds its idle deadline. */\nexport function streamDeadlineErrorMessage(deadlineMs: number): string {\n\treturn `Provider stream timed out after ${deadlineMs}ms without a new event (stream deadline exceeded)`;\n}\n\n/**\n * Raised when a provider stream produces no event within its idle deadline.\n *\n * The message intentionally carries transport-timeout wording so the shared\n * transient-error classifier treats it as a retryable transport failure.\n */\nexport class StreamDeadlineError extends Error {\n\treadonly deadlineMs: number;\n\n\tconstructor(deadlineMs: number) {\n\t\tsuper(streamDeadlineErrorMessage(deadlineMs));\n\t\tthis.name = \"StreamDeadlineError\";\n\t\tthis.deadlineMs = deadlineMs;\n\t}\n}\n\n/**\n * Deadline-owned signal used to cancel the provider request when the stream\n * deadline fires. The caller signal remains separate, so an internal deadline\n * abort is reported as a retryable error rather than `stopReason: \"aborted\"`.\n */\nexport interface StreamDeadlineHandle {\n\treadonly deadlineMs: number | undefined;\n\treadonly signal: AbortSignal | undefined;\n\treadonly abortedByDeadline: boolean;\n\tabort(): void;\n\tcleanup(): void;\n}\n\n/**\n * Resolve the effective idle deadline for a stream.\n *\n * `undefined` selects {@link DEFAULT_STREAM_DEADLINE_MS}. A non-positive or\n * non-finite value disables the deadline and returns `undefined`, matching how\n * `httpIdleTimeoutMs` and `websocketConnectTimeoutMs` treat `0`/`\"disabled\"`.\n */\nexport function resolveStreamDeadlineMs(value: number | undefined): number | undefined {\n\tif (value === undefined) return DEFAULT_STREAM_DEADLINE_MS;\n\tif (!Number.isFinite(value) || value <= 0) return undefined;\n\treturn Math.floor(value);\n}\n\n/**\n * Create a request signal that combines caller cancellation with a private\n * deadline controller. Calling {@link StreamDeadlineHandle.abort} aborts the\n * provider transport without marking the caller's signal as aborted.\n */\nexport function createStreamDeadline(value: number | undefined, callerSignal?: AbortSignal): StreamDeadlineHandle {\n\tconst deadlineMs = resolveStreamDeadlineMs(value);\n\tif (deadlineMs === undefined) {\n\t\treturn {\n\t\t\tdeadlineMs,\n\t\t\tsignal: callerSignal,\n\t\t\tabortedByDeadline: false,\n\t\t\tabort: () => {},\n\t\t\tcleanup: () => {},\n\t\t};\n\t}\n\n\tconst controller = new AbortController();\n\tconst combined: CombinedAbortSignal = combineAbortSignals([callerSignal, controller.signal]);\n\tlet abortedByDeadline = false;\n\treturn {\n\t\tdeadlineMs,\n\t\tsignal: combined.signal,\n\t\tget abortedByDeadline() {\n\t\t\treturn abortedByDeadline;\n\t\t},\n\t\tabort: () => {\n\t\t\tif (!controller.signal.aborted) {\n\t\t\t\tabortedByDeadline = true;\n\t\t\t\tcontroller.abort(new StreamDeadlineError(deadlineMs));\n\t\t\t}\n\t\t},\n\t\tcleanup: combined.cleanup,\n\t};\n}\n\n/**\n * Schedule a timer without allowing the platform's 32-bit delay clamp to turn\n * a valid long deadline into a one-millisecond timeout.\n */\nfunction scheduleDeadline(callback: () => void, delayMs: number): () => void {\n\tlet remaining = delayMs;\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tlet cancelled = false;\n\n\tconst arm = () => {\n\t\tif (cancelled) return;\n\t\tconst delay = Math.min(remaining, MAX_TIMER_DELAY_MS);\n\t\ttimer = setTimeout(() => {\n\t\t\tif (cancelled) return;\n\t\t\tremaining -= delay;\n\t\t\tif (remaining <= 0) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tarm();\n\t\t}, delay);\n\t};\n\n\tarm();\n\treturn () => {\n\t\tcancelled = true;\n\t\tif (timer !== undefined) clearTimeout(timer);\n\t};\n}\n\n/**\n * Wrap an async iterable so each pending `next()` is bounded by an idle deadline.\n *\n * The timer is restarted per event, so it caps the gap between events rather than\n * total stream duration: a long but progressing stream is never cut. When the\n * deadline expires, `onDeadline` is invoked before the wrapper rejects. Adapters\n * use that callback to abort the request signal, which interrupts the pending\n * provider read and runs the source's cleanup before fallback starts.\n *\n * A deadline of `undefined` delegates straight to the source and adds no timer.\n */\nexport async function* withStreamDeadline<T>(\n\tsource: AsyncIterable<T>,\n\tdeadlineMs: number | undefined,\n\tonDeadline?: () => void,\n): AsyncGenerator<T, void, undefined> {\n\tif (deadlineMs === undefined) {\n\t\tyield* source;\n\t\treturn;\n\t}\n\n\tconst iterator = source[Symbol.asyncIterator]();\n\tlet closed = false;\n\tconst closeSource = (): void => {\n\t\tif (closed) return;\n\t\tclosed = true;\n\t\ttry {\n\t\t\tvoid Promise.resolve(iterator.return?.()).catch(() => {});\n\t\t} catch {\n\t\t\t// A source iterator without a usable `return` needs no cleanup.\n\t\t}\n\t};\n\n\ttry {\n\t\tfor (;;) {\n\t\t\tlet cancelTimer: (() => void) | undefined;\n\t\t\tlet deadlineFired = false;\n\t\t\tconst pending = Promise.resolve(iterator.next());\n\t\t\tconst deadline = new Promise<never>((_resolve, reject) => {\n\t\t\t\tcancelTimer = scheduleDeadline(() => {\n\t\t\t\t\tdeadlineFired = true;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tonDeadline?.();\n\t\t\t\t\t} finally {\n\t\t\t\t\t\treject(new StreamDeadlineError(deadlineMs));\n\t\t\t\t\t}\n\t\t\t\t}, deadlineMs);\n\t\t\t});\n\n\t\t\tlet result: IteratorResult<T>;\n\t\t\ttry {\n\t\t\t\tresult = await Promise.race([pending, deadline]);\n\t\t\t} catch (error) {\n\t\t\t\t// The transport abort normally rejects the losing read. Swallow its\n\t\t\t\t// eventual rejection, but preserve the deadline error as the public\n\t\t\t\t// failure even if abort delivery wins the race by a microtask.\n\t\t\t\tvoid pending.catch(() => {});\n\t\t\t\tcloseSource();\n\t\t\t\tif (deadlineFired) throw new StreamDeadlineError(deadlineMs);\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tcancelTimer?.();\n\t\t\t}\n\n\t\t\tif (result.done) {\n\t\t\t\tclosed = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tyield result.value;\n\t\t}\n\t} finally {\n\t\tcloseSource();\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"stream-deadline.js","sourceRoot":"","sources":["../../src/utils/stream-deadline.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Idle deadline for provider response streams (#2553).\n *\n * The HTTP layer only bounds the request/response handshake and, for SDK clients,\n * the socket idle timeout its dispatcher enforces. A body that decodes into a\n * decompression failure can destroy the underlying stream without ever rejecting\n * the async iterator the adapter is awaiting, so `for await (...)` stays pending\n * forever, the adapter's promise never settles, and retry/model-fallback logic\n * never advances. GitHub Copilot with the default `transport: \"auto\"` reproduces\n * this as a repeated `Library error: zlib error: incorrect header check`.\n *\n * {@link withStreamDeadline} bounds the gap *between* stream events, below the\n * HTTP layer, so a stalled stream always settles as a transient transport error\n * that {@link isRetryableAssistantError} classifies as retryable.\n */\n\nimport { type CombinedAbortSignal, combineAbortSignals } from \"./abort-signals.ts\";\n\n/**\n * Default idle gap allowed between two provider stream events, in milliseconds.\n *\n * Deliberately below the 600000 ms default HTTP idle timeout so a stalled stream\n * is cut by this deadline rather than waiting on the transport, while staying\n * generous enough for slow reasoning models that go quiet between events.\n */\nexport const DEFAULT_STREAM_DEADLINE_MS = 300_000;\n\n/** The largest delay accepted by a platform timer without overflow. */\nconst MAX_TIMER_DELAY_MS = 2_147_483_647;\n\n/** Message text used when a stream exceeds its idle deadline. */\nexport function streamDeadlineErrorMessage(deadlineMs: number): string {\n\treturn `Provider stream timed out after ${deadlineMs}ms without a new event (stream deadline exceeded)`;\n}\n\n/**\n * Raised when a provider stream produces no event within its idle deadline.\n *\n * The message intentionally carries transport-timeout wording so the shared\n * transient-error classifier treats it as a retryable transport failure.\n */\nexport class StreamDeadlineError extends Error {\n\treadonly deadlineMs: number;\n\n\tconstructor(deadlineMs: number) {\n\t\tsuper(streamDeadlineErrorMessage(deadlineMs));\n\t\tthis.name = \"StreamDeadlineError\";\n\t\tthis.deadlineMs = deadlineMs;\n\t}\n}\n\n/**\n * Deadline-owned signal used to cancel the provider request when the stream\n * deadline fires. The caller signal remains separate, so an internal deadline\n * abort is reported as a retryable error rather than `stopReason: \"aborted\"`.\n */\nexport interface StreamDeadlineHandle {\n\treadonly deadlineMs: number | undefined;\n\treadonly signal: AbortSignal | undefined;\n\treadonly abortedByDeadline: boolean;\n\tabort(): void;\n\tcleanup(): void;\n}\n\n/**\n * Resolve the effective idle deadline for a stream.\n *\n * `undefined` selects {@link DEFAULT_STREAM_DEADLINE_MS}. A non-positive or\n * non-finite value disables the deadline and returns `undefined`, matching how\n * `httpIdleTimeoutMs` and `websocketConnectTimeoutMs` treat `0`/`\"disabled\"`.\n */\nexport function resolveStreamDeadlineMs(value: number | undefined): number | undefined {\n\tif (value === undefined) return DEFAULT_STREAM_DEADLINE_MS;\n\tif (!Number.isFinite(value) || value <= 0) return undefined;\n\treturn Math.floor(value);\n}\n\n/**\n * Create a request signal that combines caller cancellation with a private\n * deadline controller. Calling {@link StreamDeadlineHandle.abort} aborts the\n * provider transport without marking the caller's signal as aborted.\n */\nexport function createStreamDeadline(value: number | undefined, callerSignal?: AbortSignal): StreamDeadlineHandle {\n\tconst deadlineMs = resolveStreamDeadlineMs(value);\n\tif (deadlineMs === undefined) {\n\t\treturn {\n\t\t\tdeadlineMs,\n\t\t\tsignal: callerSignal,\n\t\t\tabortedByDeadline: false,\n\t\t\tabort: () => {},\n\t\t\tcleanup: () => {},\n\t\t};\n\t}\n\n\tconst controller = new AbortController();\n\tconst combined: CombinedAbortSignal = combineAbortSignals([callerSignal, controller.signal]);\n\tlet abortedByDeadline = false;\n\treturn {\n\t\tdeadlineMs,\n\t\tsignal: combined.signal,\n\t\tget abortedByDeadline() {\n\t\t\treturn abortedByDeadline;\n\t\t},\n\t\tabort: () => {\n\t\t\tif (!controller.signal.aborted) {\n\t\t\t\tabortedByDeadline = true;\n\t\t\t\tcontroller.abort(new StreamDeadlineError(deadlineMs));\n\t\t\t}\n\t\t},\n\t\tcleanup: combined.cleanup,\n\t};\n}\n\n/**\n * Schedule a timer without allowing the platform's 32-bit delay clamp to turn\n * a valid long deadline into a one-millisecond timeout.\n */\nfunction scheduleDeadline(callback: () => void, delayMs: number): () => void {\n\tlet remaining = delayMs;\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tlet cancelled = false;\n\n\tconst arm = () => {\n\t\tif (cancelled) return;\n\t\tconst delay = Math.min(remaining, MAX_TIMER_DELAY_MS);\n\t\ttimer = setTimeout(() => {\n\t\t\tif (cancelled) return;\n\t\t\tremaining -= delay;\n\t\t\tif (remaining <= 0) {\n\t\t\t\tcallback();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tarm();\n\t\t}, delay);\n\t};\n\n\tarm();\n\treturn () => {\n\t\tcancelled = true;\n\t\tif (timer !== undefined) clearTimeout(timer);\n\t};\n}\n\n/**\n * Wrap an async iterable so each pending `next()` is bounded by an idle deadline.\n *\n * The timer is restarted per event, so it caps the gap between events rather than\n * total stream duration: a long but progressing stream is never cut. When the\n * deadline expires, `onDeadline` is invoked before the wrapper rejects. Adapters\n * use that callback to abort the request signal, which interrupts the pending\n * provider read and runs the source's cleanup before fallback starts.\n *\n * A deadline of `undefined` delegates straight to the source and adds no timer.\n */\nexport async function* withStreamDeadline<T>(\n\tsource: AsyncIterable<T>,\n\tdeadlineMs: number | undefined,\n\tonDeadline?: () => void,\n): AsyncGenerator<T, void, undefined> {\n\tif (deadlineMs === undefined) {\n\t\tyield* source;\n\t\treturn;\n\t}\n\n\tconst iterator = source[Symbol.asyncIterator]();\n\tlet closed = false;\n\tconst closeSource = (): void => {\n\t\tif (closed) return;\n\t\tclosed = true;\n\t\ttry {\n\t\t\tvoid Promise.resolve(iterator.return?.()).catch(() => {});\n\t\t} catch {\n\t\t\t// A source iterator without a usable `return` needs no cleanup.\n\t\t}\n\t};\n\n\ttry {\n\t\tfor (;;) {\n\t\t\tlet cancelTimer: (() => void) | undefined;\n\t\t\tlet deadlineFired = false;\n\t\t\tconst pending = Promise.resolve(iterator.next());\n\t\t\tconst deadline = new Promise<never>((_resolve, reject) => {\n\t\t\t\tcancelTimer = scheduleDeadline(() => {\n\t\t\t\t\tdeadlineFired = true;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tonDeadline?.();\n\t\t\t\t\t} finally {\n\t\t\t\t\t\treject(new StreamDeadlineError(deadlineMs));\n\t\t\t\t\t}\n\t\t\t\t}, deadlineMs);\n\t\t\t});\n\n\t\t\tlet result: IteratorResult<T>;\n\t\t\ttry {\n\t\t\t\tresult = await Promise.race([pending, deadline]);\n\t\t\t} catch (error) {\n\t\t\t\t// The transport abort normally rejects the losing read. Swallow its\n\t\t\t\t// eventual rejection, but preserve the deadline error as the public\n\t\t\t\t// failure even if abort delivery wins the race by a microtask.\n\t\t\t\tvoid pending.catch(() => {});\n\t\t\t\tcloseSource();\n\t\t\t\tif (deadlineFired) throw new StreamDeadlineError(deadlineMs);\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tcancelTimer?.();\n\t\t\t}\n\n\t\t\tif (result.done) {\n\t\t\t\tclosed = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tyield result.value;\n\t\t}\n\t} finally {\n\t\tcloseSource();\n\t}\n}\n"]}
|
package/dist/utils/text.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/utils/text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAExH,KAAK,OAAO,GAAG,WAAW,GAAG,YAAY,GAAG,eAAe,GAAG,QAAQ,GAAG,eAAe,CAAC;AAEzF,kDAAkD;AAClD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,OAAO,EAAE,EAAE,SAAS,SAAO,GAAG,MAAM,CAM1F;AAED,0FAA0F;AAC1F,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAMnE;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAYxE"
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/utils/text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAExH,KAAK,OAAO,GAAG,WAAW,GAAG,YAAY,GAAG,eAAe,GAAG,QAAQ,GAAG,eAAe,CAAC;AAEzF,kDAAkD;AAClD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,OAAO,EAAE,EAAE,SAAS,SAAO,GAAG,MAAM,CAM1F;AAED,0FAA0F;AAC1F,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAMnE;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAYxE"}
|
package/dist/utils/text.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/utils/text.ts"],"names":[],"mappings":"AAIA,kDAAkD;AAClD,MAAM,UAAU,WAAW,CAAC,OAAoC,EAAE,SAAS,GAAG,IAAI
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/utils/text.ts"],"names":[],"mappings":"AAIA,kDAAkD;AAClD,MAAM,UAAU,WAAW,CAAC,OAAoC,EAAE,SAAS,GAAG,IAAI;IACjF,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,OAAO,CAAC;IAChD,OAAO,OAAO;SACZ,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC;SACxC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;SAC1B,IAAI,CAAC,SAAS,CAAC,CAAC;AACnB,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,oBAAoB,CAAC,OAAsB;IAC1D,MAAM,KAAK,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,CAAC;QAC1D,IAAI,IAAI,KAAK,IAAI;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC7D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAAsB;IAC/D,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,CAAC;QACpE,KAAK,CAAC,IAAI,CACT,KAAK,KAAK,IAAI;YACb,CAAC,CAAC,kCAAkC,IAAI,IAAI;YAC5C,CAAC,CAAC,kCAAkC,IAAI,SAAS,KAAK,EAAE,CACzD,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC3B,CAAC","sourcesContent":["import type { FallbackContent, ImageContent, SystemMessage, TextContent, ThinkingContent, ToolCall } from \"../types.ts\";\n\ntype Content = TextContent | ImageContent | ThinkingContent | ToolCall | FallbackContent;\n\n/** Extract and join text from message content. */\nexport function contentText(content: string | readonly Content[], separator = \"\\n\"): string {\n\tif (typeof content === \"string\") return content;\n\treturn content\n\t\t.filter((block) => block.type === \"text\")\n\t\t.map((block) => block.text)\n\t\t.join(separator);\n}\n\n/** Render a system message as a complete prompt: its content followed by its sections. */\nexport function getSystemMessageText(message: SystemMessage): string {\n\tconst parts = [contentText(message.content)];\n\tfor (const text of Object.values(message.sections ?? {})) {\n\t\tif (text !== null) parts.push(text);\n\t}\n\treturn parts.filter((part) => part.length > 0).join(\"\\n\\n\");\n}\n\n/**\n * Render a later system message for APIs that accept system messages mid-conversation.\n * Section changes are framed by name so the model can relate them to the leading prompt.\n * This framing is request-time only and may change between versions.\n */\nexport function renderSystemMessageUpdate(message: SystemMessage): string {\n\tconst parts: string[] = [];\n\tconst text = contentText(message.content);\n\tif (text.length > 0) parts.push(text);\n\tfor (const [name, value] of Object.entries(message.sections ?? {})) {\n\t\tparts.push(\n\t\t\tvalue === null\n\t\t\t\t? `Removed system prompt section \"${name}\".`\n\t\t\t\t: `Updated system prompt section \"${name}\":\\n\\n${value}`,\n\t\t);\n\t}\n\treturn parts.join(\"\\n\\n\");\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transcript.d.ts","sourceRoot":"","sources":["../../src/utils/transcript.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAG3G,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD;;;GAGG;AACH,wBAAgB,0BAA0B,CACzC,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,KAAK,EAAE,IAAI,EAAE,GAAG,SAAS,GACvB,aAAa,GAAG,SAAS,CAU3B;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,iBAAiB,CAIpE;AAED;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC;AAM7D,4EAA4E;AAC5E,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,aAAa,GAAG,SAAS,CAG/F;AAED,+FAA+F;AAC/F,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CAE1E;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI,EAAE,CAQpE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,aAAa,GAAG,SAAS,CAuB/F;AAED,kFAAkF;AAClF,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,MAAM,CAG3E;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,iBAAiB,GAAG,iBAAiB,CAIpF;AAED,gGAAgG;AAChG,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,iBAAiB,EAC1B,8BAA8B,EAAE,OAAO,GAAG,SAAS,GACjD,iBAAiB,CAEnB;AAED,wGAAwG;AACxG,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAOlD;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,GAAG,OAAO,CAElE;AAED,MAAM,WAAW,gBAAgB;IAChC,UAAU,EAAE,IAAI,EAAE,CAAC;IACnB,YAAY,EAAE,aAAa,EAAE,CAAC;CAC9B;AAED,mGAAmG;AACnG,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,SAAS,IAAI,EAAE,EAAE,OAAO,EAAE,SAAS,IAAI,EAAE,GAAG,gBAAgB,CAiBzG;AAED,wFAAwF;AACxF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI,EAAE,CAOrE;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAW1E;AAED,wHAAwH;AACxH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAW/E;AAED,MAAM,WAAW,eAAe;IAC/B,iDAAiD;IACjD,YAAY,EAAE,IAAI,EAAE,CAAC;IACrB;;;OAGG;IACH,gBAAgB,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,OAAO,GAAG,eAAe,CAQpH","sourcesContent":["import type { Context, Message, SystemMessage, Tool, ToolReference, TranscriptContext } from \"../types.ts\";\nimport { contentText, getSystemMessageText } from \"./text.ts\";\n\nexport type { TranscriptContext } from \"../types.ts\";\n\n/**\n * Build the leading system message for a prompt and tool set. Returns undefined when\n * both are empty, so an empty transcript stays empty.\n */\nexport function createInitialSystemMessage(\n\tsystemPrompt: string | undefined,\n\ttools: Tool[] | undefined,\n): SystemMessage | undefined {\n\tconst hasSystemPrompt = systemPrompt !== undefined && systemPrompt.length > 0;\n\tconst hasTools = tools !== undefined && tools.length > 0;\n\tif (!hasSystemPrompt && !hasTools) return undefined;\n\treturn {\n\t\trole: \"system\",\n\t\tcontent: systemPrompt ?? \"\",\n\t\t...(hasTools ? { toolsAdded: tools } : {}),\n\t\ttimestamp: 0,\n\t};\n}\n\n/**\n * Fold `Context.systemPrompt` and `Context.tools` into a leading system message.\n * This is the only entry point that produces a {@link TranscriptContext}; every\n * provider-facing function expects the result.\n */\nexport function normalizeContext(context: Context): TranscriptContext {\n\tconst initialMessage = createInitialSystemMessage(context.systemPrompt, context.tools);\n\tconst messages = initialMessage ? [initialMessage, ...context.messages] : context.messages;\n\treturn { messages } as TranscriptContext;\n}\n\n/**\n * Any message list. The replay helpers only read entries whose role is `\"system\"`, so\n * agent transcripts that carry custom message roles can be passed without filtering.\n */\nexport type TranscriptMessages = readonly { role: string }[];\n\nfunction isSystemMessage(message: { role: string }): message is SystemMessage {\n\treturn message.role === \"system\";\n}\n\n/** Return the leading system message, if the transcript starts with one. */\nexport function getInitialSystemMessage(messages: TranscriptMessages): SystemMessage | undefined {\n\tconst first = messages[0];\n\treturn first && isSystemMessage(first) ? first : undefined;\n}\n\n/** Drop the leading system message for APIs that carry the prompt outside the message list. */\nexport function withoutInitialSystemMessage(messages: Message[]): Message[] {\n\treturn getInitialSystemMessage(messages) ? messages.slice(1) : messages;\n}\n\n/** Resolve the tools available after applying every transcript delta in order. */\nexport function getCurrentTools(messages: TranscriptMessages): Tool[] {\n\tconst tools = new Map<string, Tool>();\n\tfor (const message of messages) {\n\t\tif (!isSystemMessage(message)) continue;\n\t\tfor (const tool of message.toolsRemoved ?? []) tools.delete(tool.name);\n\t\tfor (const tool of message.toolsAdded ?? []) tools.set(tool.name, tool);\n\t}\n\treturn [...tools.values()];\n}\n\n/**\n * Replay every system message into one leading system message holding the current\n * prompt and tools. Later `content` is appended to the base prompt, `sections` are\n * patched by name, and tools are resolved with {@link getCurrentTools}.\n */\nexport function getCurrentSystemMessage(messages: TranscriptMessages): SystemMessage | undefined {\n\tconst content: string[] = [];\n\tconst sections = new Map<string, string>();\n\tlet timestamp: number | undefined;\n\tfor (const message of messages) {\n\t\tif (!isSystemMessage(message)) continue;\n\t\ttimestamp ??= message.timestamp;\n\t\tconst text = contentText(message.content);\n\t\tif (text.length > 0) content.push(text);\n\t\tfor (const [name, value] of Object.entries(message.sections ?? {})) {\n\t\t\tif (value === null) sections.delete(name);\n\t\t\telse sections.set(name, value);\n\t\t}\n\t}\n\tconst tools = getCurrentTools(messages);\n\tif (timestamp === undefined && tools.length === 0) return undefined;\n\treturn {\n\t\trole: \"system\",\n\t\tcontent: content.join(\"\\n\\n\"),\n\t\t...(sections.size > 0 ? { sections: Object.fromEntries(sections) } : {}),\n\t\t...(tools.length > 0 ? { toolsAdded: tools } : {}),\n\t\ttimestamp: timestamp ?? 0,\n\t};\n}\n\n/** Render the current system prompt text after replaying every system message. */\nexport function getCurrentSystemPrompt(messages: TranscriptMessages): string {\n\tconst message = getCurrentSystemMessage(messages);\n\treturn message ? getSystemMessageText(message) : \"\";\n}\n\n/**\n * Rebuild the transcript for APIs without mid-conversation system messages: the replayed\n * system message leads, and every later system message is dropped.\n */\nexport function collapseSystemMessages(context: TranscriptContext): TranscriptContext {\n\tconst head = getCurrentSystemMessage(context.messages);\n\tconst messages = context.messages.filter((message) => message.role !== \"system\");\n\treturn { messages: head ? [head, ...messages] : messages } as TranscriptContext;\n}\n\n/** Keep later system messages in place when the model accepts them; otherwise collapse them. */\nexport function resolveTranscript(\n\tcontext: TranscriptContext,\n\tsupportsMidConvoSystemMessages: boolean | undefined,\n): TranscriptContext {\n\treturn supportsMidConvoSystemMessages ? context : collapseSystemMessages(context);\n}\n\n/** Strip executable and display-only fields from a tool before transcript comparison or persistence. */\nexport function toToolDeclaration(tool: Tool): Tool {\n\treturn {\n\t\tname: tool.name,\n\t\tdescription: tool.description,\n\t\tparameters: JSON.parse(JSON.stringify(tool.parameters)) as Tool[\"parameters\"],\n\t\t...(tool.constrainedSampling === undefined ? {} : { constrainedSampling: tool.constrainedSampling }),\n\t};\n}\n\n/**\n * Whether two tools declare the same interface to the model.\n *\n * Both sides go through {@link toToolDeclaration} first: its JSON round-trip drops the\n * typebox symbol keys and `undefined` fields that a structural comparison would see, and\n * builds both objects with the same key order, so comparing the serialized declarations\n * is exact. This avoids a deep-equal dependency in a browser-safe package.\n */\nexport function declarationsEqual(left: Tool, right: Tool): boolean {\n\treturn JSON.stringify(toToolDeclaration(left)) === JSON.stringify(toToolDeclaration(right));\n}\n\nexport interface ToolStateChanges {\n\ttoolsAdded: Tool[];\n\ttoolsRemoved: ToolReference[];\n}\n\n/** Compare two complete tool states. A changed definition is a removal followed by an addition. */\nexport function getToolStateChanges(previous: readonly Tool[], current: readonly Tool[]): ToolStateChanges {\n\tconst previousTools = new Map(previous.map((tool) => [tool.name, tool]));\n\tconst currentTools = new Map(current.map((tool) => [tool.name, tool]));\n\treturn {\n\t\ttoolsAdded: current\n\t\t\t.filter((tool) => {\n\t\t\t\tconst previousTool = previousTools.get(tool.name);\n\t\t\t\treturn previousTool === undefined || !declarationsEqual(previousTool, tool);\n\t\t\t})\n\t\t\t.map(toToolDeclaration),\n\t\ttoolsRemoved: previous\n\t\t\t.filter((tool) => {\n\t\t\t\tconst currentTool = currentTools.get(tool.name);\n\t\t\t\treturn currentTool === undefined || !declarationsEqual(tool, currentTool);\n\t\t\t})\n\t\t\t.map((tool) => ({ name: tool.name })),\n\t};\n}\n\n/** Every definition referenced by transcript tool state, in first-declaration order. */\nexport function getDeclaredTools(messages: TranscriptMessages): Tool[] {\n\tconst definitions = new Map<string, Tool>();\n\tfor (const message of messages) {\n\t\tif (!isSystemMessage(message)) continue;\n\t\tfor (const tool of message.toolsAdded ?? []) definitions.set(tool.name, tool);\n\t}\n\treturn [...definitions.values()];\n}\n\n/**\n * Whether a tool name was declared twice with different definitions. Transports that\n * reference tools by name (Anthropic `tool_addition`/`tool_removal`) cannot express that.\n */\nexport function hasToolRedefinitions(messages: TranscriptMessages): boolean {\n\tconst declared = new Map<string, Tool>();\n\tfor (const message of messages) {\n\t\tif (!isSystemMessage(message)) continue;\n\t\tfor (const tool of message.toolsAdded ?? []) {\n\t\t\tconst previous = declared.get(tool.name);\n\t\t\tif (previous !== undefined && !declarationsEqual(previous, tool)) return true;\n\t\t\tdeclared.set(tool.name, tool);\n\t\t}\n\t}\n\treturn false;\n}\n\n/** Whether tool history contains a removal or same-name redeclaration that an addition-only transport cannot replay. */\nexport function hasNonAdditiveToolChanges(messages: TranscriptMessages): boolean {\n\tconst declared = new Set<string>();\n\tfor (const message of messages) {\n\t\tif (!isSystemMessage(message)) continue;\n\t\tif ((message.toolsRemoved?.length ?? 0) > 0) return true;\n\t\tfor (const tool of message.toolsAdded ?? []) {\n\t\t\tif (declared.has(tool.name)) return true;\n\t\t\tdeclared.add(tool.name);\n\t\t}\n\t}\n\treturn false;\n}\n\nexport interface TranscriptTools {\n\t/** Tools sent in the top-level request field. */\n\trequestTools: Tool[];\n\t/**\n\t * Whether later system messages carry their own `toolsAdded` as in-place additions.\n\t * When false, `requestTools` already holds the complete current tool set.\n\t */\n\tanchorsAdditions: boolean;\n}\n\n/**\n * Split tool declarations between the top-level request field and in-place additions.\n * Transports that can anchor additions at a system message keep the initial tools at the\n * top and load later ones where they appear; that only works when no tool was removed or\n * redeclared, so everything else sends the current tool list.\n */\nexport function resolveTranscriptTools(messages: TranscriptMessages, supportsToolAdditions: boolean): TranscriptTools {\n\tconst anchorsAdditions = supportsToolAdditions && !hasNonAdditiveToolChanges(messages);\n\treturn {\n\t\trequestTools: anchorsAdditions\n\t\t\t? (getInitialSystemMessage(messages)?.toolsAdded ?? [])\n\t\t\t: getCurrentTools(messages),\n\t\tanchorsAdditions,\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"transcript.d.ts","sourceRoot":"","sources":["../../src/utils/transcript.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAG3G,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD;;;GAGG;AACH,wBAAgB,0BAA0B,CACzC,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,KAAK,EAAE,IAAI,EAAE,GAAG,SAAS,GACvB,aAAa,GAAG,SAAS,CAU3B;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,iBAAiB,CAIpE;AAED;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC;AAM7D,4EAA4E;AAC5E,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,aAAa,GAAG,SAAS,CAG/F;AAED,+FAA+F;AAC/F,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CAE1E;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI,EAAE,CAQpE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,aAAa,GAAG,SAAS,CAuB/F;AAED,kFAAkF;AAClF,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,MAAM,CAG3E;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,iBAAiB,GAAG,iBAAiB,CAIpF;AAED,gGAAgG;AAChG,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,iBAAiB,EAC1B,8BAA8B,EAAE,OAAO,GAAG,SAAS,GACjD,iBAAiB,CAEnB;AAED,wGAAwG;AACxG,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAOlD;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,GAAG,OAAO,CAElE;AAED,MAAM,WAAW,gBAAgB;IAChC,UAAU,EAAE,IAAI,EAAE,CAAC;IACnB,YAAY,EAAE,aAAa,EAAE,CAAC;CAC9B;AAED,mGAAmG;AACnG,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,SAAS,IAAI,EAAE,EAAE,OAAO,EAAE,SAAS,IAAI,EAAE,GAAG,gBAAgB,CAiBzG;AAED,wFAAwF;AACxF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI,EAAE,CAOrE;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAW1E;AAED,wHAAwH;AACxH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAW/E;AAED,MAAM,WAAW,eAAe;IAC/B,iDAAiD;IACjD,YAAY,EAAE,IAAI,EAAE,CAAC;IACrB;;;OAGG;IACH,gBAAgB,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,OAAO,GAAG,eAAe,CAQpH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transcript.js","sourceRoot":"","sources":["../../src/utils/transcript.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Context, Message, SystemMessage, Tool, ToolReference, TranscriptContext } from \"../types.ts\";\nimport { contentText, getSystemMessageText } from \"./text.ts\";\n\nexport type { TranscriptContext } from \"../types.ts\";\n\n/**\n * Build the leading system message for a prompt and tool set. Returns undefined when\n * both are empty, so an empty transcript stays empty.\n */\nexport function createInitialSystemMessage(\n\tsystemPrompt: string | undefined,\n\ttools: Tool[] | undefined,\n): SystemMessage | undefined {\n\tconst hasSystemPrompt = systemPrompt !== undefined && systemPrompt.length > 0;\n\tconst hasTools = tools !== undefined && tools.length > 0;\n\tif (!hasSystemPrompt && !hasTools) return undefined;\n\treturn {\n\t\trole: \"system\",\n\t\tcontent: systemPrompt ?? \"\",\n\t\t...(hasTools ? { toolsAdded: tools } : {}),\n\t\ttimestamp: 0,\n\t};\n}\n\n/**\n * Fold `Context.systemPrompt` and `Context.tools` into a leading system message.\n * This is the only entry point that produces a {@link TranscriptContext}; every\n * provider-facing function expects the result.\n */\nexport function normalizeContext(context: Context): TranscriptContext {\n\tconst initialMessage = createInitialSystemMessage(context.systemPrompt, context.tools);\n\tconst messages = initialMessage ? [initialMessage, ...context.messages] : context.messages;\n\treturn { messages } as TranscriptContext;\n}\n\n/**\n * Any message list. The replay helpers only read entries whose role is `\"system\"`, so\n * agent transcripts that carry custom message roles can be passed without filtering.\n */\nexport type TranscriptMessages = readonly { role: string }[];\n\nfunction isSystemMessage(message: { role: string }): message is SystemMessage {\n\treturn message.role === \"system\";\n}\n\n/** Return the leading system message, if the transcript starts with one. */\nexport function getInitialSystemMessage(messages: TranscriptMessages): SystemMessage | undefined {\n\tconst first = messages[0];\n\treturn first && isSystemMessage(first) ? first : undefined;\n}\n\n/** Drop the leading system message for APIs that carry the prompt outside the message list. */\nexport function withoutInitialSystemMessage(messages: Message[]): Message[] {\n\treturn getInitialSystemMessage(messages) ? messages.slice(1) : messages;\n}\n\n/** Resolve the tools available after applying every transcript delta in order. */\nexport function getCurrentTools(messages: TranscriptMessages): Tool[] {\n\tconst tools = new Map<string, Tool>();\n\tfor (const message of messages) {\n\t\tif (!isSystemMessage(message)) continue;\n\t\tfor (const tool of message.toolsRemoved ?? []) tools.delete(tool.name);\n\t\tfor (const tool of message.toolsAdded ?? []) tools.set(tool.name, tool);\n\t}\n\treturn [...tools.values()];\n}\n\n/**\n * Replay every system message into one leading system message holding the current\n * prompt and tools. Later `content` is appended to the base prompt, `sections` are\n * patched by name, and tools are resolved with {@link getCurrentTools}.\n */\nexport function getCurrentSystemMessage(messages: TranscriptMessages): SystemMessage | undefined {\n\tconst content: string[] = [];\n\tconst sections = new Map<string, string>();\n\tlet timestamp: number | undefined;\n\tfor (const message of messages) {\n\t\tif (!isSystemMessage(message)) continue;\n\t\ttimestamp ??= message.timestamp;\n\t\tconst text = contentText(message.content);\n\t\tif (text.length > 0) content.push(text);\n\t\tfor (const [name, value] of Object.entries(message.sections ?? {})) {\n\t\t\tif (value === null) sections.delete(name);\n\t\t\telse sections.set(name, value);\n\t\t}\n\t}\n\tconst tools = getCurrentTools(messages);\n\tif (timestamp === undefined && tools.length === 0) return undefined;\n\treturn {\n\t\trole: \"system\",\n\t\tcontent: content.join(\"\\n\\n\"),\n\t\t...(sections.size > 0 ? { sections: Object.fromEntries(sections) } : {}),\n\t\t...(tools.length > 0 ? { toolsAdded: tools } : {}),\n\t\ttimestamp: timestamp ?? 0,\n\t};\n}\n\n/** Render the current system prompt text after replaying every system message. */\nexport function getCurrentSystemPrompt(messages: TranscriptMessages): string {\n\tconst message = getCurrentSystemMessage(messages);\n\treturn message ? getSystemMessageText(message) : \"\";\n}\n\n/**\n * Rebuild the transcript for APIs without mid-conversation system messages: the replayed\n * system message leads, and every later system message is dropped.\n */\nexport function collapseSystemMessages(context: TranscriptContext): TranscriptContext {\n\tconst head = getCurrentSystemMessage(context.messages);\n\tconst messages = context.messages.filter((message) => message.role !== \"system\");\n\treturn { messages: head ? [head, ...messages] : messages } as TranscriptContext;\n}\n\n/** Keep later system messages in place when the model accepts them; otherwise collapse them. */\nexport function resolveTranscript(\n\tcontext: TranscriptContext,\n\tsupportsMidConvoSystemMessages: boolean | undefined,\n): TranscriptContext {\n\treturn supportsMidConvoSystemMessages ? context : collapseSystemMessages(context);\n}\n\n/** Strip executable and display-only fields from a tool before transcript comparison or persistence. */\nexport function toToolDeclaration(tool: Tool): Tool {\n\treturn {\n\t\tname: tool.name,\n\t\tdescription: tool.description,\n\t\tparameters: JSON.parse(JSON.stringify(tool.parameters)) as Tool[\"parameters\"],\n\t\t...(tool.constrainedSampling === undefined ? {} : { constrainedSampling: tool.constrainedSampling }),\n\t};\n}\n\n/**\n * Whether two tools declare the same interface to the model.\n *\n * Both sides go through {@link toToolDeclaration} first: its JSON round-trip drops the\n * typebox symbol keys and `undefined` fields that a structural comparison would see, and\n * builds both objects with the same key order, so comparing the serialized declarations\n * is exact. This avoids a deep-equal dependency in a browser-safe package.\n */\nexport function declarationsEqual(left: Tool, right: Tool): boolean {\n\treturn JSON.stringify(toToolDeclaration(left)) === JSON.stringify(toToolDeclaration(right));\n}\n\nexport interface ToolStateChanges {\n\ttoolsAdded: Tool[];\n\ttoolsRemoved: ToolReference[];\n}\n\n/** Compare two complete tool states. A changed definition is a removal followed by an addition. */\nexport function getToolStateChanges(previous: readonly Tool[], current: readonly Tool[]): ToolStateChanges {\n\tconst previousTools = new Map(previous.map((tool) => [tool.name, tool]));\n\tconst currentTools = new Map(current.map((tool) => [tool.name, tool]));\n\treturn {\n\t\ttoolsAdded: current\n\t\t\t.filter((tool) => {\n\t\t\t\tconst previousTool = previousTools.get(tool.name);\n\t\t\t\treturn previousTool === undefined || !declarationsEqual(previousTool, tool);\n\t\t\t})\n\t\t\t.map(toToolDeclaration),\n\t\ttoolsRemoved: previous\n\t\t\t.filter((tool) => {\n\t\t\t\tconst currentTool = currentTools.get(tool.name);\n\t\t\t\treturn currentTool === undefined || !declarationsEqual(tool, currentTool);\n\t\t\t})\n\t\t\t.map((tool) => ({ name: tool.name })),\n\t};\n}\n\n/** Every definition referenced by transcript tool state, in first-declaration order. */\nexport function getDeclaredTools(messages: TranscriptMessages): Tool[] {\n\tconst definitions = new Map<string, Tool>();\n\tfor (const message of messages) {\n\t\tif (!isSystemMessage(message)) continue;\n\t\tfor (const tool of message.toolsAdded ?? []) definitions.set(tool.name, tool);\n\t}\n\treturn [...definitions.values()];\n}\n\n/**\n * Whether a tool name was declared twice with different definitions. Transports that\n * reference tools by name (Anthropic `tool_addition`/`tool_removal`) cannot express that.\n */\nexport function hasToolRedefinitions(messages: TranscriptMessages): boolean {\n\tconst declared = new Map<string, Tool>();\n\tfor (const message of messages) {\n\t\tif (!isSystemMessage(message)) continue;\n\t\tfor (const tool of message.toolsAdded ?? []) {\n\t\t\tconst previous = declared.get(tool.name);\n\t\t\tif (previous !== undefined && !declarationsEqual(previous, tool)) return true;\n\t\t\tdeclared.set(tool.name, tool);\n\t\t}\n\t}\n\treturn false;\n}\n\n/** Whether tool history contains a removal or same-name redeclaration that an addition-only transport cannot replay. */\nexport function hasNonAdditiveToolChanges(messages: TranscriptMessages): boolean {\n\tconst declared = new Set<string>();\n\tfor (const message of messages) {\n\t\tif (!isSystemMessage(message)) continue;\n\t\tif ((message.toolsRemoved?.length ?? 0) > 0) return true;\n\t\tfor (const tool of message.toolsAdded ?? []) {\n\t\t\tif (declared.has(tool.name)) return true;\n\t\t\tdeclared.add(tool.name);\n\t\t}\n\t}\n\treturn false;\n}\n\nexport interface TranscriptTools {\n\t/** Tools sent in the top-level request field. */\n\trequestTools: Tool[];\n\t/**\n\t * Whether later system messages carry their own `toolsAdded` as in-place additions.\n\t * When false, `requestTools` already holds the complete current tool set.\n\t */\n\tanchorsAdditions: boolean;\n}\n\n/**\n * Split tool declarations between the top-level request field and in-place additions.\n * Transports that can anchor additions at a system message keep the initial tools at the\n * top and load later ones where they appear; that only works when no tool was removed or\n * redeclared, so everything else sends the current tool list.\n */\nexport function resolveTranscriptTools(messages: TranscriptMessages, supportsToolAdditions: boolean): TranscriptTools {\n\tconst anchorsAdditions = supportsToolAdditions && !hasNonAdditiveToolChanges(messages);\n\treturn {\n\t\trequestTools: anchorsAdditions\n\t\t\t? (getInitialSystemMessage(messages)?.toolsAdded ?? [])\n\t\t\t: getCurrentTools(messages),\n\t\tanchorsAdditions,\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"transcript.js","sourceRoot":"","sources":["../../src/utils/transcript.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Context, Message, SystemMessage, Tool, ToolReference, TranscriptContext } from \"../types.ts\";\nimport { contentText, getSystemMessageText } from \"./text.ts\";\n\nexport type { TranscriptContext } from \"../types.ts\";\n\n/**\n * Build the leading system message for a prompt and tool set. Returns undefined when\n * both are empty, so an empty transcript stays empty.\n */\nexport function createInitialSystemMessage(\n\tsystemPrompt: string | undefined,\n\ttools: Tool[] | undefined,\n): SystemMessage | undefined {\n\tconst hasSystemPrompt = systemPrompt !== undefined && systemPrompt.length > 0;\n\tconst hasTools = tools !== undefined && tools.length > 0;\n\tif (!hasSystemPrompt && !hasTools) return undefined;\n\treturn {\n\t\trole: \"system\",\n\t\tcontent: systemPrompt ?? \"\",\n\t\t...(hasTools ? { toolsAdded: tools } : {}),\n\t\ttimestamp: 0,\n\t};\n}\n\n/**\n * Fold `Context.systemPrompt` and `Context.tools` into a leading system message.\n * This is the only entry point that produces a {@link TranscriptContext}; every\n * provider-facing function expects the result.\n */\nexport function normalizeContext(context: Context): TranscriptContext {\n\tconst initialMessage = createInitialSystemMessage(context.systemPrompt, context.tools);\n\tconst messages = initialMessage ? [initialMessage, ...context.messages] : context.messages;\n\treturn { messages } as TranscriptContext;\n}\n\n/**\n * Any message list. The replay helpers only read entries whose role is `\"system\"`, so\n * agent transcripts that carry custom message roles can be passed without filtering.\n */\nexport type TranscriptMessages = readonly { role: string }[];\n\nfunction isSystemMessage(message: { role: string }): message is SystemMessage {\n\treturn message.role === \"system\";\n}\n\n/** Return the leading system message, if the transcript starts with one. */\nexport function getInitialSystemMessage(messages: TranscriptMessages): SystemMessage | undefined {\n\tconst first = messages[0];\n\treturn first && isSystemMessage(first) ? first : undefined;\n}\n\n/** Drop the leading system message for APIs that carry the prompt outside the message list. */\nexport function withoutInitialSystemMessage(messages: Message[]): Message[] {\n\treturn getInitialSystemMessage(messages) ? messages.slice(1) : messages;\n}\n\n/** Resolve the tools available after applying every transcript delta in order. */\nexport function getCurrentTools(messages: TranscriptMessages): Tool[] {\n\tconst tools = new Map<string, Tool>();\n\tfor (const message of messages) {\n\t\tif (!isSystemMessage(message)) continue;\n\t\tfor (const tool of message.toolsRemoved ?? []) tools.delete(tool.name);\n\t\tfor (const tool of message.toolsAdded ?? []) tools.set(tool.name, tool);\n\t}\n\treturn [...tools.values()];\n}\n\n/**\n * Replay every system message into one leading system message holding the current\n * prompt and tools. Later `content` is appended to the base prompt, `sections` are\n * patched by name, and tools are resolved with {@link getCurrentTools}.\n */\nexport function getCurrentSystemMessage(messages: TranscriptMessages): SystemMessage | undefined {\n\tconst content: string[] = [];\n\tconst sections = new Map<string, string>();\n\tlet timestamp: number | undefined;\n\tfor (const message of messages) {\n\t\tif (!isSystemMessage(message)) continue;\n\t\ttimestamp ??= message.timestamp;\n\t\tconst text = contentText(message.content);\n\t\tif (text.length > 0) content.push(text);\n\t\tfor (const [name, value] of Object.entries(message.sections ?? {})) {\n\t\t\tif (value === null) sections.delete(name);\n\t\t\telse sections.set(name, value);\n\t\t}\n\t}\n\tconst tools = getCurrentTools(messages);\n\tif (timestamp === undefined && tools.length === 0) return undefined;\n\treturn {\n\t\trole: \"system\",\n\t\tcontent: content.join(\"\\n\\n\"),\n\t\t...(sections.size > 0 ? { sections: Object.fromEntries(sections) } : {}),\n\t\t...(tools.length > 0 ? { toolsAdded: tools } : {}),\n\t\ttimestamp: timestamp ?? 0,\n\t};\n}\n\n/** Render the current system prompt text after replaying every system message. */\nexport function getCurrentSystemPrompt(messages: TranscriptMessages): string {\n\tconst message = getCurrentSystemMessage(messages);\n\treturn message ? getSystemMessageText(message) : \"\";\n}\n\n/**\n * Rebuild the transcript for APIs without mid-conversation system messages: the replayed\n * system message leads, and every later system message is dropped.\n */\nexport function collapseSystemMessages(context: TranscriptContext): TranscriptContext {\n\tconst head = getCurrentSystemMessage(context.messages);\n\tconst messages = context.messages.filter((message) => message.role !== \"system\");\n\treturn { messages: head ? [head, ...messages] : messages } as TranscriptContext;\n}\n\n/** Keep later system messages in place when the model accepts them; otherwise collapse them. */\nexport function resolveTranscript(\n\tcontext: TranscriptContext,\n\tsupportsMidConvoSystemMessages: boolean | undefined,\n): TranscriptContext {\n\treturn supportsMidConvoSystemMessages ? context : collapseSystemMessages(context);\n}\n\n/** Strip executable and display-only fields from a tool before transcript comparison or persistence. */\nexport function toToolDeclaration(tool: Tool): Tool {\n\treturn {\n\t\tname: tool.name,\n\t\tdescription: tool.description,\n\t\tparameters: JSON.parse(JSON.stringify(tool.parameters)) as Tool[\"parameters\"],\n\t\t...(tool.constrainedSampling === undefined ? {} : { constrainedSampling: tool.constrainedSampling }),\n\t};\n}\n\n/**\n * Whether two tools declare the same interface to the model.\n *\n * Both sides go through {@link toToolDeclaration} first: its JSON round-trip drops the\n * typebox symbol keys and `undefined` fields that a structural comparison would see, and\n * builds both objects with the same key order, so comparing the serialized declarations\n * is exact. This avoids a deep-equal dependency in a browser-safe package.\n */\nexport function declarationsEqual(left: Tool, right: Tool): boolean {\n\treturn JSON.stringify(toToolDeclaration(left)) === JSON.stringify(toToolDeclaration(right));\n}\n\nexport interface ToolStateChanges {\n\ttoolsAdded: Tool[];\n\ttoolsRemoved: ToolReference[];\n}\n\n/** Compare two complete tool states. A changed definition is a removal followed by an addition. */\nexport function getToolStateChanges(previous: readonly Tool[], current: readonly Tool[]): ToolStateChanges {\n\tconst previousTools = new Map(previous.map((tool) => [tool.name, tool]));\n\tconst currentTools = new Map(current.map((tool) => [tool.name, tool]));\n\treturn {\n\t\ttoolsAdded: current\n\t\t\t.filter((tool) => {\n\t\t\t\tconst previousTool = previousTools.get(tool.name);\n\t\t\t\treturn previousTool === undefined || !declarationsEqual(previousTool, tool);\n\t\t\t})\n\t\t\t.map(toToolDeclaration),\n\t\ttoolsRemoved: previous\n\t\t\t.filter((tool) => {\n\t\t\t\tconst currentTool = currentTools.get(tool.name);\n\t\t\t\treturn currentTool === undefined || !declarationsEqual(tool, currentTool);\n\t\t\t})\n\t\t\t.map((tool) => ({ name: tool.name })),\n\t};\n}\n\n/** Every definition referenced by transcript tool state, in first-declaration order. */\nexport function getDeclaredTools(messages: TranscriptMessages): Tool[] {\n\tconst definitions = new Map<string, Tool>();\n\tfor (const message of messages) {\n\t\tif (!isSystemMessage(message)) continue;\n\t\tfor (const tool of message.toolsAdded ?? []) definitions.set(tool.name, tool);\n\t}\n\treturn [...definitions.values()];\n}\n\n/**\n * Whether a tool name was declared twice with different definitions. Transports that\n * reference tools by name (Anthropic `tool_addition`/`tool_removal`) cannot express that.\n */\nexport function hasToolRedefinitions(messages: TranscriptMessages): boolean {\n\tconst declared = new Map<string, Tool>();\n\tfor (const message of messages) {\n\t\tif (!isSystemMessage(message)) continue;\n\t\tfor (const tool of message.toolsAdded ?? []) {\n\t\t\tconst previous = declared.get(tool.name);\n\t\t\tif (previous !== undefined && !declarationsEqual(previous, tool)) return true;\n\t\t\tdeclared.set(tool.name, tool);\n\t\t}\n\t}\n\treturn false;\n}\n\n/** Whether tool history contains a removal or same-name redeclaration that an addition-only transport cannot replay. */\nexport function hasNonAdditiveToolChanges(messages: TranscriptMessages): boolean {\n\tconst declared = new Set<string>();\n\tfor (const message of messages) {\n\t\tif (!isSystemMessage(message)) continue;\n\t\tif ((message.toolsRemoved?.length ?? 0) > 0) return true;\n\t\tfor (const tool of message.toolsAdded ?? []) {\n\t\t\tif (declared.has(tool.name)) return true;\n\t\t\tdeclared.add(tool.name);\n\t\t}\n\t}\n\treturn false;\n}\n\nexport interface TranscriptTools {\n\t/** Tools sent in the top-level request field. */\n\trequestTools: Tool[];\n\t/**\n\t * Whether later system messages carry their own `toolsAdded` as in-place additions.\n\t * When false, `requestTools` already holds the complete current tool set.\n\t */\n\tanchorsAdditions: boolean;\n}\n\n/**\n * Split tool declarations between the top-level request field and in-place additions.\n * Transports that can anchor additions at a system message keep the initial tools at the\n * top and load later ones where they appear; that only works when no tool was removed or\n * redeclared, so everything else sends the current tool list.\n */\nexport function resolveTranscriptTools(messages: TranscriptMessages, supportsToolAdditions: boolean): TranscriptTools {\n\tconst anchorsAdditions = supportsToolAdditions && !hasNonAdditiveToolChanges(messages);\n\treturn {\n\t\trequestTools: anchorsAdditions\n\t\t\t? (getInitialSystemMessage(messages)?.toolsAdded ?? [])\n\t\t\t: getCurrentTools(messages),\n\t\tanchorsAdditions,\n\t};\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typebox-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/typebox-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAQ,MAAM,SAAS,CAAC;AAE7C;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,SAAS,MAAM,EAAE,EACrD,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAA;CAAE,GACrD,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAOpB"
|
|
1
|
+
{"version":3,"file":"typebox-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/typebox-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAQ,MAAM,SAAS,CAAC;AAE7C;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,SAAS,MAAM,EAAE,EACrD,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAA;CAAE,GACrD,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAOpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typebox-helpers.js","sourceRoot":"","sources":["../../src/utils/typebox-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,IAAI,EAAE,MAAM,SAAS,CAAC;AAE7C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,UAAU,CACzB,MAAS,EACT,OAAuD
|
|
1
|
+
{"version":3,"file":"typebox-helpers.js","sourceRoot":"","sources":["../../src/utils/typebox-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,IAAI,EAAE,MAAM,SAAS,CAAC;AAE7C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,UAAU,CACzB,MAAS,EACT,OAAuD;IAEvD,OAAO,IAAI,CAAC,MAAM,CAAY;QAC7B,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,MAAa;QACnB,GAAG,CAAC,OAAO,EAAE,WAAW,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;QACjE,GAAG,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;KACrD,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { type TUnsafe, Type } from \"typebox\";\n\n/**\n * Creates a string enum schema compatible with Google's API and other providers\n * that don't support anyOf/const patterns.\n *\n * @example\n * const OperationSchema = StringEnum([\"add\", \"subtract\", \"multiply\", \"divide\"], {\n * description: \"The operation to perform\"\n * });\n *\n * type Operation = Static<typeof OperationSchema>; // \"add\" | \"subtract\" | \"multiply\" | \"divide\"\n */\nexport function StringEnum<T extends readonly string[]>(\n\tvalues: T,\n\toptions?: { description?: string; default?: T[number] },\n): TUnsafe<T[number]> {\n\treturn Type.Unsafe<T[number]>({\n\t\ttype: \"string\",\n\t\tenum: values as any,\n\t\t...(options?.description && { description: options.description }),\n\t\t...(options?.default && { default: options.default }),\n\t});\n}\n"]}
|
package/dist/utils/uuid.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uuid.d.ts","sourceRoot":"","sources":["../../src/utils/uuid.ts"],"names":[],"mappings":"AAaA,sCAAsC;AACtC,wBAAgB,MAAM,IAAI,MAAM,CAiC/B"
|
|
1
|
+
{"version":3,"file":"uuid.d.ts","sourceRoot":"","sources":["../../src/utils/uuid.ts"],"names":[],"mappings":"AAaA,sCAAsC;AACtC,wBAAgB,MAAM,IAAI,MAAM,CAiC/B"}
|
package/dist/utils/uuid.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uuid.js","sourceRoot":"","sources":["../../src/utils/uuid.ts"],"names":[],"mappings":"AAAA,IAAI,aAAa,GAAG,CAAC,QAAQ,CAAC;AAC9B,IAAI,QAAQ,GAAG,CAAC,CAAC;AAEjB,SAAS,eAAe,CAAC,KAA8B
|
|
1
|
+
{"version":3,"file":"uuid.js","sourceRoot":"","sources":["../../src/utils/uuid.ts"],"names":[],"mappings":"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","sourcesContent":["let lastTimestamp = -Infinity;\nlet sequence = 0;\n\nfunction fillRandomBytes(bytes: Uint8Array<ArrayBuffer>): void {\n\tif (globalThis.crypto?.getRandomValues) {\n\t\tglobalThis.crypto.getRandomValues(bytes);\n\t\treturn;\n\t}\n\tfor (let i = 0; i < bytes.length; i++) {\n\t\tbytes[i] = Math.floor(Math.random() * 256);\n\t}\n}\n\n/** Generate a time-ordered UUIDv7. */\nexport function uuidv7(): string {\n\tconst random = new Uint8Array(16);\n\tfillRandomBytes(random);\n\tconst timestamp = Date.now();\n\n\tif (timestamp > lastTimestamp) {\n\t\tsequence = random[6] * 0x1000000 + random[7] * 0x10000 + random[8] * 0x100 + random[9];\n\t\tlastTimestamp = timestamp;\n\t} else {\n\t\tsequence = (sequence + 1) >>> 0;\n\t\tif (sequence === 0) lastTimestamp++;\n\t}\n\n\tconst bytes = new Uint8Array(16);\n\tbytes[0] = (lastTimestamp / 0x10000000000) & 0xff;\n\tbytes[1] = (lastTimestamp / 0x100000000) & 0xff;\n\tbytes[2] = (lastTimestamp / 0x1000000) & 0xff;\n\tbytes[3] = (lastTimestamp / 0x10000) & 0xff;\n\tbytes[4] = (lastTimestamp / 0x100) & 0xff;\n\tbytes[5] = lastTimestamp & 0xff;\n\tbytes[6] = 0x70 | ((sequence >>> 28) & 0x0f);\n\tbytes[7] = (sequence >>> 20) & 0xff;\n\tbytes[8] = 0x80 | ((sequence >>> 14) & 0x3f);\n\tbytes[9] = (sequence >>> 6) & 0xff;\n\tbytes[10] = ((sequence & 0x3f) << 2) | (random[10] & 0x03);\n\tbytes[11] = random[11];\n\tbytes[12] = random[12];\n\tbytes[13] = random[13];\n\tbytes[14] = random[14];\n\tbytes[15] = random[15];\n\n\tconst hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, \"0\"));\n\treturn `${hex.slice(0, 4).join(\"\")}-${hex.slice(4, 6).join(\"\")}-${hex.slice(6, 8).join(\"\")}-${hex.slice(8, 10).join(\"\")}-${hex.slice(10, 16).join(\"\")}`;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAmSlD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,QAAQ,GAAG,GAAG,CAMvE;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,GAAG,GAAG,CAiCzE","sourcesContent":["import { Compile } from \"typebox/compile\";\nimport type { TLocalizedValidationError } from \"typebox/error\";\nimport { Value } from \"typebox/value\";\nimport type { Tool, ToolCall } from \"../types.ts\";\n\nconst validatorCache = new WeakMap<object, ReturnType<typeof Compile>>();\nconst TYPEBOX_KIND = Symbol.for(\"TypeBox.Kind\");\n\ninterface JsonSchemaObject {\n\ttype?: string | string[];\n\tproperties?: Record<string, JsonSchemaObject>;\n\trequired?: string[];\n\titems?: JsonSchemaObject | JsonSchemaObject[];\n\tadditionalProperties?: boolean | JsonSchemaObject;\n\tallOf?: JsonSchemaObject[];\n\tanyOf?: JsonSchemaObject[];\n\toneOf?: JsonSchemaObject[];\n}\n\nfunction getSchemaTypes(schema: JsonSchemaObject): string[] {\n\tif (typeof schema.type === \"string\") {\n\t\treturn [schema.type];\n\t}\n\tif (Array.isArray(schema.type)) {\n\t\treturn schema.type.filter((type): type is string => typeof type === \"string\");\n\t}\n\treturn [];\n}\n\nfunction matchesJsonType(value: unknown, type: string): boolean {\n\tswitch (type) {\n\t\tcase \"number\":\n\t\t\treturn typeof value === \"number\";\n\t\tcase \"integer\":\n\t\t\treturn typeof value === \"number\" && Number.isInteger(value);\n\t\tcase \"boolean\":\n\t\t\treturn typeof value === \"boolean\";\n\t\tcase \"string\":\n\t\t\treturn typeof value === \"string\";\n\t\tcase \"null\":\n\t\t\treturn value === null;\n\t\tcase \"array\":\n\t\t\treturn Array.isArray(value);\n\t\tcase \"object\":\n\t\t\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n\t\tdefault:\n\t\t\treturn false;\n\t}\n}\n\nfunction getSubSchemaValidator(schema: JsonSchemaObject): ReturnType<typeof Compile> | undefined {\n\ttry {\n\t\treturn getValidator(schema as Tool[\"parameters\"]);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction coercePrimitiveByType(value: unknown, type: string): unknown {\n\tswitch (type) {\n\t\tcase \"number\": {\n\t\t\tif (value === null) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif (typeof value === \"string\" && value.trim() !== \"\") {\n\t\t\t\tconst parsed = Number(value);\n\t\t\t\tif (Number.isFinite(parsed)) {\n\t\t\t\t\treturn parsed;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (typeof value === \"boolean\") {\n\t\t\t\treturn value ? 1 : 0;\n\t\t\t}\n\t\t\treturn value;\n\t\t}\n\t\tcase \"integer\": {\n\t\t\tif (value === null) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif (typeof value === \"string\" && value.trim() !== \"\") {\n\t\t\t\tconst parsed = Number(value);\n\t\t\t\tif (Number.isInteger(parsed)) {\n\t\t\t\t\treturn parsed;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (typeof value === \"boolean\") {\n\t\t\t\treturn value ? 1 : 0;\n\t\t\t}\n\t\t\treturn value;\n\t\t}\n\t\tcase \"boolean\": {\n\t\t\tif (value === null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (typeof value === \"string\") {\n\t\t\t\tif (value === \"true\") {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (value === \"false\") {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (typeof value === \"number\") {\n\t\t\t\tif (value === 1) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (value === 0) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn value;\n\t\t}\n\t\tcase \"string\": {\n\t\t\tif (value === null) {\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t\tif (typeof value === \"number\" || typeof value === \"boolean\") {\n\t\t\t\treturn String(value);\n\t\t\t}\n\t\t\treturn value;\n\t\t}\n\t\tcase \"null\": {\n\t\t\tif (value === \"\" || value === 0 || value === false) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn value;\n\t\t}\n\t\tdefault:\n\t\t\treturn value;\n\t}\n}\n\nfunction applySchemaObjectCoercion(value: Record<string, unknown>, schema: JsonSchemaObject): void {\n\tconst properties = schema.properties;\n\tconst definedKeys = new Set<string>(properties ? Object.keys(properties) : []);\n\n\tif (properties) {\n\t\tfor (const [key, propertySchema] of Object.entries(properties)) {\n\t\t\tif (!(key in value)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tvalue[key] = coerceWithJsonSchema(value[key], propertySchema);\n\t\t}\n\t}\n\n\tif (schema.additionalProperties && typeof schema.additionalProperties === \"object\") {\n\t\tfor (const [key, propertyValue] of Object.entries(value)) {\n\t\t\tif (definedKeys.has(key)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tvalue[key] = coerceWithJsonSchema(propertyValue, schema.additionalProperties);\n\t\t}\n\t}\n}\n\nfunction applySchemaArrayCoercion(value: unknown[], schema: JsonSchemaObject): void {\n\tif (Array.isArray(schema.items)) {\n\t\tfor (let index = 0; index < value.length; index++) {\n\t\t\tconst itemSchema = schema.items[index];\n\t\t\tif (!itemSchema) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tvalue[index] = coerceWithJsonSchema(value[index], itemSchema);\n\t\t}\n\t\treturn;\n\t}\n\n\tif (schema.items && typeof schema.items === \"object\") {\n\t\tfor (let index = 0; index < value.length; index++) {\n\t\t\tvalue[index] = coerceWithJsonSchema(value[index], schema.items);\n\t\t}\n\t}\n}\n\nfunction coerceWithUnionSchema(value: unknown, schemas: JsonSchemaObject[]): unknown {\n\tfor (const schema of schemas) {\n\t\tconst validator = getSubSchemaValidator(schema);\n\t\tif (validator?.Check(value)) {\n\t\t\treturn value;\n\t\t}\n\t}\n\n\tfor (const schema of schemas) {\n\t\tconst candidate = structuredClone(value);\n\t\tconst coerced = coerceWithJsonSchema(candidate, schema);\n\t\tconst validator = getSubSchemaValidator(schema);\n\t\tif (validator?.Check(coerced)) {\n\t\t\treturn coerced;\n\t\t}\n\t}\n\treturn value;\n}\n\nfunction coerceWithJsonSchema(value: unknown, schema: JsonSchemaObject): unknown {\n\tlet nextValue = value;\n\n\tif (Array.isArray(schema.allOf)) {\n\t\tfor (const nested of schema.allOf) {\n\t\t\tnextValue = coerceWithJsonSchema(nextValue, nested);\n\t\t}\n\t}\n\n\tif (Array.isArray(schema.anyOf)) {\n\t\tnextValue = coerceWithUnionSchema(nextValue, schema.anyOf);\n\t}\n\n\tif (Array.isArray(schema.oneOf)) {\n\t\tnextValue = coerceWithUnionSchema(nextValue, schema.oneOf);\n\t}\n\n\tconst schemaTypes = getSchemaTypes(schema);\n\tconst matchesUnionMember =\n\t\tschemaTypes.length > 1 && schemaTypes.some((schemaType) => matchesJsonType(nextValue, schemaType));\n\tif (schemaTypes.length > 0 && !matchesUnionMember) {\n\t\tfor (const schemaType of schemaTypes) {\n\t\t\tconst candidate = coercePrimitiveByType(nextValue, schemaType);\n\t\t\tif (candidate !== nextValue) {\n\t\t\t\tnextValue = candidate;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (\n\t\tschemaTypes.includes(\"object\") &&\n\t\ttypeof nextValue === \"object\" &&\n\t\tnextValue !== null &&\n\t\t!Array.isArray(nextValue)\n\t) {\n\t\tapplySchemaObjectCoercion(nextValue as Record<string, unknown>, schema);\n\t}\n\n\tif (schemaTypes.includes(\"array\") && Array.isArray(nextValue)) {\n\t\tapplySchemaArrayCoercion(nextValue, schema);\n\t}\n\n\treturn nextValue;\n}\n\nfunction normalizeOptionalNulls(value: unknown, schema: JsonSchemaObject): void {\n\tif (Array.isArray(value)) {\n\t\tif (Array.isArray(schema.items)) {\n\t\t\tfor (let index = 0; index < value.length; index++) {\n\t\t\t\tconst itemSchema = schema.items[index];\n\t\t\t\tif (itemSchema) normalizeOptionalNulls(value[index], itemSchema);\n\t\t\t}\n\t\t} else if (schema.items) {\n\t\t\tfor (const item of value) normalizeOptionalNulls(item, schema.items);\n\t\t}\n\t\treturn;\n\t}\n\tif (typeof value !== \"object\" || value === null || !schema.properties) return;\n\n\tconst object = value as Record<string, unknown>;\n\tconst required = new Set(schema.required ?? []);\n\tfor (const [key, propertySchema] of Object.entries(schema.properties)) {\n\t\tif (!(key in object)) continue;\n\t\tif (\n\t\t\tobject[key] === null &&\n\t\t\t!required.has(key) &&\n\t\t\ttypeof (propertySchema as { $ref?: unknown }).$ref !== \"string\" &&\n\t\t\tgetSubSchemaValidator(propertySchema)?.Check(null) === false\n\t\t) {\n\t\t\tdelete object[key];\n\t\t} else {\n\t\t\tnormalizeOptionalNulls(object[key], propertySchema);\n\t\t}\n\t}\n}\n\nfunction getValidator(schema: Tool[\"parameters\"]): ReturnType<typeof Compile> {\n\tconst key = schema as object;\n\tconst cached = validatorCache.get(key);\n\tif (cached) {\n\t\treturn cached;\n\t}\n\tconst validator = Compile(schema);\n\tvalidatorCache.set(key, validator);\n\treturn validator;\n}\n\nfunction formatValidationPath(error: TLocalizedValidationError): string {\n\tif (error.keyword === \"required\") {\n\t\tconst requiredProperties = (error.params as { requiredProperties?: string[] }).requiredProperties;\n\t\tconst requiredProperty = requiredProperties?.[0];\n\t\tif (requiredProperty) {\n\t\t\tconst basePath = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n\t\t\treturn basePath ? `${basePath}.${requiredProperty}` : requiredProperty;\n\t\t}\n\t}\n\tconst path = error.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\");\n\treturn path || \"root\";\n}\n\n/**\n * Finds a tool by name and validates the tool call arguments against its TypeBox schema\n * @param tools Array of tool definitions\n * @param toolCall The tool call from the LLM\n * @returns The validated arguments\n * @throws Error if tool is not found or validation fails\n */\nexport function validateToolCall(tools: Tool[], toolCall: ToolCall): any {\n\tconst tool = tools.find((t) => t.name === toolCall.name);\n\tif (!tool) {\n\t\tthrow new Error(`Tool \"${toolCall.name}\" not found`);\n\t}\n\treturn validateToolArguments(tool, toolCall);\n}\n\n/**\n * Validates tool call arguments against the tool's TypeBox schema\n * @param tool The tool definition with TypeBox schema\n * @param toolCall The tool call from the LLM\n * @returns The validated (and potentially coerced) arguments\n * @throws Error with formatted message if validation fails\n */\nexport function validateToolArguments(tool: Tool, toolCall: ToolCall): any {\n\tconst args = structuredClone(toolCall.arguments);\n\tnormalizeOptionalNulls(args, tool.parameters as JsonSchemaObject);\n\tValue.Convert(tool.parameters, args);\n\n\tconst validator = getValidator(tool.parameters);\n\tif (!Object.getOwnPropertySymbols(tool.parameters).includes(TYPEBOX_KIND)) {\n\t\tconst coerced = coerceWithJsonSchema(args, tool.parameters as JsonSchemaObject);\n\t\tif (coerced !== args) {\n\t\t\tif (typeof args === \"object\" && args !== null && typeof coerced === \"object\" && coerced !== null) {\n\t\t\t\tfor (const key of Object.keys(args)) {\n\t\t\t\t\tdelete args[key];\n\t\t\t\t}\n\t\t\t\tObject.assign(args, coerced);\n\t\t\t} else {\n\t\t\t\treturn validator.Check(coerced) ? coerced : args;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (validator.Check(args)) {\n\t\treturn args;\n\t}\n\n\tconst errors =\n\t\tvalidator\n\t\t\t.Errors(args)\n\t\t\t.map((error) => ` - ${formatValidationPath(error)}: ${error.message}`)\n\t\t\t.join(\"\\n\") || \"Unknown validation error\";\n\n\tconst errorMessage = `Validation failed for tool \"${toolCall.name}\":\\n${errors}\\n\\nReceived arguments:\\n${JSON.stringify(toolCall.arguments, null, 2)}`;\n\n\tthrow new Error(errorMessage);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAmSlD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,QAAQ,GAAG,GAAG,CAMvE;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,GAAG,GAAG,CAiCzE"}
|