@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
|
@@ -1052,4 +1052,92 @@ describe("ContextWindowManager", () => {
|
|
|
1052
1052
|
normalResult.compactedMessages,
|
|
1053
1053
|
);
|
|
1054
1054
|
});
|
|
1055
|
+
|
|
1056
|
+
test("subtracts summaryOffset only when summary at index 0 was injected from parent", async () => {
|
|
1057
|
+
const provider = createProvider(() => ({
|
|
1058
|
+
content: [{ type: "text", text: "## Goals\n- new child summary" }],
|
|
1059
|
+
model: "mock-model",
|
|
1060
|
+
usage: { inputTokens: 75, outputTokens: 20 },
|
|
1061
|
+
stopReason: "end_turn",
|
|
1062
|
+
}));
|
|
1063
|
+
const manager = new ContextWindowManager({
|
|
1064
|
+
provider,
|
|
1065
|
+
systemPrompt: "system prompt",
|
|
1066
|
+
config: makeConfig({
|
|
1067
|
+
maxInputTokens: 320,
|
|
1068
|
+
targetBudgetRatio: 0.58,
|
|
1069
|
+
}),
|
|
1070
|
+
});
|
|
1071
|
+
const long = "k".repeat(220);
|
|
1072
|
+
// Parent-injected summary at index 0, plus 2 injected non-persisted
|
|
1073
|
+
// messages, plus 3 child-persisted messages. nonPersistedPrefixCount
|
|
1074
|
+
// includes the summary (set by injectInheritedContext).
|
|
1075
|
+
const history: Message[] = [
|
|
1076
|
+
createContextSummaryMessage("parent summary"),
|
|
1077
|
+
message("user", `injected-u ${long}`),
|
|
1078
|
+
message("assistant", `injected-a ${long}`),
|
|
1079
|
+
message("user", `persisted-u1 ${long}`),
|
|
1080
|
+
message("assistant", `persisted-a1 ${long}`),
|
|
1081
|
+
message("user", `persisted-u2 ${long}`),
|
|
1082
|
+
];
|
|
1083
|
+
manager.nonPersistedPrefixCount = 3;
|
|
1084
|
+
manager.summaryIsInjected = true;
|
|
1085
|
+
|
|
1086
|
+
const result = await manager.maybeCompact(history, undefined, {
|
|
1087
|
+
force: true,
|
|
1088
|
+
});
|
|
1089
|
+
expect(result.compacted).toBe(true);
|
|
1090
|
+
// 4 messages compacted (2 injected + 2 child-persisted), but only the
|
|
1091
|
+
// 2 child-persisted ones count as DB-persisted.
|
|
1092
|
+
expect(result.compactedMessages).toBe(4);
|
|
1093
|
+
expect(result.compactedPersistedMessages).toBe(2);
|
|
1094
|
+
// Flag clears and prefix drains (both injected messages + summary slot).
|
|
1095
|
+
expect(manager.summaryIsInjected).toBe(false);
|
|
1096
|
+
expect(manager.nonPersistedPrefixCount).toBe(0);
|
|
1097
|
+
});
|
|
1098
|
+
|
|
1099
|
+
test("does not subtract summaryOffset when summary at index 0 is child-owned from prior compaction", async () => {
|
|
1100
|
+
const provider = createProvider(() => ({
|
|
1101
|
+
content: [{ type: "text", text: "## Goals\n- next child summary" }],
|
|
1102
|
+
model: "mock-model",
|
|
1103
|
+
usage: { inputTokens: 75, outputTokens: 20 },
|
|
1104
|
+
stopReason: "end_turn",
|
|
1105
|
+
}));
|
|
1106
|
+
const manager = new ContextWindowManager({
|
|
1107
|
+
provider,
|
|
1108
|
+
systemPrompt: "system prompt",
|
|
1109
|
+
config: makeConfig({
|
|
1110
|
+
maxInputTokens: 320,
|
|
1111
|
+
targetBudgetRatio: 0.58,
|
|
1112
|
+
}),
|
|
1113
|
+
});
|
|
1114
|
+
const long = "k".repeat(220);
|
|
1115
|
+
// Post-first-compaction state: child-owned summary at index 0, 2
|
|
1116
|
+
// still-injected messages that survived the first compaction's keep
|
|
1117
|
+
// region, 3 child-persisted messages. nonPersistedPrefixCount reflects
|
|
1118
|
+
// only the 2 remaining injected messages — the summary slot was already
|
|
1119
|
+
// consumed when the flag-gated decrement ran on the prior compaction.
|
|
1120
|
+
const history: Message[] = [
|
|
1121
|
+
createContextSummaryMessage("prior child summary"),
|
|
1122
|
+
message("user", `injected-u ${long}`),
|
|
1123
|
+
message("assistant", `injected-a ${long}`),
|
|
1124
|
+
message("user", `persisted-u1 ${long}`),
|
|
1125
|
+
message("assistant", `persisted-a1 ${long}`),
|
|
1126
|
+
message("user", `persisted-u2 ${long}`),
|
|
1127
|
+
];
|
|
1128
|
+
manager.nonPersistedPrefixCount = 2;
|
|
1129
|
+
manager.summaryIsInjected = false;
|
|
1130
|
+
|
|
1131
|
+
const result = await manager.maybeCompact(history, undefined, {
|
|
1132
|
+
force: true,
|
|
1133
|
+
});
|
|
1134
|
+
expect(result.compacted).toBe(true);
|
|
1135
|
+
expect(result.compactedMessages).toBe(4);
|
|
1136
|
+
// Regression guard: without the flag gate, the subtraction from the
|
|
1137
|
+
// #24353 fix would double-apply here (nonPersistedPrefixCount - 1),
|
|
1138
|
+
// undercounting injectedInCompactable and inflating
|
|
1139
|
+
// compactedPersistedMessages by 1 (to 3).
|
|
1140
|
+
expect(result.compactedPersistedMessages).toBe(2);
|
|
1141
|
+
expect(manager.nonPersistedPrefixCount).toBe(0);
|
|
1142
|
+
});
|
|
1055
1143
|
});
|
|
@@ -112,6 +112,8 @@ mock.module("../memory/conversation-crud.js", () => ({
|
|
|
112
112
|
},
|
|
113
113
|
updateConversationUsage: () => {},
|
|
114
114
|
updateConversationTitle: () => {},
|
|
115
|
+
getMessageById: () => null,
|
|
116
|
+
getLastUserTimestampBefore: () => 0,
|
|
115
117
|
}));
|
|
116
118
|
|
|
117
119
|
mock.module("../memory/conversation-queries.js", () => ({
|
|
@@ -137,6 +137,8 @@ mock.module("../memory/conversation-crud.js", () => ({
|
|
|
137
137
|
updateConversationContextWindow: () => {},
|
|
138
138
|
updateConversationTitle: () => {},
|
|
139
139
|
getConversationOriginChannel: () => null,
|
|
140
|
+
getMessageById: () => null,
|
|
141
|
+
getLastUserTimestampBefore: () => 0,
|
|
140
142
|
}));
|
|
141
143
|
|
|
142
144
|
const syncMessageToDiskMock = mock(() => {});
|
|
@@ -444,11 +446,17 @@ function makeCtx(
|
|
|
444
446
|
|
|
445
447
|
graphMemory: {
|
|
446
448
|
onCompacted: () => {},
|
|
447
|
-
prepareMemory: async () => ({
|
|
449
|
+
prepareMemory: async () => ({
|
|
450
|
+
runMessages: [],
|
|
451
|
+
injectedTokens: 0,
|
|
452
|
+
latencyMs: 0,
|
|
453
|
+
mode: "none" as const,
|
|
454
|
+
}),
|
|
448
455
|
reinjectCachedMemory: (messages: Message[]) => ({
|
|
449
456
|
runMessages: messages,
|
|
450
457
|
injectedTokens: 0,
|
|
451
458
|
}),
|
|
459
|
+
retrackCachedNodes: () => {},
|
|
452
460
|
} as unknown as AgentLoopConversationContext["graphMemory"],
|
|
453
461
|
|
|
454
462
|
...overrides,
|
|
@@ -763,6 +771,95 @@ describe("session-agent-loop", () => {
|
|
|
763
771
|
];
|
|
764
772
|
expect(call[4]).toBe("openrouter");
|
|
765
773
|
});
|
|
774
|
+
|
|
775
|
+
test("record request log handles Responses API shaped payloads", async () => {
|
|
776
|
+
const events: ServerMessage[] = [];
|
|
777
|
+
const rawRequest = {
|
|
778
|
+
model: "gpt-5.4",
|
|
779
|
+
instructions: "Be helpful.",
|
|
780
|
+
input: [
|
|
781
|
+
{
|
|
782
|
+
role: "user",
|
|
783
|
+
content: [{ type: "input_text", text: "Hello" }],
|
|
784
|
+
type: "message",
|
|
785
|
+
},
|
|
786
|
+
],
|
|
787
|
+
};
|
|
788
|
+
const rawResponse = {
|
|
789
|
+
id: "resp_test",
|
|
790
|
+
model: "gpt-5.4",
|
|
791
|
+
output: [
|
|
792
|
+
{
|
|
793
|
+
type: "message",
|
|
794
|
+
role: "assistant",
|
|
795
|
+
content: [{ type: "output_text", text: "Hi there." }],
|
|
796
|
+
},
|
|
797
|
+
],
|
|
798
|
+
usage: {
|
|
799
|
+
input_tokens: 12,
|
|
800
|
+
output_tokens: 3,
|
|
801
|
+
},
|
|
802
|
+
status: "completed",
|
|
803
|
+
};
|
|
804
|
+
|
|
805
|
+
const agentLoopRun: AgentLoopRun = async (messages, onEvent) => {
|
|
806
|
+
onEvent({
|
|
807
|
+
type: "message_complete",
|
|
808
|
+
message: {
|
|
809
|
+
role: "assistant",
|
|
810
|
+
content: [{ type: "text", text: "Hi there." }],
|
|
811
|
+
},
|
|
812
|
+
});
|
|
813
|
+
onEvent({
|
|
814
|
+
type: "usage",
|
|
815
|
+
inputTokens: 12,
|
|
816
|
+
outputTokens: 3,
|
|
817
|
+
model: "gpt-5.4",
|
|
818
|
+
actualProvider: "openai",
|
|
819
|
+
providerDurationMs: 45,
|
|
820
|
+
rawRequest,
|
|
821
|
+
rawResponse,
|
|
822
|
+
});
|
|
823
|
+
return [
|
|
824
|
+
...messages,
|
|
825
|
+
{
|
|
826
|
+
role: "assistant" as const,
|
|
827
|
+
content: [{ type: "text", text: "Hi there." }] as ContentBlock[],
|
|
828
|
+
},
|
|
829
|
+
];
|
|
830
|
+
};
|
|
831
|
+
|
|
832
|
+
const ctx = makeCtx({
|
|
833
|
+
agentLoopRun,
|
|
834
|
+
provider: {
|
|
835
|
+
name: "openai",
|
|
836
|
+
sendMessage: async () => ({
|
|
837
|
+
content: [{ type: "text", text: "title" }],
|
|
838
|
+
model: "mock",
|
|
839
|
+
usage: { inputTokens: 0, outputTokens: 0 },
|
|
840
|
+
stopReason: "end_turn",
|
|
841
|
+
}),
|
|
842
|
+
} as unknown as AgentLoopConversationContext["provider"],
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
|
|
846
|
+
|
|
847
|
+
expect(recordRequestLogMock).toHaveBeenCalledTimes(1);
|
|
848
|
+
const call = recordRequestLogMock.mock.calls[0] as unknown as [
|
|
849
|
+
string,
|
|
850
|
+
string,
|
|
851
|
+
string,
|
|
852
|
+
undefined,
|
|
853
|
+
string,
|
|
854
|
+
];
|
|
855
|
+
expect(call).toEqual([
|
|
856
|
+
"test-conv",
|
|
857
|
+
JSON.stringify(rawRequest),
|
|
858
|
+
JSON.stringify(rawResponse),
|
|
859
|
+
undefined,
|
|
860
|
+
"openai",
|
|
861
|
+
]);
|
|
862
|
+
});
|
|
766
863
|
});
|
|
767
864
|
|
|
768
865
|
describe("usage accounting", () => {
|
|
@@ -1938,7 +2035,6 @@ describe("session-agent-loop", () => {
|
|
|
1938
2035
|
|
|
1939
2036
|
expect(drainReason).toBe("loop_complete");
|
|
1940
2037
|
});
|
|
1941
|
-
|
|
1942
2038
|
});
|
|
1943
2039
|
|
|
1944
2040
|
describe("stale pending surface cleanup", () => {
|
|
@@ -713,3 +713,138 @@ describe("restoreBrowserProxyAvailability", () => {
|
|
|
713
713
|
expect(registry).not.toContain(probe);
|
|
714
714
|
});
|
|
715
715
|
});
|
|
716
|
+
|
|
717
|
+
describe("hostBrowserSenderOverride is sender-mode based, not interface-string based", () => {
|
|
718
|
+
test("macOS turn with registry override routes browser frames through the registry sender", () => {
|
|
719
|
+
// When a macOS turn sets hostBrowserSenderOverride (because the
|
|
720
|
+
// guardian has an active extension connection), the browser proxy
|
|
721
|
+
// must route through the registry sender, not the SSE hub — the
|
|
722
|
+
// same behavior chrome-extension turns have always used.
|
|
723
|
+
const sseHub: ServerMessage[] = [];
|
|
724
|
+
const registry: ServerMessage[] = [];
|
|
725
|
+
const conversation = makeConversation((msg) => sseHub.push(msg));
|
|
726
|
+
const browserProxy = new HostBrowserProxy(() => {});
|
|
727
|
+
conversation.setHostBrowserProxy(browserProxy);
|
|
728
|
+
|
|
729
|
+
// macOS is interactive — hasNoClient is false.
|
|
730
|
+
conversation.updateClient((msg) => sseHub.push(msg), false);
|
|
731
|
+
|
|
732
|
+
// The POST /messages handler detected an active extension connection
|
|
733
|
+
// and set the registry-routed sender override.
|
|
734
|
+
const registrySender = (msg: ServerMessage) => registry.push(msg);
|
|
735
|
+
conversation.hostBrowserSenderOverride = registrySender;
|
|
736
|
+
|
|
737
|
+
// restoreBrowserProxyAvailability (called after updateClient in the
|
|
738
|
+
// POST handler) must prefer the override.
|
|
739
|
+
conversation.restoreBrowserProxyAvailability();
|
|
740
|
+
expect(browserProxy.isAvailable()).toBe(true);
|
|
741
|
+
|
|
742
|
+
// Verify frames flow through the registry, not the SSE hub.
|
|
743
|
+
const internalSend = (
|
|
744
|
+
browserProxy as unknown as {
|
|
745
|
+
sendToClient: (msg: ServerMessage) => void;
|
|
746
|
+
}
|
|
747
|
+
).sendToClient;
|
|
748
|
+
const probe: ServerMessage = {
|
|
749
|
+
type: "host_browser_cancel",
|
|
750
|
+
requestId: "probe-macos-registry",
|
|
751
|
+
} as ServerMessage;
|
|
752
|
+
internalSend(probe);
|
|
753
|
+
expect(registry).toHaveLength(1);
|
|
754
|
+
expect(sseHub.some((m) => m === probe)).toBe(false);
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
test("macOS turn without registry override clears the browser proxy on restore", () => {
|
|
758
|
+
// When a macOS turn has no active extension connection, the override
|
|
759
|
+
// is cleared and restoreBrowserProxyAvailability falls back to the
|
|
760
|
+
// SSE hub sender. The proxy should not be stuck on an unavailable
|
|
761
|
+
// registry-routed sender from a prior chrome-extension turn.
|
|
762
|
+
const sseHub: ServerMessage[] = [];
|
|
763
|
+
const conversation = makeConversation((msg) => sseHub.push(msg));
|
|
764
|
+
const browserProxy = new HostBrowserProxy(() => {});
|
|
765
|
+
conversation.setHostBrowserProxy(browserProxy);
|
|
766
|
+
|
|
767
|
+
// Interactive macOS turn without extension connectivity.
|
|
768
|
+
conversation.updateClient((msg) => sseHub.push(msg), false);
|
|
769
|
+
conversation.hostBrowserSenderOverride = undefined;
|
|
770
|
+
conversation.restoreBrowserProxyAvailability();
|
|
771
|
+
|
|
772
|
+
// The proxy should be available and routed through SSE.
|
|
773
|
+
expect(browserProxy.isAvailable()).toBe(true);
|
|
774
|
+
const internalSend = (
|
|
775
|
+
browserProxy as unknown as {
|
|
776
|
+
sendToClient: (msg: ServerMessage) => void;
|
|
777
|
+
}
|
|
778
|
+
).sendToClient;
|
|
779
|
+
const probe: ServerMessage = {
|
|
780
|
+
type: "host_browser_cancel",
|
|
781
|
+
requestId: "probe-macos-sse",
|
|
782
|
+
} as ServerMessage;
|
|
783
|
+
internalSend(probe);
|
|
784
|
+
expect(sseHub).toContain(probe);
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
test("override semantics are symmetric: chrome-extension and macOS both set override when registry-routed", () => {
|
|
788
|
+
// The override field must be set for ANY interface that uses a
|
|
789
|
+
// registry-routed sender, and cleared for any that does not.
|
|
790
|
+
// This test verifies the field is not gated on interface strings.
|
|
791
|
+
const conversation = makeConversation();
|
|
792
|
+
const registrySender = () => {};
|
|
793
|
+
|
|
794
|
+
// Simulate chrome-extension setting the override.
|
|
795
|
+
conversation.hostBrowserSenderOverride = registrySender;
|
|
796
|
+
expect(conversation.hostBrowserSenderOverride).toBe(registrySender);
|
|
797
|
+
|
|
798
|
+
// Simulate macOS-with-extension setting the same override.
|
|
799
|
+
// The field value is the same registry sender, not gated by interface.
|
|
800
|
+
const macosRegistrySender = () => {};
|
|
801
|
+
conversation.hostBrowserSenderOverride = macosRegistrySender;
|
|
802
|
+
expect(conversation.hostBrowserSenderOverride).toBe(macosRegistrySender);
|
|
803
|
+
|
|
804
|
+
// Simulate macOS-without-extension clearing the override.
|
|
805
|
+
conversation.hostBrowserSenderOverride = undefined;
|
|
806
|
+
expect(conversation.hostBrowserSenderOverride).toBeUndefined();
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
test("queue-drain restore path preserves registry-routed sender for macOS turns", () => {
|
|
810
|
+
// When a macOS turn with an active extension connection has its
|
|
811
|
+
// messages queued and later drained, the drain-queue path calls
|
|
812
|
+
// restoreBrowserProxyAvailability(). With the override set, the
|
|
813
|
+
// proxy must be restored with the registry sender, not the SSE hub.
|
|
814
|
+
const sseHub: ServerMessage[] = [];
|
|
815
|
+
const registry: ServerMessage[] = [];
|
|
816
|
+
const conversation = makeConversation((msg) => sseHub.push(msg));
|
|
817
|
+
const browserProxy = new HostBrowserProxy(() => {});
|
|
818
|
+
conversation.setHostBrowserProxy(browserProxy);
|
|
819
|
+
|
|
820
|
+
// macOS interactive turn with extension connectivity.
|
|
821
|
+
conversation.updateClient((msg) => sseHub.push(msg), false);
|
|
822
|
+
const registrySender = (msg: ServerMessage) => registry.push(msg);
|
|
823
|
+
conversation.hostBrowserSenderOverride = registrySender;
|
|
824
|
+
conversation.restoreBrowserProxyAvailability();
|
|
825
|
+
expect(browserProxy.isAvailable()).toBe(true);
|
|
826
|
+
|
|
827
|
+
// Simulate drain-queue clearing all proxies for a non-interactive
|
|
828
|
+
// queued message, then restoring for the next macOS turn.
|
|
829
|
+
conversation.clearProxyAvailability();
|
|
830
|
+
expect(browserProxy.isAvailable()).toBe(false);
|
|
831
|
+
|
|
832
|
+
// Drain restore — override is still set from the POST handler.
|
|
833
|
+
conversation.restoreBrowserProxyAvailability();
|
|
834
|
+
expect(browserProxy.isAvailable()).toBe(true);
|
|
835
|
+
|
|
836
|
+
// Verify the registry sender was preserved, not the SSE hub.
|
|
837
|
+
const internalSend = (
|
|
838
|
+
browserProxy as unknown as {
|
|
839
|
+
sendToClient: (msg: ServerMessage) => void;
|
|
840
|
+
}
|
|
841
|
+
).sendToClient;
|
|
842
|
+
const probe: ServerMessage = {
|
|
843
|
+
type: "host_browser_cancel",
|
|
844
|
+
requestId: "probe-drain-macos",
|
|
845
|
+
} as ServerMessage;
|
|
846
|
+
internalSend(probe);
|
|
847
|
+
expect(registry).toHaveLength(1);
|
|
848
|
+
expect(sseHub.some((m) => m === probe)).toBe(false);
|
|
849
|
+
});
|
|
850
|
+
});
|
|
@@ -6,6 +6,10 @@ import {
|
|
|
6
6
|
classifyConversationError,
|
|
7
7
|
isUserCancellation,
|
|
8
8
|
} from "../daemon/conversation-error.js";
|
|
9
|
+
import {
|
|
10
|
+
type AbortReasonKind,
|
|
11
|
+
createAbortReason,
|
|
12
|
+
} from "../util/abort-reasons.js";
|
|
9
13
|
import { ProviderError, ProviderNotConfiguredError } from "../util/errors.js";
|
|
10
14
|
|
|
11
15
|
describe("isUserCancellation", () => {
|
|
@@ -563,6 +567,72 @@ describe("classifyConversationError", () => {
|
|
|
563
567
|
expect(isUserCancellation(err, aborted)).toBe(true);
|
|
564
568
|
});
|
|
565
569
|
});
|
|
570
|
+
|
|
571
|
+
describe("wrapped ProviderError carrying tagged abort reason", () => {
|
|
572
|
+
const abortedCtx: ErrorContext = { phase: "agent_loop", aborted: true };
|
|
573
|
+
const taggedKinds: AbortReasonKind[] = [
|
|
574
|
+
"user_cancel",
|
|
575
|
+
"preempted_by_new_message",
|
|
576
|
+
"conversation_disposed",
|
|
577
|
+
"subagent_aborted",
|
|
578
|
+
"signal_cancel",
|
|
579
|
+
"voice_session_aborted",
|
|
580
|
+
"work_item_aborted",
|
|
581
|
+
];
|
|
582
|
+
|
|
583
|
+
for (const kind of taggedKinds) {
|
|
584
|
+
it(`treats ProviderError with abortReason kind="${kind}" as user cancellation`, () => {
|
|
585
|
+
const wrapped = new ProviderError(
|
|
586
|
+
"Anthropic API error (undefined): Request was aborted.",
|
|
587
|
+
"anthropic",
|
|
588
|
+
undefined,
|
|
589
|
+
{ abortReason: createAbortReason(kind, `test:${kind}`) },
|
|
590
|
+
);
|
|
591
|
+
expect(isUserCancellation(wrapped, abortedCtx)).toBe(true);
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
it("does NOT treat tagged ProviderError as cancellation when ctx.aborted is false", () => {
|
|
596
|
+
const wrapped = new ProviderError(
|
|
597
|
+
"Anthropic API error (undefined): Request was aborted.",
|
|
598
|
+
"anthropic",
|
|
599
|
+
undefined,
|
|
600
|
+
{ abortReason: createAbortReason("user_cancel", "test") },
|
|
601
|
+
);
|
|
602
|
+
const notAborted: ErrorContext = { phase: "agent_loop", aborted: false };
|
|
603
|
+
expect(isUserCancellation(wrapped, notAborted)).toBe(false);
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
it("does NOT treat ProviderError without abortReason as cancellation", () => {
|
|
607
|
+
const wrapped = new ProviderError(
|
|
608
|
+
"Anthropic API error (undefined): Request was aborted.",
|
|
609
|
+
"anthropic",
|
|
610
|
+
undefined,
|
|
611
|
+
);
|
|
612
|
+
expect(isUserCancellation(wrapped, abortedCtx)).toBe(false);
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
it("does NOT treat ProviderError with foreign reason as cancellation", () => {
|
|
616
|
+
const wrapped = new ProviderError(
|
|
617
|
+
"Anthropic API error (undefined): Request was aborted.",
|
|
618
|
+
"anthropic",
|
|
619
|
+
undefined,
|
|
620
|
+
{ abortReason: { kind: "user_cancel", source: "spoofed" } },
|
|
621
|
+
);
|
|
622
|
+
expect(isUserCancellation(wrapped, abortedCtx)).toBe(false);
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
it("falls through to CONVERSATION_ABORTED when wrapped ProviderError has no tagged reason", () => {
|
|
626
|
+
const wrapped = new ProviderError(
|
|
627
|
+
"Anthropic API error (undefined): Request was aborted.",
|
|
628
|
+
"anthropic",
|
|
629
|
+
undefined,
|
|
630
|
+
);
|
|
631
|
+
const result = classifyConversationError(wrapped, abortedCtx);
|
|
632
|
+
expect(result.code).toBe("CONVERSATION_ABORTED");
|
|
633
|
+
expect(result.errorCategory).toBe("session_aborted");
|
|
634
|
+
});
|
|
635
|
+
});
|
|
566
636
|
});
|
|
567
637
|
|
|
568
638
|
describe("buildConversationErrorMessage", () => {
|
|
@@ -753,10 +753,17 @@ describe("web_search_tool_result structural guard", () => {
|
|
|
753
753
|
// It has a separate isWebSearchToolResultBlock for the other type.
|
|
754
754
|
"providers/anthropic/client.ts",
|
|
755
755
|
|
|
756
|
-
//
|
|
757
|
-
//
|
|
758
|
-
// blocks are handled upstream
|
|
759
|
-
|
|
756
|
+
// Chat-completions transport used by OpenAI-compatible providers
|
|
757
|
+
// (OpenRouter, Fireworks, Ollama). These APIs do not support
|
|
758
|
+
// web_search_tool_result natively; those blocks are handled upstream
|
|
759
|
+
// before reaching the chat-completions provider.
|
|
760
|
+
"providers/openai/chat-completions-provider.ts",
|
|
761
|
+
|
|
762
|
+
// OpenAI Responses API transport (used for direct OpenAI inference).
|
|
763
|
+
// Converts Anthropic-style messages to Responses API input format.
|
|
764
|
+
// web_search_tool_result blocks are handled upstream before reaching
|
|
765
|
+
// the responses provider.
|
|
766
|
+
"providers/openai/responses-provider.ts",
|
|
760
767
|
|
|
761
768
|
// Renders tool_result blocks for client display. web_search_tool_result
|
|
762
769
|
// blocks are rendered by the client via their own display path.
|
|
@@ -44,7 +44,6 @@ writeFileSync(
|
|
|
44
44
|
"# Test Identity\nYou are a test assistant.",
|
|
45
45
|
);
|
|
46
46
|
writeFileSync(join(testDir, "SOUL.md"), "# Test Soul\nBe helpful.");
|
|
47
|
-
writeFileSync(join(testDir, "USER.md"), "# Test User\nName: Benchmark Runner");
|
|
48
47
|
|
|
49
48
|
// Create real skill directories so projectSkillTools can load them from the catalog
|
|
50
49
|
const testSkillIds = ["bench-skill-a", "bench-skill-b", "bench-skill-c"];
|
|
@@ -150,8 +149,13 @@ mock.module("../memory/conversation-crud.js", () => ({
|
|
|
150
149
|
getConversationOriginInterface: () => null,
|
|
151
150
|
getConversationType: () => "standard",
|
|
152
151
|
getConversationMemoryScopeId: () => "default",
|
|
152
|
+
getConversationHostAccess: () => false,
|
|
153
|
+
getConversationGroupId: () => null,
|
|
153
154
|
getConversationRecentProvenanceTrustClass: () => null,
|
|
154
155
|
provenanceFromTrustContext: () => ({}),
|
|
156
|
+
updateConversationHostAccess: () => {},
|
|
157
|
+
updateMessageMetadata: () => {},
|
|
158
|
+
getLastUserTimestampBefore: () => null,
|
|
155
159
|
relinkAttachments: () => 0,
|
|
156
160
|
setConversationOriginChannelIfUnset: () => {},
|
|
157
161
|
setConversationOriginInterfaceIfUnset: () => {},
|
|
@@ -251,6 +255,7 @@ mock.module("../calls/call-store.js", () => ({
|
|
|
251
255
|
recordProcessedCallback: () => {},
|
|
252
256
|
claimCallback: () => true,
|
|
253
257
|
releaseCallbackClaim: () => {},
|
|
258
|
+
finalizeCallbackClaim: () => true,
|
|
254
259
|
}));
|
|
255
260
|
|
|
256
261
|
mock.module("../daemon/watch-handler.js", () => ({
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { describe, expect, test } from "bun:test";
|
|
4
|
+
|
|
5
|
+
const REPO_ROOT = resolve(import.meta.dirname ?? __dirname, "..", "..", "..");
|
|
6
|
+
const SKILL_PATH = resolve(
|
|
7
|
+
REPO_ROOT,
|
|
8
|
+
"skills",
|
|
9
|
+
"conversation-launcher",
|
|
10
|
+
"SKILL.md",
|
|
11
|
+
);
|
|
12
|
+
const skillContent = readFileSync(SKILL_PATH, "utf-8");
|
|
13
|
+
|
|
14
|
+
describe("conversation-launcher skill regression", () => {
|
|
15
|
+
test("describes the direct surface-action contract the daemon dispatches on", () => {
|
|
16
|
+
// The skill must render one `ui_show` card whose actions carry the wire
|
|
17
|
+
// contract that `handleSurfaceAction`'s `launch_conversation` branch reads.
|
|
18
|
+
// These tokens are the minimum the model needs to produce a valid card.
|
|
19
|
+
const requiredTokens = [
|
|
20
|
+
"ui_show",
|
|
21
|
+
"persistent: true",
|
|
22
|
+
'_action: "launch_conversation"',
|
|
23
|
+
"title",
|
|
24
|
+
"seedPrompt",
|
|
25
|
+
'"await_action": false',
|
|
26
|
+
];
|
|
27
|
+
for (const token of requiredTokens) {
|
|
28
|
+
expect(skillContent).toContain(token);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("does not resurrect the deprecated bash + signal-file launch flow", () => {
|
|
33
|
+
// The skill must not reference signal files, HOME-based workspace paths,
|
|
34
|
+
// or shell-based plumbing — it dispatches surface actions directly.
|
|
35
|
+
const forbiddenTokens = [
|
|
36
|
+
"bash",
|
|
37
|
+
"curl",
|
|
38
|
+
"signals/",
|
|
39
|
+
"jq ",
|
|
40
|
+
// Assembled from parts so this literal does not appear in repo grep
|
|
41
|
+
// results — the forbidden-tokens check would otherwise match this file.
|
|
42
|
+
["launch", "conversation."].join("-"),
|
|
43
|
+
"VELLUM_WORKSPACE_DIR",
|
|
44
|
+
"INTERNAL_GATEWAY_BASE_URL",
|
|
45
|
+
"emit-event",
|
|
46
|
+
];
|
|
47
|
+
for (const token of forbiddenTokens) {
|
|
48
|
+
expect(skillContent).not.toContain(token);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
});
|