@vellumai/assistant 0.8.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +11 -0
- package/Dockerfile +5 -4
- package/README.md +2 -2
- package/docker-entrypoint.sh +16 -0
- package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
- package/eslint-rules/cli-no-daemon-internals.js +283 -0
- package/eslint.config.mjs +12 -0
- package/knip.json +2 -1
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
- package/openapi.yaml +4847 -1698
- package/package.json +3 -1
- package/scripts/generate-openapi.ts +52 -4
- package/scripts/sync-llm-catalog.ts +165 -0
- package/scripts/sync-web-search-catalog.ts +107 -0
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
- package/src/__tests__/anthropic-provider.test.ts +92 -2
- package/src/__tests__/app-control-flow.test.ts +7 -0
- package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
- package/src/__tests__/avatar-identity-sync.test.ts +87 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
- package/src/__tests__/btw-routes.test.ts +1 -0
- package/src/__tests__/call-site-routing-provider.test.ts +172 -45
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
- package/src/__tests__/channel-policy.test.ts +12 -0
- package/src/__tests__/checker.test.ts +89 -0
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +35 -7
- package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
- package/src/__tests__/config-loader-backfill.test.ts +526 -102
- package/src/__tests__/config-loader-corrupt.test.ts +68 -0
- package/src/__tests__/config-loader-platform-defaults.test.ts +77 -23
- package/src/__tests__/config-schema-cmd.test.ts +63 -29
- package/src/__tests__/config-schema.test.ts +14 -3
- package/src/__tests__/config-set-platform-guard.test.ts +75 -152
- package/src/__tests__/config-set-route.test.ts +198 -0
- package/src/__tests__/config-watcher.test.ts +6 -0
- package/src/__tests__/contacts-tools.test.ts +51 -199
- package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
- package/src/__tests__/context-search-agent-runner.test.ts +22 -138
- package/src/__tests__/context-search-conversations-source.test.ts +42 -16
- package/src/__tests__/context-search-fanout.test.ts +20 -157
- package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
- package/src/__tests__/context-search-types.test.ts +7 -2
- package/src/__tests__/context-window-manager.test.ts +389 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
- package/src/__tests__/conversation-error.test.ts +38 -0
- package/src/__tests__/conversation-fork-crud.test.ts +241 -1
- package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
- package/src/__tests__/conversation-init.benchmark.test.ts +1 -0
- package/src/__tests__/conversation-lifecycle.test.ts +124 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
- package/src/__tests__/conversation-process-callsite.test.ts +21 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +4 -4
- package/src/__tests__/conversation-slash-commands.test.ts +194 -2
- package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
- package/src/__tests__/credential-security-invariants.test.ts +5 -6
- package/src/__tests__/daemon-credential-client.test.ts +56 -1
- package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
- package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
- package/src/__tests__/db-proxy-transaction.test.ts +206 -0
- package/src/__tests__/external-plugin-loader.test.ts +458 -0
- package/src/__tests__/filing-service.test.ts +23 -3
- package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -8
- package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
- package/src/__tests__/heartbeat-service.test.ts +50 -233
- package/src/__tests__/history-repair.test.ts +89 -0
- package/src/__tests__/host-app-control-proxy.test.ts +109 -1
- package/src/__tests__/host-app-control-routes.test.ts +247 -1
- package/src/__tests__/host-browser-proxy.test.ts +416 -20
- package/src/__tests__/host-browser-routes.test.ts +325 -33
- package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
- package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
- package/src/__tests__/inference-profile-reaper.test.ts +154 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
- package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
- package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
- package/src/__tests__/install-skill-routing.test.ts +2 -2
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +15 -0
- package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
- package/src/__tests__/llm-catalog-parity.test.ts +146 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
- package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
- package/src/__tests__/llm-resolver.test.ts +46 -0
- package/src/__tests__/managed-profile-guard.test.ts +131 -2
- package/src/__tests__/mcp-auth-routes.test.ts +1 -0
- package/src/__tests__/mcp-cli.test.ts +182 -220
- package/src/__tests__/mcp-health-check.test.ts +56 -27
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
- package/src/__tests__/message-complete-display-id.test.ts +175 -0
- package/src/__tests__/notification-platform-adapter.test.ts +229 -0
- package/src/__tests__/oauth-cli.test.ts +38 -2009
- package/src/__tests__/oauth-commands-routes.test.ts +711 -0
- package/src/__tests__/oauth-connect-routes.test.ts +174 -11
- package/src/__tests__/oauth-providers-routes.test.ts +14 -10
- package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
- package/src/__tests__/openai-responses-provider.test.ts +17 -0
- package/src/__tests__/plugin-bootstrap.test.ts +31 -2
- package/src/__tests__/plugin-route-contribution.test.ts +31 -3
- package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
- package/src/__tests__/plugin-types.test.ts +13 -11
- package/src/__tests__/process-message-background-slack.test.ts +46 -0
- package/src/__tests__/profile-entry-status.test.ts +43 -0
- package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
- package/src/__tests__/provider-registry-ollama.test.ts +12 -4
- package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
- package/src/__tests__/relay-server.test.ts +118 -0
- package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
- package/src/__tests__/schedule-retry.test.ts +56 -4
- package/src/__tests__/schedule-routes.test.ts +104 -0
- package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
- package/src/__tests__/scheduler-recurrence.test.ts +87 -34
- package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
- package/src/__tests__/scheduler-wake.test.ts +0 -63
- package/src/__tests__/secret-allowlist.test.ts +1 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
- package/src/__tests__/shell-credential-ref.test.ts +95 -3
- package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
- package/src/__tests__/skill-load-tool.test.ts +2 -4
- package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
- package/src/__tests__/suggestion-routes.test.ts +3 -3
- package/src/__tests__/sync-message-contract.test.ts +63 -0
- package/src/__tests__/task-scheduler.test.ts +88 -23
- package/src/__tests__/update-bulletin-job.test.ts +96 -193
- package/src/__tests__/usage-cli.test.ts +11 -73
- package/src/__tests__/user-plugin-loader.test.ts +145 -0
- package/src/__tests__/vercel-config.test.ts +168 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
- package/src/__tests__/web-search.test.ts +303 -2
- package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
- package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
- package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +53 -20
- package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
- package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
- package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
- package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
- package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
- package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
- package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
- package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
- package/src/acp/__tests__/helpers/which-stub.ts +4 -2
- package/src/acp/resolve-agent.test.ts +25 -0
- package/src/acp/resolve-agent.ts +13 -2
- package/src/acp/session-manager.ts +14 -0
- package/src/approvals/guardian-request-resolvers.ts +32 -87
- package/src/calls/relay-server.ts +35 -0
- package/src/calls/relay-setup-router.ts +36 -0
- package/src/calls/types.ts +1 -0
- package/src/calls/voice-session-bridge.ts +23 -4
- package/src/channels/config.ts +14 -1
- package/src/channels/types.ts +1 -0
- package/src/cli/AGENTS.md +164 -4
- package/src/cli/__tests__/notifications.test.ts +54 -0
- package/src/cli/commands/__tests__/avatar.test.ts +540 -0
- package/src/cli/commands/__tests__/backup.test.ts +236 -776
- package/src/cli/commands/__tests__/cache.test.ts +1 -1
- package/src/cli/commands/__tests__/changelog.test.ts +593 -0
- package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
- package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
- package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
- package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
- package/src/cli/commands/__tests__/email-core.test.ts +579 -0
- package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
- package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
- package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
- package/src/cli/commands/__tests__/skills.test.ts +563 -0
- package/src/cli/commands/__tests__/status.test.ts +249 -0
- package/src/cli/commands/__tests__/stt.test.ts +320 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
- package/src/cli/commands/__tests__/tts.test.ts +321 -0
- package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
- package/src/cli/commands/attachment.ts +8 -3
- package/src/cli/commands/audit.ts +95 -64
- package/src/cli/commands/auth.ts +61 -58
- package/src/cli/commands/avatar.ts +276 -390
- package/src/cli/commands/backup.ts +409 -505
- package/src/cli/commands/bash.ts +9 -5
- package/src/cli/commands/browser.ts +28 -9
- package/src/cli/commands/cache.ts +9 -4
- package/src/cli/commands/changelog.ts +414 -0
- package/src/cli/commands/channel-verification-sessions.ts +238 -317
- package/src/cli/commands/clients.ts +8 -3
- package/src/cli/commands/completions.ts +9 -9
- package/src/cli/commands/config.ts +102 -72
- package/src/cli/commands/contacts.ts +575 -696
- package/src/cli/commands/conversations-defer.ts +17 -69
- package/src/cli/commands/conversations-import.ts +90 -253
- package/src/cli/commands/conversations.ts +346 -436
- package/src/cli/commands/credential-execution.ts +9 -6
- package/src/cli/commands/credentials.ts +456 -736
- package/src/cli/commands/domain.ts +128 -206
- package/src/cli/commands/email.ts +606 -794
- package/src/cli/commands/gateway.ts +8 -1
- package/src/cli/commands/image-generation.ts +157 -205
- package/src/cli/commands/inference-providers.ts +352 -0
- package/src/cli/commands/inference-session.ts +415 -0
- package/src/cli/commands/inference.ts +87 -65
- package/src/cli/commands/keys.ts +8 -3
- package/src/cli/commands/mcp.ts +103 -287
- package/src/cli/commands/memory-v2.ts +162 -516
- package/src/cli/commands/notifications.ts +33 -7
- package/src/cli/commands/oauth/apps.ts +292 -261
- package/src/cli/commands/oauth/connect.ts +176 -297
- package/src/cli/commands/oauth/disconnect.ts +16 -215
- package/src/cli/commands/oauth/index.ts +49 -45
- package/src/cli/commands/oauth/mode.ts +43 -199
- package/src/cli/commands/oauth/ping.ts +17 -125
- package/src/cli/commands/oauth/providers.ts +732 -921
- package/src/cli/commands/oauth/request.ts +60 -350
- package/src/cli/commands/oauth/shared.ts +11 -121
- package/src/cli/commands/oauth/status.ts +31 -121
- package/src/cli/commands/oauth/token.ts +13 -55
- package/src/cli/commands/pending.ts +19 -10
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
- package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
- package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
- package/src/cli/commands/platform/connect.ts +16 -80
- package/src/cli/commands/platform/disconnect.ts +14 -112
- package/src/cli/commands/platform/index.ts +177 -246
- package/src/cli/commands/routes.ts +153 -336
- package/src/cli/commands/sequence.ts +316 -360
- package/src/cli/commands/skills.ts +449 -671
- package/src/cli/commands/status.ts +58 -37
- package/src/cli/commands/stt.ts +94 -262
- package/src/cli/commands/task.ts +14 -40
- package/src/cli/commands/trust.ts +8 -3
- package/src/cli/commands/tts.ts +162 -167
- package/src/cli/commands/ui.ts +35 -42
- package/src/cli/commands/usage.ts +188 -126
- package/src/cli/commands/watchers.ts +8 -3
- package/src/cli/commands/webhooks.ts +99 -193
- package/src/cli/lib/__tests__/register-command.test.ts +85 -0
- package/src/cli/lib/daemon-credential-client.ts +4 -5
- package/src/cli/lib/nested-value.ts +44 -0
- package/src/cli/lib/open-browser.ts +36 -0
- package/src/cli/lib/register-command.ts +19 -0
- package/src/cli/lib/time-ago.ts +34 -0
- package/src/cli/program.ts +2 -4
- package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
- package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
- package/src/cli/utils/conversation-id.ts +30 -0
- package/src/cli/utils/parse-duration.ts +41 -0
- package/src/config/acp-defaults.test.ts +5 -1
- package/src/config/acp-defaults.ts +11 -4
- package/src/config/bundled-skills/acp/TOOLS.json +2 -2
- package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
- package/src/config/bundled-skills/contacts/SKILL.md +12 -45
- package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
- package/src/config/bundled-tool-registry.ts +0 -2
- package/src/config/feature-flag-registry.json +16 -0
- package/src/config/llm-resolver.ts +16 -1
- package/src/config/loader.ts +76 -14
- package/src/config/raw-config-utils.ts +2 -30
- package/src/config/schema.ts +4 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
- package/src/config/schemas/call-site-catalog.ts +29 -7
- package/src/config/schemas/llm-request-logs.ts +57 -0
- package/src/config/schemas/llm.ts +52 -2
- package/src/config/schemas/memory-retrospective.ts +48 -0
- package/src/config/schemas/memory-v2.ts +32 -1
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/services.ts +15 -12
- package/src/config/seed-inference-profiles.ts +195 -134
- package/src/contacts/contact-store.ts +0 -61
- package/src/context/window-manager.ts +191 -5
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +79 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
- package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
- package/src/daemon/approval-generators.ts +23 -29
- package/src/daemon/config-watcher.ts +2 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +24 -0
- package/src/daemon/conversation-agent-loop.ts +127 -97
- package/src/daemon/conversation-error.ts +21 -0
- package/src/daemon/conversation-lifecycle.ts +46 -5
- package/src/daemon/conversation-process.ts +36 -19
- package/src/daemon/conversation-runtime-assembly.ts +14 -5
- package/src/daemon/conversation-slash.ts +175 -23
- package/src/daemon/conversation-store.ts +17 -10
- package/src/daemon/conversation-surfaces.ts +76 -12
- package/src/daemon/conversation-tool-setup.ts +24 -14
- package/src/daemon/conversation.ts +48 -9
- package/src/daemon/external-plugins-bootstrap.ts +18 -8
- package/src/daemon/guardian-action-generators.ts +7 -22
- package/src/daemon/handlers/config-model.ts +8 -126
- package/src/daemon/handlers/config-slack-channel.ts +10 -7
- package/src/daemon/handlers/config-vercel.ts +3 -1
- package/src/daemon/handlers/skills.ts +84 -5
- package/src/daemon/history-repair.ts +33 -6
- package/src/daemon/host-app-control-proxy.ts +44 -19
- package/src/daemon/host-bash-proxy.ts +85 -158
- package/src/daemon/host-browser-proxy.ts +96 -35
- package/src/daemon/host-proxy-base.ts +13 -1
- package/src/daemon/host-proxy-preactivation.ts +25 -1
- package/src/daemon/identity-helpers.ts +19 -0
- package/src/daemon/lifecycle.ts +42 -43
- package/src/daemon/meet-host-supervisor.ts +15 -15
- package/src/daemon/memory-v2-startup.ts +9 -2
- package/src/daemon/message-protocol.ts +6 -0
- package/src/daemon/message-types/bookmarks.ts +18 -0
- package/src/daemon/message-types/conversations.ts +12 -9
- package/src/daemon/message-types/messages.ts +9 -1
- package/src/daemon/message-types/sync.ts +60 -0
- package/src/daemon/pkb-reminder-builder.test.ts +54 -13
- package/src/daemon/pkb-reminder-builder.ts +21 -7
- package/src/daemon/process-message.ts +56 -23
- package/src/daemon/server.ts +23 -18
- package/src/daemon/shutdown-handlers.ts +0 -2
- package/src/daemon/tool-setup-types.ts +9 -0
- package/src/daemon/tool-side-effects.ts +6 -4
- package/src/daemon/wake-target-adapter.ts +11 -0
- package/src/export/transcript-formatter.ts +61 -2
- package/src/filing/filing-service.ts +40 -53
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
- package/src/heartbeat/heartbeat-run-store.ts +2 -1
- package/src/heartbeat/heartbeat-service.ts +148 -127
- package/src/home/__tests__/feed-types.test.ts +63 -131
- package/src/home/__tests__/feed-writer.test.ts +77 -278
- package/src/home/__tests__/post-connect-feed.test.ts +9 -12
- package/src/home/feed-types.ts +19 -73
- package/src/home/feed-writer.ts +25 -156
- package/src/home/post-connect-feed.ts +1 -3
- package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
- package/src/ipc/__tests__/email-ipc.test.ts +506 -0
- package/src/ipc/__tests__/exit-helper.test.ts +104 -0
- package/src/ipc/__tests__/streaming-client.test.ts +237 -0
- package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
- package/src/ipc/assistant-server.ts +55 -6
- package/src/ipc/cli-client.ts +370 -50
- package/src/ipc/routes/db-proxy-transaction.ts +151 -0
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
- package/src/ipc/skill-routes/events.ts +30 -3
- package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
- package/src/live-voice/live-voice-session-manager.ts +11 -4
- package/src/live-voice/live-voice-session.ts +14 -6
- package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
- package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
- package/src/memory/__tests__/conversation-types.test.ts +36 -0
- package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
- package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
- package/src/memory/bookmark-crud.ts +179 -0
- package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
- package/src/memory/context-search/agent-protocol.ts +5 -1
- package/src/memory/context-search/agent-runner.ts +60 -85
- package/src/memory/context-search/limits.ts +1 -4
- package/src/memory/context-search/search.ts +23 -113
- package/src/memory/context-search/sources/conversations.ts +18 -6
- package/src/memory/context-search/sources/memory-v2.ts +39 -14
- package/src/memory/context-search/sources/memory.ts +7 -0
- package/src/memory/context-search/sources/workspace.ts +13 -10
- package/src/memory/context-search/types.ts +1 -1
- package/src/memory/conversation-bootstrap.ts +11 -0
- package/src/memory/conversation-crud.ts +312 -10
- package/src/memory/conversation-queries.ts +9 -5
- package/src/memory/conversation-title-service.ts +1 -0
- package/src/memory/conversation-types.ts +16 -0
- package/src/memory/db-init.ts +14 -0
- package/src/memory/embedding-backend.ts +2 -1
- package/src/memory/embedding-runtime-manager.ts +1 -2
- package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
- package/src/memory/graph/conversation-graph-memory.ts +76 -5
- package/src/memory/graph/extraction.ts +4 -0
- package/src/memory/graph/graph-memory-state-store.ts +16 -3
- package/src/memory/graph/tool-handlers.ts +17 -7
- package/src/memory/graph/tools.ts +44 -5
- package/src/memory/indexer.ts +17 -0
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +13 -15
- package/src/memory/jobs/embed-concept-page.ts +45 -9
- package/src/memory/jobs-store.ts +51 -1
- package/src/memory/jobs-worker.ts +52 -3
- package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
- package/src/memory/llm-request-log-source-local.ts +26 -0
- package/src/memory/llm-request-log-source.ts +97 -0
- package/src/memory/llm-request-log-store.ts +1 -1
- package/src/memory/memory-retrospective-constants.ts +13 -0
- package/src/memory/memory-retrospective-enqueue.ts +114 -0
- package/src/memory/memory-retrospective-job.ts +351 -0
- package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
- package/src/memory/memory-retrospective-state.ts +162 -0
- package/src/memory/memory-retrospective-trigger-check.ts +91 -0
- package/src/memory/memory-v2-activation-log-store.ts +49 -5
- package/src/memory/memory-v2-concept-frequency.ts +4 -0
- package/src/memory/message-content.ts +38 -1
- package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
- package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
- package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
- package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
- package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
- package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
- package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
- package/src/memory/migrations/242-message-bookmarks.ts +38 -0
- package/src/memory/migrations/243-provider-connections.ts +68 -0
- package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
- package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
- package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
- package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
- package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
- package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
- package/src/memory/migrations/index.ts +7 -0
- package/src/memory/published-pages-store.ts +16 -0
- package/src/memory/schema/bookmarks.ts +38 -0
- package/src/memory/schema/conversations.ts +2 -0
- package/src/memory/schema/index.ts +2 -0
- package/src/memory/schema/inference.ts +29 -0
- package/src/memory/schema/memory-core.ts +9 -0
- package/src/memory/search/semantic.ts +1 -4
- package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
- package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
- package/src/memory/v2/__tests__/activation.test.ts +11 -4
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
- package/src/memory/v2/__tests__/consolidation-job.test.ts +123 -135
- package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
- package/src/memory/v2/__tests__/injection.test.ts +628 -10
- package/src/memory/v2/__tests__/migration.test.ts +7 -3
- package/src/memory/v2/__tests__/page-index.test.ts +277 -0
- package/src/memory/v2/__tests__/page-store.test.ts +14 -1
- package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
- package/src/memory/v2/__tests__/qdrant.test.ts +72 -0
- package/src/memory/v2/__tests__/reranker.test.ts +4 -4
- package/src/memory/v2/__tests__/router.test.ts +516 -0
- package/src/memory/v2/__tests__/sim.test.ts +45 -1
- package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
- package/src/memory/v2/__tests__/static-context.test.ts +7 -22
- package/src/memory/v2/__tests__/sweep-job.test.ts +95 -0
- package/src/memory/v2/activation-store.ts +34 -5
- package/src/memory/v2/activation.ts +40 -27
- package/src/memory/v2/backfill-jobs.ts +17 -84
- package/src/memory/v2/consolidation-job.ts +85 -78
- package/src/memory/v2/frontmatter-sweep.ts +91 -0
- package/src/memory/v2/injection.ts +440 -109
- package/src/memory/v2/migration.ts +117 -20
- package/src/memory/v2/page-index.ts +191 -0
- package/src/memory/v2/page-store.ts +3 -0
- package/src/memory/v2/prompts/consolidation.ts +9 -7
- package/src/memory/v2/prompts/router.ts +192 -0
- package/src/memory/v2/qdrant.ts +100 -87
- package/src/memory/v2/reranker.ts +14 -7
- package/src/memory/v2/router.ts +322 -0
- package/src/memory/v2/sim.ts +25 -12
- package/src/memory/v2/skill-store.ts +118 -29
- package/src/memory/v2/static-context.ts +16 -9
- package/src/memory/v2/sweep-job.ts +122 -96
- package/src/memory/v2/types.ts +10 -6
- package/src/memory/validation.ts +13 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
- package/src/notifications/__tests__/signal-registry.test.ts +17 -0
- package/src/notifications/adapters/platform.ts +171 -0
- package/src/notifications/conversation-pairing.ts +2 -2
- package/src/notifications/copy-composer.ts +15 -0
- package/src/notifications/destination-resolver.ts +21 -0
- package/src/notifications/emit-signal.ts +28 -1
- package/src/notifications/home-feed-side-effect.ts +111 -0
- package/src/notifications/signal.ts +5 -0
- package/src/permissions/checker.ts +12 -0
- package/src/permissions/ipc-risk-types.ts +2 -0
- package/src/plugin-api/index.ts +13 -0
- package/src/plugin-api/package.json +12 -0
- package/src/plugin-api/types.ts +62 -0
- package/src/plugins/defaults/injectors.ts +19 -3
- package/src/plugins/external-plugin-loader.ts +294 -0
- package/src/plugins/types.ts +46 -30
- package/src/plugins/user-loader.ts +64 -41
- package/src/proactive-artifact/job.test.ts +12 -4
- package/src/proactive-artifact/job.ts +4 -0
- package/src/proactive-artifact/trigger-state.test.ts +9 -0
- package/src/proactive-artifact/trigger-state.ts +4 -0
- package/src/prompts/__tests__/system-prompt.test.ts +105 -0
- package/src/prompts/system-prompt.ts +22 -1
- package/src/prompts/update-bulletin-job.ts +61 -73
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
- package/src/providers/__tests__/inference.test.ts +288 -0
- package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
- package/src/providers/__tests__/retry-callsite.test.ts +14 -32
- package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
- package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
- package/src/providers/anthropic/client.ts +95 -26
- package/src/providers/call-site-routing.ts +94 -16
- package/src/providers/connection-resolution.ts +163 -0
- package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
- package/src/providers/inference/adapter-factory.ts +173 -0
- package/src/providers/inference/auth.ts +112 -0
- package/src/providers/inference/backfill.ts +196 -0
- package/src/providers/inference/connections.ts +356 -0
- package/src/providers/inference/resolve-auth.ts +65 -0
- package/src/providers/model-catalog.ts +104 -6
- package/src/providers/openai/responses-provider.ts +4 -2
- package/src/providers/provider-env-vars.ts +17 -7
- package/src/providers/provider-secret-catalog.ts +49 -30
- package/src/providers/provider-send-message.ts +41 -20
- package/src/providers/registry.ts +143 -159
- package/src/providers/retry.ts +18 -10
- package/src/providers/search-provider-catalog.ts +121 -0
- package/src/runtime/AGENTS.md +18 -5
- package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
- package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
- package/src/runtime/actor-trust-resolver.ts +32 -10
- package/src/runtime/agent-wake.ts +35 -6
- package/src/runtime/assistant-event-hub.ts +3 -85
- package/src/runtime/auth/route-policy.ts +303 -8
- package/src/runtime/auth/same-actor.ts +2 -0
- package/src/runtime/background-job-runner.ts +339 -0
- package/src/runtime/btw-sidechain.ts +1 -0
- package/src/runtime/http-router.ts +36 -1
- package/src/runtime/http-server.ts +31 -5
- package/src/runtime/http-types.ts +2 -0
- package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
- package/src/runtime/middleware/request-logger.ts +62 -1
- package/src/runtime/pre-first-message-gate.ts +83 -0
- package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
- package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +4 -4
- package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
- package/src/runtime/routes/acp-routes.ts +10 -8
- package/src/runtime/routes/app-management-routes.ts +228 -3
- package/src/runtime/routes/approval-routes.ts +0 -18
- package/src/runtime/routes/audit-routes.ts +43 -0
- package/src/runtime/routes/auth-routes.ts +72 -0
- package/src/runtime/routes/avatar-routes.ts +273 -20
- package/src/runtime/routes/backup-routes.ts +406 -2
- package/src/runtime/routes/bookmark-routes.ts +154 -0
- package/src/runtime/routes/channel-verification-routes.ts +2 -1
- package/src/runtime/routes/contact-routes.ts +0 -160
- package/src/runtime/routes/conversation-cli-routes.ts +192 -0
- package/src/runtime/routes/conversation-management-routes.ts +30 -43
- package/src/runtime/routes/conversation-query-routes.ts +334 -86
- package/src/runtime/routes/conversation-routes.ts +31 -10
- package/src/runtime/routes/conversations-import-routes.ts +229 -0
- package/src/runtime/routes/credential-routes.ts +540 -0
- package/src/runtime/routes/debug-routes.ts +2 -2
- package/src/runtime/routes/document-pdf-renderer.ts +5 -1
- package/src/runtime/routes/domain-routes.ts +167 -0
- package/src/runtime/routes/email-routes.ts +603 -0
- package/src/runtime/routes/errors.ts +2 -2
- package/src/runtime/routes/events-routes.ts +192 -0
- package/src/runtime/routes/home-feed-routes.ts +6 -78
- package/src/runtime/routes/host-app-control-routes.ts +44 -2
- package/src/runtime/routes/host-browser-routes.ts +103 -22
- package/src/runtime/routes/http-adapter.ts +2 -0
- package/src/runtime/routes/identity-routes.ts +5 -0
- package/src/runtime/routes/image-generation-routes.ts +99 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -4
- package/src/runtime/routes/index.ts +36 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
- package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
- package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
- package/src/runtime/routes/inference-send-routes.ts +115 -0
- package/src/runtime/routes/integrations/twilio.ts +1 -0
- package/src/runtime/routes/mcp-auth-routes.ts +283 -9
- package/src/runtime/routes/memory-v2-routes.ts +13 -398
- package/src/runtime/routes/notification-routes.ts +2 -0
- package/src/runtime/routes/oauth-apps.ts +112 -7
- package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
- package/src/runtime/routes/oauth-connect-routes.ts +67 -5
- package/src/runtime/routes/oauth-providers.ts +298 -8
- package/src/runtime/routes/platform-routes.ts +336 -0
- package/src/runtime/routes/playground/inject-failures.ts +2 -1
- package/src/runtime/routes/playground/reset-circuit.ts +2 -1
- package/src/runtime/routes/playground/state.ts +2 -1
- package/src/runtime/routes/publish-routes.ts +221 -0
- package/src/runtime/routes/schedule-routes.ts +82 -0
- package/src/runtime/routes/sequence-routes.ts +291 -0
- package/src/runtime/routes/settings-routes.ts +2 -10
- package/src/runtime/routes/skills-routes.ts +31 -1
- package/src/runtime/routes/stt-routes.ts +240 -3
- package/src/runtime/routes/surface-action-routes.ts +43 -7
- package/src/runtime/routes/tts-routes.ts +67 -0
- package/src/runtime/routes/types.ts +32 -0
- package/src/runtime/routes/user-routes-cli.ts +243 -0
- package/src/runtime/routes/webhook-routes.ts +165 -0
- package/src/runtime/sync/resource-sync-events.ts +25 -0
- package/src/runtime/sync/sync-publisher.test.ts +105 -0
- package/src/runtime/sync/sync-publisher.ts +21 -0
- package/src/schedule/scheduler.ts +200 -123
- package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
- package/src/security/secret-patterns.ts +3 -0
- package/src/sequence/engine.ts +38 -40
- package/src/subagent/manager.ts +20 -15
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
- package/src/tools/browser/browser-execution.ts +15 -4
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
- package/src/tools/browser/cdp-client/factory.ts +66 -5
- package/src/tools/browser/runtime-check.ts +77 -0
- package/src/tools/memory/register.test.ts +3 -3
- package/src/tools/memory/register.ts +9 -1
- package/src/tools/network/__tests__/web-search.test.ts +156 -0
- package/src/tools/network/web-search.ts +280 -37
- package/src/tools/permission-checker.ts +13 -5
- package/src/tools/subagent/spawn.ts +3 -3
- package/src/tools/terminal/shell.ts +44 -0
- package/src/usage/attribution.ts +3 -2
- package/src/util/pricing.ts +86 -160
- package/src/watcher/__tests__/engine.test.ts +301 -0
- package/src/watcher/constants.ts +7 -0
- package/src/watcher/engine.ts +90 -90
- package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
- package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
- package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
- package/src/workspace/migrations/069-seed-onboarding-threads.ts +8 -2
- package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
- package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
- package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
- package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
- package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
- package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
- package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
- package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
- package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
- package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
- package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
- package/src/workspace/migrations/registry.ts +22 -0
- package/src/workspace/migrations/runner.ts +13 -2
- package/src/workspace/migrations/types.ts +13 -3
- package/src/workspace/provider-commit-message-generator.ts +3 -2
- package/src/__tests__/context-search-pkb-source.test.ts +0 -498
- package/src/__tests__/credentials-cli.test.ts +0 -1225
- package/src/__tests__/memory-admin-recall.test.ts +0 -213
- package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
- package/src/cli/commands/__tests__/email-download.test.ts +0 -260
- package/src/cli/commands/__tests__/email-list.test.ts +0 -216
- package/src/cli/commands/__tests__/email-register.test.ts +0 -186
- package/src/cli/commands/__tests__/email-send.test.ts +0 -416
- package/src/cli/commands/__tests__/email-status.test.ts +0 -185
- package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
- package/src/cli/commands/__tests__/routes.test.ts +0 -562
- package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
- package/src/cli/commands/autonomy.ts +0 -365
- package/src/cli/commands/memory.ts +0 -424
- package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -947
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
- package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
- package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
- package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
- package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
- package/src/cli/lib/daemon-avatar-client.ts +0 -37
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
- package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
- package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
- package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
- package/src/home/__tests__/emit-feed-event.test.ts +0 -169
- package/src/home/__tests__/feed-population-integration.test.ts +0 -312
- package/src/home/__tests__/feed-scheduler.test.ts +0 -222
- package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
- package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
- package/src/home/__tests__/rollup-producer.test.ts +0 -507
- package/src/home/assistant-feed-authoring.ts +0 -135
- package/src/home/emit-feed-event.ts +0 -169
- package/src/home/feed-scheduler.ts +0 -281
- package/src/home/platform-gmail-digest.ts +0 -163
- package/src/home/rewrite-command-preview.ts +0 -66
- package/src/home/rewrite-feed-title.ts +0 -58
- package/src/home/rollup-producer.ts +0 -426
- package/src/memory/admin.ts +0 -326
- package/src/memory/context-search/sources/pkb.ts +0 -476
- package/src/memory/graph/compaction.ts +0 -299
- /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
import { emitContactChange } from "./contact-events.js";
|
|
11
11
|
import type {
|
|
12
12
|
AssistantContactMetadata,
|
|
13
|
-
AssistantSpecies,
|
|
14
13
|
ChannelPolicy,
|
|
15
14
|
ChannelStatus,
|
|
16
15
|
Contact,
|
|
@@ -1013,66 +1012,6 @@ function parseAssistantMetadata(
|
|
|
1013
1012
|
} as AssistantContactMetadata;
|
|
1014
1013
|
}
|
|
1015
1014
|
|
|
1016
|
-
/**
|
|
1017
|
-
* Validate that metadata matches the expected shape for the given species.
|
|
1018
|
-
* Enforces the invariant that makes the discriminated union cast in
|
|
1019
|
-
* parseAssistantMetadata safe.
|
|
1020
|
-
*/
|
|
1021
|
-
export function validateSpeciesMetadata(
|
|
1022
|
-
species: AssistantSpecies,
|
|
1023
|
-
metadata: Record<string, unknown> | null | undefined,
|
|
1024
|
-
): void {
|
|
1025
|
-
if (metadata == null) return;
|
|
1026
|
-
|
|
1027
|
-
if (species === "vellum") {
|
|
1028
|
-
if (typeof metadata.assistantId !== "string" || !metadata.assistantId) {
|
|
1029
|
-
throw new Error(
|
|
1030
|
-
'Vellum assistant metadata requires a non-empty "assistantId" string',
|
|
1031
|
-
);
|
|
1032
|
-
}
|
|
1033
|
-
if (typeof metadata.gatewayUrl !== "string" || !metadata.gatewayUrl) {
|
|
1034
|
-
throw new Error(
|
|
1035
|
-
'Vellum assistant metadata requires a non-empty "gatewayUrl" string',
|
|
1036
|
-
);
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
|
|
1041
|
-
export function upsertAssistantContactMetadata(params: {
|
|
1042
|
-
contactId: string;
|
|
1043
|
-
species: AssistantSpecies;
|
|
1044
|
-
metadata?: Record<string, unknown> | null;
|
|
1045
|
-
}): AssistantContactMetadata {
|
|
1046
|
-
validateSpeciesMetadata(params.species, params.metadata);
|
|
1047
|
-
|
|
1048
|
-
const db = getDb();
|
|
1049
|
-
const metadataJson =
|
|
1050
|
-
params.metadata != null ? JSON.stringify(params.metadata) : null;
|
|
1051
|
-
|
|
1052
|
-
db.insert(assistantContactMetadata)
|
|
1053
|
-
.values({
|
|
1054
|
-
contactId: params.contactId,
|
|
1055
|
-
species: params.species,
|
|
1056
|
-
metadata: metadataJson,
|
|
1057
|
-
})
|
|
1058
|
-
.onConflictDoUpdate({
|
|
1059
|
-
target: assistantContactMetadata.contactId,
|
|
1060
|
-
set: {
|
|
1061
|
-
species: params.species,
|
|
1062
|
-
metadata: metadataJson,
|
|
1063
|
-
},
|
|
1064
|
-
})
|
|
1065
|
-
.run();
|
|
1066
|
-
|
|
1067
|
-
const row = db
|
|
1068
|
-
.select()
|
|
1069
|
-
.from(assistantContactMetadata)
|
|
1070
|
-
.where(eq(assistantContactMetadata.contactId, params.contactId))
|
|
1071
|
-
.get();
|
|
1072
|
-
|
|
1073
|
-
return parseAssistantMetadata(row!);
|
|
1074
|
-
}
|
|
1075
|
-
|
|
1076
1015
|
export function getAssistantContactMetadata(
|
|
1077
1016
|
contactId: string,
|
|
1078
1017
|
): AssistantContactMetadata | null {
|
|
@@ -32,6 +32,19 @@ const COMPACTION_TOOL_RESULT_MAX_CHARS = 6_000;
|
|
|
32
32
|
const MIN_COMPACTABLE_PERSISTED_MESSAGES = 2;
|
|
33
33
|
const INTERNAL_CONTEXT_SUMMARY_MESSAGES = new WeakSet<Message>();
|
|
34
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Hard cap on the verbatim tail-anchor block we splice into the
|
|
37
|
+
* post-compaction summary message (see `extractTailAssistantText`). 1500
|
|
38
|
+
* chars (~375 tokens) covers a few paragraphs of recent assistant
|
|
39
|
+
* narration without bloating the summary. When the tail exceeds this
|
|
40
|
+
* size we keep the END (most recent text), since "next step" / "now I'll
|
|
41
|
+
* …" statements typically live at the end of the assistant's last text
|
|
42
|
+
* block and that's the part the post-compaction model needs most.
|
|
43
|
+
*/
|
|
44
|
+
const TAIL_ANCHOR_MAX_CHARS = 1500;
|
|
45
|
+
const TAIL_ANCHOR_OPEN_TAG = "<verbatim_tail>";
|
|
46
|
+
const TAIL_ANCHOR_CLOSE_TAG = "</verbatim_tail>";
|
|
47
|
+
|
|
35
48
|
/**
|
|
36
49
|
* When the existing summary is this fraction or more of the per-summary
|
|
37
50
|
* token budget, inject a "compress older content aggressively" instruction
|
|
@@ -488,13 +501,45 @@ export class ContextWindowManager {
|
|
|
488
501
|
};
|
|
489
502
|
}
|
|
490
503
|
|
|
491
|
-
const
|
|
504
|
+
const keepPlanInitial = this.pickKeepBoundary(messages, userTurnStarts, {
|
|
492
505
|
minKeepRecentUserTurns: options?.minKeepRecentUserTurns,
|
|
493
506
|
targetInputTokensOverride: options?.targetInputTokensOverride,
|
|
494
507
|
conversationOriginChannel: options?.conversationOriginChannel,
|
|
495
508
|
force: options?.force,
|
|
496
509
|
previousEstimatedInputTokens,
|
|
497
510
|
});
|
|
511
|
+
// Under force (user-explicit `/compact`), never route through the
|
|
512
|
+
// "already fits" / "truncated tool results without summarization"
|
|
513
|
+
// early-return — those are no-op responses to a direct user command.
|
|
514
|
+
// The boundary can collapse to the summary in two cases the
|
|
515
|
+
// projection-optimism clamp in pickKeepBoundary does not cover:
|
|
516
|
+
// 1. `adjustForToolPairs` walked the boundary back through a
|
|
517
|
+
// tool_use/tool_result chain at the start of the conversation.
|
|
518
|
+
// 2. The binary search settled below `userTurnStarts.length` (so
|
|
519
|
+
// the clamp at the top of pickKeepBoundary did not fire) but
|
|
520
|
+
// `adjustForToolPairs` still walked the resulting boundary
|
|
521
|
+
// backwards past `summaryOffset`.
|
|
522
|
+
// Rescue: restore the binary search's intended keep depth (capped at
|
|
523
|
+
// `length - 1` so we always summarize at least one turn) and bypass
|
|
524
|
+
// `adjustForToolPairs`. The kept region's first message may then
|
|
525
|
+
// contain a `tool_result` whose matching `tool_use` lives in the
|
|
526
|
+
// compacted region; we strip such orphans below before assembling
|
|
527
|
+
// the final messages array so the next agent turn does not fail
|
|
528
|
+
// when sending to the LLM.
|
|
529
|
+
const forceRescueApplied =
|
|
530
|
+
options?.force === true &&
|
|
531
|
+
keepPlanInitial.keepFromIndex <= summaryOffset &&
|
|
532
|
+
userTurnStarts.length >= 2;
|
|
533
|
+
const safeKeepTurns = Math.max(
|
|
534
|
+
1,
|
|
535
|
+
Math.min(keepPlanInitial.keepTurns, userTurnStarts.length - 1),
|
|
536
|
+
);
|
|
537
|
+
const keepPlan = forceRescueApplied
|
|
538
|
+
? {
|
|
539
|
+
keepFromIndex: userTurnStarts[userTurnStarts.length - safeKeepTurns],
|
|
540
|
+
keepTurns: safeKeepTurns,
|
|
541
|
+
}
|
|
542
|
+
: keepPlanInitial;
|
|
498
543
|
if (keepPlan.keepFromIndex <= summaryOffset) {
|
|
499
544
|
// All turns fit after truncation projection, but the real in-memory
|
|
500
545
|
// messages may still contain un-truncated tool results. Apply truncation
|
|
@@ -511,6 +556,14 @@ export class ContextWindowManager {
|
|
|
511
556
|
toolTokenBudget: this.toolTokenBudget,
|
|
512
557
|
})
|
|
513
558
|
: previousEstimatedInputTokens;
|
|
559
|
+
// Under force with only one user turn, the rescue above could not
|
|
560
|
+
// fire — there is nothing earlier to summarize. Surface that
|
|
561
|
+
// explicitly instead of "conversation already fits..." so the user
|
|
562
|
+
// knows why `/compact` did not produce a summary.
|
|
563
|
+
const noSummarizationReason =
|
|
564
|
+
options?.force && userTurnStarts.length < 2
|
|
565
|
+
? "only one user turn — nothing earlier to compact"
|
|
566
|
+
: "conversation already fits within the compaction target";
|
|
514
567
|
return {
|
|
515
568
|
messages: truncatedMessages,
|
|
516
569
|
compacted: didTruncate,
|
|
@@ -527,7 +580,7 @@ export class ContextWindowManager {
|
|
|
527
580
|
summaryText: existingSummary ?? "",
|
|
528
581
|
reason: didTruncate
|
|
529
582
|
? "truncated tool results without summarization"
|
|
530
|
-
:
|
|
583
|
+
: noSummarizationReason,
|
|
531
584
|
};
|
|
532
585
|
}
|
|
533
586
|
|
|
@@ -645,9 +698,15 @@ export class ContextWindowManager {
|
|
|
645
698
|
};
|
|
646
699
|
}
|
|
647
700
|
|
|
701
|
+
// `severePressure` already bypasses this guard to keep context from
|
|
702
|
+
// overflowing. Forced compaction also bypasses: when the user
|
|
703
|
+
// explicitly types `/compact` we must summarize whatever is
|
|
704
|
+
// available rather than return "insufficient compactable persisted
|
|
705
|
+
// messages" — that is a no-op response to a direct user command.
|
|
648
706
|
if (
|
|
649
707
|
compactedPersistedMessages < MIN_COMPACTABLE_PERSISTED_MESSAGES &&
|
|
650
|
-
!severePressure
|
|
708
|
+
!severePressure &&
|
|
709
|
+
!options?.force
|
|
651
710
|
) {
|
|
652
711
|
return {
|
|
653
712
|
messages,
|
|
@@ -688,7 +747,6 @@ export class ContextWindowManager {
|
|
|
688
747
|
signal,
|
|
689
748
|
options?.overrideProfile ?? null,
|
|
690
749
|
);
|
|
691
|
-
const summary = summaryUpdate.summary;
|
|
692
750
|
const summaryInputTokens = summaryUpdate.inputTokens;
|
|
693
751
|
const summaryOutputTokens = summaryUpdate.outputTokens;
|
|
694
752
|
const summaryModel = summaryUpdate.model;
|
|
@@ -704,6 +762,19 @@ export class ContextWindowManager {
|
|
|
704
762
|
}
|
|
705
763
|
const summaryCalls = 1;
|
|
706
764
|
|
|
765
|
+
// Force-keep the most recent assistant text from the compactable region
|
|
766
|
+
// by splicing it verbatim into the summary message. This is independent
|
|
767
|
+
// of what the LLM summarizer chose to surface — when compaction
|
|
768
|
+
// interrupts a long assistant work span, this anchor preserves the
|
|
769
|
+
// model's last self-narration ("Next step: …", "About to …") so the
|
|
770
|
+
// post-compaction model has unambiguous continuity instead of falling
|
|
771
|
+
// back to a "where am I?" recovery shape.
|
|
772
|
+
const tailAnchorText = extractTailAssistantText(compactableMessages);
|
|
773
|
+
const summary =
|
|
774
|
+
tailAnchorText != null
|
|
775
|
+
? appendTailAnchorToSummary(summaryUpdate.summary, tailAnchorText)
|
|
776
|
+
: summaryUpdate.summary;
|
|
777
|
+
|
|
707
778
|
// Media (images, files) in kept turns is preserved naturally — those
|
|
708
779
|
// turns are carried forward as-is and their token cost is already
|
|
709
780
|
// accounted for by pickKeepBoundary's estimatePromptTokens call.
|
|
@@ -716,7 +787,14 @@ export class ContextWindowManager {
|
|
|
716
787
|
messages.slice(keepPlan.keepFromIndex),
|
|
717
788
|
COMPACTION_TOOL_RESULT_MAX_CHARS,
|
|
718
789
|
);
|
|
719
|
-
|
|
790
|
+
// The force-rescue boundary bypasses `adjustForToolPairs`, so the
|
|
791
|
+
// kept region may contain `tool_result` blocks whose matching
|
|
792
|
+
// `tool_use` is in the (now-compacted) prefix. Strip those orphans
|
|
793
|
+
// so the next agent turn does not fail with an LLM API error.
|
|
794
|
+
const keptMessages = forceRescueApplied
|
|
795
|
+
? stripOrphanToolResults(truncatedKeptMessages)
|
|
796
|
+
: truncatedKeptMessages;
|
|
797
|
+
const compactedMessages = [summaryMessage, ...keptMessages];
|
|
720
798
|
const estimatedInputTokens = estimatePromptTokens(
|
|
721
799
|
compactedMessages,
|
|
722
800
|
this.systemPrompt,
|
|
@@ -1251,6 +1329,53 @@ function adjustForToolPairs(
|
|
|
1251
1329
|
return idx;
|
|
1252
1330
|
}
|
|
1253
1331
|
|
|
1332
|
+
/**
|
|
1333
|
+
* Strip `tool_result` blocks whose matching `tool_use` is not present in
|
|
1334
|
+
* the message array. Used by the force-rescue path in `_maybeCompact`
|
|
1335
|
+
* which bypasses `adjustForToolPairs` to honor user-explicit `/compact`
|
|
1336
|
+
* commands — the kept region's first user message can otherwise contain
|
|
1337
|
+
* an orphan `tool_result`, which the LLM API rejects.
|
|
1338
|
+
*
|
|
1339
|
+
* A user message that contains only orphan `tool_result` blocks is
|
|
1340
|
+
* dropped entirely; partial messages keep the surviving content blocks.
|
|
1341
|
+
*/
|
|
1342
|
+
function stripOrphanToolResults(messages: Message[]): Message[] {
|
|
1343
|
+
const knownToolUseIds = new Set<string>();
|
|
1344
|
+
for (const msg of messages) {
|
|
1345
|
+
if (msg.role !== "assistant") continue;
|
|
1346
|
+
for (const block of msg.content) {
|
|
1347
|
+
if (
|
|
1348
|
+
(block.type === "tool_use" || block.type === "server_tool_use") &&
|
|
1349
|
+
"id" in block
|
|
1350
|
+
) {
|
|
1351
|
+
knownToolUseIds.add((block as { id: string }).id);
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
return messages.flatMap((msg) => {
|
|
1357
|
+
if (msg.role !== "user") return [msg];
|
|
1358
|
+
let stripped = false;
|
|
1359
|
+
const filtered = msg.content.filter((block) => {
|
|
1360
|
+
if (
|
|
1361
|
+
(block.type === "tool_result" ||
|
|
1362
|
+
block.type === "web_search_tool_result") &&
|
|
1363
|
+
"tool_use_id" in block
|
|
1364
|
+
) {
|
|
1365
|
+
const id = (block as { tool_use_id: string }).tool_use_id;
|
|
1366
|
+
if (!knownToolUseIds.has(id)) {
|
|
1367
|
+
stripped = true;
|
|
1368
|
+
return false;
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
return true;
|
|
1372
|
+
});
|
|
1373
|
+
if (!stripped) return [msg];
|
|
1374
|
+
if (filtered.length === 0) return [];
|
|
1375
|
+
return [{ ...msg, content: filtered }];
|
|
1376
|
+
});
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1254
1379
|
export function getSummaryFromContextMessage(
|
|
1255
1380
|
message: Message | undefined,
|
|
1256
1381
|
): string | null {
|
|
@@ -1286,6 +1411,67 @@ export function createContextSummaryMessage(summary: string): Message {
|
|
|
1286
1411
|
return message;
|
|
1287
1412
|
}
|
|
1288
1413
|
|
|
1414
|
+
/**
|
|
1415
|
+
* Walk `messages` backward and return the concatenated text content of the
|
|
1416
|
+
* most recent assistant message that contains at least one non-empty text
|
|
1417
|
+
* block. tool_use / tool_result / image / unknown blocks are skipped. The
|
|
1418
|
+
* result is trimmed and (if longer than `maxChars`) clamped from the START
|
|
1419
|
+
* so the END — where "next step" / "now I'll …" narration tends to land —
|
|
1420
|
+
* is preserved.
|
|
1421
|
+
*
|
|
1422
|
+
* Returns `null` when no eligible assistant text is found (e.g. compactable
|
|
1423
|
+
* region was all user/tool messages, or all assistant messages were
|
|
1424
|
+
* tool_use-only). The caller treats `null` as "no anchor to splice".
|
|
1425
|
+
*
|
|
1426
|
+
* Used by `_maybeCompact` to force-keep the last assistant text from the
|
|
1427
|
+
* compactable region into the post-compaction summary message, so the
|
|
1428
|
+
* model's most recent self-narration survives summarization regardless of
|
|
1429
|
+
* whether the LLM summarizer chose to surface it.
|
|
1430
|
+
*/
|
|
1431
|
+
export function extractTailAssistantText(
|
|
1432
|
+
messages: Message[],
|
|
1433
|
+
maxChars: number = TAIL_ANCHOR_MAX_CHARS,
|
|
1434
|
+
): string | null {
|
|
1435
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1436
|
+
const message = messages[i];
|
|
1437
|
+
if (message?.role !== "assistant") continue;
|
|
1438
|
+
const text = extractText(message.content).trim();
|
|
1439
|
+
if (text.length === 0) continue;
|
|
1440
|
+
if (text.length <= maxChars) return text;
|
|
1441
|
+
// Keep the END — most recent narration wins.
|
|
1442
|
+
const truncated = safeStringSlice(
|
|
1443
|
+
text,
|
|
1444
|
+
text.length - maxChars,
|
|
1445
|
+
text.length,
|
|
1446
|
+
);
|
|
1447
|
+
return `[...truncated] ${truncated}`;
|
|
1448
|
+
}
|
|
1449
|
+
return null;
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
/**
|
|
1453
|
+
* Splice a verbatim tail-anchor block onto the end of the LLM-produced
|
|
1454
|
+
* summary text. The tag-wrapped block is structurally distinct from any
|
|
1455
|
+
* `## ` section the LLM might generate, so it survives section-boundary
|
|
1456
|
+
* clamping in `clampSummaryAtSectionBoundary` (which only runs on the LLM
|
|
1457
|
+
* summary itself, before this splice).
|
|
1458
|
+
*
|
|
1459
|
+
* Idempotent: if the summary already ends with a `<verbatim_tail>…` block
|
|
1460
|
+
* (e.g. from a prior compaction whose summary was carried forward as
|
|
1461
|
+
* `existingSummary`), it is replaced rather than stacked, so successive
|
|
1462
|
+
* compactions don't accumulate stale tails.
|
|
1463
|
+
*/
|
|
1464
|
+
export function appendTailAnchorToSummary(
|
|
1465
|
+
summary: string,
|
|
1466
|
+
tailText: string,
|
|
1467
|
+
): string {
|
|
1468
|
+
const trimmed = summary.trimEnd();
|
|
1469
|
+
const existingOpen = trimmed.lastIndexOf(TAIL_ANCHOR_OPEN_TAG);
|
|
1470
|
+
const base =
|
|
1471
|
+
existingOpen >= 0 ? trimmed.slice(0, existingOpen).trimEnd() : trimmed;
|
|
1472
|
+
return `${base}\n\n${TAIL_ANCHOR_OPEN_TAG}\n${tailText.trim()}\n${TAIL_ANCHOR_CLOSE_TAG}`;
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1289
1475
|
/**
|
|
1290
1476
|
* Build content blocks for the summary prompt. Returns a mix of text blocks
|
|
1291
1477
|
* (for the scaffolding, existing summary, and serialized non-image content)
|
|
@@ -91,6 +91,27 @@ mock.module("../../memory/auto-analysis-enqueue.js", () => ({
|
|
|
91
91
|
},
|
|
92
92
|
}));
|
|
93
93
|
|
|
94
|
+
let memoryRetroEnabled = false;
|
|
95
|
+
const memoryRetroCalls: Array<{
|
|
96
|
+
conversationId: string;
|
|
97
|
+
trigger: string;
|
|
98
|
+
}> = [];
|
|
99
|
+
|
|
100
|
+
mock.module("../../memory/memory-retrospective-enqueue.js", () => ({
|
|
101
|
+
enqueueMemoryRetrospectiveIfEnabled: (args: {
|
|
102
|
+
conversationId: string;
|
|
103
|
+
trigger: string;
|
|
104
|
+
}) => {
|
|
105
|
+
if (!memoryRetroEnabled) return;
|
|
106
|
+
memoryRetroCalls.push(args);
|
|
107
|
+
},
|
|
108
|
+
// Also export sibling functions other modules import from this file, so
|
|
109
|
+
// mocking it here doesn't break transitive imports loaded during the
|
|
110
|
+
// `disposeConversation` dynamic-import chain.
|
|
111
|
+
enqueueMemoryRetrospectiveOnCompaction: () => {},
|
|
112
|
+
isMemoryRetrospectiveConversation: (_id: string) => false,
|
|
113
|
+
}));
|
|
114
|
+
|
|
94
115
|
// Stub all side-effecting cleanup helpers that disposeConversation chains
|
|
95
116
|
// into after the enqueue block. We assert on enqueue behavior only.
|
|
96
117
|
mock.module("../../tools/browser/browser-screencast.js", () => ({
|
|
@@ -168,7 +189,9 @@ describe("disposeConversation — auto-analysis enqueue", () => {
|
|
|
168
189
|
beforeEach(() => {
|
|
169
190
|
memoryJobCalls.length = 0;
|
|
170
191
|
autoAnalyzeCalls.length = 0;
|
|
192
|
+
memoryRetroCalls.length = 0;
|
|
171
193
|
autoAnalyzeEnabled = true;
|
|
194
|
+
memoryRetroEnabled = false;
|
|
172
195
|
autoAnalysisConversations.clear();
|
|
173
196
|
v2Enabled = false;
|
|
174
197
|
});
|
|
@@ -346,3 +369,59 @@ describe("disposeConversation — auto-analysis enqueue", () => {
|
|
|
346
369
|
});
|
|
347
370
|
});
|
|
348
371
|
});
|
|
372
|
+
|
|
373
|
+
describe("disposeConversation — memory-retrospective lifecycle safety net", () => {
|
|
374
|
+
beforeEach(() => {
|
|
375
|
+
memoryJobCalls.length = 0;
|
|
376
|
+
autoAnalyzeCalls.length = 0;
|
|
377
|
+
memoryRetroCalls.length = 0;
|
|
378
|
+
autoAnalyzeEnabled = false;
|
|
379
|
+
memoryRetroEnabled = false;
|
|
380
|
+
autoAnalysisConversations.clear();
|
|
381
|
+
v2Enabled = false;
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
test("guardian conversation + flag on — enqueues memory-retrospective with trigger 'lifecycle'", () => {
|
|
385
|
+
memoryRetroEnabled = true;
|
|
386
|
+
const ctx = makeDisposeContext({
|
|
387
|
+
conversationId: "conv-retro",
|
|
388
|
+
trustClass: "guardian",
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
disposeConversation(ctx);
|
|
392
|
+
|
|
393
|
+
expect(memoryRetroCalls).toHaveLength(1);
|
|
394
|
+
expect(memoryRetroCalls[0]).toEqual({
|
|
395
|
+
conversationId: "conv-retro",
|
|
396
|
+
trigger: "lifecycle",
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
test("flag off — no memory-retrospective enqueue", () => {
|
|
401
|
+
memoryRetroEnabled = false;
|
|
402
|
+
const ctx = makeDisposeContext({
|
|
403
|
+
conversationId: "conv-retro-off",
|
|
404
|
+
trustClass: "guardian",
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
disposeConversation(ctx);
|
|
408
|
+
|
|
409
|
+
expect(memoryRetroCalls).toHaveLength(0);
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
test("untrusted actor — no memory-retrospective enqueue even when flag is on", () => {
|
|
413
|
+
memoryRetroEnabled = true;
|
|
414
|
+
const ctx = makeDisposeContext({
|
|
415
|
+
conversationId: "conv-retro-untrusted",
|
|
416
|
+
trustClass: "unknown",
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
disposeConversation(ctx);
|
|
420
|
+
|
|
421
|
+
// The outer trust-class guard in disposeConversation gates ALL three
|
|
422
|
+
// enqueues (graph_extract, auto-analyze, memory-retrospective). When
|
|
423
|
+
// the actor is untrusted, none of them fire.
|
|
424
|
+
expect(memoryRetroCalls).toHaveLength(0);
|
|
425
|
+
expect(autoAnalyzeCalls).toHaveLength(0);
|
|
426
|
+
});
|
|
427
|
+
});
|
|
@@ -20,10 +20,11 @@
|
|
|
20
20
|
* hasNoClient flag.
|
|
21
21
|
*
|
|
22
22
|
* Cross-client exception: tools whose capabilities are in
|
|
23
|
-
* CROSS_CLIENT_EXPOSED_CAPABILITIES (host_bash, host_file)
|
|
24
|
-
* non-host-proxy interfaces (
|
|
25
|
-
* is connected via the event hub.
|
|
26
|
-
* is
|
|
23
|
+
* CROSS_CLIENT_EXPOSED_CAPABILITIES (host_bash, host_file, host_browser)
|
|
24
|
+
* are allowed for non-host-proxy interactive interfaces ("web", "ios")
|
|
25
|
+
* when at least one capable client is connected via the event hub.
|
|
26
|
+
* chrome-extension is excluded as a security boundary, regardless of
|
|
27
|
+
* whether the capability is technically supported elsewhere.
|
|
27
28
|
*/
|
|
28
29
|
|
|
29
30
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
@@ -358,6 +359,110 @@ describe("isToolActiveForContext — cross-client exposure for host_file_*", ()
|
|
|
358
359
|
});
|
|
359
360
|
});
|
|
360
361
|
|
|
362
|
+
describe("isToolActiveForContext — cross-client exposure for host_browser", () => {
|
|
363
|
+
// host_browser cross-client routing was shipped in PR #27489 (host-
|
|
364
|
+
// browser-via-macos-host-proxy); LLM-exposure for non-host-proxy
|
|
365
|
+
// transports is added by including "host_browser" in
|
|
366
|
+
// CROSS_CLIENT_EXPOSED_CAPABILITIES. Web and iOS turns can now drive a
|
|
367
|
+
// connected macOS or chrome-extension client via the event hub.
|
|
368
|
+
test("host_browser is exposed for web transport when a host_browser client is connected", () => {
|
|
369
|
+
mockClientCountByCapability.set("host_browser", 1);
|
|
370
|
+
expect(
|
|
371
|
+
isToolActiveForContext(
|
|
372
|
+
"host_browser",
|
|
373
|
+
makeCtx({ hasNoClient: false, transportInterface: "web" }),
|
|
374
|
+
),
|
|
375
|
+
).toBe(true);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
test("host_browser is exposed for ios transport when a host_browser client is connected", () => {
|
|
379
|
+
// INTERACTIVE_INTERFACES = {macos, ios, web}; ios goes through the same
|
|
380
|
+
// cross-client branch as web because supportsHostProxy("ios", *) is
|
|
381
|
+
// false. This pins the parity guarantee.
|
|
382
|
+
mockClientCountByCapability.set("host_browser", 1);
|
|
383
|
+
expect(
|
|
384
|
+
isToolActiveForContext(
|
|
385
|
+
"host_browser",
|
|
386
|
+
makeCtx({ hasNoClient: false, transportInterface: "ios" }),
|
|
387
|
+
),
|
|
388
|
+
).toBe(true);
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
test("host_browser is NOT exposed for web when no host_browser client is connected", () => {
|
|
392
|
+
mockClientCountByCapability.set("host_browser", 0);
|
|
393
|
+
expect(
|
|
394
|
+
isToolActiveForContext(
|
|
395
|
+
"host_browser",
|
|
396
|
+
makeCtx({ hasNoClient: false, transportInterface: "web" }),
|
|
397
|
+
),
|
|
398
|
+
).toBe(false);
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
test("host_browser is NOT exposed for ios when no host_browser client is connected", () => {
|
|
402
|
+
mockClientCountByCapability.set("host_browser", 0);
|
|
403
|
+
expect(
|
|
404
|
+
isToolActiveForContext(
|
|
405
|
+
"host_browser",
|
|
406
|
+
makeCtx({ hasNoClient: false, transportInterface: "ios" }),
|
|
407
|
+
),
|
|
408
|
+
).toBe(false);
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
test("host_browser is NOT exposed when hasNoClient is true (no approval UI)", () => {
|
|
412
|
+
// hasNoClient gate: cross-client exception must not bypass this.
|
|
413
|
+
mockClientCountByCapability.set("host_browser", 1);
|
|
414
|
+
expect(
|
|
415
|
+
isToolActiveForContext(
|
|
416
|
+
"host_browser",
|
|
417
|
+
makeCtx({ hasNoClient: true, transportInterface: "web" }),
|
|
418
|
+
),
|
|
419
|
+
).toBe(false);
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
test("host_browser for macos transport is unaffected by the cross-client exception", () => {
|
|
423
|
+
// macos natively supports host_browser via host proxy — the
|
|
424
|
+
// supportsHostProxy check passes, so the cross-client branch is never
|
|
425
|
+
// reached.
|
|
426
|
+
mockClientCountByCapability.set("host_browser", 0);
|
|
427
|
+
expect(
|
|
428
|
+
isToolActiveForContext(
|
|
429
|
+
"host_browser",
|
|
430
|
+
makeCtx({ hasNoClient: false, transportInterface: "macos" }),
|
|
431
|
+
),
|
|
432
|
+
).toBe(true);
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
test("host_browser for chrome-extension transport is unaffected by the cross-client exception", () => {
|
|
436
|
+
// chrome-extension natively supports host_browser via its own
|
|
437
|
+
// executor (supportsHostProxy("chrome-extension", "host_browser")
|
|
438
|
+
// returns true), so the cross-client branch is never reached. The
|
|
439
|
+
// hasNoClient gate is also bypassed for chrome-extension transports
|
|
440
|
+
// because the extension provides its own approval UI.
|
|
441
|
+
mockClientCountByCapability.set("host_browser", 0);
|
|
442
|
+
expect(
|
|
443
|
+
isToolActiveForContext(
|
|
444
|
+
"host_browser",
|
|
445
|
+
makeCtx({ hasNoClient: true, transportInterface: "chrome-extension" }),
|
|
446
|
+
),
|
|
447
|
+
).toBe(true);
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
test("listClientsByCapability is queried with host_browser, not host_bash or host_file (per-capability invariant)", () => {
|
|
451
|
+
// Defense against any future regression that hardcodes a different
|
|
452
|
+
// capability in the cross-client check. Only host_browser-capable
|
|
453
|
+
// clients should satisfy host_browser exposure.
|
|
454
|
+
mockClientCountByCapability.set("host_bash", 1);
|
|
455
|
+
mockClientCountByCapability.set("host_file", 1);
|
|
456
|
+
mockClientCountByCapability.set("host_browser", 0);
|
|
457
|
+
expect(
|
|
458
|
+
isToolActiveForContext(
|
|
459
|
+
"host_browser",
|
|
460
|
+
makeCtx({ hasNoClient: false, transportInterface: "web" }),
|
|
461
|
+
),
|
|
462
|
+
).toBe(false);
|
|
463
|
+
});
|
|
464
|
+
});
|
|
465
|
+
|
|
361
466
|
describe("HOST_TOOL_NAMES derivation", () => {
|
|
362
467
|
test("HOST_TOOL_NAMES is derived from HOST_TOOL_TO_CAPABILITY", () => {
|
|
363
468
|
// Sanity check: every tool in the names set has a capability mapping.
|
|
@@ -23,8 +23,9 @@ const loggerSpy = {
|
|
|
23
23
|
warn: mock(() => {}),
|
|
24
24
|
error: mock(() => {}),
|
|
25
25
|
};
|
|
26
|
+
const getLoggerSpy = mock((_name: string) => loggerSpy);
|
|
26
27
|
mock.module("../../util/logger.js", () => ({
|
|
27
|
-
getLogger:
|
|
28
|
+
getLogger: getLoggerSpy,
|
|
28
29
|
}));
|
|
29
30
|
|
|
30
31
|
mock.module("../../config/loader.js", () => ({
|
|
@@ -163,12 +164,13 @@ describe("createDaemonSkillHost", () => {
|
|
|
163
164
|
expect(host.speakers).toBeDefined();
|
|
164
165
|
});
|
|
165
166
|
|
|
166
|
-
test("logger.get
|
|
167
|
+
test("logger.get prefixes the scope with the skillId", () => {
|
|
167
168
|
const log = host.logger.get("test-scope");
|
|
168
169
|
log.debug("d", { k: "v" });
|
|
169
170
|
log.info("i");
|
|
170
171
|
log.warn("w");
|
|
171
172
|
log.error("e");
|
|
173
|
+
expect(getLoggerSpy).toHaveBeenCalledWith("meet-join:test-scope");
|
|
172
174
|
expect(loggerSpy.debug).toHaveBeenCalled();
|
|
173
175
|
expect(loggerSpy.info).toHaveBeenCalled();
|
|
174
176
|
expect(loggerSpy.warn).toHaveBeenCalled();
|
|
@@ -255,8 +257,12 @@ describe("createDaemonSkillHost", () => {
|
|
|
255
257
|
});
|
|
256
258
|
expect(handle).toBeDefined();
|
|
257
259
|
expect(registerSkillRouteSpy).toHaveBeenCalled();
|
|
258
|
-
|
|
259
|
-
|
|
260
|
+
const hook = async () => {};
|
|
261
|
+
host.registries.registerShutdownHook("test-hook", hook);
|
|
262
|
+
expect(registerShutdownHookSpy).toHaveBeenCalledWith(
|
|
263
|
+
"meet-join:test-hook",
|
|
264
|
+
hook,
|
|
265
|
+
);
|
|
260
266
|
});
|
|
261
267
|
|
|
262
268
|
test("speakers.createTracker yields a concrete tracker instance", () => {
|