@vellumai/assistant 0.6.3 → 0.6.4
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/ARCHITECTURE.md +273 -10
- package/Dockerfile +2 -3
- package/bun.lock +5 -13
- package/docs/backup-troubleshooting.md +52 -0
- package/docs/browser-use-architecture-phase2.md +174 -0
- package/docs/stt-provider-onboarding.md +120 -0
- package/knip.json +12 -2
- package/node_modules/@vellumai/ces-contracts/bun.lock +8 -6
- package/node_modules/@vellumai/ces-contracts/package.json +3 -3
- package/openapi.yaml +982 -72
- package/package.json +4 -6
- package/scripts/generate-openapi.ts +0 -1
- package/scripts/test.sh +73 -18
- package/src/__tests__/agent-image-optimize.test.ts +28 -0
- package/src/__tests__/agent-loop.test.ts +123 -0
- package/src/__tests__/anthropic-provider.test.ts +263 -10
- package/src/__tests__/auto-analysis-end-to-end.test.ts +550 -0
- package/src/__tests__/auto-analysis-prompt.test.ts +50 -0
- package/src/__tests__/browser-fill-credential.test.ts +11 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
- package/src/__tests__/browser-skill-endstate.test.ts +31 -7
- package/src/__tests__/btw-routes.test.ts +7 -0
- package/src/__tests__/call-controller.test.ts +581 -20
- package/src/__tests__/catalog-files.test.ts +138 -0
- package/src/__tests__/channel-invite-transport.test.ts +2 -2
- package/src/__tests__/channel-readiness-routes.test.ts +16 -20
- package/src/__tests__/channel-readiness-service.test.ts +12 -7
- package/src/__tests__/checker.test.ts +157 -10
- package/src/__tests__/clawhub-files.test.ts +347 -0
- package/src/__tests__/commit-message-enrichment-service.test.ts +36 -19
- package/src/__tests__/config-analysis.test.ts +100 -0
- package/src/__tests__/config-schema.test.ts +1013 -66
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
- package/src/__tests__/config-watcher.test.ts +43 -8
- package/src/__tests__/contact-store-user-file.test.ts +512 -0
- package/src/__tests__/contacts-write.test.ts +197 -0
- package/src/__tests__/context-window-manager.test.ts +88 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop.test.ts +98 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +135 -0
- package/src/__tests__/conversation-error.test.ts +70 -0
- package/src/__tests__/conversation-history-web-search.test.ts +11 -4
- package/src/__tests__/conversation-init.benchmark.test.ts +6 -1
- package/src/__tests__/conversation-launcher-skill-regression.test.ts +51 -0
- package/src/__tests__/conversation-list-source.test.ts +145 -0
- package/src/__tests__/conversation-pre-run-repair.test.ts +2 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
- package/src/__tests__/conversation-queue.test.ts +901 -60
- package/src/__tests__/conversation-routes-disk-view.test.ts +270 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +55 -0
- package/src/__tests__/conversation-skill-tools.test.ts +7 -4
- package/src/__tests__/conversation-slash-commands.test.ts +33 -0
- package/src/__tests__/conversation-slash-queue.test.ts +89 -18
- package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +226 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
- package/src/__tests__/credential-health-service.test.ts +352 -0
- package/src/__tests__/credential-security-invariants.test.ts +5 -3
- package/src/__tests__/credential-vault-unit.test.ts +379 -3
- package/src/__tests__/credentials-cli.test.ts +40 -16
- package/src/__tests__/cross-provider-web-search.test.ts +146 -35
- package/src/__tests__/deterministic-verification-control-plane.test.ts +10 -1
- package/src/__tests__/device-id.test.ts +112 -0
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +167 -4
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -3
- package/src/__tests__/email-html-renderer.test.ts +71 -0
- package/src/__tests__/email-invite-adapter.test.ts +36 -32
- package/src/__tests__/emit-event-signal.test.ts +71 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +75 -8
- package/src/__tests__/fixtures/mock-chrome-extension.ts +11 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +206 -1
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/gemini-provider.test.ts +64 -0
- package/src/__tests__/get-skill-detail-audit.test.ts +325 -0
- package/src/__tests__/gmail-archive-fallback.test.ts +193 -0
- package/src/__tests__/gmail-archive-gate.test.ts +246 -0
- package/src/__tests__/gmail-preferences.test.ts +117 -0
- package/src/__tests__/headless-browser-interactions.test.ts +43 -0
- package/src/__tests__/headless-browser-mode.test.ts +614 -0
- package/src/__tests__/headless-browser-navigate.test.ts +142 -5
- package/src/__tests__/headless-browser-read-tools.test.ts +11 -0
- package/src/__tests__/headless-browser-snapshot.test.ts +10 -0
- package/src/__tests__/heartbeat-service.test.ts +70 -17
- package/src/__tests__/home-state-routes.test.ts +162 -0
- package/src/__tests__/host-bash-proxy.test.ts +0 -5
- package/src/__tests__/host-browser-e2e-cloud.test.ts +138 -4
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +4 -4
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +103 -0
- package/src/__tests__/host-cu-proxy.test.ts +0 -5
- package/src/__tests__/identity-intro-cache.test.ts +40 -10
- package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
- package/src/__tests__/llm-context-normalization.test.ts +488 -0
- package/src/__tests__/llm-context-route-provider.test.ts +86 -5
- package/src/__tests__/llm-usage-store.test.ts +363 -0
- package/src/__tests__/media-stream-output.test.ts +555 -0
- package/src/__tests__/media-stream-parser.test.ts +374 -0
- package/src/__tests__/media-stream-server-integration.test.ts +1234 -0
- package/src/__tests__/media-stream-stt-session.test.ts +588 -0
- package/src/__tests__/media-turn-detector.test.ts +440 -0
- package/src/__tests__/message-queue.test.ts +125 -0
- package/src/__tests__/migration-export-http.test.ts +6 -6
- package/src/__tests__/migration-import-commit-http.test.ts +8 -6
- package/src/__tests__/migration-import-preflight-http.test.ts +6 -5
- package/src/__tests__/migration-validate-http.test.ts +3 -3
- package/src/__tests__/mock-gateway-ipc.ts +151 -0
- package/src/__tests__/model-intents.test.ts +2 -2
- package/src/__tests__/oauth-apps-routes.test.ts +1 -0
- package/src/__tests__/oauth-cli.test.ts +2 -0
- package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +1 -0
- package/src/__tests__/oauth-providers-routes.test.ts +2 -0
- package/src/__tests__/oauth-store.test.ts +85 -0
- package/src/__tests__/oauth2-gateway-transport.test.ts +249 -6
- package/src/__tests__/onboarding-template-contract.test.ts +6 -13
- package/src/__tests__/openai-provider.test.ts +176 -0
- package/src/__tests__/openai-responses-cutover-guard.test.ts +184 -0
- package/src/__tests__/openai-responses-provider.test.ts +1105 -0
- package/src/__tests__/openrouter-token-estimation.test.ts +100 -0
- package/src/__tests__/outlook-unsubscribe.test.ts +31 -2
- package/src/__tests__/persona-resolver.test.ts +251 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +4 -0
- package/src/__tests__/platform.test.ts +92 -1
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +47 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +267 -0
- package/src/__tests__/pricing.test.ts +174 -0
- package/src/__tests__/qdrant-manager.test.ts +29 -8
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +194 -0
- package/src/__tests__/relationship-state-contract.test.ts +175 -0
- package/src/__tests__/relay-server.test.ts +423 -5
- package/src/__tests__/search-skills-unified.test.ts +118 -0
- package/src/__tests__/secret-scanner-executor.test.ts +4 -0
- package/src/__tests__/secure-keys.test.ts +107 -0
- package/src/__tests__/send-endpoint-busy.test.ts +5 -1
- package/src/__tests__/sequence-store.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +49 -0
- package/src/__tests__/settings-routes.test.ts +201 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
- package/src/__tests__/skills-file-content-endpoint.test.ts +276 -145
- package/src/__tests__/skills-files-catalog-fallback.test.ts +381 -93
- package/src/__tests__/skills.test.ts +5 -2
- package/src/__tests__/skillssh-files.test.ts +446 -0
- package/src/__tests__/slack-block-formatting.test.ts +110 -0
- package/src/__tests__/slack-channel-config.test.ts +564 -1
- package/src/__tests__/stt-catalog-parity.test.ts +282 -0
- package/src/__tests__/stt-stream-session.test.ts +535 -0
- package/src/__tests__/system-prompt.test.ts +112 -26
- package/src/__tests__/telephony-stt-routing.test.ts +329 -0
- package/src/__tests__/terminal-tools.test.ts +18 -7
- package/src/__tests__/test-preload.ts +18 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +4 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +9 -5
- package/src/__tests__/tool-executor-shell-integration.test.ts +4 -0
- package/src/__tests__/tool-executor.test.ts +33 -24
- package/src/__tests__/tool-result-truncation.test.ts +36 -0
- package/src/__tests__/trust-store.test.ts +7 -1
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -1
- package/src/__tests__/tts-catalog-parity.test.ts +345 -0
- package/src/__tests__/twilio-routes-twiml.test.ts +512 -114
- package/src/__tests__/twilio-routes.test.ts +376 -0
- package/src/__tests__/unicode.test.ts +293 -0
- package/src/__tests__/update-bulletin-format.test.ts +59 -0
- package/src/__tests__/update-bulletin.test.ts +206 -5
- package/src/__tests__/usage-routes.test.ts +25 -4
- package/src/__tests__/user-reference.test.ts +46 -61
- package/src/__tests__/verification-control-plane-policy.test.ts +4 -0
- package/src/__tests__/voice-config-update.test.ts +403 -0
- package/src/__tests__/voice-quality.test.ts +434 -19
- package/src/__tests__/workspace-heartbeat-service.test.ts +7 -0
- package/src/__tests__/workspace-migration-033-stt-service-explicit-config.test.ts +547 -0
- package/src/__tests__/workspace-migration-034-remove-calls-voice-transcription-provider.test.ts +596 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +368 -0
- package/src/__tests__/workspace-migration-meets.test.ts +244 -0
- package/src/__tests__/workspace-migration-seed-device-id.test.ts +14 -20
- package/src/__tests__/workspace-policy.test.ts +2 -0
- package/src/agent/image-optimize.ts +24 -12
- package/src/agent/loop.ts +43 -3
- package/src/backup/__tests__/backup-key.test.ts +152 -0
- package/src/backup/__tests__/backup-worker.test.ts +767 -0
- package/src/backup/__tests__/list-snapshots.test.ts +87 -0
- package/src/backup/__tests__/local-writer.test.ts +218 -0
- package/src/backup/__tests__/offsite-writer.test.ts +641 -0
- package/src/backup/__tests__/paths.test.ts +300 -0
- package/src/backup/__tests__/restore.test.ts +498 -0
- package/src/backup/__tests__/snapshot-lock.test.ts +352 -0
- package/src/backup/__tests__/stream-crypt.test.ts +228 -0
- package/src/backup/backup-key.ts +137 -0
- package/src/backup/backup-worker.ts +459 -0
- package/src/backup/list-snapshots.ts +147 -0
- package/src/backup/local-writer.ts +133 -0
- package/src/backup/offsite-writer.ts +222 -0
- package/src/backup/paths.ts +226 -0
- package/src/backup/restore.ts +322 -0
- package/src/backup/snapshot-lock.ts +431 -0
- package/src/backup/stream-crypt.ts +263 -0
- package/src/bundler/package-resolver.ts +4 -0
- package/src/calls/audio-store.ts +11 -5
- package/src/calls/call-controller.ts +226 -71
- package/src/calls/call-domain.ts +9 -0
- package/src/calls/call-speech-output.ts +190 -0
- package/src/calls/call-transport.ts +77 -0
- package/src/calls/media-stream-audio-transcode.ts +173 -0
- package/src/calls/media-stream-output.ts +660 -0
- package/src/calls/media-stream-parser.ts +300 -0
- package/src/calls/media-stream-protocol.ts +166 -0
- package/src/calls/media-stream-server.ts +592 -0
- package/src/calls/media-stream-stt-session.ts +460 -0
- package/src/calls/media-turn-detector.ts +230 -0
- package/src/calls/relay-server.ts +90 -75
- package/src/calls/resolve-call-tts-provider.ts +136 -0
- package/src/calls/telephony-stt-routing.ts +145 -0
- package/src/calls/tts-call-strategy.ts +161 -0
- package/src/calls/tts-text-sanitizer.ts +32 -16
- package/src/calls/twilio-routes.ts +281 -17
- package/src/calls/voice-quality.ts +78 -35
- package/src/calls/voice-session-bridge.ts +8 -1
- package/src/channels/types.ts +16 -0
- package/src/cli/__tests__/run-assistant-command.ts +11 -1
- package/src/cli/commands/__tests__/backup.test.ts +1165 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +234 -0
- package/src/cli/commands/__tests__/domain-status.test.ts +132 -0
- package/src/cli/commands/__tests__/email-attachment.test.ts +422 -0
- package/src/cli/commands/__tests__/email-download.test.ts +16 -1
- package/src/cli/commands/__tests__/email-list.test.ts +22 -4
- package/src/cli/commands/__tests__/email-register.test.ts +4 -4
- package/src/cli/commands/__tests__/email-send.test.ts +37 -4
- package/src/cli/commands/__tests__/email-status.test.ts +5 -1
- package/src/cli/commands/__tests__/email-unregister.test.ts +34 -5
- package/src/cli/commands/backup.ts +993 -0
- package/src/cli/commands/conversations.ts +77 -0
- package/src/cli/commands/credentials.ts +0 -1
- package/src/cli/commands/domain.ts +210 -0
- package/src/cli/commands/email.ts +255 -3
- package/src/cli/commands/oauth/__tests__/connect.test.ts +12 -0
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +1 -0
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -0
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -0
- package/src/cli/commands/oauth/mode.ts +12 -3
- package/src/cli/commands/oauth/providers.ts +15 -0
- package/src/cli/commands/oauth/shared.ts +2 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +4 -9
- package/src/cli/commands/platform/__tests__/connect.test.ts +6 -0
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +6 -0
- package/src/cli/program.ts +30 -4
- package/src/config/__tests__/backup-schema.test.ts +134 -0
- package/src/config/assistant-feature-flags.ts +61 -62
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +37 -1
- package/src/config/bundled-skills/browser/SKILL.md +30 -5
- package/src/config/bundled-skills/browser/TOOLS.json +123 -0
- package/src/config/bundled-skills/browser/tools/browser-attach.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-detach.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-status.ts +12 -0
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +17 -0
- package/src/config/bundled-skills/contacts/SKILL.md +2 -2
- package/src/config/bundled-skills/gmail/SKILL.md +53 -7
- package/src/config/bundled-skills/gmail/TOOLS.json +33 -3
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +116 -9
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +138 -11
- package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +59 -0
- package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +82 -0
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +113 -17
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -2
- package/src/config/bundled-skills/media-processing/SKILL.md +3 -9
- package/src/config/bundled-skills/media-processing/TOOLS.json +1 -6
- package/src/config/bundled-skills/media-processing/__tests__/audio-transcribe.test.ts +125 -0
- package/src/config/bundled-skills/media-processing/__tests__/extract-keyframes.test.ts +181 -0
- package/src/config/bundled-skills/media-processing/__tests__/preprocess-audio.test.ts +141 -0
- package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +32 -87
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +8 -4
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +0 -10
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
- package/src/config/bundled-skills/outlook/SKILL.md +2 -2
- package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +2 -2
- package/src/config/bundled-skills/phone-calls/SKILL.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +27 -18
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +3 -3
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +26 -22
- package/src/config/bundled-skills/slack/SKILL.md +1 -0
- package/src/config/bundled-skills/transcribe/SKILL.md +9 -14
- package/src/config/bundled-skills/transcribe/TOOLS.json +2 -7
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +256 -0
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +38 -188
- package/src/config/bundled-tool-registry.ts +8 -0
- package/src/config/env-registry.ts +24 -0
- package/src/config/env.ts +34 -10
- package/src/config/feature-flag-registry.json +46 -14
- package/src/config/loader.ts +26 -12
- package/src/config/schema.ts +35 -10
- package/src/config/schemas/__tests__/stt.test.ts +43 -0
- package/src/config/schemas/analysis.ts +51 -0
- package/src/config/schemas/backup.ts +72 -0
- package/src/config/schemas/calls.ts +1 -26
- package/src/config/schemas/elevenlabs.ts +0 -59
- package/src/config/schemas/filing.ts +47 -7
- package/src/config/schemas/heartbeat.ts +27 -5
- package/src/config/schemas/host-browser.ts +47 -1
- package/src/config/schemas/inference.ts +1 -1
- package/src/config/schemas/memory-lifecycle.ts +14 -2
- package/src/config/schemas/services.ts +44 -0
- package/src/config/schemas/stt.ts +59 -0
- package/src/config/schemas/tts.ts +230 -0
- package/src/config/schemas/updates.ts +14 -0
- package/src/config/skills.ts +4 -0
- package/src/config/types.ts +4 -0
- package/src/contacts/contact-store.ts +56 -11
- package/src/contacts/contacts-write.ts +38 -1
- package/src/context/post-turn-tool-result-truncation.ts +3 -2
- package/src/context/tool-result-truncation.ts +2 -1
- package/src/context/window-manager.ts +45 -12
- package/src/credential-execution/executable-discovery.ts +12 -2
- package/src/credential-execution/process-manager.ts +33 -2
- package/src/credential-health/credential-health-service.ts +366 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +324 -0
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +497 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +17 -8
- package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +127 -0
- package/src/daemon/config-watcher.ts +99 -5
- package/src/daemon/conversation-agent-loop-handlers.ts +6 -0
- package/src/daemon/conversation-agent-loop.ts +101 -24
- package/src/daemon/conversation-error.ts +11 -0
- package/src/daemon/conversation-history.ts +40 -6
- package/src/daemon/conversation-launch.ts +220 -0
- package/src/daemon/conversation-lifecycle.ts +59 -9
- package/src/daemon/conversation-messaging.ts +37 -3
- package/src/daemon/conversation-notifiers.ts +5 -0
- package/src/daemon/conversation-process.ts +581 -19
- package/src/daemon/conversation-queue-manager.ts +24 -0
- package/src/daemon/conversation-runtime-assembly.ts +11 -1
- package/src/daemon/conversation-slash.ts +36 -0
- package/src/daemon/conversation-surfaces.ts +94 -4
- package/src/daemon/conversation-tool-setup.ts +25 -0
- package/src/daemon/conversation-usage.ts +7 -4
- package/src/daemon/conversation.ts +86 -28
- package/src/daemon/handlers/config-slack-channel.ts +269 -94
- package/src/daemon/handlers/conversations.ts +4 -1
- package/src/daemon/handlers/shared.ts +22 -0
- package/src/daemon/handlers/skills.ts +321 -77
- package/src/daemon/host-browser-proxy.ts +2 -1
- package/src/daemon/lifecycle.ts +122 -25
- package/src/daemon/message-protocol.ts +6 -0
- package/src/daemon/message-types/conversations.ts +34 -1
- package/src/daemon/message-types/home.ts +40 -0
- package/src/daemon/message-types/meet.ts +143 -0
- package/src/daemon/message-types/messages.ts +14 -0
- package/src/daemon/message-types/schedules.ts +34 -2
- package/src/daemon/message-types/skills.ts +16 -0
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/daemon/server.ts +347 -2
- package/src/daemon/shutdown-handlers.ts +32 -4
- package/src/daemon/shutdown-registry.ts +40 -0
- package/src/daemon/tool-side-effects.ts +9 -0
- package/src/email/html-renderer.ts +76 -0
- package/src/heartbeat/heartbeat-service.ts +93 -7
- package/src/home/__tests__/assistant-feed-authoring.test.ts +156 -0
- package/src/home/__tests__/emit-feed-event.test.ts +169 -0
- package/src/home/__tests__/feed-scheduler.test.ts +194 -0
- package/src/home/__tests__/feed-types.test.ts +275 -0
- package/src/home/__tests__/feed-writer.test.ts +688 -0
- package/src/home/__tests__/phase5-exit-criteria.test.ts +212 -0
- package/src/home/__tests__/platform-gmail-digest.test.ts +222 -0
- package/src/home/__tests__/progress-formula.test.ts +213 -0
- package/src/home/__tests__/relationship-state-writer.test.ts +740 -0
- package/src/home/__tests__/rollup-producer.test.ts +398 -0
- package/src/home/assistant-feed-authoring.ts +124 -0
- package/src/home/emit-feed-event.ts +158 -0
- package/src/home/feed-scheduler.ts +247 -0
- package/src/home/feed-types.ts +181 -0
- package/src/home/feed-writer.ts +469 -0
- package/src/home/platform-gmail-digest.ts +163 -0
- package/src/home/progress-formula.ts +86 -0
- package/src/home/relationship-state-writer.ts +824 -0
- package/src/home/relationship-state.ts +143 -0
- package/src/home/rollup-producer.ts +384 -0
- package/src/hooks/runner.ts +7 -0
- package/src/inbound/platform-callback-registration.ts +12 -3
- package/src/inbound/public-ingress-urls.ts +12 -0
- package/src/instrument.ts +1 -1
- package/src/ipc/__tests__/cli-ipc.test.ts +200 -0
- package/src/ipc/cli-client.ts +151 -0
- package/src/ipc/cli-server.ts +234 -0
- package/src/ipc/gateway-client.ts +180 -0
- package/src/ipc/routes/index.ts +5 -0
- package/src/ipc/routes/wake-conversation.ts +19 -0
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +356 -0
- package/src/memory/__tests__/auto-analysis-guard.test.ts +57 -0
- package/src/memory/__tests__/conversation-analyze-job.test.ts +232 -0
- package/src/memory/__tests__/find-analysis-conversation.test.ts +196 -0
- package/src/memory/app-store.ts +1 -1
- package/src/memory/attachments-store.ts +70 -0
- package/src/memory/auto-analysis-enqueue.ts +127 -0
- package/src/memory/auto-analysis-guard.ts +27 -0
- package/src/memory/cleanup-schedule-state.ts +37 -0
- package/src/memory/conversation-analyze-job.ts +73 -0
- package/src/memory/conversation-crud.ts +99 -0
- package/src/memory/conversation-disk-view.ts +7 -0
- package/src/memory/conversation-group-migration.ts +34 -2
- package/src/memory/conversation-queries.ts +6 -5
- package/src/memory/db-init.ts +6 -0
- package/src/memory/db-maintenance.ts +108 -0
- package/src/memory/db.ts +1 -0
- package/src/memory/graph/conversation-graph-memory.ts +15 -0
- package/src/memory/graph/extraction.test.ts +23 -0
- package/src/memory/graph/extraction.ts +8 -0
- package/src/memory/graph/retriever.ts +27 -18
- package/src/memory/graph/scoring.test.ts +186 -0
- package/src/memory/graph/scoring.ts +31 -1
- package/src/memory/graph/tools.ts +1 -1
- package/src/memory/group-crud.ts +6 -1
- package/src/memory/indexer.ts +95 -16
- package/src/memory/job-handlers/cleanup.ts +11 -8
- package/src/memory/job-handlers/conversation-starters.ts +16 -10
- package/src/memory/jobs-store.ts +64 -4
- package/src/memory/jobs-worker.ts +22 -9
- package/src/memory/llm-usage-store.ts +92 -56
- package/src/memory/migrations/219-oauth-providers-token-exchange-body-format.ts +15 -0
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +190 -0
- package/src/memory/migrations/221-conversations-archived-at.ts +16 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/qdrant-manager.ts +43 -16
- package/src/memory/schema/conversations.ts +2 -0
- package/src/memory/schema/oauth.ts +3 -0
- package/src/memory/usage-buckets.ts +396 -0
- package/src/messaging/providers/gmail/client.ts +57 -6
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +282 -0
- package/src/messaging/providers/slack/adapter.ts +143 -38
- package/src/messaging/providers/slack/client.ts +16 -0
- package/src/messaging/providers/slack/types.ts +4 -0
- package/src/notifications/decision-engine.ts +3 -3
- package/src/notifications/signal.ts +5 -0
- package/src/oauth/__tests__/identity-verifier.test.ts +1 -0
- package/src/oauth/byo-connection.test.ts +18 -1
- package/src/oauth/byo-connection.ts +3 -1
- package/src/oauth/connect-orchestrator.ts +2 -0
- package/src/oauth/connection-resolver.ts +6 -2
- package/src/oauth/connection.ts +2 -0
- package/src/oauth/oauth-store.ts +9 -0
- package/src/oauth/platform-connection.test.ts +98 -0
- package/src/oauth/platform-connection.ts +52 -31
- package/src/oauth/seed-providers.ts +7 -0
- package/src/permissions/checker.ts +16 -6
- package/src/permissions/defaults.ts +49 -1
- package/src/permissions/trust-store.ts +3 -3
- package/src/permissions/workspace-policy.ts +3 -0
- package/src/platform/client.test.ts +10 -0
- package/src/platform/sync-identity.ts +129 -0
- package/src/prompts/persona-resolver.ts +126 -2
- package/src/prompts/system-prompt.ts +59 -18
- package/src/prompts/templates/BOOTSTRAP.md +5 -5
- package/src/prompts/templates/SOUL.md +3 -1
- package/src/prompts/templates/UPDATES.md +12 -0
- package/src/prompts/templates/channels/slack.md +20 -0
- package/src/prompts/update-bulletin-format.ts +26 -9
- package/src/prompts/update-bulletin.ts +34 -23
- package/src/prompts/user-reference.ts +20 -17
- package/src/providers/__tests__/provider-secret-catalog.test.ts +42 -0
- package/src/providers/anthropic/client.ts +157 -61
- package/src/providers/fireworks/client.ts +2 -2
- package/src/providers/gemini/client.ts +9 -1
- package/src/providers/model-catalog.ts +6 -0
- package/src/providers/model-intents.ts +4 -4
- package/src/providers/ollama/client.ts +2 -2
- package/src/providers/openai/chat-completions-provider.ts +474 -0
- package/src/providers/openai/client.ts +25 -440
- package/src/providers/openai/responses-provider.ts +502 -0
- package/src/providers/openrouter/client.ts +101 -4
- package/src/providers/provider-secret-catalog.ts +139 -0
- package/src/providers/registry.ts +2 -2
- package/src/providers/retry.ts +14 -3
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +251 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +828 -0
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +980 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +767 -0
- package/src/providers/speech-to-text/deepgram.test.ts +332 -0
- package/src/providers/speech-to-text/deepgram.ts +115 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.test.ts +743 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.ts +625 -0
- package/src/providers/speech-to-text/google-gemini.test.ts +226 -0
- package/src/providers/speech-to-text/google-gemini.ts +101 -0
- package/src/providers/speech-to-text/openai-whisper-stream.test.ts +564 -0
- package/src/providers/speech-to-text/openai-whisper-stream.ts +381 -0
- package/src/providers/speech-to-text/openai-whisper.test.ts +1 -37
- package/src/providers/speech-to-text/openai-whisper.ts +63 -33
- package/src/providers/speech-to-text/provider-catalog.ts +306 -0
- package/src/providers/speech-to-text/resolve.ts +386 -6
- package/src/providers/types.ts +9 -0
- package/src/runtime/AGENTS.md +43 -1
- package/src/runtime/__tests__/agent-wake.test.ts +831 -0
- package/src/runtime/__tests__/runtime-mode.test.ts +62 -0
- package/src/runtime/__tests__/slack-block-formatting.test.ts +481 -0
- package/src/runtime/agent-wake.ts +512 -0
- package/src/runtime/auth/__tests__/route-policy.test.ts +40 -0
- package/src/runtime/auth/route-policy.ts +30 -5
- package/src/runtime/auth/token-service.ts +56 -1
- package/src/runtime/btw-sidechain.ts +2 -0
- package/src/runtime/capability-tokens.ts +10 -10
- package/src/runtime/channel-invite-transport.ts +1 -1
- package/src/runtime/channel-invite-transports/email.ts +14 -6
- package/src/runtime/channel-readiness-service.ts +12 -22
- package/src/runtime/chrome-extension-registry.ts +38 -2
- package/src/runtime/http-server.ts +395 -10
- package/src/runtime/http-types.ts +6 -2
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +36 -0
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +360 -0
- package/src/runtime/migrations/migration-transport.ts +1 -0
- package/src/runtime/migrations/migration-wizard.ts +1 -0
- package/src/runtime/migrations/vbundle-import-analyzer.ts +77 -1
- package/src/runtime/migrations/vbundle-importer.ts +34 -0
- package/src/runtime/pending-interactions.ts +0 -11
- package/src/runtime/routes/__tests__/backup-routes.test.ts +967 -0
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +507 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +208 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +406 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +474 -0
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +148 -17
- package/src/runtime/routes/app-management-routes.ts +12 -18
- package/src/runtime/routes/attachment-routes.test.ts +9 -3
- package/src/runtime/routes/attachment-routes.ts +216 -17
- package/src/runtime/routes/backup-routes.ts +519 -0
- package/src/runtime/routes/browser-extension-pair-routes.ts +82 -23
- package/src/runtime/routes/btw-routes.ts +8 -6
- package/src/runtime/routes/contact-routes.test.ts +298 -0
- package/src/runtime/routes/contact-routes.ts +132 -5
- package/src/runtime/routes/conversation-analysis-routes.ts +22 -142
- package/src/runtime/routes/conversation-management-routes.ts +115 -0
- package/src/runtime/routes/conversation-routes.ts +367 -146
- package/src/runtime/routes/filing-routes.ts +93 -0
- package/src/runtime/routes/home-feed-routes.ts +334 -0
- package/src/runtime/routes/home-state-routes.ts +138 -0
- package/src/runtime/routes/host-browser-routes.ts +3 -14
- package/src/runtime/routes/identity-intro-cache.ts +7 -3
- package/src/runtime/routes/identity-routes.ts +3 -17
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +46 -39
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +15 -15
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +137 -0
- package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +179 -0
- package/src/runtime/routes/integrations/slack/channel.ts +11 -3
- package/src/runtime/routes/integrations/slack/share.ts +45 -7
- package/src/runtime/routes/llm-context-normalization.ts +303 -0
- package/src/runtime/routes/memory-item-routes.test.ts +3 -2
- package/src/runtime/routes/migration-routes.ts +40 -5
- package/src/runtime/routes/settings-routes.ts +22 -5
- package/src/runtime/routes/skills-routes.ts +76 -7
- package/src/runtime/routes/stt-routes.ts +233 -0
- package/src/runtime/routes/surface-action-routes.ts +41 -2
- package/src/runtime/routes/tts-routes.ts +108 -24
- package/src/runtime/routes/usage-routes.ts +30 -2
- package/src/runtime/routes/user-route-dispatcher.ts +50 -5
- package/src/runtime/routes/user-routes.ts +13 -1
- package/src/runtime/routes/work-items-routes.ts +8 -1
- package/src/runtime/runtime-mode.ts +33 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +444 -0
- package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +67 -0
- package/src/runtime/services/__tests__/auto-analysis-prompt.test.ts +53 -0
- package/src/runtime/services/__tests__/manual-analysis-prompt.test.ts +41 -0
- package/src/runtime/services/analyze-conversation.ts +344 -0
- package/src/runtime/services/analyze-deps-singleton.ts +32 -0
- package/src/runtime/services/auto-analysis-prompt.ts +55 -0
- package/src/runtime/skill-route-registry.ts +49 -0
- package/src/runtime/slack-block-formatting.ts +437 -10
- package/src/schedule/scheduler.ts +50 -0
- package/src/security/oauth2.ts +26 -4
- package/src/security/secure-keys.ts +25 -2
- package/src/security/token-manager.ts +8 -0
- package/src/sequence/engine.ts +23 -0
- package/src/sequence/types.ts +1 -1
- package/src/skills/catalog-files.ts +64 -2
- package/src/skills/category-inference.ts +122 -0
- package/src/skills/clawhub-files.ts +213 -0
- package/src/skills/clawhub.ts +84 -23
- package/src/skills/skill-file-provider.ts +40 -0
- package/src/skills/skillssh-files.ts +395 -0
- package/src/skills/skillssh-registry.ts +4 -4
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +392 -0
- package/src/stt/__tests__/types.test.ts +89 -0
- package/src/stt/daemon-batch-transcriber.ts +195 -0
- package/src/stt/stt-stream-session.ts +499 -0
- package/src/stt/types.ts +330 -0
- package/src/stt/wav-encoder.test.ts +373 -0
- package/src/stt/wav-encoder.ts +175 -0
- package/src/subagent/manager.ts +38 -14
- package/src/tools/browser/__tests__/browser-mode.test.ts +119 -0
- package/src/tools/browser/__tests__/browser-status.test.ts +123 -0
- package/src/tools/browser/browser-execution.ts +1163 -23
- package/src/tools/browser/browser-manager.ts +45 -0
- package/src/tools/browser/browser-mode-constants.ts +12 -0
- package/src/tools/browser/browser-mode.ts +92 -0
- package/src/tools/browser/browser-status-constants.ts +33 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +393 -0
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +29 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +1648 -32
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +264 -0
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +183 -17
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +254 -21
- package/src/tools/browser/cdp-client/errors.ts +15 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +39 -16
- package/src/tools/browser/cdp-client/factory.ts +797 -87
- package/src/tools/browser/cdp-client/index.ts +16 -2
- package/src/tools/browser/cdp-client/types.ts +68 -0
- package/src/tools/credentials/vault.ts +35 -6
- package/src/tools/network/web-fetch.ts +5 -2
- package/src/tools/network/web-search.ts +5 -2
- package/src/tools/shared/shell-output.ts +3 -1
- package/src/tools/side-effects.ts +2 -0
- package/src/tools/skills/sandbox-runner.ts +3 -2
- package/src/tools/terminal/safe-env.ts +10 -2
- package/src/tools/terminal/shell.ts +15 -4
- package/src/tools/tool-manifest.ts +21 -0
- package/src/tools/types.ts +17 -0
- package/src/tools/ui-surface/definitions.ts +6 -1
- package/src/tts/__tests__/provider-adapters.test.ts +834 -0
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +196 -0
- package/src/tts/__tests__/provider-catalog.test.ts +183 -0
- package/src/tts/__tests__/provider-registry.test.ts +90 -0
- package/src/tts/provider-catalog.ts +201 -0
- package/src/tts/provider-registry.ts +73 -0
- package/src/tts/providers/deepgram-provider.ts +219 -0
- package/src/tts/providers/elevenlabs-provider.ts +211 -0
- package/src/tts/providers/fish-audio-provider.ts +183 -0
- package/src/tts/providers/index.ts +42 -0
- package/src/tts/providers/register-builtins.ts +130 -0
- package/src/tts/synthesize-text.ts +110 -0
- package/src/tts/tts-config-resolver.ts +78 -0
- package/src/tts/types.ts +153 -0
- package/src/types/onboarding-context.ts +7 -0
- package/src/util/abort-reasons.ts +58 -0
- package/src/util/device-id.ts +32 -16
- package/src/util/errors.ts +9 -1
- package/src/util/platform.ts +54 -10
- package/src/util/pricing.ts +66 -3
- package/src/util/spawn.ts +1 -1
- package/src/util/truncate.ts +4 -2
- package/src/util/unicode.ts +201 -0
- package/src/version.ts +19 -24
- package/src/watcher/engine.ts +23 -0
- package/src/watcher/watcher-store.ts +31 -0
- package/src/workspace/migrations/003-seed-device-id.ts +9 -3
- package/src/workspace/migrations/017-seed-persona-dirs.ts +68 -4
- package/src/workspace/migrations/029-seed-pkb.ts +1 -1
- package/src/workspace/migrations/031-drop-user-md.ts +317 -0
- package/src/workspace/migrations/031-llm-log-retention-zero-to-null.ts +73 -0
- package/src/workspace/migrations/032-tts-provider-unification.ts +227 -0
- package/src/workspace/migrations/033-stt-service-explicit-config.ts +122 -0
- package/src/workspace/migrations/034-remove-calls-voice-transcription-provider.ts +215 -0
- package/src/workspace/migrations/035-seed-slack-channel-persona.ts +50 -0
- package/src/workspace/migrations/036-update-pkb-index-bar.ts +37 -0
- package/src/workspace/migrations/037-create-meets-dir.ts +61 -0
- package/src/workspace/migrations/registry.ts +16 -0
- package/src/workspace/top-level-renderer.ts +13 -1
- package/src/workspace/turn-commit.ts +31 -0
- package/src/__tests__/email-cli.test.ts +0 -297
- package/src/__tests__/email-service-config-fallback.test.ts +0 -102
- package/src/cli/commands/browser-relay.ts +0 -466
- package/src/email/guardrails.ts +0 -221
- package/src/email/provider.ts +0 -117
- package/src/email/providers/agentmail.ts +0 -361
- package/src/email/providers/index.ts +0 -65
- package/src/email/service.ts +0 -384
- package/src/email/types.ts +0 -126
- package/src/prompts/templates/USER.md +0 -13
- package/src/providers/speech-to-text/types.ts +0 -17
- package/src/runtime/routes/browser-cdp-routes.ts +0 -229
|
@@ -8,14 +8,14 @@ import {
|
|
|
8
8
|
writeFileSync,
|
|
9
9
|
} from "node:fs";
|
|
10
10
|
|
|
11
|
+
import { getConfig } from "../config/loader.js";
|
|
11
12
|
import { getWorkspacePromptPath } from "../util/platform.js";
|
|
12
13
|
import { stripCommentLines } from "../util/strip-comment-lines.js";
|
|
13
14
|
import { APP_VERSION } from "../version.js";
|
|
14
15
|
import {
|
|
15
16
|
appendReleaseBlock,
|
|
16
|
-
|
|
17
|
+
filterNewContentBlocks,
|
|
17
18
|
hasReleaseBlock,
|
|
18
|
-
releaseMarker,
|
|
19
19
|
} from "./update-bulletin-format.js";
|
|
20
20
|
import {
|
|
21
21
|
addActiveRelease,
|
|
@@ -67,25 +67,43 @@ function atomicWriteFileSync(filePath: string, content: string): void {
|
|
|
67
67
|
/**
|
|
68
68
|
* Materializes the current release's update bulletin on startup.
|
|
69
69
|
*
|
|
70
|
-
* First checks for
|
|
71
|
-
*
|
|
72
|
-
* (the
|
|
70
|
+
* First checks for dismissal: if the workspace UPDATES.md was deleted or
|
|
71
|
+
* emptied after we'd previously materialized it, that's an explicit signal
|
|
72
|
+
* (from the user or the assistant) that the current release has been handled.
|
|
73
|
+
* Mark any active releases plus the current release as completed and return
|
|
74
|
+
* without recreating the file.
|
|
73
75
|
*
|
|
74
|
-
*
|
|
75
|
-
* appends a release block to the workspace UPDATES.md if one doesn't
|
|
76
|
-
*
|
|
76
|
+
* Otherwise reads the bundled UPDATES.md template, strips comment lines, and
|
|
77
|
+
* appends a release block to the workspace UPDATES.md if one doesn't already
|
|
78
|
+
* exist for this version. Skips completed releases entirely.
|
|
77
79
|
*/
|
|
78
80
|
export function syncUpdateBulletinOnStartup(): void {
|
|
81
|
+
if (!getConfig().updates.enabled) return;
|
|
82
|
+
|
|
79
83
|
const currentReleaseId = APP_VERSION;
|
|
80
84
|
const workspacePath = getWorkspacePromptPath("UPDATES.md");
|
|
81
85
|
|
|
82
|
-
// ---
|
|
83
|
-
// If UPDATES.md
|
|
84
|
-
//
|
|
86
|
+
// --- Dismissal detection ---
|
|
87
|
+
// If UPDATES.md is missing or empty AND the CURRENT release has been
|
|
88
|
+
// materialized before (i.e. it's in the active set, or already marked
|
|
89
|
+
// completed), treat it as a dismissal: mark the active set plus the
|
|
90
|
+
// current release completed and stop. Scoping to the current release is
|
|
91
|
+
// critical — a prior release having been completed must NOT cause a new
|
|
92
|
+
// version's bulletin to be suppressed as "already dismissed". It also
|
|
93
|
+
// preserves fresh-install semantics: on a brand-new DB we want to create
|
|
94
|
+
// the file, not treat its absence as dismissal.
|
|
85
95
|
const activeReleases = getActiveReleases();
|
|
86
|
-
|
|
87
|
-
|
|
96
|
+
const fileMissing = !existsSync(workspacePath);
|
|
97
|
+
const fileEmpty =
|
|
98
|
+
!fileMissing && readFileSync(workspacePath, "utf-8").trim().length === 0;
|
|
99
|
+
const currentReleaseMaterialized =
|
|
100
|
+
activeReleases.includes(currentReleaseId) ||
|
|
101
|
+
isReleaseCompleted(currentReleaseId);
|
|
102
|
+
|
|
103
|
+
if ((fileMissing || fileEmpty) && currentReleaseMaterialized) {
|
|
104
|
+
markReleasesCompleted([...activeReleases, currentReleaseId]);
|
|
88
105
|
setActiveReleases([]);
|
|
106
|
+
return;
|
|
89
107
|
}
|
|
90
108
|
|
|
91
109
|
// --- Template materialization ---
|
|
@@ -105,19 +123,12 @@ export function syncUpdateBulletinOnStartup(): void {
|
|
|
105
123
|
} else {
|
|
106
124
|
const existing = readFileSync(workspacePath, "utf-8");
|
|
107
125
|
if (!hasReleaseBlock(existing, currentReleaseId)) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
// appended on every version bump when the template isn't cleared.
|
|
111
|
-
const contentMarkers = extractContentMarkers(templateContent);
|
|
112
|
-
const allContentAlreadyPresent =
|
|
113
|
-
contentMarkers.length > 0 &&
|
|
114
|
-
contentMarkers.every((m) => existing.includes(releaseMarker(m)));
|
|
115
|
-
|
|
116
|
-
if (!allContentAlreadyPresent) {
|
|
126
|
+
const contentToAppend = filterNewContentBlocks(templateContent, existing);
|
|
127
|
+
if (contentToAppend.length > 0) {
|
|
117
128
|
const updated = appendReleaseBlock(
|
|
118
129
|
existing,
|
|
119
130
|
currentReleaseId,
|
|
120
|
-
|
|
131
|
+
contentToAppend,
|
|
121
132
|
);
|
|
122
133
|
atomicWriteFileSync(workspacePath, updated);
|
|
123
134
|
}
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getWorkspacePromptPath } from "../util/platform.js";
|
|
1
|
+
import { resolveGuardianPersonaStrict } from "./persona-resolver.js";
|
|
3
2
|
|
|
4
3
|
export const DEFAULT_USER_REFERENCE = "my human";
|
|
5
4
|
export const DECLINED_BY_USER_SENTINEL = "declined_by_user";
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
|
-
* Read the raw "Preferred name/reference:" value from
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* Read the raw "Preferred name/reference:" value from the guardian's
|
|
8
|
+
* per-user persona file (`users/<slug>.md`).
|
|
9
|
+
*
|
|
10
|
+
* Returns the trimmed value when present, or `null` when no guardian
|
|
11
|
+
* is resolvable, the persona file is missing / empty, or the field
|
|
12
|
+
* itself is blank.
|
|
11
13
|
*/
|
|
12
14
|
function readPreferredNameFromUserMd(): string | null {
|
|
13
|
-
const content =
|
|
15
|
+
const content = resolveGuardianPersonaStrict();
|
|
14
16
|
if (content != null) {
|
|
15
17
|
const match = content.match(/Preferred name\/reference:[ \t]*(.*)/);
|
|
16
18
|
if (match && match[1].trim()) {
|
|
@@ -24,9 +26,9 @@ function readPreferredNameFromUserMd(): string | null {
|
|
|
24
26
|
* Resolve the name/reference the assistant uses when referring to
|
|
25
27
|
* the human it represents in external communications.
|
|
26
28
|
*
|
|
27
|
-
* Reads the "Preferred name/reference:" field from
|
|
28
|
-
* Falls back to "my human" when the file is missing,
|
|
29
|
-
* or the field is empty.
|
|
29
|
+
* Reads the "Preferred name/reference:" field from the guardian's
|
|
30
|
+
* persona file. Falls back to "my human" when the file is missing,
|
|
31
|
+
* unreadable, or the field is empty.
|
|
30
32
|
*/
|
|
31
33
|
export function resolveUserReference(): string {
|
|
32
34
|
const preferredName = readPreferredNameFromUserMd();
|
|
@@ -37,9 +39,9 @@ export function resolveUserReference(): string {
|
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
/**
|
|
40
|
-
* Resolve the user's pronouns from
|
|
41
|
-
*
|
|
42
|
-
* `declined_by_user`.
|
|
42
|
+
* Resolve the user's pronouns from the guardian's per-user persona file.
|
|
43
|
+
* Returns `null` when no guardian is resolvable, the file is missing,
|
|
44
|
+
* the field is empty, or the value is a sentinel like `declined_by_user`.
|
|
43
45
|
*
|
|
44
46
|
* When a legacy `## Onboarding Snapshot` section exists, a `Pronouns:`
|
|
45
47
|
* line *above* that section takes priority (explicit post-onboarding edit).
|
|
@@ -47,7 +49,7 @@ export function resolveUserReference(): string {
|
|
|
47
49
|
* in the file.
|
|
48
50
|
*/
|
|
49
51
|
export function resolveUserPronouns(): string | null {
|
|
50
|
-
const content =
|
|
52
|
+
const content = resolveGuardianPersonaStrict();
|
|
51
53
|
if (content == null) return null;
|
|
52
54
|
|
|
53
55
|
const snapshotIdx = content.indexOf("## Onboarding Snapshot");
|
|
@@ -82,10 +84,11 @@ function cleanPronounValue(raw: string): string | null {
|
|
|
82
84
|
* Resolve the guardian's display name.
|
|
83
85
|
*
|
|
84
86
|
* Priority:
|
|
85
|
-
* 1.
|
|
86
|
-
* maintained source of truth.
|
|
87
|
-
* 2. guardianDisplayName (fallback for when
|
|
88
|
-
* e.g. pre-onboarding). Callers pass in
|
|
87
|
+
* 1. Guardian persona file "Preferred name/reference:" — the
|
|
88
|
+
* user-editable, actively maintained source of truth.
|
|
89
|
+
* 2. guardianDisplayName (fallback for when the persona file is
|
|
90
|
+
* missing or empty, e.g. pre-onboarding). Callers pass in
|
|
91
|
+
* Contact.displayName.
|
|
89
92
|
* 3. DEFAULT_USER_REFERENCE ("my human").
|
|
90
93
|
*/
|
|
91
94
|
export function resolveGuardianName(
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { API_KEY_PROVIDERS } from "../provider-secret-catalog.js";
|
|
4
|
+
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// API_KEY_PROVIDERS derivation invariants
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
|
|
9
|
+
describe("API_KEY_PROVIDERS", () => {
|
|
10
|
+
test("includes deepgram (shared by STT and TTS catalogs)", () => {
|
|
11
|
+
expect(API_KEY_PROVIDERS).toContain("deepgram");
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test("includes deepgram exactly once despite appearing in both STT and TTS catalogs", () => {
|
|
15
|
+
const occurrences = API_KEY_PROVIDERS.filter((p) => p === "deepgram");
|
|
16
|
+
expect(occurrences.length).toBe(1);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test("includes openai exactly once (shared by LLM and STT)", () => {
|
|
20
|
+
const occurrences = API_KEY_PROVIDERS.filter((p) => p === "openai");
|
|
21
|
+
expect(occurrences.length).toBe(1);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("contains no duplicate entries", () => {
|
|
25
|
+
const unique = new Set(API_KEY_PROVIDERS);
|
|
26
|
+
expect(API_KEY_PROVIDERS.length).toBe(unique.size);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("is deterministic across calls", () => {
|
|
30
|
+
// Re-import would return the same module-level constant, but this
|
|
31
|
+
// validates that the composition does not introduce non-determinism.
|
|
32
|
+
const first = [...API_KEY_PROVIDERS];
|
|
33
|
+
const second = [...API_KEY_PROVIDERS];
|
|
34
|
+
expect(first).toEqual(second);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("includes core LLM providers", () => {
|
|
38
|
+
expect(API_KEY_PROVIDERS).toContain("anthropic");
|
|
39
|
+
expect(API_KEY_PROVIDERS).toContain("openai");
|
|
40
|
+
expect(API_KEY_PROVIDERS).toContain("gemini");
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import Anthropic from "@anthropic-ai/sdk";
|
|
2
2
|
|
|
3
3
|
import { SYSTEM_PROMPT_CACHE_BOUNDARY } from "../../prompts/system-prompt.js";
|
|
4
|
+
import { isAbortReason } from "../../util/abort-reasons.js";
|
|
4
5
|
import { ProviderError } from "../../util/errors.js";
|
|
5
6
|
import { getLogger } from "../../util/logger.js";
|
|
6
7
|
import { extractRetryAfterMs } from "../../util/retry.js";
|
|
8
|
+
import { stripOrphanedSurrogatesDeep } from "../../util/unicode.js";
|
|
7
9
|
import { createStreamTimeout } from "../stream-timeout.js";
|
|
8
10
|
import type {
|
|
9
11
|
ContentBlock,
|
|
@@ -19,6 +21,35 @@ const log = getLogger("anthropic-client");
|
|
|
19
21
|
/** Validation-specific timeout (10s) so a stalled network doesn't block key submission. */
|
|
20
22
|
const VALIDATION_TIMEOUT_MS = 10_000;
|
|
21
23
|
|
|
24
|
+
/** Rate-limit the orphaned-surrogate warning so a single bad stream can't flood logs. */
|
|
25
|
+
const ORPHAN_WARNING_THROTTLE_MS = 60_000;
|
|
26
|
+
let lastOrphanWarningMs = 0;
|
|
27
|
+
|
|
28
|
+
function logOrphanedSurrogateWarning(
|
|
29
|
+
fixedStringCount: number,
|
|
30
|
+
messages: Anthropic.MessageParam[],
|
|
31
|
+
): void {
|
|
32
|
+
const now = Date.now();
|
|
33
|
+
if (now - lastOrphanWarningMs < ORPHAN_WARNING_THROTTLE_MS) return;
|
|
34
|
+
lastOrphanWarningMs = now;
|
|
35
|
+
const blockTypes = new Set<string>();
|
|
36
|
+
for (const msg of messages) {
|
|
37
|
+
if (!Array.isArray(msg.content)) continue;
|
|
38
|
+
for (const block of msg.content) {
|
|
39
|
+
if (typeof block !== "object" || block == null) continue;
|
|
40
|
+
const type = (block as { type?: string }).type;
|
|
41
|
+
if (type) blockTypes.add(type);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
log.warn(
|
|
45
|
+
{
|
|
46
|
+
fixedStringCount,
|
|
47
|
+
blockTypes: Array.from(blockTypes),
|
|
48
|
+
},
|
|
49
|
+
"stripped orphaned UTF-16 surrogates from outbound Anthropic request — upstream truncation is not surrogate-aware",
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
22
53
|
/**
|
|
23
54
|
* Validate an Anthropic API key by making a lightweight GET /v1/models call.
|
|
24
55
|
* Returns `{ valid: true }` on success or `{ valid: false, reason: string }` on failure.
|
|
@@ -361,7 +392,10 @@ function repairOrphanedServerToolUse(
|
|
|
361
392
|
repairedContent.push({
|
|
362
393
|
type: "web_search_tool_result",
|
|
363
394
|
tool_use_id: block.id,
|
|
364
|
-
content:
|
|
395
|
+
content: {
|
|
396
|
+
type: "web_search_tool_result_error",
|
|
397
|
+
error_code: "unavailable",
|
|
398
|
+
},
|
|
365
399
|
} as unknown as Anthropic.ContentBlockParam);
|
|
366
400
|
}
|
|
367
401
|
}
|
|
@@ -564,9 +598,22 @@ export class AnthropicProvider implements Provider {
|
|
|
564
598
|
useNativeWebSearch?: boolean;
|
|
565
599
|
streamTimeoutMs?: number;
|
|
566
600
|
baseURL?: string;
|
|
601
|
+
/**
|
|
602
|
+
* Authenticate via `Authorization: Bearer <token>` instead of
|
|
603
|
+
* `x-api-key`. Required for proxies that front the Anthropic Messages
|
|
604
|
+
* API with their own Bearer scheme (e.g. OpenRouter). When set, the
|
|
605
|
+
* positional `apiKey` argument is ignored on the wire.
|
|
606
|
+
*/
|
|
607
|
+
authToken?: string;
|
|
567
608
|
} = {},
|
|
568
609
|
) {
|
|
569
|
-
this.client =
|
|
610
|
+
this.client = options.authToken
|
|
611
|
+
? new Anthropic({
|
|
612
|
+
apiKey: null,
|
|
613
|
+
authToken: options.authToken,
|
|
614
|
+
baseURL: options.baseURL,
|
|
615
|
+
})
|
|
616
|
+
: new Anthropic({ apiKey, baseURL: options.baseURL });
|
|
570
617
|
this.model = model;
|
|
571
618
|
this.useNativeWebSearch = options.useNativeWebSearch ?? false;
|
|
572
619
|
this.streamTimeoutMs = options.streamTimeoutMs ?? 1_800_000;
|
|
@@ -579,7 +626,10 @@ export class AnthropicProvider implements Provider {
|
|
|
579
626
|
options?: SendMessageOptions,
|
|
580
627
|
): Promise<ProviderResponse> {
|
|
581
628
|
const { config, onEvent, signal } = options ?? {};
|
|
582
|
-
const cacheTtl: "5m" | "1h" =
|
|
629
|
+
const cacheTtl: "5m" | "1h" =
|
|
630
|
+
((config as Record<string, unknown> | undefined)?.cacheTtl as
|
|
631
|
+
| "5m"
|
|
632
|
+
| "1h") ?? "1h";
|
|
583
633
|
let sentMessages: Anthropic.MessageParam[] | undefined;
|
|
584
634
|
try {
|
|
585
635
|
const formatted = messages
|
|
@@ -689,25 +739,49 @@ export class AnthropicProvider implements Provider {
|
|
|
689
739
|
// — the API accepts them. No provider-side stripping needed.
|
|
690
740
|
|
|
691
741
|
sentMessages = ensureToolPairing(repairOrphanedServerToolUse(formatted));
|
|
692
|
-
const {
|
|
693
|
-
|
|
742
|
+
const {
|
|
743
|
+
effort,
|
|
744
|
+
speed,
|
|
745
|
+
output_config,
|
|
746
|
+
cacheTtl: _cacheTtl,
|
|
747
|
+
max_tokens: callerMaxTokens,
|
|
748
|
+
...restConfig
|
|
749
|
+
} = (config ?? {}) as Record<string, unknown> & {
|
|
694
750
|
effort?: Anthropic.OutputConfig["effort"];
|
|
695
751
|
speed?: "standard" | "fast";
|
|
696
752
|
output_config?: Record<string, unknown>;
|
|
697
753
|
};
|
|
698
|
-
// Haiku does not support the effort / output_config parameter
|
|
754
|
+
// Haiku does not support the effort / output_config parameter,
|
|
755
|
+
// extended cache TTL betas, 1M context, or 64K output tokens.
|
|
699
756
|
// Determine the effective model (per-call override or provider default)
|
|
700
|
-
// and
|
|
757
|
+
// and gate features accordingly.
|
|
701
758
|
const effectiveModel =
|
|
702
759
|
(restConfig as Record<string, unknown>).model?.toString() ?? this.model;
|
|
703
|
-
const
|
|
760
|
+
const isHaiku = effectiveModel.includes("haiku");
|
|
761
|
+
const supportsEffort = !isHaiku;
|
|
704
762
|
const mergedOutputConfig = {
|
|
705
763
|
...(output_config ?? {}),
|
|
706
764
|
...(effort && supportsEffort ? { effort } : {}),
|
|
707
765
|
};
|
|
708
|
-
|
|
766
|
+
// Build cache_control objects: Haiku doesn't support the extended
|
|
767
|
+
// cache TTL beta, so omit the ttl field for Haiku models.
|
|
768
|
+
const cacheControl = isHaiku
|
|
769
|
+
? { type: "ephemeral" as const }
|
|
770
|
+
: { type: "ephemeral" as const, ttl: cacheTtl };
|
|
771
|
+
const tailCacheControl = isHaiku
|
|
772
|
+
? { type: "ephemeral" as const }
|
|
773
|
+
: { type: "ephemeral" as const, ttl: "5m" as const };
|
|
774
|
+
|
|
775
|
+
let params: Anthropic.MessageStreamParams = {
|
|
709
776
|
model: this.model,
|
|
710
|
-
max_tokens:
|
|
777
|
+
max_tokens: isHaiku
|
|
778
|
+
? Math.min(
|
|
779
|
+
typeof callerMaxTokens === "number" ? callerMaxTokens : 8192,
|
|
780
|
+
8192,
|
|
781
|
+
)
|
|
782
|
+
: typeof callerMaxTokens === "number"
|
|
783
|
+
? callerMaxTokens
|
|
784
|
+
: 64000,
|
|
711
785
|
messages: sentMessages,
|
|
712
786
|
...restConfig,
|
|
713
787
|
...(Object.keys(mergedOutputConfig).length > 0
|
|
@@ -733,12 +807,12 @@ export class AnthropicProvider implements Provider {
|
|
|
733
807
|
{
|
|
734
808
|
type: "text" as const,
|
|
735
809
|
text: staticBlock,
|
|
736
|
-
cache_control:
|
|
810
|
+
cache_control: cacheControl,
|
|
737
811
|
},
|
|
738
812
|
{
|
|
739
813
|
type: "text" as const,
|
|
740
814
|
text: dynamicBlock,
|
|
741
|
-
cache_control:
|
|
815
|
+
cache_control: cacheControl,
|
|
742
816
|
},
|
|
743
817
|
];
|
|
744
818
|
} else {
|
|
@@ -746,7 +820,7 @@ export class AnthropicProvider implements Provider {
|
|
|
746
820
|
{
|
|
747
821
|
type: "text" as const,
|
|
748
822
|
text: systemPrompt,
|
|
749
|
-
cache_control:
|
|
823
|
+
cache_control: cacheControl,
|
|
750
824
|
},
|
|
751
825
|
];
|
|
752
826
|
}
|
|
@@ -763,12 +837,7 @@ export class AnthropicProvider implements Provider {
|
|
|
763
837
|
description: t.description,
|
|
764
838
|
input_schema: t.input_schema as Anthropic.Tool["input_schema"],
|
|
765
839
|
...(i === otherTools.length - 1
|
|
766
|
-
? {
|
|
767
|
-
cache_control: {
|
|
768
|
-
type: "ephemeral" as const,
|
|
769
|
-
ttl: cacheTtl,
|
|
770
|
-
},
|
|
771
|
-
}
|
|
840
|
+
? { cache_control: cacheControl }
|
|
772
841
|
: {}),
|
|
773
842
|
}));
|
|
774
843
|
const webSearchTool: Anthropic.WebSearchTool20250305 = {
|
|
@@ -782,14 +851,7 @@ export class AnthropicProvider implements Provider {
|
|
|
782
851
|
name: t.name,
|
|
783
852
|
description: t.description,
|
|
784
853
|
input_schema: t.input_schema as Anthropic.Tool["input_schema"],
|
|
785
|
-
...(i === tools.length - 1
|
|
786
|
-
? {
|
|
787
|
-
cache_control: {
|
|
788
|
-
type: "ephemeral" as const,
|
|
789
|
-
ttl: cacheTtl,
|
|
790
|
-
},
|
|
791
|
-
}
|
|
792
|
-
: {}),
|
|
854
|
+
...(i === tools.length - 1 ? { cache_control: cacheControl } : {}),
|
|
793
855
|
}));
|
|
794
856
|
}
|
|
795
857
|
}
|
|
@@ -813,10 +875,8 @@ export class AnthropicProvider implements Provider {
|
|
|
813
875
|
if (!hasText) continue;
|
|
814
876
|
const lastBlock = msg.content[msg.content.length - 1];
|
|
815
877
|
if (typeof lastBlock !== "string") {
|
|
816
|
-
(lastBlock as unknown as Record<string, unknown>).cache_control =
|
|
817
|
-
|
|
818
|
-
ttl: cacheTtl,
|
|
819
|
-
};
|
|
878
|
+
(lastBlock as unknown as Record<string, unknown>).cache_control =
|
|
879
|
+
cacheControl;
|
|
820
880
|
}
|
|
821
881
|
turnStartIdx = i;
|
|
822
882
|
break;
|
|
@@ -832,7 +892,10 @@ export class AnthropicProvider implements Provider {
|
|
|
832
892
|
if (turnStartIdx >= 0 && turnStartIdx < sentMessages.length - 1) {
|
|
833
893
|
const lastMsg = sentMessages[sentMessages.length - 1];
|
|
834
894
|
if (Array.isArray(lastMsg.content) && lastMsg.content.length > 0) {
|
|
835
|
-
const NON_CACHEABLE_TYPES = new Set([
|
|
895
|
+
const NON_CACHEABLE_TYPES = new Set([
|
|
896
|
+
"thinking",
|
|
897
|
+
"redacted_thinking",
|
|
898
|
+
]);
|
|
836
899
|
let tailBlock: (typeof lastMsg.content)[number] | undefined;
|
|
837
900
|
for (let j = lastMsg.content.length - 1; j >= 0; j--) {
|
|
838
901
|
const block = lastMsg.content[j];
|
|
@@ -845,10 +908,8 @@ export class AnthropicProvider implements Provider {
|
|
|
845
908
|
}
|
|
846
909
|
}
|
|
847
910
|
if (tailBlock && typeof tailBlock !== "string") {
|
|
848
|
-
(tailBlock as unknown as Record<string, unknown>).cache_control =
|
|
849
|
-
|
|
850
|
-
ttl: "5m",
|
|
851
|
-
};
|
|
911
|
+
(tailBlock as unknown as Record<string, unknown>).cache_control =
|
|
912
|
+
tailCacheControl;
|
|
852
913
|
tailBreakpointApplied = true;
|
|
853
914
|
}
|
|
854
915
|
}
|
|
@@ -872,7 +933,17 @@ export class AnthropicProvider implements Provider {
|
|
|
872
933
|
params.system.length === 2 &&
|
|
873
934
|
hasToolCacheBreakpoint
|
|
874
935
|
) {
|
|
875
|
-
delete (params.system[0] as unknown as Record<string, unknown>)
|
|
936
|
+
delete (params.system[0] as unknown as Record<string, unknown>)
|
|
937
|
+
.cache_control;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
// Strip orphaned UTF-16 surrogates so the Anthropic JSON parser never
|
|
941
|
+
// sees invalid strings produced by upstream surrogate-splitting `.slice()` calls.
|
|
942
|
+
const sanitized = stripOrphanedSurrogatesDeep(params);
|
|
943
|
+
if (sanitized.changed) {
|
|
944
|
+
logOrphanedSurrogateWarning(sanitized.fixedStringCount, sentMessages);
|
|
945
|
+
params = sanitized.value;
|
|
946
|
+
sentMessages = params.messages;
|
|
876
947
|
}
|
|
877
948
|
|
|
878
949
|
const { signal: timeoutSignal, cleanup: cleanupTimeout } =
|
|
@@ -890,15 +961,15 @@ export class AnthropicProvider implements Provider {
|
|
|
890
961
|
finalMessage(): Promise<Anthropic.Message>;
|
|
891
962
|
}
|
|
892
963
|
|
|
893
|
-
// Fast mode: use the beta endpoint with speed: "fast" for Opus 4.6
|
|
964
|
+
// Fast mode: use the beta endpoint with speed: "fast" for Opus models (4.6, 4.7)
|
|
894
965
|
const useFastMode = speed === "fast" && effectiveModel.includes("opus");
|
|
895
966
|
|
|
896
967
|
// Collect required betas: extended cache TTL for 1h system prompt caching,
|
|
897
968
|
// 1M context window, and fast-mode when applicable.
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
969
|
+
// Haiku doesn't support the extended cache TTL or 1M context betas.
|
|
970
|
+
const betas: string[] = isHaiku
|
|
971
|
+
? []
|
|
972
|
+
: ["extended-cache-ttl-2025-04-11", "context-1m-2025-08-07"];
|
|
902
973
|
if (useFastMode) {
|
|
903
974
|
betas.push("fast-mode-2026-02-01");
|
|
904
975
|
}
|
|
@@ -915,14 +986,18 @@ export class AnthropicProvider implements Provider {
|
|
|
915
986
|
Anthropic.Beta.Messages.MessageCreateParamsStreaming,
|
|
916
987
|
{ signal: timeoutSignal },
|
|
917
988
|
) as unknown as UnifiedStream)
|
|
918
|
-
:
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
Anthropic.Beta.Messages.
|
|
924
|
-
|
|
925
|
-
|
|
989
|
+
: betas.length > 0
|
|
990
|
+
? (this.client.beta.messages.stream(
|
|
991
|
+
{
|
|
992
|
+
...(params as Record<string, unknown>),
|
|
993
|
+
betas,
|
|
994
|
+
} as Anthropic.Beta.Messages.MessageCreateParamsNonStreaming &
|
|
995
|
+
Anthropic.Beta.Messages.MessageCreateParamsStreaming,
|
|
996
|
+
{ signal: timeoutSignal },
|
|
997
|
+
) as unknown as UnifiedStream)
|
|
998
|
+
: (this.client.messages.stream(params, {
|
|
999
|
+
signal: timeoutSignal,
|
|
1000
|
+
}) as unknown as UnifiedStream);
|
|
926
1001
|
|
|
927
1002
|
stream.on("text", (text) => {
|
|
928
1003
|
onEvent?.({ type: "text_delta", text });
|
|
@@ -982,7 +1057,9 @@ export class AnthropicProvider implements Provider {
|
|
|
982
1057
|
type: "server_tool_complete",
|
|
983
1058
|
toolUseId: block.tool_use_id,
|
|
984
1059
|
isError: !!isError,
|
|
985
|
-
...(Array.isArray(block.content)
|
|
1060
|
+
...(Array.isArray(block.content)
|
|
1061
|
+
? { content: block.content }
|
|
1062
|
+
: {}),
|
|
986
1063
|
});
|
|
987
1064
|
}
|
|
988
1065
|
if (event.type === "content_block_stop") {
|
|
@@ -1064,6 +1141,12 @@ export class AnthropicProvider implements Provider {
|
|
|
1064
1141
|
rawResponse: response,
|
|
1065
1142
|
};
|
|
1066
1143
|
} catch (error) {
|
|
1144
|
+
// Propagate a tagged AbortReason (set by the daemon at controller.abort())
|
|
1145
|
+
// so wrapped errors can be classified as user cancellation downstream.
|
|
1146
|
+
const abortReason =
|
|
1147
|
+
signal?.aborted && isAbortReason(signal.reason)
|
|
1148
|
+
? signal.reason
|
|
1149
|
+
: undefined;
|
|
1067
1150
|
if (error instanceof Anthropic.APIError) {
|
|
1068
1151
|
// Log detailed message structure for tool_use/tool_result ordering errors
|
|
1069
1152
|
if (
|
|
@@ -1079,20 +1162,33 @@ export class AnthropicProvider implements Provider {
|
|
|
1079
1162
|
"Anthropic 400: tool_use/tool_result pairing error — dumping message structure",
|
|
1080
1163
|
);
|
|
1081
1164
|
}
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1165
|
+
if (abortReason) {
|
|
1166
|
+
log.info(
|
|
1167
|
+
{ abortReason, message: error.message },
|
|
1168
|
+
"Anthropic request aborted by daemon",
|
|
1169
|
+
);
|
|
1170
|
+
} else {
|
|
1171
|
+
log.error(
|
|
1172
|
+
{
|
|
1173
|
+
status: error.status,
|
|
1174
|
+
message: error.message,
|
|
1175
|
+
headers: Object.fromEntries(error.headers?.entries() ?? []),
|
|
1176
|
+
},
|
|
1177
|
+
`Anthropic API error (${error.status})`,
|
|
1178
|
+
);
|
|
1179
|
+
}
|
|
1090
1180
|
const retryAfterMs = extractRetryAfterMs(error.headers);
|
|
1181
|
+
const errorOptions: {
|
|
1182
|
+
retryAfterMs?: number;
|
|
1183
|
+
abortReason?: unknown;
|
|
1184
|
+
} = {};
|
|
1185
|
+
if (retryAfterMs !== undefined) errorOptions.retryAfterMs = retryAfterMs;
|
|
1186
|
+
if (abortReason) errorOptions.abortReason = abortReason;
|
|
1091
1187
|
throw new ProviderError(
|
|
1092
1188
|
`Anthropic API error (${error.status}): ${error.message}`,
|
|
1093
1189
|
"anthropic",
|
|
1094
1190
|
error.status,
|
|
1095
|
-
|
|
1191
|
+
Object.keys(errorOptions).length > 0 ? errorOptions : undefined,
|
|
1096
1192
|
);
|
|
1097
1193
|
}
|
|
1098
1194
|
throw new ProviderError(
|
|
@@ -1101,7 +1197,7 @@ export class AnthropicProvider implements Provider {
|
|
|
1101
1197
|
}`,
|
|
1102
1198
|
"anthropic",
|
|
1103
1199
|
undefined,
|
|
1104
|
-
{ cause: error },
|
|
1200
|
+
abortReason ? { cause: error, abortReason } : { cause: error },
|
|
1105
1201
|
);
|
|
1106
1202
|
}
|
|
1107
1203
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { OpenAIChatCompletionsProvider } from "../openai/chat-completions-provider.js";
|
|
2
2
|
|
|
3
3
|
export interface FireworksProviderOptions {
|
|
4
4
|
apiKey?: string;
|
|
@@ -8,7 +8,7 @@ export interface FireworksProviderOptions {
|
|
|
8
8
|
|
|
9
9
|
const DEFAULT_FIREWORKS_BASE_URL = "https://api.fireworks.ai/inference/v1";
|
|
10
10
|
|
|
11
|
-
export class FireworksProvider extends
|
|
11
|
+
export class FireworksProvider extends OpenAIChatCompletionsProvider {
|
|
12
12
|
constructor(
|
|
13
13
|
apiKey: string,
|
|
14
14
|
model: string,
|
|
@@ -2,6 +2,7 @@ import type * as genai from "@google/genai";
|
|
|
2
2
|
import { ApiError, GoogleGenAI } from "@google/genai";
|
|
3
3
|
|
|
4
4
|
import { SYSTEM_PROMPT_CACHE_BOUNDARY } from "../../prompts/cache-boundary.js";
|
|
5
|
+
import { isAbortReason } from "../../util/abort-reasons.js";
|
|
5
6
|
import { ProviderError } from "../../util/errors.js";
|
|
6
7
|
import { getLogger } from "../../util/logger.js";
|
|
7
8
|
import { createStreamTimeout } from "../stream-timeout.js";
|
|
@@ -230,11 +231,18 @@ export class GeminiProvider implements Provider {
|
|
|
230
231
|
rawResponse,
|
|
231
232
|
};
|
|
232
233
|
} catch (error) {
|
|
234
|
+
// Propagate a tagged AbortReason (set by the daemon at controller.abort())
|
|
235
|
+
// so wrapped errors can be classified as user cancellation downstream.
|
|
236
|
+
const abortReason =
|
|
237
|
+
signal?.aborted && isAbortReason(signal.reason)
|
|
238
|
+
? signal.reason
|
|
239
|
+
: undefined;
|
|
233
240
|
if (error instanceof ApiError) {
|
|
234
241
|
throw new ProviderError(
|
|
235
242
|
`Gemini API error (${error.status}): ${error.message}`,
|
|
236
243
|
"gemini",
|
|
237
244
|
error.status,
|
|
245
|
+
abortReason ? { abortReason } : undefined,
|
|
238
246
|
);
|
|
239
247
|
}
|
|
240
248
|
throw new ProviderError(
|
|
@@ -243,7 +251,7 @@ export class GeminiProvider implements Provider {
|
|
|
243
251
|
}`,
|
|
244
252
|
"gemini",
|
|
245
253
|
undefined,
|
|
246
|
-
{ cause: error },
|
|
254
|
+
abortReason ? { cause: error, abortReason } : { cause: error },
|
|
247
255
|
);
|
|
248
256
|
}
|
|
249
257
|
}
|
|
@@ -18,6 +18,7 @@ export const PROVIDER_CATALOG: ProviderCatalogEntry[] = [
|
|
|
18
18
|
id: "anthropic",
|
|
19
19
|
displayName: "Anthropic",
|
|
20
20
|
models: [
|
|
21
|
+
{ id: "claude-opus-4-7", displayName: "Claude Opus 4.7" },
|
|
21
22
|
{ id: "claude-opus-4-6", displayName: "Claude Opus 4.6" },
|
|
22
23
|
{ id: "claude-sonnet-4-6", displayName: "Claude Sonnet 4.6" },
|
|
23
24
|
{ id: "claude-haiku-4-5-20251001", displayName: "Claude Haiku 4.5" },
|
|
@@ -76,6 +77,11 @@ export const PROVIDER_CATALOG: ProviderCatalogEntry[] = [
|
|
|
76
77
|
id: "openrouter",
|
|
77
78
|
displayName: "OpenRouter",
|
|
78
79
|
models: [
|
|
80
|
+
// Anthropic
|
|
81
|
+
{ id: "anthropic/claude-opus-4.7", displayName: "Claude Opus 4.7" },
|
|
82
|
+
{ id: "anthropic/claude-opus-4.6", displayName: "Claude Opus 4.6" },
|
|
83
|
+
{ id: "anthropic/claude-sonnet-4.6", displayName: "Claude Sonnet 4.6" },
|
|
84
|
+
{ id: "anthropic/claude-haiku-4.5", displayName: "Claude Haiku 4.5" },
|
|
79
85
|
// xAI
|
|
80
86
|
{ id: "x-ai/grok-4.20-beta", displayName: "Grok 4.20 Beta" },
|
|
81
87
|
{ id: "x-ai/grok-4", displayName: "Grok 4" },
|