@vellumai/assistant 0.11.4 → 0.11.5-staging.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/AGENTS.md +2 -2
- package/ARCHITECTURE.md +29 -4
- package/README.md +1 -1
- package/docs/architecture/memory.md +17 -5
- package/docs/architecture/security.md +96 -152
- package/docs/guardian-request-flow.md +13 -2
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +166 -1
- package/node_modules/@vellumai/gateway-client/src/http-delivery.ts +7 -14
- package/node_modules/@vellumai/gateway-client/src/index.ts +2 -0
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +29 -31
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/openapi.yaml +193 -3
- package/package.json +1 -1
- package/src/__tests__/anthropic-provider.test.ts +10 -3
- package/src/__tests__/approval-interception-trust-gates.test.ts +40 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +4 -0
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +5 -6
- package/src/__tests__/channel-reply-delivery.test.ts +26 -13
- package/src/__tests__/checker.test.ts +20 -314
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +6 -2
- package/src/__tests__/client-os-metadata-persistence.test.ts +16 -0
- package/src/__tests__/compactor-retained-image-validation.test.ts +142 -0
- package/src/__tests__/container-cpu-sampler.test.ts +153 -0
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
- package/src/__tests__/conversation-attachments.test.ts +0 -1
- package/src/__tests__/conversation-error.test.ts +17 -0
- package/src/__tests__/conversation-lifecycle.test.ts +20 -26
- package/src/__tests__/conversation-pairing.test.ts +186 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +21 -2
- package/src/__tests__/credential-broker-server-use.test.ts +24 -5
- package/src/__tests__/credential-routes.test.ts +22 -3
- package/src/__tests__/credential-security-invariants.test.ts +2 -1
- package/src/__tests__/daemon-credential-client.test.ts +88 -0
- package/src/__tests__/default-plugin-names-guard.test.ts +12 -1
- package/src/__tests__/dm-backfill.test.ts +63 -0
- package/src/__tests__/dynamic-skill-background-guard.test.ts +0 -2
- package/src/__tests__/edit-propagation.test.ts +107 -4
- package/src/__tests__/events-client-registration.test.ts +28 -0
- package/src/__tests__/file-write-tool.test.ts +4 -2
- package/src/__tests__/guardian-prompt-notice-privacy.test.ts +133 -0
- package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +143 -97
- package/src/__tests__/helpers/gateway-classify-mock.ts +27 -6
- package/src/__tests__/host-proxy-interface.test.ts +11 -1
- package/src/__tests__/host-shell-tool.test.ts +23 -4
- package/src/__tests__/image-conversion.test.ts +143 -1
- package/src/__tests__/inline-skill-load-permissions.test.ts +47 -36
- package/src/__tests__/input-repairs.test.ts +207 -0
- package/src/__tests__/live-workspace-guard.test.ts +75 -0
- package/src/__tests__/mcp-abort-signal.test.ts +1 -1
- package/src/__tests__/mcp-client-auth.test.ts +1 -1
- package/src/__tests__/mcp-tool-annotations-risk.test.ts +1 -1
- package/src/__tests__/media-resolve-image-validation.test.ts +310 -0
- package/src/__tests__/mtime-cache.test.ts +2 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +124 -1
- package/src/__tests__/openai-provider.test.ts +22 -0
- package/src/__tests__/personal-memory-auth-bypass.test.ts +22 -6
- package/src/__tests__/platform-bash-auto-approve.test.ts +0 -4
- package/src/__tests__/platform.test.ts +16 -1
- package/src/__tests__/plugin-api-resolve-credential.test.ts +22 -13
- package/src/__tests__/plugin-api-shim.test.ts +5 -0
- package/src/__tests__/plugin-api-store-credential.test.ts +268 -0
- package/src/__tests__/plugin-config-data-migration.test.ts +8 -1
- package/src/__tests__/plugin-disabled-state.test.ts +2 -0
- package/src/__tests__/plugin-effective-enabled-set.test.ts +55 -3
- package/src/__tests__/plugin-execution-context.test.ts +73 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -1
- package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +0 -1
- package/src/__tests__/reaction-persistence.test.ts +200 -7
- package/src/__tests__/require-fresh-approval.test.ts +0 -4
- package/src/__tests__/resource-pressure-guard.test.ts +428 -0
- package/src/__tests__/resource-pressure-routes.test.ts +113 -0
- package/src/__tests__/risk-classification-boundary-guard.test.ts +115 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +27 -1
- package/src/__tests__/secret-routes-platform-proxy.test.ts +7 -0
- package/src/__tests__/skill-tool-factory.test.ts +161 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +132 -5
- package/src/__tests__/tool-executor.test.ts +63 -38
- package/src/__tests__/tool-policy.test.ts +97 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +7 -4
- package/src/__tests__/user-plugin-loader.test.ts +2 -0
- package/src/__tests__/validate-input.test.ts +243 -7
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
- package/src/acp/__tests__/acp-claude-oauth.test.ts +97 -29
- package/src/acp/__tests__/prepare-agent-env.test.ts +376 -153
- package/src/acp/acp-claude-oauth.ts +38 -21
- package/src/acp/prepare-agent-env.ts +146 -55
- package/src/agent/loop-tool-dedup.test.ts +161 -0
- package/src/agent/loop.ts +68 -22
- package/src/api/constants/app-tools.ts +34 -0
- package/src/api/events/resource-pressure-status-changed.ts +53 -0
- package/src/api/index.ts +19 -0
- package/src/api/responses/resource-pressure-status.ts +25 -0
- package/src/approvals/guardian-channel-delivery.ts +70 -6
- package/src/approvals/guardian-request-resolvers.ts +32 -66
- package/src/channels/__tests__/message-audience.test.ts +49 -0
- package/src/channels/__tests__/types.test.ts +17 -3
- package/src/channels/message-audience.ts +40 -0
- package/src/channels/types.ts +16 -12
- package/src/cli/__tests__/catalog-search-help.test.ts +50 -0
- package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +31 -0
- package/src/cli/commands/__tests__/conversations-search.test.ts +289 -0
- package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -0
- package/src/cli/commands/__tests__/inference-providers.test.ts +68 -0
- package/src/cli/commands/__tests__/keys.test.ts +89 -8
- package/src/cli/commands/__tests__/plugins.test.ts +57 -1
- package/src/cli/commands/channel-verification-sessions.help.ts +11 -9
- package/src/cli/commands/channel-verification-sessions.ts +11 -21
- package/src/cli/commands/conversations.help.ts +34 -0
- package/src/cli/commands/conversations.ts +125 -0
- package/src/cli/commands/inference-providers.ts +9 -4
- package/src/cli/commands/inference.help.ts +9 -4
- package/src/cli/commands/keys.help.ts +13 -1
- package/src/cli/commands/keys.ts +26 -15
- package/src/cli/commands/memory/__tests__/memory-v2.test.ts +57 -7
- package/src/cli/commands/memory/index.help.ts +41 -27
- package/src/cli/commands/memory/index.ts +2 -0
- package/src/cli/commands/memory/memory-v2.ts +58 -54
- package/src/cli/commands/memory/memory-validate.ts +18 -0
- package/src/cli/commands/monitoring.ts +1 -0
- package/src/cli/commands/plugins.help.ts +28 -31
- package/src/cli/commands/plugins.ts +10 -0
- package/src/cli/commands/skills.help.ts +13 -16
- package/src/cli/commands/trust.ts +3 -14
- package/src/cli/lib/__tests__/install-from-github.test.ts +38 -0
- package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +34 -0
- package/src/cli/lib/__tests__/plugin-surfaces.test.ts +32 -1
- package/src/cli/lib/__tests__/toggle-plugin.test.ts +2 -1
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +64 -0
- package/src/cli/lib/bundled-marketplace.json +13 -0
- package/src/cli/lib/daemon-credential-client.ts +25 -3
- package/src/cli/lib/install-from-github.ts +35 -24
- package/src/cli/lib/merge-plugin-tree.ts +22 -4
- package/src/cli/lib/plugin-surfaces.ts +27 -0
- package/src/config/feature-flag-registry.json +35 -19
- package/src/config/webhook-routing.ts +8 -0
- package/src/context/compactor.ts +31 -2
- package/src/daemon/__tests__/provider-rejection-log-fields.test.ts +272 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +4 -1
- package/src/daemon/conversation-error.ts +13 -0
- package/src/daemon/conversation-messaging.ts +22 -2
- package/src/daemon/conversation-process.ts +11 -0
- package/src/daemon/conversation-store.ts +10 -0
- package/src/daemon/conversation-surfaces.ts +21 -8
- package/src/daemon/conversation.ts +12 -10
- package/src/daemon/lifecycle.ts +6 -2
- package/src/daemon/message-types/conversations.ts +5 -7
- package/src/daemon/provider-rejection-log-fields.ts +124 -0
- package/src/daemon/resource-pressure-guard-lifecycle.ts +66 -0
- package/src/daemon/resource-pressure-guard.ts +387 -0
- package/src/daemon/shutdown-handlers.ts +2 -0
- package/src/daemon/startup-error.ts +16 -0
- package/src/daemon/trust-context.ts +14 -10
- package/src/daemon/unsendable-image-notice.ts +76 -0
- package/src/hooks/registry.ts +65 -51
- package/src/ipc/__tests__/socket-path.test.ts +15 -7
- package/src/ipc/gateway-client.test.ts +1 -1
- package/src/ipc/gateway-client.ts +14 -21
- package/src/ipc/socket-cleanup.ts +2 -11
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +1 -1
- package/src/messaging/provider-message-metadata.ts +128 -0
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +116 -68
- package/src/messaging/providers/channel-transport.ts +90 -13
- package/src/messaging/providers/discord/send.ts +16 -0
- package/src/messaging/providers/discord/transport.ts +11 -1
- package/src/messaging/providers/index.ts +109 -16
- package/src/messaging/providers/slack/message-metadata.ts +45 -0
- package/src/messaging/providers/slack/render-transcript.ts +1 -4
- package/src/messaging/providers/slack/send.test.ts +6 -9
- package/src/messaging/providers/slack/send.ts +40 -28
- package/src/messaging/providers/slack/transport.ts +22 -26
- package/src/messaging/providers/telegram-bot/send.test.ts +2 -8
- package/src/messaging/providers/telegram-bot/transport.ts +3 -6
- package/src/messaging/read-provider-metadata.test.ts +157 -0
- package/src/messaging/read-provider-metadata.ts +51 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +94 -0
- package/src/notifications/__tests__/edit-notification.test.ts +174 -2
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +536 -4
- package/src/notifications/adapters/macos.ts +55 -0
- package/src/notifications/adapters/slack.ts +10 -5
- package/src/notifications/assistant-reply-producer.ts +37 -4
- package/src/notifications/conversation-pairing.ts +111 -21
- package/src/notifications/edit-notification.ts +38 -8
- package/src/notifications/emit-signal.ts +12 -14
- package/src/notifications/home-feed-side-effect.ts +218 -15
- package/src/notifications/types.ts +5 -0
- package/src/permissions/AGENTS.md +16 -0
- package/src/permissions/checker.test.ts +75 -122
- package/src/permissions/checker.ts +44 -560
- package/src/permissions/confirmation-guardian-request.test.ts +28 -3
- package/src/permissions/confirmation-guardian-request.ts +5 -1
- package/src/persistence/conversation-crud.ts +23 -20
- package/src/persistence/conversation-queries.ts +14 -1
- package/src/persistence/conversation-types.ts +22 -0
- package/src/persistence/delivery-crud.ts +122 -15
- package/src/plugin-api/__tests__/import-graph-partial-mock.test.ts +67 -0
- package/src/plugin-api/conversation-turn.ts +27 -0
- package/src/plugin-api/credential-scope.test.ts +15 -0
- package/src/plugin-api/credential-scope.ts +14 -0
- package/src/plugin-api/index.ts +19 -1
- package/src/plugin-api/resolve-credential.ts +15 -10
- package/src/plugin-api/store-credential.ts +148 -0
- package/src/plugin-api/system-card.ts +36 -0
- package/src/plugin-api/vision-support.test.ts +82 -0
- package/src/plugin-api/vision-support.ts +14 -2
- package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +361 -110
- package/src/plugins/defaults/image-fallback/__tests__/vision-recovery.test.ts +4 -0
- package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +58 -0
- package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +64 -23
- package/src/plugins/defaults/image-recovery/detect.ts +24 -1
- package/src/plugins/defaults/main.ts +15 -0
- package/src/plugins/defaults/memory/AGENTS.md +11 -3
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +0 -1
- package/src/plugins/defaults/memory/graph-topology/pending-buffer.ts +9 -12
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +1 -1
- package/src/plugins/defaults/memory/src/memory-v2-routes.ts +12 -10
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +114 -0
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +8 -0
- package/src/plugins/defaults/memory/substrate/__tests__/edge-index.test.ts +0 -30
- package/src/plugins/defaults/memory/substrate/__tests__/ingest.test.ts +73 -1
- package/src/plugins/defaults/memory/substrate/__tests__/page-index.test.ts +37 -0
- package/src/plugins/defaults/memory/substrate/__tests__/page-links.test.ts +208 -0
- package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +158 -1
- package/src/plugins/defaults/memory/substrate/__tests__/static-context.test.ts +1 -61
- package/src/plugins/defaults/memory/substrate/consolidation-job.ts +68 -6
- package/src/plugins/defaults/memory/substrate/edge-index.ts +0 -31
- package/src/plugins/defaults/memory/substrate/ingest.ts +59 -0
- package/src/plugins/defaults/memory/substrate/page-index.ts +35 -8
- package/src/plugins/defaults/memory/substrate/page-links.ts +133 -0
- package/src/plugins/defaults/memory/substrate/page-store.ts +10 -0
- package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +124 -34
- package/src/plugins/defaults/memory/substrate/static-context.ts +0 -29
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +3 -1
- package/src/plugins/defaults/memory/v3/card.ts +9 -9
- package/src/plugins/defaults/memory/v3/core-set.test.ts +7 -0
- package/src/plugins/defaults/memory/v3/core-set.ts +5 -1
- package/src/plugins/defaults/memory/v3/edge.ts +13 -57
- package/src/plugins/mtime-cache.ts +1 -1
- package/src/plugins/pipeline.ts +14 -7
- package/src/plugins/plugin-execution-context.ts +35 -11
- package/src/plugins/plugin-tree-walk.ts +63 -4
- package/src/providers/anthropic/__tests__/pause-turn-continuation.test.ts +170 -0
- package/src/providers/anthropic/client.ts +332 -241
- package/src/providers/connection-resolution.ts +2 -1
- package/src/providers/content-blocks.ts +22 -0
- package/src/providers/gemini/client.ts +5 -2
- package/src/providers/inference/__tests__/adapter-factory-litellm.test.ts +47 -1
- package/src/providers/inference/__tests__/adapter-factory-ollama.test.ts +83 -0
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +98 -1
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +38 -0
- package/src/providers/inference/__tests__/base-url-security.test.ts +10 -0
- package/src/providers/inference/__tests__/connections-ollama.test.ts +90 -0
- package/src/providers/inference/__tests__/missing-credential-guard.test.ts +117 -0
- package/src/providers/inference/adapter-factory.ts +33 -2
- package/src/providers/inference/auth.ts +13 -2
- package/src/providers/inference/credential-usage.ts +37 -0
- package/src/providers/inference/missing-credential-guard.ts +110 -0
- package/src/providers/inference/resolve-auth.ts +7 -7
- package/src/providers/media-resolve.ts +176 -15
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +576 -46
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +125 -2
- package/src/providers/openai/chat-completions-provider.ts +322 -42
- package/src/routes/route-host-protocol.ts +7 -0
- package/src/routes/worker.ts +31 -10
- package/src/runtime/AGENTS.md +35 -0
- package/src/runtime/__tests__/runtime-http-port-collision.test.ts +131 -0
- package/src/runtime/__tests__/web-presence.test.ts +234 -0
- package/src/runtime/assistant-event-hub.ts +38 -0
- package/src/runtime/channel-reply-delivery.ts +54 -31
- package/src/runtime/channel-retry-sweep.ts +6 -4
- package/src/runtime/effective-capabilities.test.ts +19 -0
- package/src/runtime/effective-capabilities.ts +25 -0
- package/src/runtime/guardian-reply-router.ts +6 -2
- package/src/runtime/http-errors.ts +1 -0
- package/src/runtime/http-server.ts +20 -5
- package/src/runtime/routes/__tests__/client-routes.test.ts +150 -0
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +133 -0
- package/src/runtime/routes/__tests__/credential-delete-in-use.test.ts +155 -0
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +52 -1
- package/src/runtime/routes/__tests__/monitoring-routes.test.ts +1 -0
- package/src/runtime/routes/__tests__/pending-interactions-route.test.ts +175 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +88 -35
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +55 -6
- package/src/runtime/routes/__tests__/system-card-turn-termination.test.ts +107 -0
- package/src/runtime/routes/__tests__/user-route-dispatcher-host.test.ts +52 -1
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +75 -4
- package/src/runtime/routes/approval-routes.ts +37 -4
- package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +16 -22
- package/src/runtime/routes/canned-message-complete.ts +68 -29
- package/src/runtime/routes/client-routes.ts +113 -0
- package/src/runtime/routes/conversation-list-routes.ts +22 -7
- package/src/runtime/routes/conversation-management-routes.ts +15 -9
- package/src/runtime/routes/conversation-routes.ts +36 -22
- package/src/runtime/routes/credential-in-use.ts +85 -0
- package/src/runtime/routes/credential-routes.ts +55 -85
- package/src/runtime/routes/guardian-approval-interception.ts +22 -22
- package/src/runtime/routes/guardian-approval-reply-helpers.ts +14 -12
- package/src/runtime/routes/identity-routes.ts +5 -121
- package/src/runtime/routes/inbound-message-handler.ts +71 -27
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +16 -17
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +77 -50
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -97
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +101 -77
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +17 -8
- package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +91 -7
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +72 -70
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +9 -7
- package/src/runtime/routes/monitoring-routes.ts +9 -1
- package/src/runtime/routes/plugins-routes.ts +17 -5
- package/src/runtime/routes/resource-pressure-routes.ts +22 -0
- package/src/runtime/routes/secret-routes.ts +39 -8
- package/src/runtime/routes/settings-routes.ts +6 -6
- package/src/runtime/routes/surface-action-routes.ts +20 -19
- package/src/runtime/routes/user-route-dispatcher.ts +31 -2
- package/src/runtime/routes/user-route-resolution.ts +18 -1
- package/src/runtime/slack-reply-session.test.ts +23 -13
- package/src/runtime/slack-reply-session.ts +38 -55
- package/src/runtime/web-presence.ts +90 -0
- package/src/skills/validate-input.ts +177 -40
- package/src/subagent/__tests__/consult-context-gating.test.ts +6 -10
- package/src/subagent/consult-context.ts +7 -23
- package/src/tools/credentials/broker.ts +24 -79
- package/src/tools/credentials/ref-parse.ts +35 -0
- package/src/tools/credentials/resolve.ts +4 -10
- package/src/tools/credentials/store.ts +168 -0
- package/src/tools/credentials/tool-policy.ts +67 -0
- package/src/tools/executor.ts +53 -15
- package/src/tools/network/__tests__/web-search.test.ts +41 -1
- package/src/tools/network/url-safety.ts +9 -16
- package/src/tools/network/web-search.ts +21 -3
- package/src/tools/permission-checker.ts +43 -52
- package/src/tools/schema-transforms.ts +40 -5
- package/src/tools/shared/input-repairs.ts +160 -0
- package/src/tools/skills/skill-tool-factory.ts +18 -4
- package/src/tools/subagent/spawn.ts +0 -1
- package/src/tools/tool-approval-handler.ts +16 -10
- package/src/tools/tool-types.ts +26 -13
- package/src/tools/types.ts +6 -6
- package/src/util/__tests__/cgroup-memory.test.ts +3 -0
- package/src/util/cgroup-memory.ts +3 -0
- package/src/util/container-cpu-sampler.ts +250 -0
- package/src/util/image-conversion.ts +178 -14
- package/src/util/platform.ts +93 -10
- package/src/permissions/ipc-risk-types.ts +0 -143
- package/src/permissions/risk-types.ts +0 -76
|
@@ -47,6 +47,18 @@ const log = getLogger("anthropic-client");
|
|
|
47
47
|
/** Validation-specific timeout (10s) so a stalled network doesn't block key submission. */
|
|
48
48
|
const VALIDATION_TIMEOUT_MS = 10_000;
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Cap on `pause_turn` continuations within one `sendMessage` call. The API
|
|
52
|
+
* pauses a long-running server-tool turn (e.g. web search) with
|
|
53
|
+
* `stop_reason: "pause_turn"`; the client resumes it by re-sending the paused
|
|
54
|
+
* assistant content as-is. The cap bounds pathological pause loops; web
|
|
55
|
+
* search allows `max_uses: 5` per turn, so 6 leaves headroom for one pause
|
|
56
|
+
* per search. On cap-out the response is returned as-is and the deferred-tail
|
|
57
|
+
* preservation in `analyzeServerToolPairing` keeps any unresolved
|
|
58
|
+
* `server_tool_use` blocks intact for a later request.
|
|
59
|
+
*/
|
|
60
|
+
export const MAX_PAUSE_TURN_CONTINUATIONS = 6;
|
|
61
|
+
|
|
50
62
|
/**
|
|
51
63
|
* Detect Anthropic's `prompt_too_long` context-overflow signal.
|
|
52
64
|
*
|
|
@@ -1357,6 +1369,10 @@ export class AnthropicProvider implements Provider {
|
|
|
1357
1369
|
}
|
|
1358
1370
|
|
|
1359
1371
|
let response: Anthropic.Message;
|
|
1372
|
+
// Paused segments accumulated by the `pause_turn` continuation loop,
|
|
1373
|
+
// in stream order, excluding the final response. Empty for the normal
|
|
1374
|
+
// single-request case.
|
|
1375
|
+
const pausedSegments: Anthropic.Message[] = [];
|
|
1360
1376
|
try {
|
|
1361
1377
|
recordProviderRequestDiagnostics({ model_id: params.model });
|
|
1362
1378
|
const requestHeaders = {
|
|
@@ -1369,284 +1385,359 @@ export class AnthropicProvider implements Provider {
|
|
|
1369
1385
|
? { headers: requestHeaders }
|
|
1370
1386
|
: {}),
|
|
1371
1387
|
};
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
requestOptions,
|
|
1381
|
-
) as unknown as UnifiedStream)
|
|
1382
|
-
: betas.length > 0
|
|
1388
|
+
// Issue one streaming request and return its final message. A local
|
|
1389
|
+
// helper so `pause_turn` continuations get fresh listener state per
|
|
1390
|
+
// request (content shadow, text sentinel buffer, tool-input
|
|
1391
|
+
// accumulators) instead of inheriting a prior segment's buffers.
|
|
1392
|
+
const streamOnce = async (
|
|
1393
|
+
streamParams: Anthropic.MessageStreamParams,
|
|
1394
|
+
): Promise<Anthropic.Message> => {
|
|
1395
|
+
const stream: UnifiedStream = useFastMode
|
|
1383
1396
|
? (this.client.beta.messages.stream(
|
|
1384
1397
|
{
|
|
1385
|
-
...(
|
|
1398
|
+
...(streamParams as Record<string, unknown>),
|
|
1399
|
+
speed: "fast" as const,
|
|
1386
1400
|
betas,
|
|
1387
1401
|
} as Anthropic.Beta.Messages.MessageCreateParamsNonStreaming &
|
|
1388
1402
|
Anthropic.Beta.Messages.MessageCreateParamsStreaming,
|
|
1389
1403
|
requestOptions,
|
|
1390
1404
|
) as unknown as UnifiedStream)
|
|
1391
|
-
:
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1405
|
+
: betas.length > 0
|
|
1406
|
+
? (this.client.beta.messages.stream(
|
|
1407
|
+
{
|
|
1408
|
+
...(streamParams as Record<string, unknown>),
|
|
1409
|
+
betas,
|
|
1410
|
+
} as Anthropic.Beta.Messages.MessageCreateParamsNonStreaming &
|
|
1411
|
+
Anthropic.Beta.Messages.MessageCreateParamsStreaming,
|
|
1412
|
+
requestOptions,
|
|
1413
|
+
) as unknown as UnifiedStream)
|
|
1414
|
+
: (this.client.messages.stream(
|
|
1415
|
+
streamParams,
|
|
1416
|
+
requestOptions,
|
|
1417
|
+
) as unknown as UnifiedStream);
|
|
1418
|
+
|
|
1419
|
+
// Shadow the streamed content blocks so a mid-stream SDK accumulator
|
|
1420
|
+
// failure on malformed tool-argument JSON can be salvaged instead of
|
|
1421
|
+
// discarding the whole response (see StreamContentShadow).
|
|
1422
|
+
const contentShadow = new StreamContentShadow();
|
|
1423
|
+
|
|
1424
|
+
// Buffer streaming text until it's clear the accumulated text isn't
|
|
1425
|
+
// going to form a placeholder sentinel. Sentinels are injected into
|
|
1426
|
+
// outbound requests for role alternation and are sometimes echoed by
|
|
1427
|
+
// the model — including an echo whose `\x00` guard arrived as a leading
|
|
1428
|
+
// space — so the prefix and completion checks normalize edge whitespace
|
|
1429
|
+
// and control bytes (the same normalization cleanAssistantContent and
|
|
1430
|
+
// the display serializer use). Holding back partial prefixes keeps them
|
|
1431
|
+
// off the live UI before they are stripped at completion. The buffer
|
|
1432
|
+
// resets on every content_block_start.
|
|
1433
|
+
let textBuffer = "";
|
|
1434
|
+
|
|
1435
|
+
stream.on("text", (text) => {
|
|
1436
|
+
textBuffer += text;
|
|
1437
|
+
if (couldBePlaceholderSentinelPrefix(textBuffer)) {
|
|
1438
|
+
return;
|
|
1439
|
+
}
|
|
1440
|
+
onEvent?.({ type: "text_delta", text: textBuffer });
|
|
1441
|
+
textBuffer = "";
|
|
1442
|
+
});
|
|
1420
1443
|
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1444
|
+
stream.on("thinking", (thinking) => {
|
|
1445
|
+
onEvent?.({ type: "thinking_delta", thinking });
|
|
1446
|
+
});
|
|
1424
1447
|
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
}
|
|
1454
|
-
if (
|
|
1455
|
-
event.type === "content_block_start" &&
|
|
1456
|
-
event.content_block.type === "tool_use"
|
|
1457
|
-
) {
|
|
1458
|
-
currentStreamingToolName = event.content_block.name;
|
|
1459
|
-
currentStreamingToolUseId = event.content_block.id;
|
|
1460
|
-
accumulatedInputJson = "";
|
|
1461
|
-
lastInputJsonEmitMs = 0;
|
|
1462
|
-
onEvent?.({
|
|
1463
|
-
type: "tool_use_preview_start",
|
|
1464
|
-
toolUseId: event.content_block.id,
|
|
1465
|
-
toolName: event.content_block.name,
|
|
1466
|
-
});
|
|
1467
|
-
}
|
|
1468
|
-
if (
|
|
1469
|
-
event.type === "content_block_start" &&
|
|
1470
|
-
event.content_block.type === "server_tool_use"
|
|
1471
|
-
) {
|
|
1472
|
-
currentServerToolUseId = event.content_block.id;
|
|
1473
|
-
accumulatedServerToolInputJson = "";
|
|
1474
|
-
onEvent?.({
|
|
1475
|
-
type: "server_tool_start",
|
|
1476
|
-
name: event.content_block.name,
|
|
1477
|
-
toolUseId: event.content_block.id,
|
|
1478
|
-
input:
|
|
1479
|
-
(event.content_block as { input?: Record<string, unknown> })
|
|
1480
|
-
.input ?? {},
|
|
1481
|
-
});
|
|
1482
|
-
}
|
|
1483
|
-
if (
|
|
1484
|
-
event.type === "content_block_start" &&
|
|
1485
|
-
event.content_block.type === "web_search_tool_result"
|
|
1486
|
-
) {
|
|
1487
|
-
const block = event.content_block as {
|
|
1488
|
-
tool_use_id: string;
|
|
1489
|
-
content?:
|
|
1490
|
-
| { type: "web_search_tool_result_error"; error_code?: string }
|
|
1491
|
-
| unknown[];
|
|
1492
|
-
};
|
|
1493
|
-
const isError =
|
|
1494
|
-
!Array.isArray(block.content) &&
|
|
1495
|
-
block.content?.type === "web_search_tool_result_error";
|
|
1496
|
-
const errorCode =
|
|
1497
|
-
isError && !Array.isArray(block.content)
|
|
1498
|
-
? block.content?.error_code
|
|
1499
|
-
: undefined;
|
|
1500
|
-
const resolvedInput = resolvedServerToolInputs.get(
|
|
1501
|
-
block.tool_use_id,
|
|
1502
|
-
);
|
|
1503
|
-
resolvedServerToolInputs.delete(block.tool_use_id);
|
|
1504
|
-
onEvent?.({
|
|
1505
|
-
type: "server_tool_complete",
|
|
1506
|
-
toolUseId: block.tool_use_id,
|
|
1507
|
-
isError: !!isError,
|
|
1508
|
-
...(Array.isArray(block.content)
|
|
1509
|
-
? { content: block.content }
|
|
1510
|
-
: {}),
|
|
1511
|
-
...(resolvedInput ? { resolvedInput } : {}),
|
|
1512
|
-
...(errorCode ? { errorCode } : {}),
|
|
1513
|
-
});
|
|
1514
|
-
}
|
|
1515
|
-
if (event.type === "content_block_stop") {
|
|
1516
|
-
if (pendingInputJsonFlush) {
|
|
1517
|
-
clearTimeout(pendingInputJsonFlush);
|
|
1518
|
-
pendingInputJsonFlush = undefined;
|
|
1448
|
+
// Track which tool is currently streaming so we can attribute inputJson deltas.
|
|
1449
|
+
let currentStreamingToolName: string | undefined;
|
|
1450
|
+
let currentStreamingToolUseId: string | undefined;
|
|
1451
|
+
let accumulatedInputJson = "";
|
|
1452
|
+
let lastInputJsonEmitMs = 0;
|
|
1453
|
+
let pendingInputJsonFlush: ReturnType<typeof setTimeout> | undefined;
|
|
1454
|
+
|
|
1455
|
+
// Anthropic streams `server_tool_use` block input via `input_json_delta`
|
|
1456
|
+
// events (the block's own `input` field is `{}` at content_block_start).
|
|
1457
|
+
// We accumulate the JSON separately from regular `tool_use` blocks so
|
|
1458
|
+
// the daemon can read the resolved query when the paired
|
|
1459
|
+
// `web_search_tool_result` arrives — without this, downstream activity
|
|
1460
|
+
// metadata sees an empty query.
|
|
1461
|
+
let currentServerToolUseId: string | undefined;
|
|
1462
|
+
let accumulatedServerToolInputJson = "";
|
|
1463
|
+
const resolvedServerToolInputs = new Map<
|
|
1464
|
+
string,
|
|
1465
|
+
Record<string, unknown>
|
|
1466
|
+
>();
|
|
1467
|
+
|
|
1468
|
+
stream.on("streamEvent", (event) => {
|
|
1469
|
+
contentShadow.handleEvent(event as ShadowStreamEvent);
|
|
1470
|
+
// Reset the text sentinel buffer at each content-block boundary.
|
|
1471
|
+
// A new block starts fresh; at the end of a block, flush any
|
|
1472
|
+
// buffered text that is NOT a complete sentinel, and drop it if
|
|
1473
|
+
// it is one.
|
|
1474
|
+
if (event.type === "content_block_start") {
|
|
1475
|
+
textBuffer = "";
|
|
1519
1476
|
}
|
|
1520
|
-
if (
|
|
1477
|
+
if (
|
|
1478
|
+
event.type === "content_block_start" &&
|
|
1479
|
+
event.content_block.type === "tool_use"
|
|
1480
|
+
) {
|
|
1481
|
+
currentStreamingToolName = event.content_block.name;
|
|
1482
|
+
currentStreamingToolUseId = event.content_block.id;
|
|
1483
|
+
accumulatedInputJson = "";
|
|
1484
|
+
lastInputJsonEmitMs = 0;
|
|
1521
1485
|
onEvent?.({
|
|
1522
|
-
type: "
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
accumulatedJson: accumulatedInputJson,
|
|
1486
|
+
type: "tool_use_preview_start",
|
|
1487
|
+
toolUseId: event.content_block.id,
|
|
1488
|
+
toolName: event.content_block.name,
|
|
1526
1489
|
});
|
|
1527
1490
|
}
|
|
1528
|
-
currentStreamingToolName = undefined;
|
|
1529
|
-
currentStreamingToolUseId = undefined;
|
|
1530
|
-
accumulatedInputJson = "";
|
|
1531
|
-
// Finalize the resolved input for a `server_tool_use` block (e.g.
|
|
1532
|
-
// the actual web-search query) so the paired `web_search_tool_result`
|
|
1533
|
-
// emits `server_tool_complete` with `resolvedInput` populated.
|
|
1534
|
-
if (currentServerToolUseId && accumulatedServerToolInputJson) {
|
|
1535
|
-
try {
|
|
1536
|
-
const parsed = JSON.parse(accumulatedServerToolInputJson);
|
|
1537
|
-
if (parsed && typeof parsed === "object") {
|
|
1538
|
-
resolvedServerToolInputs.set(
|
|
1539
|
-
currentServerToolUseId,
|
|
1540
|
-
parsed as Record<string, unknown>,
|
|
1541
|
-
);
|
|
1542
|
-
}
|
|
1543
|
-
} catch {
|
|
1544
|
-
// Malformed partial JSON — drop silently; downstream falls
|
|
1545
|
-
// back to whatever was captured at server_tool_start.
|
|
1546
|
-
}
|
|
1547
|
-
}
|
|
1548
|
-
currentServerToolUseId = undefined;
|
|
1549
|
-
accumulatedServerToolInputJson = "";
|
|
1550
|
-
// Flush residual text buffer unless it is a sentinel.
|
|
1551
1491
|
if (
|
|
1552
|
-
|
|
1553
|
-
|
|
1492
|
+
event.type === "content_block_start" &&
|
|
1493
|
+
event.content_block.type === "server_tool_use"
|
|
1554
1494
|
) {
|
|
1555
|
-
|
|
1495
|
+
currentServerToolUseId = event.content_block.id;
|
|
1496
|
+
accumulatedServerToolInputJson = "";
|
|
1497
|
+
onEvent?.({
|
|
1498
|
+
type: "server_tool_start",
|
|
1499
|
+
name: event.content_block.name,
|
|
1500
|
+
toolUseId: event.content_block.id,
|
|
1501
|
+
input:
|
|
1502
|
+
(event.content_block as { input?: Record<string, unknown> })
|
|
1503
|
+
.input ?? {},
|
|
1504
|
+
});
|
|
1556
1505
|
}
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1506
|
+
if (
|
|
1507
|
+
event.type === "content_block_start" &&
|
|
1508
|
+
event.content_block.type === "web_search_tool_result"
|
|
1509
|
+
) {
|
|
1510
|
+
const block = event.content_block as {
|
|
1511
|
+
tool_use_id: string;
|
|
1512
|
+
content?:
|
|
1513
|
+
| {
|
|
1514
|
+
type: "web_search_tool_result_error";
|
|
1515
|
+
error_code?: string;
|
|
1516
|
+
}
|
|
1517
|
+
| unknown[];
|
|
1518
|
+
};
|
|
1519
|
+
const isError =
|
|
1520
|
+
!Array.isArray(block.content) &&
|
|
1521
|
+
block.content?.type === "web_search_tool_result_error";
|
|
1522
|
+
const errorCode =
|
|
1523
|
+
isError && !Array.isArray(block.content)
|
|
1524
|
+
? block.content?.error_code
|
|
1525
|
+
: undefined;
|
|
1526
|
+
const resolvedInput = resolvedServerToolInputs.get(
|
|
1527
|
+
block.tool_use_id,
|
|
1528
|
+
);
|
|
1529
|
+
resolvedServerToolInputs.delete(block.tool_use_id);
|
|
1530
|
+
onEvent?.({
|
|
1531
|
+
type: "server_tool_complete",
|
|
1532
|
+
toolUseId: block.tool_use_id,
|
|
1533
|
+
isError: !!isError,
|
|
1534
|
+
...(Array.isArray(block.content)
|
|
1535
|
+
? { content: block.content }
|
|
1536
|
+
: {}),
|
|
1537
|
+
...(resolvedInput ? { resolvedInput } : {}),
|
|
1538
|
+
...(errorCode ? { errorCode } : {}),
|
|
1539
|
+
});
|
|
1579
1540
|
}
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
} else if (!pendingInputJsonFlush) {
|
|
1587
|
-
const toolName = currentStreamingToolName;
|
|
1588
|
-
const toolUseId = currentStreamingToolUseId!;
|
|
1589
|
-
pendingInputJsonFlush = setTimeout(() => {
|
|
1590
|
-
pendingInputJsonFlush = undefined;
|
|
1591
|
-
lastInputJsonEmitMs = Date.now();
|
|
1592
|
-
if (currentStreamingToolName === toolName) {
|
|
1541
|
+
if (event.type === "content_block_stop") {
|
|
1542
|
+
if (pendingInputJsonFlush) {
|
|
1543
|
+
clearTimeout(pendingInputJsonFlush);
|
|
1544
|
+
pendingInputJsonFlush = undefined;
|
|
1545
|
+
}
|
|
1546
|
+
if (currentStreamingToolName && accumulatedInputJson) {
|
|
1593
1547
|
onEvent?.({
|
|
1594
1548
|
type: "input_json_delta",
|
|
1595
|
-
toolName,
|
|
1596
|
-
toolUseId
|
|
1549
|
+
toolName: currentStreamingToolName,
|
|
1550
|
+
toolUseId: currentStreamingToolUseId!,
|
|
1597
1551
|
accumulatedJson: accumulatedInputJson,
|
|
1598
1552
|
});
|
|
1599
1553
|
}
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1554
|
+
currentStreamingToolName = undefined;
|
|
1555
|
+
currentStreamingToolUseId = undefined;
|
|
1556
|
+
accumulatedInputJson = "";
|
|
1557
|
+
// Finalize the resolved input for a `server_tool_use` block (e.g.
|
|
1558
|
+
// the actual web-search query) so the paired `web_search_tool_result`
|
|
1559
|
+
// emits `server_tool_complete` with `resolvedInput` populated.
|
|
1560
|
+
if (currentServerToolUseId && accumulatedServerToolInputJson) {
|
|
1561
|
+
try {
|
|
1562
|
+
const parsed = JSON.parse(accumulatedServerToolInputJson);
|
|
1563
|
+
if (parsed && typeof parsed === "object") {
|
|
1564
|
+
resolvedServerToolInputs.set(
|
|
1565
|
+
currentServerToolUseId,
|
|
1566
|
+
parsed as Record<string, unknown>,
|
|
1567
|
+
);
|
|
1568
|
+
}
|
|
1569
|
+
} catch {
|
|
1570
|
+
// Malformed partial JSON — drop silently; downstream falls
|
|
1571
|
+
// back to whatever was captured at server_tool_start.
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
currentServerToolUseId = undefined;
|
|
1575
|
+
accumulatedServerToolInputJson = "";
|
|
1576
|
+
// Flush residual text buffer unless it is a sentinel.
|
|
1577
|
+
if (
|
|
1578
|
+
textBuffer.length > 0 &&
|
|
1579
|
+
!isPlaceholderSentinelText(textBuffer)
|
|
1580
|
+
) {
|
|
1581
|
+
onEvent?.({ type: "text_delta", text: textBuffer });
|
|
1582
|
+
}
|
|
1583
|
+
textBuffer = "";
|
|
1584
|
+
}
|
|
1585
|
+
});
|
|
1603
1586
|
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1587
|
+
stream.on("inputJson", (partialJson) => {
|
|
1588
|
+
if (currentServerToolUseId) {
|
|
1589
|
+
// Server-tool input (e.g. `web_search` query) — accumulate without
|
|
1590
|
+
// emitting `input_json_delta`; the daemon only consumes the
|
|
1591
|
+
// finalized value from `server_tool_complete.resolvedInput`.
|
|
1592
|
+
accumulatedServerToolInputJson += partialJson;
|
|
1593
|
+
return;
|
|
1594
|
+
}
|
|
1595
|
+
if (!currentStreamingToolName) {
|
|
1596
|
+
return;
|
|
1597
|
+
}
|
|
1598
|
+
accumulatedInputJson += partialJson;
|
|
1599
|
+
const now = Date.now();
|
|
1600
|
+
if (now - lastInputJsonEmitMs >= 150) {
|
|
1601
|
+
lastInputJsonEmitMs = now;
|
|
1602
|
+
if (pendingInputJsonFlush) {
|
|
1603
|
+
clearTimeout(pendingInputJsonFlush);
|
|
1604
|
+
pendingInputJsonFlush = undefined;
|
|
1605
|
+
}
|
|
1606
|
+
onEvent?.({
|
|
1607
|
+
type: "input_json_delta",
|
|
1608
|
+
toolName: currentStreamingToolName,
|
|
1609
|
+
toolUseId: currentStreamingToolUseId!,
|
|
1610
|
+
accumulatedJson: accumulatedInputJson,
|
|
1611
|
+
});
|
|
1612
|
+
} else if (!pendingInputJsonFlush) {
|
|
1613
|
+
const toolName = currentStreamingToolName;
|
|
1614
|
+
const toolUseId = currentStreamingToolUseId!;
|
|
1615
|
+
pendingInputJsonFlush = setTimeout(() => {
|
|
1616
|
+
pendingInputJsonFlush = undefined;
|
|
1617
|
+
lastInputJsonEmitMs = Date.now();
|
|
1618
|
+
if (currentStreamingToolName === toolName) {
|
|
1619
|
+
onEvent?.({
|
|
1620
|
+
type: "input_json_delta",
|
|
1621
|
+
toolName,
|
|
1622
|
+
toolUseId,
|
|
1623
|
+
accumulatedJson: accumulatedInputJson,
|
|
1624
|
+
});
|
|
1625
|
+
}
|
|
1626
|
+
}, 150);
|
|
1627
|
+
}
|
|
1628
|
+
});
|
|
1629
|
+
|
|
1630
|
+
try {
|
|
1631
|
+
return await stream.finalMessage();
|
|
1632
|
+
} catch (error) {
|
|
1633
|
+
// The SDK rejects finalMessage() the moment a tool_use block's
|
|
1634
|
+
// argument JSON stops parsing, discarding everything it streamed.
|
|
1635
|
+
// Salvage the observed prefix instead: completed blocks plus the
|
|
1636
|
+
// malformed call wrapped under `_raw`, which the tool layer bounces
|
|
1637
|
+
// back to the model as an error tool_result so it can self-correct
|
|
1638
|
+
// in the next iteration. Any other rejection rethrows untouched.
|
|
1639
|
+
const salvaged = contentShadow.salvage(error);
|
|
1640
|
+
if (salvaged === undefined) {
|
|
1641
|
+
throw error;
|
|
1642
|
+
}
|
|
1643
|
+
log.warn(
|
|
1644
|
+
{
|
|
1645
|
+
model: streamParams.model,
|
|
1646
|
+
toolName: salvaged.toolName,
|
|
1647
|
+
rawArgsLength: salvaged.rawArgsLength,
|
|
1648
|
+
},
|
|
1649
|
+
"Salvaged stream with unparseable tool-call arguments; returning _raw-wrapped tool call",
|
|
1650
|
+
);
|
|
1651
|
+
return {
|
|
1652
|
+
...salvaged.message,
|
|
1653
|
+
model: streamParams.model,
|
|
1654
|
+
} as unknown as Anthropic.Message;
|
|
1616
1655
|
}
|
|
1617
|
-
|
|
1656
|
+
};
|
|
1657
|
+
|
|
1658
|
+
response = await streamOnce(params);
|
|
1659
|
+
|
|
1660
|
+
// `pause_turn`: the API paused a long-running server-tool turn (e.g.
|
|
1661
|
+
// web search) mid-execution. The documented resume flow is to re-send
|
|
1662
|
+
// the paused assistant content as-is in a follow-up request; the
|
|
1663
|
+
// model then continues the same turn. Each paused segment is kept so
|
|
1664
|
+
// the returned response carries the full turn's content and summed
|
|
1665
|
+
// usage. On cap-out the paused response returns as-is — downstream
|
|
1666
|
+
// deferred-tail preservation keeps its unresolved `server_tool_use`
|
|
1667
|
+
// blocks intact.
|
|
1668
|
+
while (
|
|
1669
|
+
response.stop_reason === "pause_turn" &&
|
|
1670
|
+
pausedSegments.length < MAX_PAUSE_TURN_CONTINUATIONS
|
|
1671
|
+
) {
|
|
1672
|
+
pausedSegments.push(response);
|
|
1673
|
+
log.info(
|
|
1618
1674
|
{
|
|
1619
1675
|
model: params.model,
|
|
1620
|
-
|
|
1621
|
-
|
|
1676
|
+
continuation: pausedSegments.length,
|
|
1677
|
+
contentBlocks: response.content.length,
|
|
1622
1678
|
},
|
|
1623
|
-
"
|
|
1679
|
+
"Anthropic pause_turn — re-sending paused assistant content to resume the turn",
|
|
1680
|
+
);
|
|
1681
|
+
params = {
|
|
1682
|
+
...params,
|
|
1683
|
+
messages: [
|
|
1684
|
+
...params.messages,
|
|
1685
|
+
{ role: "assistant" as const, content: response.content },
|
|
1686
|
+
],
|
|
1687
|
+
};
|
|
1688
|
+
// Keep the 400-diagnostics dump in the catch block accurate for
|
|
1689
|
+
// continuation requests.
|
|
1690
|
+
sentMessages = params.messages;
|
|
1691
|
+
response = await streamOnce(params);
|
|
1692
|
+
}
|
|
1693
|
+
if (response.stop_reason === "pause_turn") {
|
|
1694
|
+
log.warn(
|
|
1695
|
+
{ model: params.model, continuations: pausedSegments.length },
|
|
1696
|
+
"Anthropic pause_turn continuation cap reached; returning paused response as-is",
|
|
1624
1697
|
);
|
|
1625
|
-
response = {
|
|
1626
|
-
...salvaged.message,
|
|
1627
|
-
model: params.model,
|
|
1628
|
-
} as unknown as Anthropic.Message;
|
|
1629
1698
|
}
|
|
1630
1699
|
} finally {
|
|
1631
1700
|
cleanupTimeout();
|
|
1632
1701
|
}
|
|
1633
1702
|
|
|
1703
|
+
// A paused turn spans several billed requests: the assistant content is
|
|
1704
|
+
// every paused segment's content followed by the final response's, and
|
|
1705
|
+
// usage sums across all of them. With no paused segments this reduces
|
|
1706
|
+
// to the single response.
|
|
1707
|
+
const segments = [...pausedSegments, response];
|
|
1708
|
+
const sumOptional = (
|
|
1709
|
+
values: Array<number | null | undefined>,
|
|
1710
|
+
): number | undefined =>
|
|
1711
|
+
values.some((v) => typeof v === "number")
|
|
1712
|
+
? values.reduce<number>((acc, v) => acc + (v ?? 0), 0)
|
|
1713
|
+
: undefined;
|
|
1634
1714
|
return {
|
|
1635
|
-
content:
|
|
1636
|
-
|
|
1637
|
-
|
|
1715
|
+
content: segments
|
|
1716
|
+
.flatMap((segment) => segment.content)
|
|
1717
|
+
.map((block) => this.fromAnthropicBlock(block)),
|
|
1638
1718
|
model: response.model,
|
|
1639
1719
|
resolvedEndpoint: this.client.baseURL,
|
|
1640
1720
|
usage: {
|
|
1641
|
-
inputTokens:
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1721
|
+
inputTokens: segments.reduce(
|
|
1722
|
+
(acc, segment) =>
|
|
1723
|
+
acc +
|
|
1724
|
+
segment.usage.input_tokens +
|
|
1725
|
+
(segment.usage.cache_creation_input_tokens ?? 0) +
|
|
1726
|
+
(segment.usage.cache_read_input_tokens ?? 0),
|
|
1727
|
+
0,
|
|
1728
|
+
),
|
|
1729
|
+
outputTokens: segments.reduce(
|
|
1730
|
+
(acc, segment) => acc + segment.usage.output_tokens,
|
|
1731
|
+
0,
|
|
1732
|
+
),
|
|
1733
|
+
cacheCreationInputTokens: sumOptional(
|
|
1734
|
+
segments.map(
|
|
1735
|
+
(segment) => segment.usage.cache_creation_input_tokens,
|
|
1736
|
+
),
|
|
1737
|
+
),
|
|
1738
|
+
cacheReadInputTokens: sumOptional(
|
|
1739
|
+
segments.map((segment) => segment.usage.cache_read_input_tokens),
|
|
1740
|
+
),
|
|
1650
1741
|
},
|
|
1651
1742
|
stopReason: response.stop_reason ?? "unknown",
|
|
1652
1743
|
rawRequest: params,
|
|
@@ -706,7 +706,8 @@ export async function preflightResolvedConfig(
|
|
|
706
706
|
|
|
707
707
|
switch (connection.auth.type) {
|
|
708
708
|
case "api_key":
|
|
709
|
-
case "oauth_subscription":
|
|
709
|
+
case "oauth_subscription":
|
|
710
|
+
case "service_account": {
|
|
710
711
|
const presence = await checkCredentialPresence(
|
|
711
712
|
connection.auth.credential,
|
|
712
713
|
);
|