@nodetool-ai/runtime 0.7.0-rc.22 → 0.8.1
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/README.md +29 -0
- package/dist/.nodetool-build-stamp +1 -0
- package/dist/agent-memory.d.ts +118 -0
- package/dist/agent-memory.d.ts.map +1 -0
- package/dist/agent-memory.js +186 -0
- package/dist/agent-memory.js.map +1 -0
- package/dist/async-local-storage.d.ts +20 -0
- package/dist/async-local-storage.d.ts.map +1 -0
- package/dist/async-local-storage.js +28 -0
- package/dist/async-local-storage.js.map +1 -0
- package/dist/blender-executor.d.ts +93 -0
- package/dist/blender-executor.d.ts.map +1 -0
- package/dist/blender-executor.js +294 -0
- package/dist/blender-executor.js.map +1 -0
- package/dist/comfy-executor.d.ts +23 -1
- package/dist/comfy-executor.d.ts.map +1 -1
- package/dist/comfy-executor.js +234 -55
- package/dist/comfy-executor.js.map +1 -1
- package/dist/context-packer.d.ts +1 -1
- package/dist/context-packer.d.ts.map +1 -1
- package/dist/context-packer.js +23 -25
- package/dist/context-packer.js.map +1 -1
- package/dist/context.d.ts +954 -127
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +2424 -513
- package/dist/context.js.map +1 -1
- package/dist/cost-reconciler.d.ts +32 -0
- package/dist/cost-reconciler.d.ts.map +1 -0
- package/dist/cost-reconciler.js +21 -0
- package/dist/cost-reconciler.js.map +1 -0
- package/dist/entities.d.ts +33 -0
- package/dist/entities.d.ts.map +1 -0
- package/dist/entities.js +43 -0
- package/dist/entities.js.map +1 -0
- package/dist/external-media-fetch.d.ts +29 -0
- package/dist/external-media-fetch.d.ts.map +1 -0
- package/dist/external-media-fetch.js +38 -0
- package/dist/external-media-fetch.js.map +1 -0
- package/dist/generation-receipt.d.ts +86 -0
- package/dist/generation-receipt.d.ts.map +1 -0
- package/dist/generation-receipt.js +137 -0
- package/dist/generation-receipt.js.map +1 -0
- package/dist/generation-registry.d.ts +67 -0
- package/dist/generation-registry.d.ts.map +1 -0
- package/dist/generation-registry.js +126 -0
- package/dist/generation-registry.js.map +1 -0
- package/dist/google/client.d.ts +196 -0
- package/dist/google/client.d.ts.map +1 -0
- package/dist/google/client.js +396 -0
- package/dist/google/client.js.map +1 -0
- package/dist/google/index.d.ts +3 -0
- package/dist/google/index.d.ts.map +1 -0
- package/dist/google/index.js +3 -0
- package/dist/google/index.js.map +1 -0
- package/dist/google/token.d.ts +15 -0
- package/dist/google/token.d.ts.map +1 -0
- package/dist/google/token.js +24 -0
- package/dist/google/token.js.map +1 -0
- package/dist/host-binaries.d.ts +106 -0
- package/dist/host-binaries.d.ts.map +1 -0
- package/dist/host-binaries.js +344 -0
- package/dist/host-binaries.js.map +1 -0
- package/dist/image-codec.d.ts +74 -0
- package/dist/image-codec.d.ts.map +1 -0
- package/dist/image-codec.js +273 -0
- package/dist/image-codec.js.map +1 -0
- package/dist/index.d.ts +56 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +43 -4
- package/dist/index.js.map +1 -1
- package/dist/invocation-account.d.ts +43 -0
- package/dist/invocation-account.d.ts.map +1 -0
- package/dist/invocation-account.js +60 -0
- package/dist/invocation-account.js.map +1 -0
- package/dist/media-ref-bytes.d.ts +19 -0
- package/dist/media-ref-bytes.d.ts.map +1 -0
- package/dist/media-ref-bytes.js +181 -0
- package/dist/media-ref-bytes.js.map +1 -0
- package/dist/node-executor.d.ts +113 -2
- package/dist/node-executor.d.ts.map +1 -1
- package/dist/permission-gate.d.ts +152 -0
- package/dist/permission-gate.d.ts.map +1 -0
- package/dist/permission-gate.js +87 -0
- package/dist/permission-gate.js.map +1 -0
- package/dist/prefixed-storage-adapter.d.ts +33 -0
- package/dist/prefixed-storage-adapter.d.ts.map +1 -0
- package/dist/prefixed-storage-adapter.js +70 -0
- package/dist/prefixed-storage-adapter.js.map +1 -0
- package/dist/prompt-asset-refs.d.ts +222 -0
- package/dist/prompt-asset-refs.d.ts.map +1 -0
- package/dist/prompt-asset-refs.js +751 -0
- package/dist/prompt-asset-refs.js.map +1 -0
- package/dist/provider-cache.d.ts +3 -0
- package/dist/provider-cache.d.ts.map +1 -0
- package/dist/provider-cache.js +8 -0
- package/dist/provider-cache.js.map +1 -0
- package/dist/providers/aki-provider.d.ts +33 -10
- package/dist/providers/aki-provider.d.ts.map +1 -1
- package/dist/providers/aki-provider.js +84 -77
- package/dist/providers/aki-provider.js.map +1 -1
- package/dist/providers/alibaba-provider.d.ts +39 -0
- package/dist/providers/alibaba-provider.d.ts.map +1 -0
- package/dist/providers/alibaba-provider.js +86 -0
- package/dist/providers/alibaba-provider.js.map +1 -0
- package/dist/providers/anthropic-provider.d.ts +52 -3
- package/dist/providers/anthropic-provider.d.ts.map +1 -1
- package/dist/providers/anthropic-provider.js +1020 -338
- package/dist/providers/anthropic-provider.js.map +1 -1
- package/dist/providers/atlascloud-provider.d.ts +101 -0
- package/dist/providers/atlascloud-provider.d.ts.map +1 -0
- package/dist/providers/atlascloud-provider.js +1009 -0
- package/dist/providers/atlascloud-provider.js.map +1 -0
- package/dist/providers/atlascloud-transport.d.ts +100 -0
- package/dist/providers/atlascloud-transport.d.ts.map +1 -0
- package/dist/providers/atlascloud-transport.js +364 -0
- package/dist/providers/atlascloud-transport.js.map +1 -0
- package/dist/providers/atlascloud-webhook-registry.d.ts +35 -0
- package/dist/providers/atlascloud-webhook-registry.d.ts.map +1 -0
- package/dist/providers/atlascloud-webhook-registry.js +104 -0
- package/dist/providers/atlascloud-webhook-registry.js.map +1 -0
- package/dist/providers/audio-mime.d.ts +11 -0
- package/dist/providers/audio-mime.d.ts.map +1 -0
- package/dist/providers/audio-mime.js +46 -0
- package/dist/providers/audio-mime.js.map +1 -0
- package/dist/providers/base-provider.d.ts +481 -24
- package/dist/providers/base-provider.d.ts.map +1 -1
- package/dist/providers/base-provider.js +1259 -42
- package/dist/providers/base-provider.js.map +1 -1
- package/dist/providers/cassette-provider.d.ts +217 -0
- package/dist/providers/cassette-provider.d.ts.map +1 -0
- package/dist/providers/cassette-provider.js +502 -0
- package/dist/providers/cassette-provider.js.map +1 -0
- package/dist/providers/cerebras-provider.d.ts +6 -12
- package/dist/providers/cerebras-provider.d.ts.map +1 -1
- package/dist/providers/cerebras-provider.js +8 -33
- package/dist/providers/cerebras-provider.js.map +1 -1
- package/dist/providers/claude-agent-provider.d.ts +131 -68
- package/dist/providers/claude-agent-provider.d.ts.map +1 -1
- package/dist/providers/claude-agent-provider.js +1095 -515
- package/dist/providers/claude-agent-provider.js.map +1 -1
- package/dist/providers/codex-provider.d.ts +82 -0
- package/dist/providers/codex-provider.d.ts.map +1 -0
- package/dist/providers/codex-provider.js +492 -0
- package/dist/providers/codex-provider.js.map +1 -0
- package/dist/providers/cohere-provider.d.ts +5 -2
- package/dist/providers/cohere-provider.d.ts.map +1 -1
- package/dist/providers/cohere-provider.js +9 -2
- package/dist/providers/cohere-provider.js.map +1 -1
- package/dist/providers/comfy-cloud-provider.d.ts +30 -0
- package/dist/providers/comfy-cloud-provider.d.ts.map +1 -0
- package/dist/providers/comfy-cloud-provider.js +42 -0
- package/dist/providers/comfy-cloud-provider.js.map +1 -0
- package/dist/providers/content-filter.d.ts +46 -0
- package/dist/providers/content-filter.d.ts.map +1 -0
- package/dist/providers/content-filter.js +92 -0
- package/dist/providers/content-filter.js.map +1 -0
- package/dist/providers/context-exceeded.d.ts +37 -0
- package/dist/providers/context-exceeded.d.ts.map +1 -0
- package/dist/providers/context-exceeded.js +114 -0
- package/dist/providers/context-exceeded.js.map +1 -0
- package/dist/providers/context-window.d.ts +44 -0
- package/dist/providers/context-window.d.ts.map +1 -0
- package/dist/providers/context-window.js +145 -0
- package/dist/providers/context-window.js.map +1 -0
- package/dist/providers/contract/index.d.ts +4 -0
- package/dist/providers/contract/index.d.ts.map +1 -0
- package/dist/providers/contract/index.js +4 -0
- package/dist/providers/contract/index.js.map +1 -0
- package/dist/providers/contract/probe-manifest.d.ts +75 -0
- package/dist/providers/contract/probe-manifest.d.ts.map +1 -0
- package/dist/providers/contract/probe-manifest.js +379 -0
- package/dist/providers/contract/probe-manifest.js.map +1 -0
- package/dist/providers/contract/probe-runner.d.ts +57 -0
- package/dist/providers/contract/probe-runner.d.ts.map +1 -0
- package/dist/providers/contract/probe-runner.js +180 -0
- package/dist/providers/contract/probe-runner.js.map +1 -0
- package/dist/providers/contract/redact.d.ts +29 -0
- package/dist/providers/contract/redact.d.ts.map +1 -0
- package/dist/providers/contract/redact.js +113 -0
- package/dist/providers/contract/redact.js.map +1 -0
- package/dist/providers/core-tools.d.ts +74 -0
- package/dist/providers/core-tools.d.ts.map +1 -0
- package/dist/providers/core-tools.js +127 -0
- package/dist/providers/core-tools.js.map +1 -0
- package/dist/providers/cost-calculator.d.ts +69 -50
- package/dist/providers/cost-calculator.d.ts.map +1 -1
- package/dist/providers/cost-calculator.js +207 -397
- package/dist/providers/cost-calculator.js.map +1 -1
- package/dist/providers/credential-check.d.ts +45 -0
- package/dist/providers/credential-check.d.ts.map +1 -0
- package/dist/providers/credential-check.js +159 -0
- package/dist/providers/credential-check.js.map +1 -0
- package/dist/providers/custom-model-kinds.d.ts +33 -0
- package/dist/providers/custom-model-kinds.d.ts.map +1 -0
- package/dist/providers/custom-model-kinds.js +96 -0
- package/dist/providers/custom-model-kinds.js.map +1 -0
- package/dist/providers/custom-openai-provider.d.ts +81 -0
- package/dist/providers/custom-openai-provider.d.ts.map +1 -0
- package/dist/providers/custom-openai-provider.js +182 -0
- package/dist/providers/custom-openai-provider.js.map +1 -0
- package/dist/providers/custom-provider-registry.d.ts +19 -0
- package/dist/providers/custom-provider-registry.d.ts.map +1 -0
- package/dist/providers/custom-provider-registry.js +52 -0
- package/dist/providers/custom-provider-registry.js.map +1 -0
- package/dist/providers/deepseek-provider.d.ts +8 -14
- package/dist/providers/deepseek-provider.d.ts.map +1 -1
- package/dist/providers/deepseek-provider.js +6 -35
- package/dist/providers/deepseek-provider.js.map +1 -1
- package/dist/providers/defaults.d.ts +12 -0
- package/dist/providers/defaults.d.ts.map +1 -0
- package/dist/providers/defaults.js +12 -0
- package/dist/providers/defaults.js.map +1 -0
- package/dist/providers/elevenlabs-provider.d.ts +49 -0
- package/dist/providers/elevenlabs-provider.d.ts.map +1 -0
- package/dist/providers/elevenlabs-provider.js +142 -0
- package/dist/providers/elevenlabs-provider.js.map +1 -0
- package/dist/providers/entity-references.d.ts +31 -0
- package/dist/providers/entity-references.d.ts.map +1 -0
- package/dist/providers/entity-references.js +113 -0
- package/dist/providers/entity-references.js.map +1 -0
- package/dist/providers/evolink-provider.d.ts +38 -0
- package/dist/providers/evolink-provider.d.ts.map +1 -0
- package/dist/providers/evolink-provider.js +304 -0
- package/dist/providers/evolink-provider.js.map +1 -0
- package/dist/providers/fake-provider.d.ts +72 -1
- package/dist/providers/fake-provider.d.ts.map +1 -1
- package/dist/providers/fake-provider.js +203 -1
- package/dist/providers/fake-provider.js.map +1 -1
- package/dist/providers/fal-generations.d.ts +106 -0
- package/dist/providers/fal-generations.d.ts.map +1 -0
- package/dist/providers/fal-generations.js +286 -0
- package/dist/providers/fal-generations.js.map +1 -0
- package/dist/providers/fal-provider.d.ts +171 -7
- package/dist/providers/fal-provider.d.ts.map +1 -1
- package/dist/providers/fal-provider.js +1369 -64
- package/dist/providers/fal-provider.js.map +1 -1
- package/dist/providers/fal-queue.d.ts +47 -0
- package/dist/providers/fal-queue.d.ts.map +1 -0
- package/dist/providers/fal-queue.js +231 -0
- package/dist/providers/fal-queue.js.map +1 -0
- package/dist/providers/gemini-provider.d.ts +148 -8
- package/dist/providers/gemini-provider.d.ts.map +1 -1
- package/dist/providers/gemini-provider.js +1500 -316
- package/dist/providers/gemini-provider.js.map +1 -1
- package/dist/providers/gmi-provider.d.ts +21 -0
- package/dist/providers/gmi-provider.d.ts.map +1 -0
- package/dist/providers/gmi-provider.js +34 -0
- package/dist/providers/gmi-provider.js.map +1 -0
- package/dist/providers/gpt-image-size.d.ts +3 -0
- package/dist/providers/gpt-image-size.d.ts.map +1 -0
- package/dist/providers/gpt-image-size.js +37 -0
- package/dist/providers/gpt-image-size.js.map +1 -0
- package/dist/providers/groq-provider.d.ts +9 -12
- package/dist/providers/groq-provider.d.ts.map +1 -1
- package/dist/providers/groq-provider.js +19 -33
- package/dist/providers/groq-provider.js.map +1 -1
- package/dist/providers/groq-request.d.ts +38 -0
- package/dist/providers/groq-request.d.ts.map +1 -0
- package/dist/providers/groq-request.js +138 -0
- package/dist/providers/groq-request.js.map +1 -0
- package/dist/providers/higgsfield-provider.d.ts +30 -0
- package/dist/providers/higgsfield-provider.d.ts.map +1 -0
- package/dist/providers/higgsfield-provider.js +131 -0
- package/dist/providers/higgsfield-provider.js.map +1 -0
- package/dist/providers/higgsfield-transport.d.ts +106 -0
- package/dist/providers/higgsfield-transport.d.ts.map +1 -0
- package/dist/providers/higgsfield-transport.js +182 -0
- package/dist/providers/higgsfield-transport.js.map +1 -0
- package/dist/providers/http-transport.d.ts +74 -0
- package/dist/providers/http-transport.d.ts.map +1 -0
- package/dist/providers/http-transport.js +152 -0
- package/dist/providers/http-transport.js.map +1 -0
- package/dist/providers/huggingface-provider.d.ts +71 -3
- package/dist/providers/huggingface-provider.d.ts.map +1 -1
- package/dist/providers/huggingface-provider.js +230 -34
- package/dist/providers/huggingface-provider.js.map +1 -1
- package/dist/providers/image-mime.d.ts +39 -0
- package/dist/providers/image-mime.d.ts.map +1 -0
- package/dist/providers/image-mime.js +111 -0
- package/dist/providers/image-mime.js.map +1 -0
- package/dist/providers/image-ref.d.ts +21 -0
- package/dist/providers/image-ref.d.ts.map +1 -0
- package/dist/providers/image-ref.js +44 -0
- package/dist/providers/image-ref.js.map +1 -0
- package/dist/providers/index.d.ts +84 -8
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +239 -56
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/jina-provider.d.ts +10 -2
- package/dist/providers/jina-provider.d.ts.map +1 -1
- package/dist/providers/jina-provider.js +16 -7
- package/dist/providers/jina-provider.js.map +1 -1
- package/dist/providers/kie-provider.d.ts +170 -9
- package/dist/providers/kie-provider.d.ts.map +1 -1
- package/dist/providers/kie-provider.js +1176 -228
- package/dist/providers/kie-provider.js.map +1 -1
- package/dist/providers/kie-webhook-registry.d.ts +28 -0
- package/dist/providers/kie-webhook-registry.d.ts.map +1 -0
- package/dist/providers/kie-webhook-registry.js +91 -0
- package/dist/providers/kie-webhook-registry.js.map +1 -0
- package/dist/providers/llama-provider.d.ts +21 -37
- package/dist/providers/llama-provider.d.ts.map +1 -1
- package/dist/providers/llama-provider.js +43 -354
- package/dist/providers/llama-provider.js.map +1 -1
- package/dist/providers/lmstudio-provider.d.ts +4 -7
- package/dist/providers/lmstudio-provider.d.ts.map +1 -1
- package/dist/providers/lmstudio-provider.js +24 -15
- package/dist/providers/lmstudio-provider.js.map +1 -1
- package/dist/providers/manifest-models.d.ts +341 -1
- package/dist/providers/manifest-models.d.ts.map +1 -1
- package/dist/providers/manifest-models.js +1106 -22
- package/dist/providers/manifest-models.js.map +1 -1
- package/dist/providers/media-mime.d.ts +14 -0
- package/dist/providers/media-mime.d.ts.map +1 -0
- package/dist/providers/media-mime.js +35 -0
- package/dist/providers/media-mime.js.map +1 -0
- package/dist/providers/meshy-provider.d.ts +14 -1
- package/dist/providers/meshy-provider.d.ts.map +1 -1
- package/dist/providers/meshy-provider.js +76 -46
- package/dist/providers/meshy-provider.js.map +1 -1
- package/dist/providers/meta-provider.d.ts +22 -0
- package/dist/providers/meta-provider.d.ts.map +1 -0
- package/dist/providers/meta-provider.js +54 -0
- package/dist/providers/meta-provider.js.map +1 -0
- package/dist/providers/minimax-provider.d.ts +25 -18
- package/dist/providers/minimax-provider.d.ts.map +1 -1
- package/dist/providers/minimax-provider.js +211 -72
- package/dist/providers/minimax-provider.js.map +1 -1
- package/dist/providers/mistral-provider.d.ts +6 -12
- package/dist/providers/mistral-provider.d.ts.map +1 -1
- package/dist/providers/mistral-provider.js +10 -34
- package/dist/providers/mistral-provider.js.map +1 -1
- package/dist/providers/moonshot-provider.d.ts +11 -15
- package/dist/providers/moonshot-provider.d.ts.map +1 -1
- package/dist/providers/moonshot-provider.js +33 -23
- package/dist/providers/moonshot-provider.js.map +1 -1
- package/dist/providers/node-llama-cpp-provider.d.ts +98 -0
- package/dist/providers/node-llama-cpp-provider.d.ts.map +1 -0
- package/dist/providers/node-llama-cpp-provider.js +479 -0
- package/dist/providers/node-llama-cpp-provider.js.map +1 -0
- package/dist/providers/nodetool-provider.d.ts +49 -0
- package/dist/providers/nodetool-provider.d.ts.map +1 -0
- package/dist/providers/nodetool-provider.js +224 -0
- package/dist/providers/nodetool-provider.js.map +1 -0
- package/dist/providers/oauth/browser-launcher.d.ts +23 -0
- package/dist/providers/oauth/browser-launcher.d.ts.map +1 -0
- package/dist/providers/oauth/browser-launcher.js +45 -0
- package/dist/providers/oauth/browser-launcher.js.map +1 -0
- package/dist/providers/oauth/claude-code-credentials.d.ts +74 -0
- package/dist/providers/oauth/claude-code-credentials.d.ts.map +1 -0
- package/dist/providers/oauth/claude-code-credentials.js +133 -0
- package/dist/providers/oauth/claude-code-credentials.js.map +1 -0
- package/dist/providers/oauth/claude-code-login.d.ts +124 -0
- package/dist/providers/oauth/claude-code-login.d.ts.map +1 -0
- package/dist/providers/oauth/claude-code-login.js +230 -0
- package/dist/providers/oauth/claude-code-login.js.map +1 -0
- package/dist/providers/oauth/claude-code-oauth-client.d.ts +111 -0
- package/dist/providers/oauth/claude-code-oauth-client.d.ts.map +1 -0
- package/dist/providers/oauth/claude-code-oauth-client.js +207 -0
- package/dist/providers/oauth/claude-code-oauth-client.js.map +1 -0
- package/dist/providers/oauth/errors.d.ts +54 -0
- package/dist/providers/oauth/errors.d.ts.map +1 -0
- package/dist/providers/oauth/errors.js +79 -0
- package/dist/providers/oauth/errors.js.map +1 -0
- package/dist/providers/oauth/index.d.ts +105 -0
- package/dist/providers/oauth/index.d.ts.map +1 -0
- package/dist/providers/oauth/index.js +167 -0
- package/dist/providers/oauth/index.js.map +1 -0
- package/dist/providers/oauth/jwt-claims.d.ts +23 -0
- package/dist/providers/oauth/jwt-claims.d.ts.map +1 -0
- package/dist/providers/oauth/jwt-claims.js +67 -0
- package/dist/providers/oauth/jwt-claims.js.map +1 -0
- package/dist/providers/oauth/local-callback-server.d.ts +60 -0
- package/dist/providers/oauth/local-callback-server.d.ts.map +1 -0
- package/dist/providers/oauth/local-callback-server.js +148 -0
- package/dist/providers/oauth/local-callback-server.js.map +1 -0
- package/dist/providers/oauth/oauth-client.d.ts +55 -0
- package/dist/providers/oauth/oauth-client.d.ts.map +1 -0
- package/dist/providers/oauth/oauth-client.js +161 -0
- package/dist/providers/oauth/oauth-client.js.map +1 -0
- package/dist/providers/oauth/openai-oauth-provider.d.ts +129 -0
- package/dist/providers/oauth/openai-oauth-provider.d.ts.map +1 -0
- package/dist/providers/oauth/openai-oauth-provider.js +265 -0
- package/dist/providers/oauth/openai-oauth-provider.js.map +1 -0
- package/dist/providers/oauth/pkce-helper.d.ts +43 -0
- package/dist/providers/oauth/pkce-helper.d.ts.map +1 -0
- package/dist/providers/oauth/pkce-helper.js +57 -0
- package/dist/providers/oauth/pkce-helper.js.map +1 -0
- package/dist/providers/oauth/redaction.d.ts +22 -0
- package/dist/providers/oauth/redaction.d.ts.map +1 -0
- package/dist/providers/oauth/redaction.js +59 -0
- package/dist/providers/oauth/redaction.js.map +1 -0
- package/dist/providers/oauth/secure-credential-store.d.ts +67 -0
- package/dist/providers/oauth/secure-credential-store.d.ts.map +1 -0
- package/dist/providers/oauth/secure-credential-store.js +73 -0
- package/dist/providers/oauth/secure-credential-store.js.map +1 -0
- package/dist/providers/oauth/token-store.d.ts +53 -0
- package/dist/providers/oauth/token-store.d.ts.map +1 -0
- package/dist/providers/oauth/token-store.js +78 -0
- package/dist/providers/oauth/token-store.js.map +1 -0
- package/dist/providers/oauth/types.d.ts +64 -0
- package/dist/providers/oauth/types.d.ts.map +1 -0
- package/dist/providers/oauth/types.js +12 -0
- package/dist/providers/oauth/types.js.map +1 -0
- package/dist/providers/object-tracking.d.ts +47 -0
- package/dist/providers/object-tracking.d.ts.map +1 -0
- package/dist/providers/object-tracking.js +46 -0
- package/dist/providers/object-tracking.js.map +1 -0
- package/dist/providers/offline-model-index.d.ts +20 -0
- package/dist/providers/offline-model-index.d.ts.map +1 -0
- package/dist/providers/offline-model-index.js +112 -0
- package/dist/providers/offline-model-index.js.map +1 -0
- package/dist/providers/ollama-provider.d.ts +28 -1
- package/dist/providers/ollama-provider.d.ts.map +1 -1
- package/dist/providers/ollama-provider.js +193 -43
- package/dist/providers/ollama-provider.js.map +1 -1
- package/dist/providers/openai-compat/client.d.ts +57 -0
- package/dist/providers/openai-compat/client.d.ts.map +1 -0
- package/dist/providers/openai-compat/client.js +157 -0
- package/dist/providers/openai-compat/client.js.map +1 -0
- package/dist/providers/openai-compat/decode.d.ts +36 -0
- package/dist/providers/openai-compat/decode.d.ts.map +1 -0
- package/dist/providers/openai-compat/decode.js +55 -0
- package/dist/providers/openai-compat/decode.js.map +1 -0
- package/dist/providers/openai-compat/errors.d.ts +54 -0
- package/dist/providers/openai-compat/errors.d.ts.map +1 -0
- package/dist/providers/openai-compat/errors.js +144 -0
- package/dist/providers/openai-compat/errors.js.map +1 -0
- package/dist/providers/openai-compat/index.d.ts +8 -0
- package/dist/providers/openai-compat/index.d.ts.map +1 -0
- package/dist/providers/openai-compat/index.js +5 -0
- package/dist/providers/openai-compat/index.js.map +1 -0
- package/dist/providers/openai-compat/sse.d.ts +14 -0
- package/dist/providers/openai-compat/sse.d.ts.map +1 -0
- package/dist/providers/openai-compat/sse.js +69 -0
- package/dist/providers/openai-compat/sse.js.map +1 -0
- package/dist/providers/openai-compat/types.d.ts +75 -0
- package/dist/providers/openai-compat/types.d.ts.map +1 -0
- package/dist/providers/openai-compat/types.js +9 -0
- package/dist/providers/openai-compat/types.js.map +1 -0
- package/dist/providers/openai-compat-provider.d.ts +90 -0
- package/dist/providers/openai-compat-provider.d.ts.map +1 -0
- package/dist/providers/openai-compat-provider.js +282 -0
- package/dist/providers/openai-compat-provider.js.map +1 -0
- package/dist/providers/openai-provider.d.ts +89 -26
- package/dist/providers/openai-provider.d.ts.map +1 -1
- package/dist/providers/openai-provider.js +990 -105
- package/dist/providers/openai-provider.js.map +1 -1
- package/dist/providers/openrouter-provider.d.ts +6 -12
- package/dist/providers/openrouter-provider.d.ts.map +1 -1
- package/dist/providers/openrouter-provider.js +24 -53
- package/dist/providers/openrouter-provider.js.map +1 -1
- package/dist/providers/provider-call-failure.d.ts +39 -0
- package/dist/providers/provider-call-failure.d.ts.map +1 -0
- package/dist/providers/provider-call-failure.js +132 -0
- package/dist/providers/provider-call-failure.js.map +1 -0
- package/dist/providers/provider-error.d.ts +59 -0
- package/dist/providers/provider-error.d.ts.map +1 -0
- package/dist/providers/provider-error.js +165 -0
- package/dist/providers/provider-error.js.map +1 -0
- package/dist/providers/provider-generations.d.ts +99 -0
- package/dist/providers/provider-generations.d.ts.map +1 -0
- package/dist/providers/provider-generations.js +71 -0
- package/dist/providers/provider-generations.js.map +1 -0
- package/dist/providers/provider-queue.d.ts +62 -0
- package/dist/providers/provider-queue.d.ts.map +1 -0
- package/dist/providers/provider-queue.js +28 -0
- package/dist/providers/provider-queue.js.map +1 -0
- package/dist/providers/provider-registry.d.ts +33 -14
- package/dist/providers/provider-registry.d.ts.map +1 -1
- package/dist/providers/provider-registry.js +85 -68
- package/dist/providers/provider-registry.js.map +1 -1
- package/dist/providers/provider-request-log.d.ts +53 -0
- package/dist/providers/provider-request-log.d.ts.map +1 -0
- package/dist/providers/provider-request-log.js +157 -0
- package/dist/providers/provider-request-log.js.map +1 -0
- package/dist/providers/provider-session.d.ts +3 -0
- package/dist/providers/provider-session.d.ts.map +1 -0
- package/dist/providers/provider-session.js +10 -0
- package/dist/providers/provider-session.js.map +1 -0
- package/dist/providers/provider-transport.d.ts +11 -0
- package/dist/providers/provider-transport.d.ts.map +1 -0
- package/dist/providers/provider-transport.js +11 -0
- package/dist/providers/provider-transport.js.map +1 -0
- package/dist/providers/python-provider.d.ts +20 -12
- package/dist/providers/python-provider.d.ts.map +1 -1
- package/dist/providers/python-provider.js +185 -25
- package/dist/providers/python-provider.js.map +1 -1
- package/dist/providers/replicate-provider.d.ts +89 -7
- package/dist/providers/replicate-provider.d.ts.map +1 -1
- package/dist/providers/replicate-provider.js +801 -65
- package/dist/providers/replicate-provider.js.map +1 -1
- package/dist/providers/replicate-retry.d.ts +30 -0
- package/dist/providers/replicate-retry.d.ts.map +1 -0
- package/dist/providers/replicate-retry.js +97 -0
- package/dist/providers/replicate-retry.js.map +1 -0
- package/dist/providers/responses-api.d.ts +27 -0
- package/dist/providers/responses-api.d.ts.map +1 -0
- package/dist/providers/responses-api.js +297 -0
- package/dist/providers/responses-api.js.map +1 -0
- package/dist/providers/reve-provider.d.ts +45 -0
- package/dist/providers/reve-provider.d.ts.map +1 -0
- package/dist/providers/reve-provider.js +159 -0
- package/dist/providers/reve-provider.js.map +1 -0
- package/dist/providers/rodin-provider.d.ts +23 -1
- package/dist/providers/rodin-provider.d.ts.map +1 -1
- package/dist/providers/rodin-provider.js +89 -51
- package/dist/providers/rodin-provider.js.map +1 -1
- package/dist/providers/safe-url.d.ts +70 -0
- package/dist/providers/safe-url.d.ts.map +1 -0
- package/dist/providers/safe-url.js +277 -0
- package/dist/providers/safe-url.js.map +1 -0
- package/dist/providers/scripted-provider.d.ts +9 -0
- package/dist/providers/scripted-provider.d.ts.map +1 -1
- package/dist/providers/scripted-provider.js +86 -10
- package/dist/providers/scripted-provider.js.map +1 -1
- package/dist/providers/structured-output.d.ts +42 -0
- package/dist/providers/structured-output.d.ts.map +1 -0
- package/dist/providers/structured-output.js +83 -0
- package/dist/providers/structured-output.js.map +1 -0
- package/dist/providers/together-provider.d.ts +19 -16
- package/dist/providers/together-provider.d.ts.map +1 -1
- package/dist/providers/together-provider.js +103 -225
- package/dist/providers/together-provider.js.map +1 -1
- package/dist/providers/topaz-provider.d.ts +44 -0
- package/dist/providers/topaz-provider.d.ts.map +1 -0
- package/dist/providers/topaz-provider.js +239 -0
- package/dist/providers/topaz-provider.js.map +1 -0
- package/dist/providers/types.d.ts +603 -4
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/types.js +81 -1
- package/dist/providers/types.js.map +1 -1
- package/dist/providers/useapi-provider.d.ts +27 -0
- package/dist/providers/useapi-provider.d.ts.map +1 -0
- package/dist/providers/useapi-provider.js +266 -0
- package/dist/providers/useapi-provider.js.map +1 -0
- package/dist/providers/video-duration.d.ts +6 -0
- package/dist/providers/video-duration.d.ts.map +1 -0
- package/dist/providers/video-duration.js +63 -0
- package/dist/providers/video-duration.js.map +1 -0
- package/dist/providers/video-frame-fallback.d.ts +39 -0
- package/dist/providers/video-frame-fallback.d.ts.map +1 -0
- package/dist/providers/video-frame-fallback.js +155 -0
- package/dist/providers/video-frame-fallback.js.map +1 -0
- package/dist/providers/video-frames.d.ts +61 -0
- package/dist/providers/video-frames.d.ts.map +1 -0
- package/dist/providers/video-frames.js +208 -0
- package/dist/providers/video-frames.js.map +1 -0
- package/dist/providers/video-mime.d.ts +14 -0
- package/dist/providers/video-mime.d.ts.map +1 -0
- package/dist/providers/video-mime.js +44 -0
- package/dist/providers/video-mime.js.map +1 -0
- package/dist/providers/video-to-audio.d.ts +34 -0
- package/dist/providers/video-to-audio.d.ts.map +1 -0
- package/dist/providers/video-to-audio.js +62 -0
- package/dist/providers/video-to-audio.js.map +1 -0
- package/dist/providers/vllm-provider.d.ts +22 -8
- package/dist/providers/vllm-provider.d.ts.map +1 -1
- package/dist/providers/vllm-provider.js +48 -23
- package/dist/providers/vllm-provider.js.map +1 -1
- package/dist/providers/voyage-provider.d.ts +10 -2
- package/dist/providers/voyage-provider.d.ts.map +1 -1
- package/dist/providers/voyage-provider.js +16 -7
- package/dist/providers/voyage-provider.js.map +1 -1
- package/dist/providers/xai-provider.d.ts +54 -13
- package/dist/providers/xai-provider.d.ts.map +1 -1
- package/dist/providers/xai-provider.js +299 -22
- package/dist/providers/xai-provider.js.map +1 -1
- package/dist/python-bridge-base.d.ts +358 -0
- package/dist/python-bridge-base.d.ts.map +1 -0
- package/dist/python-bridge-base.js +1557 -0
- package/dist/python-bridge-base.js.map +1 -0
- package/dist/python-bridge-codec.d.ts +28 -0
- package/dist/python-bridge-codec.d.ts.map +1 -0
- package/dist/python-bridge-codec.js +39 -0
- package/dist/python-bridge-codec.js.map +1 -0
- package/dist/python-bridge-factory.d.ts +52 -0
- package/dist/python-bridge-factory.d.ts.map +1 -0
- package/dist/python-bridge-factory.js +69 -0
- package/dist/python-bridge-factory.js.map +1 -0
- package/dist/python-bridge-framing.d.ts +68 -0
- package/dist/python-bridge-framing.d.ts.map +1 -0
- package/dist/python-bridge-framing.js +91 -0
- package/dist/python-bridge-framing.js.map +1 -0
- package/dist/python-bridge-types.d.ts +545 -2
- package/dist/python-bridge-types.d.ts.map +1 -1
- package/dist/python-bridge-types.js +49 -1
- package/dist/python-bridge-types.js.map +1 -1
- package/dist/python-graph-resolver.d.ts +57 -0
- package/dist/python-graph-resolver.d.ts.map +1 -0
- package/dist/python-graph-resolver.js +79 -0
- package/dist/python-graph-resolver.js.map +1 -0
- package/dist/python-node-executor.d.ts +36 -4
- package/dist/python-node-executor.d.ts.map +1 -1
- package/dist/python-node-executor.js +177 -86
- package/dist/python-node-executor.js.map +1 -1
- package/dist/python-stdio-bridge.d.ts +18 -37
- package/dist/python-stdio-bridge.d.ts.map +1 -1
- package/dist/python-stdio-bridge.js +148 -475
- package/dist/python-stdio-bridge.js.map +1 -1
- package/dist/python-websocket-bridge.d.ts +140 -0
- package/dist/python-websocket-bridge.d.ts.map +1 -0
- package/dist/python-websocket-bridge.js +561 -0
- package/dist/python-websocket-bridge.js.map +1 -0
- package/dist/python-worker-stderr.d.ts +4 -0
- package/dist/python-worker-stderr.d.ts.map +1 -0
- package/dist/python-worker-stderr.js +24 -0
- package/dist/python-worker-stderr.js.map +1 -0
- package/dist/recommended-models.d.ts +2 -2
- package/dist/recommended-models.d.ts.map +1 -1
- package/dist/recommended-models.js +24 -4
- package/dist/recommended-models.js.map +1 -1
- package/dist/recoverable-node-error.d.ts +31 -0
- package/dist/recoverable-node-error.d.ts.map +1 -0
- package/dist/recoverable-node-error.js +37 -0
- package/dist/recoverable-node-error.js.map +1 -0
- package/dist/redact-params.d.ts +13 -0
- package/dist/redact-params.d.ts.map +1 -0
- package/dist/redact-params.js +57 -0
- package/dist/redact-params.js.map +1 -0
- package/dist/sandbox-module-catalog.d.ts +43 -0
- package/dist/sandbox-module-catalog.d.ts.map +1 -0
- package/dist/sandbox-module-catalog.js +25 -0
- package/dist/sandbox-module-catalog.js.map +1 -0
- package/dist/storage-workspace.d.ts +59 -0
- package/dist/storage-workspace.d.ts.map +1 -0
- package/dist/storage-workspace.js +426 -0
- package/dist/storage-workspace.js.map +1 -0
- package/dist/swappable-python-bridge.d.ts +83 -0
- package/dist/swappable-python-bridge.d.ts.map +1 -0
- package/dist/swappable-python-bridge.js +246 -0
- package/dist/swappable-python-bridge.js.map +1 -0
- package/dist/telemetry.d.ts +7 -0
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +23 -0
- package/dist/telemetry.js.map +1 -1
- package/dist/testing.d.ts +81 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +130 -0
- package/dist/testing.js.map +1 -0
- package/dist/token-counter.d.ts +30 -0
- package/dist/token-counter.d.ts.map +1 -0
- package/dist/token-counter.js +156 -0
- package/dist/token-counter.js.map +1 -0
- package/dist/trace-exporters.d.ts +10 -0
- package/dist/trace-exporters.d.ts.map +1 -1
- package/dist/trace-exporters.js +59 -20
- package/dist/trace-exporters.js.map +1 -1
- package/dist/tracing-helpers.d.ts +45 -4
- package/dist/tracing-helpers.d.ts.map +1 -1
- package/dist/tracing-helpers.js +62 -19
- package/dist/tracing-helpers.js.map +1 -1
- package/dist/turn-budget.d.ts +278 -0
- package/dist/turn-budget.d.ts.map +1 -0
- package/dist/turn-budget.js +365 -0
- package/dist/turn-budget.js.map +1 -0
- package/dist/variable-channel.d.ts +48 -0
- package/dist/variable-channel.d.ts.map +1 -0
- package/dist/variable-channel.js +110 -0
- package/dist/variable-channel.js.map +1 -0
- package/dist/workspace.d.ts +119 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +112 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +107 -19
|
@@ -1,20 +1,277 @@
|
|
|
1
1
|
import Anthropic from "@anthropic-ai/sdk";
|
|
2
2
|
import { createLogger } from "@nodetool-ai/config";
|
|
3
3
|
import { BaseProvider } from "./base-provider.js";
|
|
4
|
+
import { anthropicContextExceeded } from "./context-exceeded.js";
|
|
5
|
+
import { safeFetch } from "./safe-url.js";
|
|
6
|
+
import { isNumber, isObjectLike, isRecord, isString } from "@nodetool-ai/protocol";
|
|
4
7
|
const log = createLogger("nodetool.runtime.providers.anthropic");
|
|
8
|
+
import { WEB_SEARCH_TOOL_NAME } from "./types.js";
|
|
9
|
+
const MAX_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
10
|
+
const MAX_PAUSE_TURN_CONTINUATIONS = 5;
|
|
11
|
+
function toRawBlock(block) {
|
|
12
|
+
return Object.fromEntries(Object.entries(block));
|
|
13
|
+
}
|
|
14
|
+
function retryAfterMs(value) {
|
|
15
|
+
if (!value)
|
|
16
|
+
return null;
|
|
17
|
+
const seconds = Number(value);
|
|
18
|
+
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
19
|
+
return Math.min(seconds * 1000, 60_000);
|
|
20
|
+
}
|
|
21
|
+
const date = Date.parse(value);
|
|
22
|
+
if (Number.isNaN(date))
|
|
23
|
+
return null;
|
|
24
|
+
return Math.min(Math.max(date - Date.now(), 0), 60_000);
|
|
25
|
+
}
|
|
26
|
+
function apiErrorStatus(error) {
|
|
27
|
+
if (isObjectLike(error) && "status" in error && isNumber(error.status)) {
|
|
28
|
+
return error.status;
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
function apiErrorRetryAfter(error) {
|
|
33
|
+
if (isObjectLike(error) &&
|
|
34
|
+
"headers" in error &&
|
|
35
|
+
error.headers instanceof Headers) {
|
|
36
|
+
return error.headers.get("retry-after");
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
function mapCitation(citation) {
|
|
41
|
+
switch (citation.type) {
|
|
42
|
+
case "char_location":
|
|
43
|
+
return {
|
|
44
|
+
type: citation.type,
|
|
45
|
+
citedText: citation.cited_text,
|
|
46
|
+
documentIndex: citation.document_index,
|
|
47
|
+
documentTitle: citation.document_title,
|
|
48
|
+
fileId: citation.file_id,
|
|
49
|
+
startCharIndex: citation.start_char_index,
|
|
50
|
+
endCharIndex: citation.end_char_index
|
|
51
|
+
};
|
|
52
|
+
case "page_location":
|
|
53
|
+
return {
|
|
54
|
+
type: citation.type,
|
|
55
|
+
citedText: citation.cited_text,
|
|
56
|
+
documentIndex: citation.document_index,
|
|
57
|
+
documentTitle: citation.document_title,
|
|
58
|
+
fileId: citation.file_id,
|
|
59
|
+
startPageNumber: citation.start_page_number,
|
|
60
|
+
endPageNumber: citation.end_page_number
|
|
61
|
+
};
|
|
62
|
+
case "content_block_location":
|
|
63
|
+
return {
|
|
64
|
+
type: citation.type,
|
|
65
|
+
citedText: citation.cited_text,
|
|
66
|
+
documentIndex: citation.document_index,
|
|
67
|
+
documentTitle: citation.document_title,
|
|
68
|
+
fileId: citation.file_id,
|
|
69
|
+
startBlockIndex: citation.start_block_index,
|
|
70
|
+
endBlockIndex: citation.end_block_index
|
|
71
|
+
};
|
|
72
|
+
case "web_search_result_location":
|
|
73
|
+
return {
|
|
74
|
+
type: citation.type,
|
|
75
|
+
citedText: citation.cited_text,
|
|
76
|
+
encryptedIndex: citation.encrypted_index,
|
|
77
|
+
url: citation.url,
|
|
78
|
+
title: citation.title
|
|
79
|
+
};
|
|
80
|
+
case "search_result_location":
|
|
81
|
+
return {
|
|
82
|
+
type: citation.type,
|
|
83
|
+
citedText: citation.cited_text,
|
|
84
|
+
searchResultIndex: citation.search_result_index,
|
|
85
|
+
source: citation.source,
|
|
86
|
+
title: citation.title,
|
|
87
|
+
startBlockIndex: citation.start_block_index,
|
|
88
|
+
endBlockIndex: citation.end_block_index
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function textContentFromRawBlocks(blocks) {
|
|
93
|
+
return blocks.flatMap((block) => {
|
|
94
|
+
if (block?.type !== "text" || !isString(block.text))
|
|
95
|
+
return [];
|
|
96
|
+
const citations = Array.isArray(block.citations)
|
|
97
|
+
? block.citations.map(mapCitation)
|
|
98
|
+
: undefined;
|
|
99
|
+
const content = {
|
|
100
|
+
type: "text",
|
|
101
|
+
text: block.text
|
|
102
|
+
};
|
|
103
|
+
if (citations && citations.length > 0) {
|
|
104
|
+
content.citations = citations;
|
|
105
|
+
}
|
|
106
|
+
return [content];
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
function toAnthropicCitation(citation) {
|
|
110
|
+
switch (citation.type) {
|
|
111
|
+
case "char_location":
|
|
112
|
+
return {
|
|
113
|
+
type: citation.type,
|
|
114
|
+
cited_text: citation.citedText,
|
|
115
|
+
document_index: citation.documentIndex,
|
|
116
|
+
document_title: citation.documentTitle ?? null,
|
|
117
|
+
file_id: citation.fileId ?? null,
|
|
118
|
+
start_char_index: citation.startCharIndex,
|
|
119
|
+
end_char_index: citation.endCharIndex
|
|
120
|
+
};
|
|
121
|
+
case "page_location":
|
|
122
|
+
return {
|
|
123
|
+
type: citation.type,
|
|
124
|
+
cited_text: citation.citedText,
|
|
125
|
+
document_index: citation.documentIndex,
|
|
126
|
+
document_title: citation.documentTitle ?? null,
|
|
127
|
+
file_id: citation.fileId ?? null,
|
|
128
|
+
start_page_number: citation.startPageNumber,
|
|
129
|
+
end_page_number: citation.endPageNumber
|
|
130
|
+
};
|
|
131
|
+
case "content_block_location":
|
|
132
|
+
return {
|
|
133
|
+
type: citation.type,
|
|
134
|
+
cited_text: citation.citedText,
|
|
135
|
+
document_index: citation.documentIndex,
|
|
136
|
+
document_title: citation.documentTitle ?? null,
|
|
137
|
+
file_id: citation.fileId ?? null,
|
|
138
|
+
start_block_index: citation.startBlockIndex,
|
|
139
|
+
end_block_index: citation.endBlockIndex
|
|
140
|
+
};
|
|
141
|
+
case "web_search_result_location":
|
|
142
|
+
return {
|
|
143
|
+
type: citation.type,
|
|
144
|
+
cited_text: citation.citedText,
|
|
145
|
+
encrypted_index: citation.encryptedIndex,
|
|
146
|
+
url: citation.url,
|
|
147
|
+
title: citation.title ?? null
|
|
148
|
+
};
|
|
149
|
+
case "search_result_location":
|
|
150
|
+
return {
|
|
151
|
+
type: citation.type,
|
|
152
|
+
cited_text: citation.citedText,
|
|
153
|
+
search_result_index: citation.searchResultIndex,
|
|
154
|
+
source: citation.source,
|
|
155
|
+
title: citation.title ?? null,
|
|
156
|
+
start_block_index: citation.startBlockIndex,
|
|
157
|
+
end_block_index: citation.endBlockIndex
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* The tool fields Anthropic accepts on every tool form, with each one the
|
|
163
|
+
* caller left unset omitted.
|
|
164
|
+
*/
|
|
165
|
+
function sharedToolFields(tool) {
|
|
166
|
+
const fields = {};
|
|
167
|
+
if (tool.cacheControl) {
|
|
168
|
+
fields.cache_control = tool.cacheControl;
|
|
169
|
+
}
|
|
170
|
+
if (tool.strict !== undefined) {
|
|
171
|
+
fields.strict = tool.strict;
|
|
172
|
+
}
|
|
173
|
+
if (tool.deferLoading !== undefined) {
|
|
174
|
+
fields.defer_loading = tool.deferLoading;
|
|
175
|
+
}
|
|
176
|
+
if (tool.allowedCallers) {
|
|
177
|
+
fields.allowed_callers = tool.allowedCallers;
|
|
178
|
+
}
|
|
179
|
+
return fields;
|
|
180
|
+
}
|
|
181
|
+
function toAnthropicTextBlock(part) {
|
|
182
|
+
const block = {
|
|
183
|
+
type: "text",
|
|
184
|
+
text: part.text
|
|
185
|
+
};
|
|
186
|
+
if (part.citations) {
|
|
187
|
+
block.citations = part.citations.map(toAnthropicCitation);
|
|
188
|
+
}
|
|
189
|
+
return block;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Anthropic requires every `tool_result` block for one assistant turn to live
|
|
193
|
+
* in a single user message. `convertMessage` emits one user message per
|
|
194
|
+
* `role: "tool"` message, so parallel tool calls would produce consecutive user
|
|
195
|
+
* messages and a 400. Merge them back into one.
|
|
196
|
+
*/
|
|
197
|
+
function mergeToolResultMessages(messages) {
|
|
198
|
+
const isToolResultMessage = (m) => m.role === "user" &&
|
|
199
|
+
Array.isArray(m.content) &&
|
|
200
|
+
m.content.length > 0 &&
|
|
201
|
+
m.content.every((block) => isObjectLike(block) &&
|
|
202
|
+
block.type === "tool_result");
|
|
203
|
+
const merged = [];
|
|
204
|
+
for (const message of messages) {
|
|
205
|
+
const previous = merged[merged.length - 1];
|
|
206
|
+
if (previous &&
|
|
207
|
+
isToolResultMessage(previous) &&
|
|
208
|
+
isToolResultMessage(message)) {
|
|
209
|
+
merged[merged.length - 1] = {
|
|
210
|
+
...previous,
|
|
211
|
+
content: [
|
|
212
|
+
...previous.content,
|
|
213
|
+
...message.content
|
|
214
|
+
]
|
|
215
|
+
};
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
merged.push(message);
|
|
219
|
+
}
|
|
220
|
+
return merged;
|
|
221
|
+
}
|
|
222
|
+
function thinkingPolicy(model) {
|
|
223
|
+
const id = model.toLowerCase();
|
|
224
|
+
if (id.includes("claude-fable-5") ||
|
|
225
|
+
id.includes("claude-mythos-5") ||
|
|
226
|
+
id.includes("claude-mythos-preview")) {
|
|
227
|
+
return "adaptive_required";
|
|
228
|
+
}
|
|
229
|
+
if (id.includes("claude-sonnet-5"))
|
|
230
|
+
return "adaptive_default";
|
|
231
|
+
if (id.includes("claude-opus-4-7") || id.includes("claude-opus-4-8")) {
|
|
232
|
+
return "adaptive_optional";
|
|
233
|
+
}
|
|
234
|
+
return "manual";
|
|
235
|
+
}
|
|
236
|
+
function rejectsCustomSampling(model) {
|
|
237
|
+
return thinkingPolicy(model) !== "manual";
|
|
238
|
+
}
|
|
5
239
|
function isTextContent(content) {
|
|
6
240
|
return content.type === "text";
|
|
7
241
|
}
|
|
8
242
|
function isImageContent(content) {
|
|
9
243
|
return content.type === "image_url";
|
|
10
244
|
}
|
|
245
|
+
function isDocumentContent(content) {
|
|
246
|
+
return content.type === "document";
|
|
247
|
+
}
|
|
11
248
|
function bytesToBase64(data) {
|
|
12
249
|
if (!data)
|
|
13
250
|
return "";
|
|
14
|
-
if (
|
|
251
|
+
if (isString(data))
|
|
15
252
|
return data;
|
|
16
253
|
return Buffer.from(data).toString("base64");
|
|
17
254
|
}
|
|
255
|
+
function assertImageSize(base64) {
|
|
256
|
+
if (Buffer.byteLength(base64, "base64") > MAX_IMAGE_BYTES) {
|
|
257
|
+
throw new Error("Anthropic image exceeds the 5 MB limit");
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Anthropic's image block accepts only image/jpeg, image/png, image/gif and
|
|
262
|
+
* image/webp as `media_type`. Strip any Content-Type parameters, normalize the
|
|
263
|
+
* common `image/jpg` alias, and reject unsupported media types.
|
|
264
|
+
*/
|
|
265
|
+
function normalizeAnthropicImageMime(mime) {
|
|
266
|
+
const base = mime.split(";")[0].trim().toLowerCase();
|
|
267
|
+
if (base === "image/jpg")
|
|
268
|
+
return "image/jpeg";
|
|
269
|
+
const supported = ["image/jpeg", "image/png", "image/gif", "image/webp"];
|
|
270
|
+
if (!supported.includes(base)) {
|
|
271
|
+
throw new Error(`Anthropic does not support image media type ${base}`);
|
|
272
|
+
}
|
|
273
|
+
return base;
|
|
274
|
+
}
|
|
18
275
|
function parseDataUri(uri) {
|
|
19
276
|
const idx = uri.indexOf(",");
|
|
20
277
|
if (idx < 0) {
|
|
@@ -33,30 +290,65 @@ function parseDataUri(uri) {
|
|
|
33
290
|
};
|
|
34
291
|
}
|
|
35
292
|
export class AnthropicProvider extends BaseProvider {
|
|
293
|
+
/**
|
|
294
|
+
* Anthropic runs web search server-side via the `web_search_20250305` server
|
|
295
|
+
* tool. Gate on the provider id so subclasses that reuse the Anthropic SDK
|
|
296
|
+
* against a different endpoint (gateways that don't implement that server
|
|
297
|
+
* tool) fall back to the SerpAPI WebSearchTool instead of sending an
|
|
298
|
+
* unsupported tool that silently breaks web search.
|
|
299
|
+
*/
|
|
300
|
+
get supportsNativeWebSearch() {
|
|
301
|
+
return this.provider === "anthropic";
|
|
302
|
+
}
|
|
36
303
|
static requiredSecrets() {
|
|
37
304
|
return ["ANTHROPIC_API_KEY"];
|
|
38
305
|
}
|
|
39
306
|
apiKey;
|
|
307
|
+
authToken;
|
|
40
308
|
_client;
|
|
41
309
|
_clientFactory;
|
|
42
310
|
_fetch;
|
|
311
|
+
_clientOptions;
|
|
312
|
+
_cacheControl;
|
|
313
|
+
_betas;
|
|
43
314
|
constructor(secrets, options = {}) {
|
|
44
|
-
super("anthropic");
|
|
45
|
-
const apiKey = secrets.ANTHROPIC_API_KEY;
|
|
46
|
-
|
|
47
|
-
|
|
315
|
+
super(options.providerId ?? "anthropic");
|
|
316
|
+
const apiKey = secrets.ANTHROPIC_API_KEY?.trim() ?? "";
|
|
317
|
+
const authToken = secrets.ANTHROPIC_AUTH_TOKEN?.trim() ??
|
|
318
|
+
options.clientOptions?.authToken?.trim() ??
|
|
319
|
+
"";
|
|
320
|
+
const hasStructuredAuth = Boolean(options.clientOptions?.credentials ||
|
|
321
|
+
options.clientOptions?.config ||
|
|
322
|
+
options.clientOptions?.profile);
|
|
323
|
+
if (!apiKey && !authToken && !hasStructuredAuth) {
|
|
324
|
+
throw new Error("Anthropic authentication is not configured (API key, auth token, credentials, config, or profile required)");
|
|
48
325
|
}
|
|
49
326
|
this.apiKey = apiKey;
|
|
327
|
+
this.authToken = authToken;
|
|
50
328
|
this._client = options.client ?? null;
|
|
329
|
+
this._clientOptions = options.clientOptions;
|
|
330
|
+
this._cacheControl = options.cacheControl;
|
|
331
|
+
this._betas = options.betas ?? [];
|
|
51
332
|
this._clientFactory =
|
|
52
333
|
options.clientFactory ??
|
|
53
|
-
((key) =>
|
|
54
|
-
|
|
55
|
-
|
|
334
|
+
((key) => {
|
|
335
|
+
const clientOptions = { ...this._clientOptions };
|
|
336
|
+
if (key) {
|
|
337
|
+
clientOptions.apiKey = key;
|
|
338
|
+
}
|
|
339
|
+
if (this.authToken) {
|
|
340
|
+
clientOptions.authToken = this.authToken;
|
|
341
|
+
}
|
|
342
|
+
return new Anthropic(clientOptions);
|
|
343
|
+
});
|
|
56
344
|
this._fetch = options.fetchFn ?? globalThis.fetch.bind(globalThis);
|
|
57
345
|
}
|
|
58
346
|
getContainerEnv() {
|
|
59
|
-
|
|
347
|
+
if (this.apiKey)
|
|
348
|
+
return { ANTHROPIC_API_KEY: this.apiKey };
|
|
349
|
+
if (this.authToken)
|
|
350
|
+
return { ANTHROPIC_AUTH_TOKEN: this.authToken };
|
|
351
|
+
return {};
|
|
60
352
|
}
|
|
61
353
|
getClient() {
|
|
62
354
|
if (!this._client) {
|
|
@@ -64,217 +356,347 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
64
356
|
}
|
|
65
357
|
return this._client;
|
|
66
358
|
}
|
|
359
|
+
requestOptions(signal) {
|
|
360
|
+
const options = {};
|
|
361
|
+
if (signal) {
|
|
362
|
+
options.signal = signal;
|
|
363
|
+
}
|
|
364
|
+
if (this._betas.length > 0) {
|
|
365
|
+
options.headers = { "anthropic-beta": this._betas.join(",") };
|
|
366
|
+
}
|
|
367
|
+
return options;
|
|
368
|
+
}
|
|
67
369
|
async hasToolSupport(_model) {
|
|
68
370
|
return true;
|
|
69
371
|
}
|
|
372
|
+
/**
|
|
373
|
+
* `max_input_tokens` from the Models API. The request carries the same
|
|
374
|
+
* `anthropic-beta` header as Messages, so a 1M-context beta reports the 1M
|
|
375
|
+
* window. Null when the endpoint fails, as it does on gateways that reuse
|
|
376
|
+
* this provider without implementing it.
|
|
377
|
+
*/
|
|
378
|
+
async getContextWindow(model) {
|
|
379
|
+
try {
|
|
380
|
+
const info = await this.getClient().models.retrieve(model, null, {
|
|
381
|
+
...this.requestOptions(),
|
|
382
|
+
timeout: 10_000,
|
|
383
|
+
maxRetries: 0
|
|
384
|
+
});
|
|
385
|
+
return info.max_input_tokens ?? null;
|
|
386
|
+
}
|
|
387
|
+
catch (error) {
|
|
388
|
+
log.debug("Anthropic model lookup failed", {
|
|
389
|
+
model,
|
|
390
|
+
error: error instanceof Error ? error.message : String(error)
|
|
391
|
+
});
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
70
395
|
async getAvailableLanguageModels() {
|
|
71
396
|
const maxRetries = 3;
|
|
72
|
-
const baseDelay = 1000; // ms
|
|
73
|
-
let lastError = null;
|
|
74
397
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
75
398
|
try {
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
status: response.status
|
|
90
|
-
});
|
|
91
|
-
return [];
|
|
92
|
-
}
|
|
93
|
-
// Retry on rate limit or server errors
|
|
94
|
-
if ([429, 500, 502, 503, 504].includes(response.status)) {
|
|
95
|
-
log.warn("Anthropic API error, retrying", {
|
|
96
|
-
status: response.status,
|
|
97
|
-
attempt: attempt + 1,
|
|
98
|
-
maxRetries
|
|
399
|
+
const models = [];
|
|
400
|
+
let afterId;
|
|
401
|
+
do {
|
|
402
|
+
const listParams = {
|
|
403
|
+
limit: 1000
|
|
404
|
+
};
|
|
405
|
+
if (afterId) {
|
|
406
|
+
listParams.after_id = afterId;
|
|
407
|
+
}
|
|
408
|
+
const page = await this.getClient().models.list(listParams, {
|
|
409
|
+
...this.requestOptions(),
|
|
410
|
+
timeout: 10_000,
|
|
411
|
+
maxRetries: 0
|
|
99
412
|
});
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
413
|
+
models.push(...page.data.map((model) => ({
|
|
414
|
+
id: model.id,
|
|
415
|
+
name: model.display_name,
|
|
416
|
+
provider: "anthropic"
|
|
417
|
+
})));
|
|
418
|
+
if (page.has_more && !page.last_id) {
|
|
419
|
+
throw new Error("Anthropic Models API returned has_more without last_id");
|
|
103
420
|
}
|
|
421
|
+
afterId = page.has_more ? (page.last_id ?? undefined) : undefined;
|
|
422
|
+
} while (afterId);
|
|
423
|
+
return models;
|
|
424
|
+
}
|
|
425
|
+
catch (error) {
|
|
426
|
+
const status = apiErrorStatus(error);
|
|
427
|
+
if (status === 401 || status === 403)
|
|
104
428
|
return [];
|
|
105
|
-
|
|
106
|
-
|
|
429
|
+
if (attempt === maxRetries - 1 ||
|
|
430
|
+
(status !== undefined &&
|
|
431
|
+
![429, 500, 502, 503, 504, 529].includes(status))) {
|
|
107
432
|
log.warn("Failed to fetch Anthropic models", {
|
|
108
|
-
|
|
433
|
+
error: error instanceof Error ? error.message : String(error),
|
|
434
|
+
status
|
|
109
435
|
});
|
|
110
436
|
return [];
|
|
111
437
|
}
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
.map((m) => m.id ?? m.name)
|
|
115
|
-
.filter((id) => typeof id === "string" && id.length > 0)
|
|
116
|
-
.map((id) => ({ id, name: id, provider: "anthropic" }));
|
|
117
|
-
}
|
|
118
|
-
catch (err) {
|
|
119
|
-
lastError = err instanceof Error ? err : new Error(String(err));
|
|
120
|
-
// AbortError means timeout
|
|
121
|
-
if (lastError.name === "AbortError") {
|
|
122
|
-
log.warn("Anthropic API timeout", {
|
|
123
|
-
attempt: attempt + 1,
|
|
124
|
-
maxRetries
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
else {
|
|
128
|
-
log.warn("Anthropic API connection error", {
|
|
129
|
-
error: lastError.message,
|
|
130
|
-
attempt: attempt + 1,
|
|
131
|
-
maxRetries
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
if (attempt < maxRetries - 1) {
|
|
135
|
-
await new Promise((r) => setTimeout(r, baseDelay * 2 ** attempt));
|
|
136
|
-
}
|
|
438
|
+
const delay = retryAfterMs(apiErrorRetryAfter(error)) ?? 1000 * 2 ** attempt;
|
|
439
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
137
440
|
}
|
|
138
441
|
}
|
|
139
|
-
log.error("Failed to fetch Anthropic models after retries", {
|
|
140
|
-
error: lastError?.message
|
|
141
|
-
});
|
|
142
442
|
return [];
|
|
143
443
|
}
|
|
144
444
|
prepareJsonSchema(schema) {
|
|
145
|
-
if (!
|
|
445
|
+
if (!isRecord(schema)) {
|
|
446
|
+
// SAFETY: a schema node that is not an object is carried through as it
|
|
447
|
+
// stands — a scalar, a list, or an absent schema.
|
|
146
448
|
return schema;
|
|
147
449
|
}
|
|
148
|
-
const obj = {
|
|
450
|
+
const obj = {
|
|
451
|
+
// SAFETY: the checks above proved `schema` is a plain object of schema
|
|
452
|
+
// members.
|
|
453
|
+
...schema
|
|
454
|
+
};
|
|
149
455
|
if (obj.type === "object" && obj.additionalProperties === undefined) {
|
|
150
456
|
obj.additionalProperties = false;
|
|
151
457
|
}
|
|
152
|
-
if (obj.properties
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
458
|
+
if (isRecord(obj.properties)) {
|
|
459
|
+
obj.properties = Object.fromEntries(Object.entries(obj.properties).map(([k, v]) => [
|
|
460
|
+
k,
|
|
461
|
+
this.prepareJsonSchema(v)
|
|
462
|
+
]));
|
|
156
463
|
}
|
|
157
|
-
if (obj.items
|
|
464
|
+
if (isObjectLike(obj.items)) {
|
|
158
465
|
obj.items = this.prepareJsonSchema(obj.items);
|
|
159
466
|
}
|
|
160
467
|
for (const defsKey of ["definitions", "$defs"]) {
|
|
161
468
|
const defs = obj[defsKey];
|
|
162
|
-
if (
|
|
163
|
-
obj[defsKey] = Object.fromEntries(Object.entries(defs).map(([k, v]) => [
|
|
164
|
-
|
|
165
|
-
this.prepareJsonSchema(v)
|
|
166
|
-
]));
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
const unsupported = [
|
|
170
|
-
"default",
|
|
171
|
-
"minimum",
|
|
172
|
-
"maximum",
|
|
173
|
-
"exclusiveMinimum",
|
|
174
|
-
"exclusiveMaximum",
|
|
175
|
-
"multipleOf",
|
|
176
|
-
"minLength",
|
|
177
|
-
"maxLength",
|
|
178
|
-
"minProperties",
|
|
179
|
-
"maxProperties",
|
|
180
|
-
"minItems",
|
|
181
|
-
"maxItems",
|
|
182
|
-
"uniqueItems"
|
|
183
|
-
];
|
|
184
|
-
for (const key of unsupported) {
|
|
185
|
-
delete obj[key];
|
|
469
|
+
if (isRecord(defs)) {
|
|
470
|
+
obj[defsKey] = Object.fromEntries(Object.entries(defs).map(([k, v]) => [k, this.prepareJsonSchema(v)]));
|
|
471
|
+
}
|
|
186
472
|
}
|
|
187
473
|
return obj;
|
|
188
474
|
}
|
|
189
|
-
|
|
475
|
+
/**
|
|
476
|
+
* Convert a {@link MessageImageContent} part into an Anthropic image block
|
|
477
|
+
* (`{ type: "image", source: { type: "base64", ... } }`), resolving data
|
|
478
|
+
* URIs, raw base64, and remote/storage URIs (which are fetched and encoded).
|
|
479
|
+
*/
|
|
480
|
+
async convertImagePart(part, signal) {
|
|
481
|
+
const rawData = bytesToBase64(part.image.data);
|
|
482
|
+
const uri = part.image.uri ?? "";
|
|
483
|
+
let mediaType = part.image.mimeType ?? "image/png";
|
|
484
|
+
let base64;
|
|
485
|
+
if (rawData) {
|
|
486
|
+
if (rawData.startsWith("data:")) {
|
|
487
|
+
const parsed = parseDataUri(rawData);
|
|
488
|
+
if (part.image.mimeType &&
|
|
489
|
+
normalizeAnthropicImageMime(part.image.mimeType) !==
|
|
490
|
+
normalizeAnthropicImageMime(parsed.mime)) {
|
|
491
|
+
throw new Error("Anthropic image data URI MIME mismatch");
|
|
492
|
+
}
|
|
493
|
+
base64 = parsed.base64;
|
|
494
|
+
mediaType = part.image.mimeType ?? parsed.mime;
|
|
495
|
+
}
|
|
496
|
+
else {
|
|
497
|
+
base64 = rawData;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
else if (uri.startsWith("data:")) {
|
|
501
|
+
const parsed = parseDataUri(uri);
|
|
502
|
+
if (part.image.mimeType &&
|
|
503
|
+
normalizeAnthropicImageMime(part.image.mimeType) !==
|
|
504
|
+
normalizeAnthropicImageMime(parsed.mime)) {
|
|
505
|
+
throw new Error("Anthropic image data URI MIME mismatch");
|
|
506
|
+
}
|
|
507
|
+
base64 = parsed.base64;
|
|
508
|
+
mediaType = part.image.mimeType ?? parsed.mime;
|
|
509
|
+
}
|
|
510
|
+
else if (uri) {
|
|
511
|
+
const resolved = await this.resolveUri(uri);
|
|
512
|
+
if (resolved.startsWith("data:")) {
|
|
513
|
+
const parsed = parseDataUri(resolved);
|
|
514
|
+
if (part.image.mimeType &&
|
|
515
|
+
normalizeAnthropicImageMime(part.image.mimeType) !==
|
|
516
|
+
normalizeAnthropicImageMime(parsed.mime)) {
|
|
517
|
+
throw new Error("Anthropic image data URI MIME mismatch");
|
|
518
|
+
}
|
|
519
|
+
base64 = parsed.base64;
|
|
520
|
+
mediaType = part.image.mimeType ?? parsed.mime;
|
|
521
|
+
}
|
|
522
|
+
else {
|
|
523
|
+
const response = await safeFetch(resolved, signal ? { signal } : undefined, 5, this._fetch);
|
|
524
|
+
if (!response.ok) {
|
|
525
|
+
throw new Error(`Failed to fetch URI: ${response.status}`);
|
|
526
|
+
}
|
|
527
|
+
const contentLength = Number(response.headers.get("content-length"));
|
|
528
|
+
if (Number.isFinite(contentLength) && contentLength > MAX_IMAGE_BYTES) {
|
|
529
|
+
throw new Error("Anthropic image exceeds the 5 MB limit");
|
|
530
|
+
}
|
|
531
|
+
mediaType =
|
|
532
|
+
part.image.mimeType ??
|
|
533
|
+
response.headers.get("content-type") ??
|
|
534
|
+
"image/png";
|
|
535
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
536
|
+
if (bytes.byteLength > MAX_IMAGE_BYTES) {
|
|
537
|
+
throw new Error("Anthropic image exceeds the 5 MB limit");
|
|
538
|
+
}
|
|
539
|
+
base64 = Buffer.from(bytes).toString("base64");
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
else {
|
|
543
|
+
throw new Error("Invalid image reference with no uri or data");
|
|
544
|
+
}
|
|
545
|
+
assertImageSize(base64);
|
|
546
|
+
return {
|
|
547
|
+
type: "image",
|
|
548
|
+
source: {
|
|
549
|
+
type: "base64",
|
|
550
|
+
media_type: normalizeAnthropicImageMime(mediaType),
|
|
551
|
+
data: base64
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
async convertDocumentPart(part) {
|
|
556
|
+
const { data, uri, mimeType, title } = part.document;
|
|
557
|
+
let source;
|
|
558
|
+
if (data !== undefined) {
|
|
559
|
+
const parsed = isString(data) && data.startsWith("data:")
|
|
560
|
+
? parseDataUri(data)
|
|
561
|
+
: undefined;
|
|
562
|
+
const effectiveMime = mimeType ?? parsed?.mime ?? "application/pdf";
|
|
563
|
+
if (parsed && mimeType && parsed.mime !== mimeType) {
|
|
564
|
+
throw new Error(`Anthropic document MIME mismatch: ${mimeType} vs ${parsed.mime}`);
|
|
565
|
+
}
|
|
566
|
+
if (effectiveMime === "text/plain") {
|
|
567
|
+
const text = parsed
|
|
568
|
+
? Buffer.from(parsed.base64, "base64").toString("utf8")
|
|
569
|
+
: isString(data)
|
|
570
|
+
? data
|
|
571
|
+
: Buffer.from(data).toString("utf8");
|
|
572
|
+
source = { type: "text", media_type: "text/plain", data: text };
|
|
573
|
+
}
|
|
574
|
+
else if (effectiveMime === "application/pdf") {
|
|
575
|
+
const encoded = parsed?.base64 ?? bytesToBase64(data);
|
|
576
|
+
source = {
|
|
577
|
+
type: "base64",
|
|
578
|
+
media_type: "application/pdf",
|
|
579
|
+
data: encoded
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
else {
|
|
583
|
+
throw new Error(`Anthropic does not support document media type ${effectiveMime}`);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
else if (uri) {
|
|
587
|
+
const resolved = await this.resolveUri(uri);
|
|
588
|
+
if (/^https:\/\//i.test(resolved)) {
|
|
589
|
+
source = { type: "url", url: resolved };
|
|
590
|
+
}
|
|
591
|
+
else if (!resolved.startsWith("data:")) {
|
|
592
|
+
throw new Error("Anthropic document URI must resolve to PDF data or an HTTPS URL");
|
|
593
|
+
}
|
|
594
|
+
else {
|
|
595
|
+
const parsed = parseDataUri(resolved);
|
|
596
|
+
if (parsed.mime !== "application/pdf") {
|
|
597
|
+
throw new Error(`Anthropic does not support document media type ${parsed.mime}`);
|
|
598
|
+
}
|
|
599
|
+
source = {
|
|
600
|
+
type: "base64",
|
|
601
|
+
media_type: "application/pdf",
|
|
602
|
+
data: parsed.base64
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
else {
|
|
607
|
+
throw new Error("Anthropic document content requires PDF/text data or an HTTPS PDF URL");
|
|
608
|
+
}
|
|
609
|
+
const block = {
|
|
610
|
+
type: "document",
|
|
611
|
+
source
|
|
612
|
+
};
|
|
613
|
+
if (title) {
|
|
614
|
+
block.title = title;
|
|
615
|
+
}
|
|
616
|
+
if (part.context) {
|
|
617
|
+
block.context = part.context;
|
|
618
|
+
}
|
|
619
|
+
if (part.citations !== undefined) {
|
|
620
|
+
block.citations = { enabled: part.citations };
|
|
621
|
+
}
|
|
622
|
+
return block;
|
|
623
|
+
}
|
|
624
|
+
async convertMessage(message, signal) {
|
|
190
625
|
if (message.role === "tool") {
|
|
191
626
|
if (!message.toolCallId) {
|
|
192
627
|
throw new Error("Tool call ID must not be None");
|
|
193
628
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
629
|
+
// Anthropic tool_result content may be a string or an array of blocks
|
|
630
|
+
// (text + image). Structured content (e.g. ui_3d_capture_view's
|
|
631
|
+
// screenshot) is converted to blocks so vision models can see it; plain
|
|
632
|
+
// results stay stringified as before.
|
|
633
|
+
let resultContent;
|
|
634
|
+
if (isString(message.content)) {
|
|
635
|
+
resultContent = message.content;
|
|
636
|
+
}
|
|
637
|
+
else if (Array.isArray(message.content)) {
|
|
638
|
+
const blocks = [];
|
|
639
|
+
for (const part of message.content) {
|
|
640
|
+
if (isTextContent(part)) {
|
|
641
|
+
blocks.push(toAnthropicTextBlock(part));
|
|
642
|
+
}
|
|
643
|
+
else if (isImageContent(part)) {
|
|
644
|
+
blocks.push(await this.convertImagePart(part, signal));
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
resultContent =
|
|
648
|
+
blocks.length > 0 ? blocks : JSON.stringify(message.content);
|
|
649
|
+
}
|
|
650
|
+
else {
|
|
651
|
+
resultContent = JSON.stringify(message.content ?? null);
|
|
652
|
+
}
|
|
653
|
+
const toolResult = {
|
|
654
|
+
type: "tool_result",
|
|
655
|
+
tool_use_id: message.toolCallId,
|
|
656
|
+
content: resultContent
|
|
657
|
+
};
|
|
658
|
+
if (message.isError) {
|
|
659
|
+
toolResult.is_error = true;
|
|
660
|
+
}
|
|
197
661
|
return {
|
|
198
662
|
role: "user",
|
|
199
|
-
content: [
|
|
200
|
-
{
|
|
201
|
-
type: "tool_result",
|
|
202
|
-
tool_use_id: message.toolCallId,
|
|
203
|
-
content: contentValue
|
|
204
|
-
}
|
|
205
|
-
]
|
|
663
|
+
content: [toolResult]
|
|
206
664
|
};
|
|
207
665
|
}
|
|
208
666
|
if (message.role === "system") {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
667
|
+
// Anthropic has no `system` role in the messages array (the system prompt
|
|
668
|
+
// is a top-level param). The main generate paths strip system messages
|
|
669
|
+
// before conversion; if one still reaches here, fold it into a user
|
|
670
|
+
// message rather than mislabeling it as assistant text (and avoid
|
|
671
|
+
// String(array) producing "[object Object]").
|
|
672
|
+
const text = isString(message.content)
|
|
673
|
+
? message.content
|
|
674
|
+
: (message.content ?? [])
|
|
675
|
+
.filter(isTextContent)
|
|
676
|
+
.map((c) => c.text)
|
|
677
|
+
.join("\n");
|
|
678
|
+
return { role: "user", content: text };
|
|
215
679
|
}
|
|
216
680
|
if (message.role === "user") {
|
|
217
|
-
if (
|
|
681
|
+
if (isString(message.content)) {
|
|
218
682
|
return { role: "user", content: message.content };
|
|
219
683
|
}
|
|
220
684
|
const parts = message.content ?? [];
|
|
221
685
|
const content = [];
|
|
222
686
|
for (const part of parts) {
|
|
223
687
|
if (isTextContent(part)) {
|
|
224
|
-
content.push(
|
|
688
|
+
content.push(toAnthropicTextBlock(part));
|
|
225
689
|
continue;
|
|
226
690
|
}
|
|
227
691
|
if (isImageContent(part)) {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
let mediaType = part.image.mimeType ?? "image/png";
|
|
231
|
-
let base64;
|
|
232
|
-
if (rawData) {
|
|
233
|
-
if (rawData.startsWith("data:")) {
|
|
234
|
-
const parsed = parseDataUri(rawData);
|
|
235
|
-
base64 = parsed.base64;
|
|
236
|
-
mediaType = part.image.mimeType ?? parsed.mime;
|
|
237
|
-
}
|
|
238
|
-
else {
|
|
239
|
-
base64 = rawData;
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
else if (uri.startsWith("data:")) {
|
|
243
|
-
const parsed = parseDataUri(uri);
|
|
244
|
-
base64 = parsed.base64;
|
|
245
|
-
mediaType = part.image.mimeType ?? parsed.mime;
|
|
246
|
-
}
|
|
247
|
-
else if (uri) {
|
|
248
|
-
const resolved = await this.resolveUri(uri);
|
|
249
|
-
if (resolved.startsWith("data:")) {
|
|
250
|
-
const parsed = parseDataUri(resolved);
|
|
251
|
-
base64 = parsed.base64;
|
|
252
|
-
mediaType = part.image.mimeType ?? parsed.mime;
|
|
253
|
-
}
|
|
254
|
-
else {
|
|
255
|
-
const response = await this._fetch(resolved);
|
|
256
|
-
if (!response.ok) {
|
|
257
|
-
throw new Error(`Failed to fetch URI: ${response.status}`);
|
|
258
|
-
}
|
|
259
|
-
mediaType =
|
|
260
|
-
part.image.mimeType ??
|
|
261
|
-
response.headers.get("content-type") ??
|
|
262
|
-
"image/png";
|
|
263
|
-
base64 = Buffer.from(new Uint8Array(await response.arrayBuffer())).toString("base64");
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
else {
|
|
267
|
-
throw new Error("Invalid image reference with no uri or data");
|
|
268
|
-
}
|
|
269
|
-
content.push({
|
|
270
|
-
type: "image",
|
|
271
|
-
source: {
|
|
272
|
-
type: "base64",
|
|
273
|
-
media_type: mediaType,
|
|
274
|
-
data: base64
|
|
275
|
-
}
|
|
276
|
-
});
|
|
692
|
+
content.push(await this.convertImagePart(part, signal));
|
|
693
|
+
continue;
|
|
277
694
|
}
|
|
695
|
+
if (isDocumentContent(part)) {
|
|
696
|
+
content.push(await this.convertDocumentPart(part));
|
|
697
|
+
continue;
|
|
698
|
+
}
|
|
699
|
+
throw new Error(`Anthropic does not support ${part.type} message content`);
|
|
278
700
|
}
|
|
279
701
|
return {
|
|
280
702
|
role: "user",
|
|
@@ -289,14 +711,20 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
289
711
|
return null;
|
|
290
712
|
}
|
|
291
713
|
if (message.toolCalls && message.toolCalls.length > 0) {
|
|
292
|
-
const
|
|
293
|
-
if (
|
|
714
|
+
const rawBlocks = message.toolCalls.find((toolCall) => toolCall._anthropicContentBlocks)?._anthropicContentBlocks;
|
|
715
|
+
if (rawBlocks) {
|
|
716
|
+
return { role: "assistant", content: rawBlocks };
|
|
717
|
+
}
|
|
718
|
+
const contentBlocks = [
|
|
719
|
+
...(message._anthropicThinkingBlocks ?? [])
|
|
720
|
+
];
|
|
721
|
+
if (isString(message.content) && message.content.trim()) {
|
|
294
722
|
contentBlocks.push({ type: "text", text: message.content });
|
|
295
723
|
}
|
|
296
724
|
if (Array.isArray(message.content)) {
|
|
297
725
|
for (const part of message.content) {
|
|
298
726
|
if (isTextContent(part) && part.text.trim()) {
|
|
299
|
-
contentBlocks.push(
|
|
727
|
+
contentBlocks.push(toAnthropicTextBlock(part));
|
|
300
728
|
}
|
|
301
729
|
}
|
|
302
730
|
}
|
|
@@ -313,7 +741,7 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
313
741
|
content: contentBlocks
|
|
314
742
|
};
|
|
315
743
|
}
|
|
316
|
-
if (
|
|
744
|
+
if (isString(message.content)) {
|
|
317
745
|
return { role: "assistant", content: message.content };
|
|
318
746
|
}
|
|
319
747
|
if (Array.isArray(message.content)) {
|
|
@@ -321,236 +749,490 @@ export class AnthropicProvider extends BaseProvider {
|
|
|
321
749
|
role: "assistant",
|
|
322
750
|
content: message.content
|
|
323
751
|
.filter((part) => isTextContent(part))
|
|
324
|
-
.map(
|
|
325
|
-
type: "text",
|
|
326
|
-
text: part.text
|
|
327
|
-
}))
|
|
752
|
+
.map(toAnthropicTextBlock)
|
|
328
753
|
};
|
|
329
754
|
}
|
|
330
755
|
throw new Error(`Unknown message content type ${typeof message.content}`);
|
|
331
756
|
}
|
|
332
757
|
formatTools(tools) {
|
|
333
|
-
return tools.map((tool) =>
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
758
|
+
return tools.map((tool) => {
|
|
759
|
+
// The canonical web-search tool is rendered as Anthropic's built-in
|
|
760
|
+
// server tool — the search runs server-side and its result blocks stream
|
|
761
|
+
// back within the same turn (our stream parser ignores them), so the
|
|
762
|
+
// model answers from live web data without a client round-trip.
|
|
763
|
+
// Gated on supportsNativeWebSearch: subclasses that reuse the Anthropic
|
|
764
|
+
// SDK against a different endpoint don't implement this server tool, so
|
|
765
|
+
// for them the tool falls through to the plain function-tool shape below
|
|
766
|
+
// and runs client-side via SerpAPI.
|
|
767
|
+
if (tool.name === WEB_SEARCH_TOOL_NAME && this.supportsNativeWebSearch) {
|
|
768
|
+
return {
|
|
769
|
+
type: "web_search_20250305",
|
|
770
|
+
name: WEB_SEARCH_TOOL_NAME,
|
|
771
|
+
max_uses: 5,
|
|
772
|
+
...sharedToolFields(tool)
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
const base = {
|
|
776
|
+
name: tool.name,
|
|
777
|
+
description: tool.description ?? "",
|
|
778
|
+
input_schema: this.prepareJsonSchema(tool.inputSchema ?? { type: "object", properties: {} })
|
|
779
|
+
};
|
|
780
|
+
const withExamples = tool.inputExamples
|
|
781
|
+
? { ...base, input_examples: tool.inputExamples }
|
|
782
|
+
: base;
|
|
783
|
+
return { ...withExamples, ...sharedToolFields(tool) };
|
|
784
|
+
});
|
|
338
785
|
}
|
|
339
786
|
extractSystemMessage(messages) {
|
|
340
|
-
const
|
|
341
|
-
if (
|
|
787
|
+
const systemMessages = messages.filter((m) => m.role === "system");
|
|
788
|
+
if (systemMessages.length === 0) {
|
|
342
789
|
return "You are a helpful assistant.";
|
|
343
790
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
.
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
791
|
+
const sections = systemMessages
|
|
792
|
+
.map((message) => {
|
|
793
|
+
if (isString(message.content))
|
|
794
|
+
return message.content;
|
|
795
|
+
if (Array.isArray(message.content)) {
|
|
796
|
+
return message.content
|
|
797
|
+
.filter(isTextContent)
|
|
798
|
+
.map((part) => part.text)
|
|
799
|
+
.join(" ");
|
|
800
|
+
}
|
|
801
|
+
return message.content == null ? "" : String(message.content);
|
|
802
|
+
})
|
|
803
|
+
.filter(Boolean);
|
|
804
|
+
return sections.join("\n\n") || "You are a helpful assistant.";
|
|
354
805
|
}
|
|
355
|
-
|
|
356
|
-
const system = this.extractSystemMessage(args.messages);
|
|
357
|
-
const converted = await Promise.all(args.messages
|
|
358
|
-
.filter((m) => m.role !== "system")
|
|
359
|
-
.map((m) => this.convertMessage(m)));
|
|
360
|
-
const anthropicMessages = converted.filter((m) => m !== null);
|
|
806
|
+
buildRequest(args) {
|
|
361
807
|
const formattedTools = args.tools && args.tools.length > 0
|
|
362
808
|
? this.formatTools(args.tools)
|
|
363
809
|
: undefined;
|
|
364
|
-
|
|
810
|
+
const policy = thinkingPolicy(args.model);
|
|
811
|
+
// `thinkingBudget` predates the structured config. A model that only takes
|
|
812
|
+
// adaptive thinking has no use for the number, so it degrades to a bare
|
|
813
|
+
// request for thinking.
|
|
814
|
+
const legacyThinking = args.thinkingBudget === undefined
|
|
815
|
+
? undefined
|
|
816
|
+
: policy === "manual"
|
|
817
|
+
? { type: "manual", budgetTokens: args.thinkingBudget }
|
|
818
|
+
: { type: "adaptive" };
|
|
819
|
+
const thinking = args.thinking ?? legacyThinking;
|
|
820
|
+
if (thinking?.type === "manual") {
|
|
821
|
+
if (policy !== "manual") {
|
|
822
|
+
throw new Error(`${args.model} requires adaptive thinking; manual budgets are unsupported`);
|
|
823
|
+
}
|
|
824
|
+
if (thinking.budgetTokens < 1024) {
|
|
825
|
+
throw new Error("Anthropic thinking budget must be at least 1024 tokens");
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
if (thinking?.type === "disabled" && policy === "adaptive_required") {
|
|
829
|
+
throw new Error(`${args.model} does not allow thinking to be disabled`);
|
|
830
|
+
}
|
|
831
|
+
const explicitThinking = thinking?.type === "adaptive" || thinking?.type === "manual";
|
|
832
|
+
// Policy-default thinking (no caller-supplied config) is implicit: a forced
|
|
833
|
+
// tool choice wins over it and thinking is turned off, so callers that
|
|
834
|
+
// always force a tool can still use adaptive-default models. An explicit
|
|
835
|
+
// thinking request combined with a forced tool choice is a real conflict.
|
|
836
|
+
const implicitThinking = !thinking &&
|
|
837
|
+
(policy === "adaptive_default" || policy === "adaptive_required");
|
|
365
838
|
if (args.toolChoice) {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
839
|
+
if (explicitThinking) {
|
|
840
|
+
throw new Error("Anthropic does not allow a forced tool choice while thinking is active");
|
|
841
|
+
}
|
|
842
|
+
if (implicitThinking && policy === "adaptive_required") {
|
|
843
|
+
throw new Error(`${args.model} does not allow thinking to be disabled, so a forced tool choice is unsupported`);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
const thinkingSuppressedByToolChoice = Boolean(args.toolChoice && implicitThinking);
|
|
847
|
+
const thinkingEnabled = explicitThinking || (implicitThinking && !thinkingSuppressedByToolChoice);
|
|
848
|
+
const toolChoice = args.toolChoice
|
|
849
|
+
? args.toolChoice === "any"
|
|
850
|
+
? { type: "any" }
|
|
851
|
+
: { type: "tool", name: args.toolChoice }
|
|
852
|
+
: undefined;
|
|
853
|
+
// A manual budget has to fit inside max_tokens, with at least one token
|
|
854
|
+
// left over for the answer.
|
|
855
|
+
const requestedMaxTokens = args.maxTokens ?? 8192;
|
|
856
|
+
const maxTokens = thinking?.type === "manual"
|
|
857
|
+
? Math.max(requestedMaxTokens, thinking.budgetTokens + 1)
|
|
858
|
+
: requestedMaxTokens;
|
|
859
|
+
// Models on an adaptive thinking policy reject temperature and top_p
|
|
860
|
+
// outright, and once thinking is on the only value Anthropic still accepts
|
|
861
|
+
// is a top_p of 0.95 or above under a manual budget.
|
|
862
|
+
const sampling = {};
|
|
863
|
+
if (!rejectsCustomSampling(args.model)) {
|
|
864
|
+
if (!thinkingEnabled) {
|
|
865
|
+
if (args.temperature != null) {
|
|
866
|
+
sampling.temperature = args.temperature;
|
|
867
|
+
}
|
|
868
|
+
else if (args.topP != null) {
|
|
869
|
+
sampling.top_p = args.topP;
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
else if (thinking?.type === "manual" &&
|
|
873
|
+
args.topP != null &&
|
|
874
|
+
args.topP >= 0.95) {
|
|
875
|
+
sampling.top_p = args.topP;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
// The disabled variant carries no `display` field, hence the narrowing.
|
|
879
|
+
const display = thinking && thinking.type !== "disabled" && thinking.display
|
|
880
|
+
? { display: thinking.display }
|
|
881
|
+
: {};
|
|
882
|
+
let anthropicThinking;
|
|
883
|
+
if (thinking?.type === "adaptive") {
|
|
884
|
+
anthropicThinking = { type: "adaptive", ...display };
|
|
885
|
+
}
|
|
886
|
+
else if (thinking?.type === "manual") {
|
|
887
|
+
anthropicThinking = {
|
|
888
|
+
type: "enabled",
|
|
889
|
+
budget_tokens: thinking.budgetTokens,
|
|
890
|
+
...display
|
|
891
|
+
};
|
|
892
|
+
}
|
|
893
|
+
else if (thinking?.type === "disabled" ||
|
|
894
|
+
thinkingSuppressedByToolChoice) {
|
|
895
|
+
anthropicThinking = { type: "disabled" };
|
|
370
896
|
}
|
|
371
897
|
const request = {
|
|
898
|
+
model: args.model,
|
|
899
|
+
messages: args.messages,
|
|
900
|
+
system: args.system,
|
|
901
|
+
max_tokens: maxTokens
|
|
902
|
+
};
|
|
903
|
+
if (formattedTools) {
|
|
904
|
+
request.tools = formattedTools;
|
|
905
|
+
}
|
|
906
|
+
if (toolChoice) {
|
|
907
|
+
request.tool_choice = toolChoice;
|
|
908
|
+
}
|
|
909
|
+
Object.assign(request, sampling);
|
|
910
|
+
if (anthropicThinking) {
|
|
911
|
+
request.thinking = anthropicThinking;
|
|
912
|
+
}
|
|
913
|
+
if (args.effort) {
|
|
914
|
+
request.output_config = { effort: args.effort };
|
|
915
|
+
}
|
|
916
|
+
if (this._cacheControl) {
|
|
917
|
+
request.cache_control = this._cacheControl;
|
|
918
|
+
}
|
|
919
|
+
return request;
|
|
920
|
+
}
|
|
921
|
+
async *generateMessages(args) {
|
|
922
|
+
const system = this.extractSystemMessage(args.messages);
|
|
923
|
+
const converted = await Promise.all(args.messages
|
|
924
|
+
.filter((m) => m.role !== "system")
|
|
925
|
+
.map((m) => this.convertMessage(m, args.signal)));
|
|
926
|
+
const anthropicMessages = mergeToolResultMessages(converted.filter((m) => m !== null));
|
|
927
|
+
const request = this.buildRequest({
|
|
372
928
|
model: args.model,
|
|
373
929
|
messages: anthropicMessages,
|
|
374
930
|
system,
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
};
|
|
384
|
-
log.debug("Anthropic request", { model: args.model });
|
|
385
|
-
const stream = await this.getClient().messages.create({
|
|
386
|
-
...request,
|
|
387
|
-
stream: true
|
|
931
|
+
tools: args.tools,
|
|
932
|
+
toolChoice: args.toolChoice,
|
|
933
|
+
maxTokens: args.maxTokens,
|
|
934
|
+
temperature: args.temperature,
|
|
935
|
+
topP: args.topP,
|
|
936
|
+
thinking: args.thinking,
|
|
937
|
+
effort: args.effort,
|
|
938
|
+
thinkingBudget: args.thinkingBudget
|
|
388
939
|
});
|
|
389
|
-
|
|
390
|
-
let
|
|
391
|
-
let
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
});
|
|
940
|
+
log.debug("Anthropic request", { model: args.model });
|
|
941
|
+
let currentRequest = request;
|
|
942
|
+
for (let continuation = 0; continuation <= MAX_PAUSE_TURN_CONTINUATIONS; continuation++) {
|
|
943
|
+
// SAFETY: the request is assembled field by field as a dictionary, and
|
|
944
|
+
// the SDK's param interface is closed — it declares no index signature,
|
|
945
|
+
// so the two do not overlap.
|
|
946
|
+
const streamRequest = {
|
|
947
|
+
...currentRequest,
|
|
948
|
+
stream: true
|
|
949
|
+
};
|
|
950
|
+
this.recordRequestPayload(streamRequest);
|
|
951
|
+
const stream = await this.getClient().messages.create(streamRequest, this.requestOptions(args.signal));
|
|
952
|
+
let inputTokens = 0;
|
|
953
|
+
let outputTokens = 0;
|
|
954
|
+
let cachedTokens = 0;
|
|
955
|
+
let cacheWriteTokens = 0;
|
|
956
|
+
let stopReason = null;
|
|
957
|
+
const contentBlocks = [];
|
|
958
|
+
const jsonByIndex = new Map();
|
|
959
|
+
const thinkingBlocks = [];
|
|
960
|
+
const toolCalls = [];
|
|
961
|
+
for await (const event of stream) {
|
|
962
|
+
if (event.type === "message_start") {
|
|
963
|
+
inputTokens = event.message.usage.input_tokens ?? inputTokens;
|
|
964
|
+
cachedTokens =
|
|
965
|
+
event.message.usage.cache_read_input_tokens ?? cachedTokens;
|
|
966
|
+
cacheWriteTokens =
|
|
967
|
+
event.message.usage.cache_creation_input_tokens ?? cacheWriteTokens;
|
|
968
|
+
continue;
|
|
419
969
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
content: delta.thinking,
|
|
428
|
-
done: false,
|
|
429
|
-
thinking: true
|
|
430
|
-
};
|
|
431
|
-
yield chunk;
|
|
970
|
+
if (event.type === "message_delta") {
|
|
971
|
+
outputTokens = event.usage.output_tokens;
|
|
972
|
+
inputTokens = event.usage.input_tokens ?? inputTokens;
|
|
973
|
+
cachedTokens = event.usage.cache_read_input_tokens ?? cachedTokens;
|
|
974
|
+
cacheWriteTokens =
|
|
975
|
+
event.usage.cache_creation_input_tokens ?? cacheWriteTokens;
|
|
976
|
+
stopReason = event.delta?.stop_reason ?? stopReason;
|
|
432
977
|
continue;
|
|
433
978
|
}
|
|
434
|
-
if ("
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
979
|
+
if (event.type === "content_block_start") {
|
|
980
|
+
const raw = toRawBlock(event.content_block);
|
|
981
|
+
contentBlocks[event.index] = raw;
|
|
982
|
+
if (event.content_block.type === "tool_use" ||
|
|
983
|
+
event.content_block.type === "server_tool_use") {
|
|
984
|
+
jsonByIndex.set(event.index, "");
|
|
985
|
+
}
|
|
986
|
+
if (event.content_block.type === "thinking") {
|
|
987
|
+
thinkingBlocks.push({
|
|
988
|
+
type: "thinking",
|
|
989
|
+
thinking: event.content_block.thinking,
|
|
990
|
+
signature: event.content_block.signature
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
else if (event.content_block.type === "redacted_thinking") {
|
|
994
|
+
thinkingBlocks.push({
|
|
995
|
+
type: "redacted_thinking",
|
|
996
|
+
data: event.content_block.data
|
|
997
|
+
});
|
|
440
998
|
}
|
|
441
999
|
continue;
|
|
442
1000
|
}
|
|
443
|
-
if ("
|
|
444
|
-
|
|
445
|
-
const
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
1001
|
+
if (event.type === "content_block_delta") {
|
|
1002
|
+
const index = Number(event.index ?? 0);
|
|
1003
|
+
const raw = contentBlocks[index] ?? {};
|
|
1004
|
+
contentBlocks[index] = raw;
|
|
1005
|
+
const delta = event.delta;
|
|
1006
|
+
if ("thinking" in delta && isString(delta.thinking)) {
|
|
1007
|
+
const thinkingDelta = delta.thinking;
|
|
1008
|
+
raw.thinking = String(raw.thinking ?? "") + thinkingDelta;
|
|
1009
|
+
const thinking = thinkingBlocks.at(-1);
|
|
1010
|
+
if (thinking?.type === "thinking")
|
|
1011
|
+
thinking.thinking += thinkingDelta;
|
|
1012
|
+
yield {
|
|
1013
|
+
type: "chunk",
|
|
1014
|
+
content: thinkingDelta,
|
|
1015
|
+
done: false,
|
|
1016
|
+
thinking: true
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
else if ("signature" in delta && isString(delta.signature)) {
|
|
1020
|
+
const signatureDelta = delta.signature;
|
|
1021
|
+
raw.signature = String(raw.signature ?? "") + signatureDelta;
|
|
1022
|
+
const thinking = thinkingBlocks.at(-1);
|
|
1023
|
+
if (thinking?.type === "thinking")
|
|
1024
|
+
thinking.signature += signatureDelta;
|
|
1025
|
+
}
|
|
1026
|
+
else if ("partial_json" in delta && isString(delta.partial_json)) {
|
|
1027
|
+
jsonByIndex.set(index, (jsonByIndex.get(index) ?? "") + delta.partial_json);
|
|
1028
|
+
}
|
|
1029
|
+
else if ("text" in delta && isString(delta.text)) {
|
|
1030
|
+
const textDelta = delta.text;
|
|
1031
|
+
raw.text = String(raw.text ?? "") + textDelta;
|
|
1032
|
+
yield { type: "chunk", content: textDelta, done: false };
|
|
1033
|
+
}
|
|
1034
|
+
else if (delta.type === "citations_delta") {
|
|
1035
|
+
const citations = Array.isArray(raw.citations) ? raw.citations : [];
|
|
1036
|
+
raw.citations = [...citations, delta.citation];
|
|
1037
|
+
}
|
|
1038
|
+
continue;
|
|
451
1039
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
!
|
|
467
|
-
|
|
1040
|
+
if (event.type === "content_block_stop") {
|
|
1041
|
+
const raw = contentBlocks[event.index];
|
|
1042
|
+
const json = jsonByIndex.get(event.index);
|
|
1043
|
+
if (json !== undefined) {
|
|
1044
|
+
let input;
|
|
1045
|
+
try {
|
|
1046
|
+
input = JSON.parse(json || "{}");
|
|
1047
|
+
}
|
|
1048
|
+
catch {
|
|
1049
|
+
throw new Error("Anthropic returned incomplete tool input JSON");
|
|
1050
|
+
}
|
|
1051
|
+
raw.input = input;
|
|
1052
|
+
jsonByIndex.delete(event.index);
|
|
1053
|
+
if (raw.type === "tool_use") {
|
|
1054
|
+
if (!isRecord(input)) {
|
|
1055
|
+
throw new Error("Anthropic returned non-object tool input");
|
|
1056
|
+
}
|
|
1057
|
+
const toolCall = {
|
|
1058
|
+
id: String(raw.id ?? ""),
|
|
1059
|
+
name: String(raw.name ?? ""),
|
|
1060
|
+
args: Object.fromEntries(Object.entries(input)),
|
|
1061
|
+
_anthropicThinkingBlocks: thinkingBlocks.length > 0 ? [...thinkingBlocks] : undefined
|
|
1062
|
+
};
|
|
1063
|
+
toolCalls.push(toolCall);
|
|
468
1064
|
}
|
|
469
1065
|
}
|
|
470
|
-
catch {
|
|
471
|
-
// malformed JSON — emit empty args
|
|
472
|
-
}
|
|
473
|
-
const toolCall = {
|
|
474
|
-
id: toolBlock.id,
|
|
475
|
-
name: toolBlock.name,
|
|
476
|
-
args: parsedArgs
|
|
477
|
-
};
|
|
478
|
-
yield toolCall;
|
|
479
1066
|
}
|
|
1067
|
+
}
|
|
1068
|
+
const hasServerToolContent = contentBlocks.some((block) => block?.type === "server_tool_use" ||
|
|
1069
|
+
String(block?.type ?? "").endsWith("_tool_result"));
|
|
1070
|
+
if (hasServerToolContent) {
|
|
1071
|
+
for (const toolCall of toolCalls) {
|
|
1072
|
+
toolCall._anthropicContentBlocks = contentBlocks;
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
this.trackUsage(args.model, {
|
|
1076
|
+
inputTokens: inputTokens + cachedTokens + cacheWriteTokens,
|
|
1077
|
+
outputTokens,
|
|
1078
|
+
cachedTokens,
|
|
1079
|
+
cacheWriteTokens
|
|
1080
|
+
});
|
|
1081
|
+
if (stopReason === "pause_turn") {
|
|
1082
|
+
if (continuation === MAX_PAUSE_TURN_CONTINUATIONS) {
|
|
1083
|
+
throw new Error("Anthropic pause_turn continuation limit exceeded");
|
|
1084
|
+
}
|
|
1085
|
+
currentRequest = {
|
|
1086
|
+
...currentRequest,
|
|
1087
|
+
messages: [
|
|
1088
|
+
...(currentRequest.messages ?? []),
|
|
1089
|
+
{ role: "assistant", content: contentBlocks }
|
|
1090
|
+
]
|
|
1091
|
+
};
|
|
480
1092
|
continue;
|
|
481
1093
|
}
|
|
482
|
-
if (
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
1094
|
+
if (stopReason === "max_tokens" ||
|
|
1095
|
+
stopReason === "model_context_window_exceeded") {
|
|
1096
|
+
throw new Error(`Anthropic response was truncated (${stopReason})`);
|
|
1097
|
+
}
|
|
1098
|
+
if (stopReason === "refusal") {
|
|
1099
|
+
throw new Error("Anthropic refused the request");
|
|
1100
|
+
}
|
|
1101
|
+
const textContent = textContentFromRawBlocks(contentBlocks);
|
|
1102
|
+
if (toolCalls.length === 0 &&
|
|
1103
|
+
textContent.some((part) => part.citations?.length)) {
|
|
1104
|
+
yield {
|
|
1105
|
+
type: "message",
|
|
1106
|
+
message: { role: "assistant", content: textContent }
|
|
487
1107
|
};
|
|
488
|
-
yield chunk;
|
|
489
1108
|
}
|
|
1109
|
+
for (const toolCall of toolCalls)
|
|
1110
|
+
yield toolCall;
|
|
1111
|
+
yield { type: "chunk", content: "", done: true };
|
|
1112
|
+
return;
|
|
490
1113
|
}
|
|
491
1114
|
}
|
|
492
1115
|
async generateMessage(args) {
|
|
493
1116
|
const system = this.extractSystemMessage(args.messages);
|
|
494
1117
|
const converted = await Promise.all(args.messages
|
|
495
1118
|
.filter((m) => m.role !== "system")
|
|
496
|
-
.map((m) => this.convertMessage(m)));
|
|
497
|
-
const anthropicMessages = converted.filter((m) => m !== null);
|
|
498
|
-
const
|
|
499
|
-
? this.formatTools(args.tools)
|
|
500
|
-
: undefined;
|
|
501
|
-
let resolvedToolChoice;
|
|
502
|
-
if (args.toolChoice) {
|
|
503
|
-
resolvedToolChoice =
|
|
504
|
-
args.toolChoice === "any"
|
|
505
|
-
? { type: "any" }
|
|
506
|
-
: { type: "tool", name: args.toolChoice };
|
|
507
|
-
}
|
|
508
|
-
const request = {
|
|
1119
|
+
.map((m) => this.convertMessage(m, args.signal)));
|
|
1120
|
+
const anthropicMessages = mergeToolResultMessages(converted.filter((m) => m !== null));
|
|
1121
|
+
const request = this.buildRequest({
|
|
509
1122
|
model: args.model,
|
|
510
1123
|
messages: anthropicMessages,
|
|
511
1124
|
system,
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
};
|
|
1125
|
+
tools: args.tools,
|
|
1126
|
+
toolChoice: args.toolChoice,
|
|
1127
|
+
maxTokens: args.maxTokens,
|
|
1128
|
+
temperature: args.temperature,
|
|
1129
|
+
topP: args.topP,
|
|
1130
|
+
thinking: args.thinking,
|
|
1131
|
+
effort: args.effort,
|
|
1132
|
+
thinkingBudget: args.thinkingBudget
|
|
1133
|
+
});
|
|
521
1134
|
log.debug("Anthropic request", { model: args.model });
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
1135
|
+
let currentRequest = request;
|
|
1136
|
+
let response;
|
|
1137
|
+
for (let continuation = 0; continuation <= MAX_PAUSE_TURN_CONTINUATIONS; continuation++) {
|
|
1138
|
+
this.recordRequestPayload(currentRequest);
|
|
1139
|
+
// SAFETY: as above — a dictionary request handed to the SDK's closed
|
|
1140
|
+
// non-streaming param interface.
|
|
1141
|
+
response = await this.getClient().messages.create(currentRequest, this.requestOptions(args.signal));
|
|
1142
|
+
if (response.usage) {
|
|
1143
|
+
const cacheRead = response.usage.cache_read_input_tokens ?? 0;
|
|
1144
|
+
const cacheWrite = response.usage.cache_creation_input_tokens ?? 0;
|
|
1145
|
+
this.trackUsage(args.model, {
|
|
1146
|
+
inputTokens: response.usage.input_tokens + cacheRead + cacheWrite,
|
|
1147
|
+
outputTokens: response.usage.output_tokens,
|
|
1148
|
+
cachedTokens: cacheRead,
|
|
1149
|
+
cacheWriteTokens: cacheWrite
|
|
1150
|
+
});
|
|
1151
|
+
}
|
|
1152
|
+
if (response.stop_reason !== "pause_turn")
|
|
1153
|
+
break;
|
|
1154
|
+
if (continuation === MAX_PAUSE_TURN_CONTINUATIONS) {
|
|
1155
|
+
throw new Error("Anthropic pause_turn continuation limit exceeded");
|
|
1156
|
+
}
|
|
1157
|
+
currentRequest = {
|
|
1158
|
+
...currentRequest,
|
|
1159
|
+
messages: [
|
|
1160
|
+
...(currentRequest.messages ?? []),
|
|
1161
|
+
{
|
|
1162
|
+
role: "assistant",
|
|
1163
|
+
content: response.content.map(toRawBlock)
|
|
1164
|
+
}
|
|
1165
|
+
]
|
|
1166
|
+
};
|
|
1167
|
+
}
|
|
1168
|
+
if (!response)
|
|
1169
|
+
throw new Error("Anthropic returned no response");
|
|
1170
|
+
const stopReason = String(response.stop_reason ?? "");
|
|
1171
|
+
if (stopReason === "max_tokens" ||
|
|
1172
|
+
stopReason === "model_context_window_exceeded") {
|
|
1173
|
+
throw new Error(`Anthropic response was truncated (${stopReason})`);
|
|
1174
|
+
}
|
|
1175
|
+
if (stopReason === "refusal") {
|
|
1176
|
+
throw new Error("Anthropic refused the request");
|
|
529
1177
|
}
|
|
530
1178
|
const textParts = [];
|
|
531
1179
|
const toolCalls = [];
|
|
532
|
-
|
|
1180
|
+
const thinkingBlocks = [];
|
|
1181
|
+
const rawContentBlocks = response.content.map(toRawBlock);
|
|
1182
|
+
for (const block of response.content) {
|
|
533
1183
|
if (block.type === "tool_use") {
|
|
534
|
-
|
|
1184
|
+
const toolCall = {
|
|
535
1185
|
id: String(block.id ?? ""),
|
|
536
1186
|
name: String(block.name ?? ""),
|
|
537
|
-
args: (block.input ?? {})
|
|
1187
|
+
args: Object.fromEntries(Object.entries(block.input ?? {}))
|
|
1188
|
+
};
|
|
1189
|
+
if (rawContentBlocks.some((raw) => raw.type === "server_tool_use" ||
|
|
1190
|
+
String(raw.type ?? "").endsWith("_tool_result"))) {
|
|
1191
|
+
toolCall._anthropicContentBlocks = rawContentBlocks;
|
|
1192
|
+
}
|
|
1193
|
+
toolCalls.push(toolCall);
|
|
1194
|
+
continue;
|
|
1195
|
+
}
|
|
1196
|
+
if (block.type === "thinking") {
|
|
1197
|
+
thinkingBlocks.push({
|
|
1198
|
+
type: "thinking",
|
|
1199
|
+
thinking: block.thinking,
|
|
1200
|
+
signature: block.signature
|
|
538
1201
|
});
|
|
539
1202
|
continue;
|
|
540
1203
|
}
|
|
1204
|
+
if (block.type === "redacted_thinking") {
|
|
1205
|
+
thinkingBlocks.push({ type: "redacted_thinking", data: block.data });
|
|
1206
|
+
continue;
|
|
1207
|
+
}
|
|
541
1208
|
if (block.type === "text") {
|
|
542
|
-
|
|
1209
|
+
const citations = block.citations?.map(mapCitation);
|
|
1210
|
+
const textPart = {
|
|
1211
|
+
type: "text",
|
|
1212
|
+
text: block.text
|
|
1213
|
+
};
|
|
1214
|
+
if (citations && citations.length > 0) {
|
|
1215
|
+
textPart.citations = citations;
|
|
1216
|
+
}
|
|
1217
|
+
textParts.push(textPart);
|
|
543
1218
|
}
|
|
544
1219
|
}
|
|
1220
|
+
const hasCitations = textParts.some((part) => part.citations?.length);
|
|
545
1221
|
return {
|
|
546
1222
|
role: "assistant",
|
|
547
|
-
content:
|
|
548
|
-
|
|
1223
|
+
content: hasCitations
|
|
1224
|
+
? textParts
|
|
1225
|
+
: textParts.map((part) => part.text).join("\n"),
|
|
1226
|
+
toolCalls,
|
|
1227
|
+
_anthropicThinkingBlocks: thinkingBlocks.length > 0 ? thinkingBlocks : undefined
|
|
549
1228
|
};
|
|
550
1229
|
}
|
|
551
1230
|
asHttpStatusError(error) {
|
|
552
1231
|
return new Error(String(error));
|
|
553
1232
|
}
|
|
1233
|
+
isContextExceededError(error) {
|
|
1234
|
+
return anthropicContextExceeded(error) !== null;
|
|
1235
|
+
}
|
|
554
1236
|
isContextLengthError(error) {
|
|
555
1237
|
const msg = String(error).toLowerCase();
|
|
556
1238
|
return (msg.includes("context length") ||
|