@vellumai/assistant 0.7.3 → 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/ARCHITECTURE.md +29 -28
- package/Dockerfile +6 -4
- package/README.md +2 -2
- package/__tests__/permissions/gateway-threshold-reader.test.ts +236 -9
- package/bun.lock +3 -0
- 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 +3 -1
- package/node_modules/@vellumai/ipc-server-utils/bun.lock +24 -0
- package/node_modules/@vellumai/ipc-server-utils/package.json +18 -0
- package/node_modules/@vellumai/ipc-server-utils/src/index.ts +6 -0
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +430 -0
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +221 -0
- package/node_modules/@vellumai/ipc-server-utils/tsconfig.json +20 -0
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
- package/openapi.yaml +4126 -959
- package/package.json +5 -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__/annotate-risk-options.test.ts +291 -0
- package/src/__tests__/anthropic-provider.test.ts +92 -2
- package/src/__tests__/app-control-flow.test.ts +7 -0
- package/src/__tests__/approval-cascade.test.ts +8 -16
- package/src/__tests__/approval-routes-http.test.ts +6 -0
- package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
- package/src/__tests__/auto-analysis-end-to-end.test.ts +12 -25
- 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-constants.test.ts +10 -1
- package/src/__tests__/call-controller.test.ts +127 -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 +88 -30
- 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 +345 -8
- 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-source.test.ts +3 -26
- 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-abort-tool-results.test.ts +1 -6
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -1
- package/src/__tests__/conversation-agent-loop.test.ts +3 -3
- package/src/__tests__/conversation-confirmation-signals.test.ts +5 -13
- 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 +2 -1
- 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 +22 -7
- package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -6
- package/src/__tests__/conversation-runtime-assembly.test.ts +19 -10
- package/src/__tests__/conversation-slash-commands.test.ts +194 -2
- package/src/__tests__/conversation-slash-unknown.test.ts +1 -6
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +170 -9
- package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +73 -1
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +59 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +1 -7
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -7
- 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 +25 -22
- 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 +10 -34
- 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__/injector-chain.test.ts +24 -16
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +10 -7
- 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 +169 -67
- 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-decision-fallback.test.ts +91 -0
- package/src/__tests__/notification-decision-strategy.test.ts +22 -0
- package/src/__tests__/notification-platform-adapter.test.ts +229 -0
- package/src/__tests__/oauth-cli.test.ts +38 -1888
- 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 +164 -2
- 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-prompt-log-hygiene.test.ts +7 -5
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +7 -5
- package/src/__tests__/secret-response-routing.test.ts +7 -5
- package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
- package/src/__tests__/server-history-render.test.ts +82 -0
- 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-include-graph.test.ts +31 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
- package/src/__tests__/skill-load-tool.test.ts +42 -16
- package/src/__tests__/skills.test.ts +39 -0
- 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__/tool-execution-pipeline.benchmark.test.ts +0 -42
- package/src/__tests__/tool-executor.test.ts +155 -0
- 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__/voice-session-bridge.test.ts +3 -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 +153 -0
- package/src/__tests__/workspace-migration-071-remove-safe-storage-release-note.test.ts +206 -0
- 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-safe-storage-limits-release.test.ts +15 -27
- 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/agent/loop.ts +11 -0
- package/src/approvals/guardian-decision-primitive.ts +0 -13
- package/src/approvals/guardian-request-resolvers.ts +19 -102
- package/src/calls/call-constants.ts +5 -8
- package/src/calls/call-controller.ts +130 -67
- package/src/calls/relay-server.ts +42 -1
- package/src/calls/relay-setup-router.ts +36 -0
- package/src/calls/types.ts +1 -0
- package/src/calls/voice-session-bridge.ts +24 -5
- 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 +163 -517
- package/src/cli/commands/notifications.ts +33 -7
- package/src/cli/commands/oauth/apps.ts +292 -261
- package/src/cli/commands/oauth/connect.ts +182 -345
- 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-builder/SKILL.md +1 -3
- 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 +17 -17
- package/src/config/llm-resolver.ts +16 -1
- package/src/config/loader.ts +148 -33
- 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 +33 -2
- 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 +111 -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 +56 -0
- package/src/daemon/conversation-agent-loop.ts +140 -107
- package/src/daemon/conversation-error.ts +21 -0
- package/src/daemon/conversation-lifecycle.ts +68 -13
- 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 +92 -26
- package/src/daemon/conversation-tool-setup.ts +33 -19
- package/src/daemon/conversation.ts +49 -10
- 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/shared.ts +26 -0
- 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 +97 -36
- package/src/daemon/host-cu-proxy.ts +1 -1
- package/src/daemon/host-file-proxy.ts +1 -1
- package/src/daemon/host-proxy-base.ts +13 -1
- package/src/daemon/host-proxy-preactivation.ts +25 -1
- package/src/daemon/host-transfer-proxy.ts +2 -2
- package/src/daemon/identity-helpers.ts +19 -0
- package/src/daemon/lifecycle.ts +128 -114
- package/src/daemon/meet-host-supervisor.ts +15 -15
- package/src/daemon/memory-v2-startup.ts +62 -14
- 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 +28 -2
- 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/documents/document-store.ts +35 -1
- package/src/export/transcript-formatter.ts +61 -2
- package/src/filing/filing-service.ts +42 -56
- 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 +149 -128
- 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 +148 -42
- 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/ipc/skill-server.ts +99 -42
- 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__/jobs-worker-v2-schedule.test.ts +10 -57
- 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 +40 -31
- package/src/memory/context-search/sources/memory.ts +9 -2
- 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__/conversation-graph-memory-v2-routing.test.ts +104 -61
- package/src/memory/graph/__tests__/handle-remember-v2.test.ts +11 -26
- package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
- package/src/memory/graph/conversation-graph-memory.ts +108 -14
- package/src/memory/graph/extraction.ts +4 -0
- package/src/memory/graph/graph-memory-state-store.ts +16 -3
- package/src/memory/graph/graph-search.test.ts +6 -5
- package/src/memory/graph/graph-search.ts +3 -4
- package/src/memory/graph/retriever.test.ts +12 -7
- package/src/memory/graph/retriever.ts +4 -5
- package/src/memory/graph/tool-handlers.ts +20 -11
- package/src/memory/graph/tools.ts +48 -9
- package/src/memory/indexer.ts +18 -2
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +120 -6
- package/src/memory/jobs/embed-concept-page.ts +261 -89
- package/src/memory/jobs-store.ts +51 -1
- package/src/memory/jobs-worker.ts +60 -7
- 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/pkb/pkb-search.test.ts +6 -5
- package/src/memory/pkb/pkb-search.ts +4 -5
- package/src/memory/published-pages-store.ts +16 -0
- package/src/memory/qdrant-client.ts +3 -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 +5 -9
- 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 +46 -9
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
- package/src/memory/v2/__tests__/consolidation-job.test.ts +140 -163
- 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 +768 -33
- 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 +382 -9
- 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 +163 -8
- package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
- package/src/memory/v2/__tests__/static-context.test.ts +8 -35
- package/src/memory/v2/__tests__/sweep-job.test.ts +114 -33
- 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 +92 -86
- package/src/memory/v2/frontmatter-sweep.ts +91 -0
- package/src/memory/v2/injection.ts +466 -115
- package/src/memory/v2/migration.ts +117 -20
- package/src/memory/v2/page-index.ts +191 -0
- package/src/memory/v2/page-store.ts +42 -0
- package/src/memory/v2/prompts/consolidation.ts +14 -7
- package/src/memory/v2/prompts/router.ts +192 -0
- package/src/memory/v2/qdrant.ts +307 -133
- package/src/memory/v2/reranker.ts +14 -7
- package/src/memory/v2/router.ts +322 -0
- package/src/memory/v2/sim.ts +88 -34
- package/src/memory/v2/skill-store.ts +118 -29
- package/src/memory/v2/static-context.ts +20 -17
- package/src/memory/v2/sweep-job.ts +127 -102
- package/src/memory/v2/types.ts +16 -5
- 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 +61 -12
- package/src/notifications/decision-engine.ts +46 -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/gateway-threshold-reader.ts +116 -8
- package/src/permissions/ipc-risk-types.ts +2 -0
- package/src/permissions/prompter.ts +86 -96
- package/src/permissions/secret-prompter.ts +31 -31
- 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 +20 -5
- 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 +63 -8
- package/src/proactive-artifact/job.ts +20 -2
- package/src/proactive-artifact/message-copy.ts +18 -1
- 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/templates/SOUL.md +13 -28
- 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 +304 -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/channel-approvals.ts +3 -2
- package/src/runtime/guardian-reply-router.ts +0 -10
- 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/pending-interactions.ts +19 -15
- 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 +147 -0
- 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 +7 -21
- 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/consolidation-routes.ts +8 -9
- 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 +373 -82
- 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-bash-routes.ts +2 -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/filing-routes.ts +2 -3
- 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 -7
- 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-item-routes.test.ts +3 -9
- package/src/runtime/routes/memory-item-routes.ts +5 -6
- package/src/runtime/routes/memory-v2-routes.ts +105 -404
- 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/skills/include-graph.ts +35 -13
- 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/document/document-tool.ts +20 -0
- package/src/tools/executor.ts +18 -2
- package/src/tools/memory/register.test.ts +10 -8
- 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 +28 -5
- package/src/tools/skills/load.ts +24 -20
- package/src/tools/subagent/spawn.ts +3 -3
- package/src/tools/terminal/shell.ts +44 -0
- package/src/tools/tool-name-aliases.ts +19 -0
- package/src/tools/types.ts +19 -1
- 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/067-release-notes-safe-storage-limits.ts +4 -62
- package/src/workspace/migrations/069-seed-onboarding-threads.ts +34 -0
- package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +31 -0
- package/src/workspace/migrations/071-remove-safe-storage-release-note.ts +111 -0
- 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 +28 -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 -492
- 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 -1201
- 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 -477
- package/src/memory/graph/compaction.ts +0 -299
- /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
|
@@ -61,14 +61,10 @@ type IncludeValidationResult =
|
|
|
61
61
|
| IncludeValidationError
|
|
62
62
|
| IncludeValidationCycleError;
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
* Validate the include graph starting from the given root skill ID.
|
|
66
|
-
* Uses three-state DFS (unseen/visiting/done) to detect both missing children
|
|
67
|
-
* and cycles. Returns the first error encountered in DFS order.
|
|
68
|
-
*/
|
|
69
|
-
export function validateIncludes(
|
|
64
|
+
function validateIncludeGraph(
|
|
70
65
|
rootId: string,
|
|
71
66
|
catalogIndex: Map<string, SkillSummary>,
|
|
67
|
+
options: { failOnMissing: boolean },
|
|
72
68
|
): IncludeValidationResult {
|
|
73
69
|
const visited: string[] = [];
|
|
74
70
|
type State = "unseen" | "visiting" | "done";
|
|
@@ -97,13 +93,16 @@ export function validateIncludes(
|
|
|
97
93
|
if (skill?.includes) {
|
|
98
94
|
for (const childId of skill.includes) {
|
|
99
95
|
if (!catalogIndex.has(childId)) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
96
|
+
if (options.failOnMissing) {
|
|
97
|
+
return {
|
|
98
|
+
ok: false,
|
|
99
|
+
error: "missing",
|
|
100
|
+
missingChildId: childId,
|
|
101
|
+
parentId: id,
|
|
102
|
+
path: [...ancestry],
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
continue;
|
|
107
106
|
}
|
|
108
107
|
const childError = dfs(childId);
|
|
109
108
|
if (childError) return childError;
|
|
@@ -120,6 +119,29 @@ export function validateIncludes(
|
|
|
120
119
|
return { ok: true, visited };
|
|
121
120
|
}
|
|
122
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Validate the include graph starting from the given root skill ID.
|
|
124
|
+
* Uses three-state DFS (unseen/visiting/done) to detect both missing children
|
|
125
|
+
* and cycles. Returns the first error encountered in DFS order.
|
|
126
|
+
*/
|
|
127
|
+
export function validateIncludes(
|
|
128
|
+
rootId: string,
|
|
129
|
+
catalogIndex: Map<string, SkillSummary>,
|
|
130
|
+
): IncludeValidationResult {
|
|
131
|
+
return validateIncludeGraph(rootId, catalogIndex, { failOnMissing: true });
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Validate only cycle safety for a graph that may intentionally have missing
|
|
136
|
+
* advisory includes. Missing child IDs are skipped during traversal.
|
|
137
|
+
*/
|
|
138
|
+
export function validateIncludeCycles(
|
|
139
|
+
rootId: string,
|
|
140
|
+
catalogIndex: Map<string, SkillSummary>,
|
|
141
|
+
): IncludeValidationResult {
|
|
142
|
+
return validateIncludeGraph(rootId, catalogIndex, { failOnMissing: false });
|
|
143
|
+
}
|
|
144
|
+
|
|
123
145
|
/**
|
|
124
146
|
* Recursively traverse the include graph starting from the given root skill ID.
|
|
125
147
|
* Returns all visited skill IDs in DFS pre-order.
|
package/src/subagent/manager.ts
CHANGED
|
@@ -10,14 +10,15 @@
|
|
|
10
10
|
|
|
11
11
|
import { v4 as uuid } from "uuid";
|
|
12
12
|
|
|
13
|
+
import { resolveCallSiteConfig } from "../config/llm-resolver.js";
|
|
13
14
|
import { getConfig } from "../config/loader.js";
|
|
14
15
|
import { Conversation } from "../daemon/conversation.js";
|
|
15
16
|
import { findConversation } from "../daemon/conversation-store.js";
|
|
16
17
|
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
17
18
|
import { bootstrapConversation } from "../memory/conversation-bootstrap.js";
|
|
18
|
-
import {
|
|
19
|
+
import { wrapWithCallSiteRouting } from "../providers/call-site-routing.js";
|
|
20
|
+
import { resolveDefaultProvider } from "../providers/connection-resolution.js";
|
|
19
21
|
import { RateLimitProvider } from "../providers/ratelimit.js";
|
|
20
|
-
import { getProvider } from "../providers/registry.js";
|
|
21
22
|
import { createAbortReason } from "../util/abort-reasons.js";
|
|
22
23
|
import { getLogger } from "../util/logger.js";
|
|
23
24
|
import { getSandboxWorkingDir } from "../util/platform.js";
|
|
@@ -181,19 +182,23 @@ export class SubagentManager {
|
|
|
181
182
|
|
|
182
183
|
// ── Build conversation dependencies ─────────────────────────────
|
|
183
184
|
const appConfig = getConfig();
|
|
184
|
-
|
|
185
|
+
// Connection-aware default-provider resolution. Throws
|
|
186
|
+
// `ConnectionResolutionError` if `llm.default.provider_connection` is
|
|
187
|
+
// unset or the connection row is missing/mismatched (config bugs).
|
|
188
|
+
// Returns null on soft credential failures (vault miss, transient
|
|
189
|
+
// auth) — handled below as "no provider available". Per-call
|
|
190
|
+
// `callSite` routing is layered next.
|
|
191
|
+
const baseProvider = await resolveDefaultProvider(appConfig);
|
|
192
|
+
if (!baseProvider) {
|
|
193
|
+
throw new Error(
|
|
194
|
+
`Subagent: default provider '${resolveCallSiteConfig("mainAgent", appConfig.llm).provider}' is not registered`,
|
|
195
|
+
);
|
|
196
|
+
}
|
|
185
197
|
// Per-call `options.config.callSite` (e.g. `subagentSpawn`) can resolve
|
|
186
|
-
// to a
|
|
187
|
-
//
|
|
188
|
-
//
|
|
189
|
-
|
|
190
|
-
provider = new CallSiteRoutingProvider(provider, (name) => {
|
|
191
|
-
try {
|
|
192
|
-
return getProvider(name);
|
|
193
|
-
} catch {
|
|
194
|
-
return undefined;
|
|
195
|
-
}
|
|
196
|
-
});
|
|
198
|
+
// to a profile that differs from `llm.default`. The shared wrapper
|
|
199
|
+
// threads `appConfig` through so per-call alternate-profile routing is
|
|
200
|
+
// also connection-aware (matches the canonical dispatch path).
|
|
201
|
+
let provider = wrapWithCallSiteRouting(baseProvider, appConfig);
|
|
197
202
|
const { rateLimit } = appConfig;
|
|
198
203
|
if (rateLimit.maxRequestsPerMinute > 0) {
|
|
199
204
|
provider = new RateLimitProvider(
|
|
@@ -225,7 +230,7 @@ export class SubagentManager {
|
|
|
225
230
|
config.systemPromptOverride ??
|
|
226
231
|
buildSubagentSystemPrompt({ ...config, id: subagentId }, role);
|
|
227
232
|
}
|
|
228
|
-
const maxTokens = appConfig.llm.
|
|
233
|
+
const maxTokens = resolveCallSiteConfig("subagentSpawn", appConfig.llm).maxTokens;
|
|
229
234
|
const workingDir = getSandboxWorkingDir();
|
|
230
235
|
|
|
231
236
|
// ── Initialise state ────────────────────────────────────────────
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the target_client_id sticky-mode override in
|
|
3
|
+
* acquireCdpClientWithMode (browser-execution.ts).
|
|
4
|
+
*
|
|
5
|
+
* Fix 1: when target_client_id is provided, the sticky backend kind
|
|
6
|
+
* remembered from prior turns in the conversation must NOT be applied.
|
|
7
|
+
* The factory must receive mode:"extension" so the request reaches the
|
|
8
|
+
* host-browser proxy regardless of any prior local/cdp-inspect preference.
|
|
9
|
+
*/
|
|
10
|
+
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
11
|
+
|
|
12
|
+
import type { ToolContext } from "../../types.js";
|
|
13
|
+
import type { BrowserMode, CdpClientKind } from "../cdp-client/types.js";
|
|
14
|
+
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Captured call state
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
interface CdpClientCallOpts {
|
|
20
|
+
mode?: BrowserMode;
|
|
21
|
+
targetClientId?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const getCdpClientCalls: CdpClientCallOpts[] = [];
|
|
25
|
+
|
|
26
|
+
function makeFakeScopedClient(kind: CdpClientKind, conversationId: string) {
|
|
27
|
+
return {
|
|
28
|
+
kind,
|
|
29
|
+
conversationId,
|
|
30
|
+
send: mock(async () => ({})),
|
|
31
|
+
dispose: mock(() => {}),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const getCdpClientMock = mock(
|
|
36
|
+
(ctx: ToolContext, opts?: CdpClientCallOpts) => {
|
|
37
|
+
getCdpClientCalls.push({
|
|
38
|
+
mode: opts?.mode,
|
|
39
|
+
targetClientId: opts?.targetClientId,
|
|
40
|
+
});
|
|
41
|
+
return makeFakeScopedClient("extension", ctx.conversationId);
|
|
42
|
+
},
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// Mutable sticky-kind control
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
|
|
49
|
+
let stickyKind: CdpClientKind | null = null;
|
|
50
|
+
|
|
51
|
+
const setPreferredBackendKindMock = mock(
|
|
52
|
+
(_conversationId: string, _kind: CdpClientKind) => {},
|
|
53
|
+
);
|
|
54
|
+
const clearPreferredBackendKindMock = mock((_conversationId: string) => {});
|
|
55
|
+
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
// Module mocks (must be declared before dynamic import)
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
|
|
60
|
+
mock.module("../cdp-client/factory.js", () => ({
|
|
61
|
+
getCdpClient: getCdpClientMock,
|
|
62
|
+
buildCandidateList: mock(() => []),
|
|
63
|
+
isDesktopAutoCooldownActive: () => false,
|
|
64
|
+
}));
|
|
65
|
+
|
|
66
|
+
mock.module("../browser-manager.js", () => ({
|
|
67
|
+
browserManager: {
|
|
68
|
+
getPreferredBackendKind: (_conversationId: string) => stickyKind,
|
|
69
|
+
setPreferredBackendKind: setPreferredBackendKindMock,
|
|
70
|
+
clearPreferredBackendKind: clearPreferredBackendKindMock,
|
|
71
|
+
storeSnapshotBackendNodeMap: () => {},
|
|
72
|
+
clearSnapshotBackendNodeMap: () => {},
|
|
73
|
+
resolveSnapshotBackendNodeId: () => undefined,
|
|
74
|
+
isInteractive: () => false,
|
|
75
|
+
supportsRouteInterception: false,
|
|
76
|
+
},
|
|
77
|
+
}));
|
|
78
|
+
|
|
79
|
+
mock.module("../../../config/loader.js", () => ({
|
|
80
|
+
getConfig: () => ({
|
|
81
|
+
hostBrowser: {
|
|
82
|
+
cdpInspect: {
|
|
83
|
+
enabled: false,
|
|
84
|
+
host: "localhost",
|
|
85
|
+
port: 9222,
|
|
86
|
+
probeTimeoutMs: 500,
|
|
87
|
+
desktopAuto: { enabled: false, cooldownMs: 30_000 },
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
}),
|
|
91
|
+
}));
|
|
92
|
+
|
|
93
|
+
mock.module("../../../daemon/host-browser-proxy.js", () => ({
|
|
94
|
+
HostBrowserProxy: {
|
|
95
|
+
get instance() {
|
|
96
|
+
return {
|
|
97
|
+
isAvailable: () => false,
|
|
98
|
+
hasExtensionClient: () => false,
|
|
99
|
+
request: () => Promise.reject(new Error("no extension")),
|
|
100
|
+
};
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
}));
|
|
104
|
+
|
|
105
|
+
mock.module("../runtime-check.js", () => ({
|
|
106
|
+
checkBrowserRuntime: async () => ({
|
|
107
|
+
playwrightAvailable: true,
|
|
108
|
+
chromiumInstalled: true,
|
|
109
|
+
chromiumPath: "/tmp/chromium",
|
|
110
|
+
error: null,
|
|
111
|
+
}),
|
|
112
|
+
}));
|
|
113
|
+
|
|
114
|
+
mock.module("../../../util/logger.js", () => ({
|
|
115
|
+
getLogger: () => ({
|
|
116
|
+
debug: () => {},
|
|
117
|
+
warn: () => {},
|
|
118
|
+
info: () => {},
|
|
119
|
+
error: () => {},
|
|
120
|
+
}),
|
|
121
|
+
}));
|
|
122
|
+
|
|
123
|
+
// Import under test after all mock.module calls.
|
|
124
|
+
const { executeBrowserAttach } = await import("../browser-execution.js");
|
|
125
|
+
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
// Helpers
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
|
|
130
|
+
function makeContext(conversationId: string): ToolContext {
|
|
131
|
+
return {
|
|
132
|
+
conversationId,
|
|
133
|
+
workingDir: "/tmp",
|
|
134
|
+
trustClass: "guardian",
|
|
135
|
+
signal: new AbortController().signal,
|
|
136
|
+
} as unknown as ToolContext;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ---------------------------------------------------------------------------
|
|
140
|
+
// Tests
|
|
141
|
+
// ---------------------------------------------------------------------------
|
|
142
|
+
|
|
143
|
+
describe("acquireCdpClientWithMode: target_client_id overrides sticky backend mode", () => {
|
|
144
|
+
beforeEach(() => {
|
|
145
|
+
getCdpClientCalls.length = 0;
|
|
146
|
+
getCdpClientMock.mockClear();
|
|
147
|
+
setPreferredBackendKindMock.mockClear();
|
|
148
|
+
clearPreferredBackendKindMock.mockClear();
|
|
149
|
+
stickyKind = null;
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test("sticky local + target_client_id → getCdpClient receives mode:extension, not local", async () => {
|
|
153
|
+
// Simulate a prior turn that pinned the conversation to the local backend.
|
|
154
|
+
stickyKind = "local";
|
|
155
|
+
|
|
156
|
+
await executeBrowserAttach(
|
|
157
|
+
{ target_client_id: "host-client-abc" },
|
|
158
|
+
makeContext("sticky-local-override"),
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
expect(getCdpClientMock).toHaveBeenCalledTimes(1);
|
|
162
|
+
// Fix 1: sticky "local" must be bypassed when target_client_id is present.
|
|
163
|
+
expect(getCdpClientCalls[0].mode).toBe("extension");
|
|
164
|
+
expect(getCdpClientCalls[0].targetClientId).toBe("host-client-abc");
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test("sticky cdp-inspect + target_client_id → getCdpClient receives mode:extension, not cdp-inspect", async () => {
|
|
168
|
+
stickyKind = "cdp-inspect";
|
|
169
|
+
|
|
170
|
+
await executeBrowserAttach(
|
|
171
|
+
{ target_client_id: "host-client-xyz" },
|
|
172
|
+
makeContext("sticky-inspect-override"),
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
expect(getCdpClientMock).toHaveBeenCalledTimes(1);
|
|
176
|
+
expect(getCdpClientCalls[0].mode).toBe("extension");
|
|
177
|
+
expect(getCdpClientCalls[0].targetClientId).toBe("host-client-xyz");
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test("sticky local + no target_client_id → getCdpClient receives mode:local (sticky honored)", async () => {
|
|
181
|
+
// Without target_client_id, the sticky preference must still apply.
|
|
182
|
+
stickyKind = "local";
|
|
183
|
+
|
|
184
|
+
await executeBrowserAttach(
|
|
185
|
+
{}, // no target_client_id
|
|
186
|
+
makeContext("sticky-honored"),
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
expect(getCdpClientMock).toHaveBeenCalledTimes(1);
|
|
190
|
+
expect(getCdpClientCalls[0].mode).toBe("local");
|
|
191
|
+
expect(getCdpClientCalls[0].targetClientId).toBeUndefined();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test("no sticky + target_client_id → getCdpClient receives mode:extension", async () => {
|
|
195
|
+
stickyKind = null; // No prior sticky preference
|
|
196
|
+
|
|
197
|
+
await executeBrowserAttach(
|
|
198
|
+
{ target_client_id: "host-client-fresh" },
|
|
199
|
+
makeContext("no-sticky-targeted"),
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
expect(getCdpClientMock).toHaveBeenCalledTimes(1);
|
|
203
|
+
expect(getCdpClientCalls[0].mode).toBe("extension");
|
|
204
|
+
expect(getCdpClientCalls[0].targetClientId).toBe("host-client-fresh");
|
|
205
|
+
});
|
|
206
|
+
});
|
|
@@ -378,16 +378,25 @@ function acquireCdpClientWithMode(
|
|
|
378
378
|
}
|
|
379
379
|
const browserMode = modeResult.mode;
|
|
380
380
|
|
|
381
|
+
const targetClientId =
|
|
382
|
+
typeof input.target_client_id === "string" && input.target_client_id !== ""
|
|
383
|
+
? input.target_client_id
|
|
384
|
+
: undefined;
|
|
385
|
+
|
|
381
386
|
const rememberedKind = browserManager.getPreferredBackendKind(
|
|
382
387
|
context.conversationId,
|
|
383
388
|
);
|
|
389
|
+
// target_client_id requires the extension proxy path — bypass any sticky
|
|
390
|
+
// backend remembered from prior turns so the explicit target always wins.
|
|
384
391
|
const effectiveMode: BrowserMode =
|
|
385
|
-
|
|
392
|
+
targetClientId != null
|
|
393
|
+
? "extension"
|
|
394
|
+
: browserMode === "auto" && rememberedKind !== null
|
|
386
395
|
? rememberedKind
|
|
387
396
|
: browserMode;
|
|
388
397
|
|
|
389
398
|
try {
|
|
390
|
-
const raw = getCdpClient(context, { mode: effectiveMode });
|
|
399
|
+
const raw = getCdpClient(context, { mode: effectiveMode, targetClientId });
|
|
391
400
|
const cdp = wrapWithKindMemo(raw, context.conversationId);
|
|
392
401
|
return { cdp, browserMode };
|
|
393
402
|
} catch (err) {
|
|
@@ -395,10 +404,12 @@ function acquireCdpClientWithMode(
|
|
|
395
404
|
// a remembered backend kind that has since become unavailable. Drop
|
|
396
405
|
// the stale memo and retry with fresh auto selection so a dead
|
|
397
406
|
// sticky preference doesn't surface as a hard failure.
|
|
398
|
-
|
|
407
|
+
// Do not apply this fallback when target_client_id is set — a targeting
|
|
408
|
+
// failure must surface as an error, not silently route elsewhere.
|
|
409
|
+
if (browserMode === "auto" && effectiveMode !== "auto" && targetClientId == null) {
|
|
399
410
|
browserManager.clearPreferredBackendKind(context.conversationId);
|
|
400
411
|
try {
|
|
401
|
-
const raw = getCdpClient(context, { mode: "auto" });
|
|
412
|
+
const raw = getCdpClient(context, { mode: "auto", targetClientId });
|
|
402
413
|
const cdp = wrapWithKindMemo(raw, context.conversationId);
|
|
403
414
|
return { cdp, browserMode };
|
|
404
415
|
} catch (retryErr) {
|
|
@@ -78,13 +78,26 @@ let desktopAutoConfig = { enabled: true, cooldownMs: 30_000 };
|
|
|
78
78
|
const logWarnCalls: Array<{ args: unknown[] }> = [];
|
|
79
79
|
const logDebugCalls: Array<{ args: unknown[] }> = [];
|
|
80
80
|
|
|
81
|
+
// Spread-real-module pattern: bun's `mock.module` is process-global, so a
|
|
82
|
+
// factory that returns ONLY `{ createExtensionCdpClient }` would clobber
|
|
83
|
+
// the `ExtensionCdpClient` class export for every later test file that
|
|
84
|
+
// imports from this module path (e.g. extension-cdp-client.test.ts). We
|
|
85
|
+
// snapshot the real exports first and override only the symbols this
|
|
86
|
+
// suite stubs out.
|
|
87
|
+
import * as realCdpInspectClient from "../cdp-inspect-client.js";
|
|
88
|
+
import * as realExtensionCdpClient from "../extension-cdp-client.js";
|
|
89
|
+
import * as realLocalCdpClient from "../local-cdp-client.js";
|
|
90
|
+
|
|
81
91
|
mock.module("../extension-cdp-client.js", () => ({
|
|
92
|
+
...realExtensionCdpClient,
|
|
82
93
|
createExtensionCdpClient: createExtensionCdpClientMock,
|
|
83
94
|
}));
|
|
84
95
|
mock.module("../local-cdp-client.js", () => ({
|
|
96
|
+
...realLocalCdpClient,
|
|
85
97
|
createLocalCdpClient: createLocalCdpClientMock,
|
|
86
98
|
}));
|
|
87
99
|
mock.module("../cdp-inspect-client.js", () => ({
|
|
100
|
+
...realCdpInspectClient,
|
|
88
101
|
createCdpInspectClient: createCdpInspectClientMock,
|
|
89
102
|
}));
|
|
90
103
|
mock.module("../../../../config/loader.js", () => ({
|
|
@@ -235,9 +248,15 @@ describe("getCdpClient", () => {
|
|
|
235
248
|
);
|
|
236
249
|
expect(result).toEqual({ ok: true, via: "extension" });
|
|
237
250
|
expect(createExtensionCdpClientMock).toHaveBeenCalledTimes(1);
|
|
251
|
+
// Call signature includes optional cdpSessionId, sourceActorPrincipalId,
|
|
252
|
+
// and targetClientId (all undefined here — no pinned session id, no actor
|
|
253
|
+
// binding, no explicit client target in this legacy ctx).
|
|
238
254
|
expect(createExtensionCdpClientMock).toHaveBeenCalledWith(
|
|
239
255
|
fakeProxy,
|
|
240
256
|
"test-convo",
|
|
257
|
+
undefined,
|
|
258
|
+
undefined,
|
|
259
|
+
undefined,
|
|
241
260
|
);
|
|
242
261
|
expect(createLocalCdpClientMock).not.toHaveBeenCalled();
|
|
243
262
|
expect(createCdpInspectClientMock).not.toHaveBeenCalled();
|
|
@@ -658,6 +677,105 @@ describe("getCdpClient", () => {
|
|
|
658
677
|
await client.send("Page.navigate");
|
|
659
678
|
expect(createCdpInspectClientMock).toHaveBeenCalledTimes(1);
|
|
660
679
|
});
|
|
680
|
+
|
|
681
|
+
test("threads sourceActorPrincipalId from ToolContext into createExtensionCdpClient", async () => {
|
|
682
|
+
// The proxy uses sourceActorPrincipalId to refuse cross-user dispatch
|
|
683
|
+
// when host_browser is exposed cross-client (web/iOS turn → connected
|
|
684
|
+
// extension/macOS bridge). The factory must thread the value from the
|
|
685
|
+
// ToolContext through to ExtensionCdpClient on every candidate-list path
|
|
686
|
+
// so the actor identity reaches the proxy at request time.
|
|
687
|
+
const fakeProxy = makeAvailableProxy();
|
|
688
|
+
mockSingletonProxy = fakeProxy;
|
|
689
|
+
const ctx = makeContext({
|
|
690
|
+
conversationId: "actor-bound",
|
|
691
|
+
sourceActorPrincipalId: "user-actor-1",
|
|
692
|
+
});
|
|
693
|
+
|
|
694
|
+
const client = getCdpClient(ctx);
|
|
695
|
+
await client.send("Page.navigate");
|
|
696
|
+
|
|
697
|
+
expect(createExtensionCdpClientMock).toHaveBeenCalledTimes(1);
|
|
698
|
+
expect(createExtensionCdpClientMock).toHaveBeenCalledWith(
|
|
699
|
+
fakeProxy,
|
|
700
|
+
"actor-bound",
|
|
701
|
+
undefined,
|
|
702
|
+
"user-actor-1",
|
|
703
|
+
undefined,
|
|
704
|
+
);
|
|
705
|
+
});
|
|
706
|
+
|
|
707
|
+
test("threads targetClientId from options into createExtensionCdpClient", async () => {
|
|
708
|
+
const fakeProxy = makeAvailableProxy();
|
|
709
|
+
mockSingletonProxy = fakeProxy;
|
|
710
|
+
const ctx = makeContext({
|
|
711
|
+
conversationId: "targeted-client",
|
|
712
|
+
sourceActorPrincipalId: "user-actor-1",
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
const client = getCdpClient(ctx, { targetClientId: "specific-ext-client" });
|
|
716
|
+
await client.send("Page.navigate");
|
|
717
|
+
|
|
718
|
+
expect(createExtensionCdpClientMock).toHaveBeenCalledTimes(1);
|
|
719
|
+
expect(createExtensionCdpClientMock).toHaveBeenCalledWith(
|
|
720
|
+
fakeProxy,
|
|
721
|
+
"targeted-client",
|
|
722
|
+
undefined,
|
|
723
|
+
"user-actor-1",
|
|
724
|
+
"specific-ext-client",
|
|
725
|
+
);
|
|
726
|
+
});
|
|
727
|
+
|
|
728
|
+
// ── auto mode + targetClientId: no fallback (Fix 2) ─────────────────
|
|
729
|
+
|
|
730
|
+
test("auto mode + targetClientId + no extension → throws targeting error, does not fall through to local", () => {
|
|
731
|
+
// No extension connected — without targetClientId, local would be the
|
|
732
|
+
// fallback. With targetClientId, the factory must fail immediately.
|
|
733
|
+
const ctx = makeContext({ conversationId: "auto-targeted-no-ext" });
|
|
734
|
+
|
|
735
|
+
expect(() =>
|
|
736
|
+
getCdpClient(ctx, { mode: "auto", targetClientId: "specific-host-client" }),
|
|
737
|
+
).toThrow(
|
|
738
|
+
expect.objectContaining({
|
|
739
|
+
code: "transport_error",
|
|
740
|
+
message: expect.stringContaining("specific-host-client"),
|
|
741
|
+
}),
|
|
742
|
+
);
|
|
743
|
+
expect(createLocalCdpClientMock).not.toHaveBeenCalled();
|
|
744
|
+
expect(createCdpInspectClientMock).not.toHaveBeenCalled();
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
test("auto mode + targetClientId + extension available → routes only to extension, no other backends tried", async () => {
|
|
748
|
+
cdpInspectEnabled = true; // cdp-inspect would normally be in the candidate list
|
|
749
|
+
const fakeProxy = makeAvailableProxy();
|
|
750
|
+
mockSingletonProxy = fakeProxy;
|
|
751
|
+
const ctx = makeContext({
|
|
752
|
+
conversationId: "auto-targeted-ext-available",
|
|
753
|
+
sourceActorPrincipalId: "actor-42",
|
|
754
|
+
});
|
|
755
|
+
|
|
756
|
+
const client = getCdpClient(ctx, {
|
|
757
|
+
mode: "auto",
|
|
758
|
+
targetClientId: "specific-host-client",
|
|
759
|
+
});
|
|
760
|
+
expect(client.kind).toBe("extension");
|
|
761
|
+
|
|
762
|
+
const result = await client.send<{ ok: boolean; via: string }>(
|
|
763
|
+
"Page.navigate",
|
|
764
|
+
);
|
|
765
|
+
expect(result).toEqual({ ok: true, via: "extension" });
|
|
766
|
+
|
|
767
|
+
expect(createExtensionCdpClientMock).toHaveBeenCalledTimes(1);
|
|
768
|
+
expect(createExtensionCdpClientMock).toHaveBeenCalledWith(
|
|
769
|
+
fakeProxy,
|
|
770
|
+
"auto-targeted-ext-available",
|
|
771
|
+
undefined,
|
|
772
|
+
"actor-42",
|
|
773
|
+
"specific-host-client",
|
|
774
|
+
);
|
|
775
|
+
// cdp-inspect and local must NOT have been tried — no fallback.
|
|
776
|
+
expect(createCdpInspectClientMock).not.toHaveBeenCalled();
|
|
777
|
+
expect(createLocalCdpClientMock).not.toHaveBeenCalled();
|
|
778
|
+
});
|
|
661
779
|
});
|
|
662
780
|
|
|
663
781
|
// ── buildCandidateList tests ─────────────────────────────────────────────
|
|
@@ -748,6 +866,62 @@ describe("buildCandidateList", () => {
|
|
|
748
866
|
expect(candidates.length).toBe(1);
|
|
749
867
|
expect(candidates[0].kind).toBe("local");
|
|
750
868
|
});
|
|
869
|
+
|
|
870
|
+
// ── targetClientId: no-fallback single-extension list (Fix 2) ────────
|
|
871
|
+
|
|
872
|
+
test("targetClientId: returns a single extension candidate when extension is available", () => {
|
|
873
|
+
const fakeProxy = makeAvailableProxy();
|
|
874
|
+
mockSingletonProxy = fakeProxy;
|
|
875
|
+
const ctx = makeContext({ conversationId: "target-with-ext" });
|
|
876
|
+
|
|
877
|
+
const candidates = buildCandidateList(ctx, "host-client-42");
|
|
878
|
+
|
|
879
|
+
// Must be exactly one candidate — no cdp-inspect or local fallbacks.
|
|
880
|
+
expect(candidates.length).toBe(1);
|
|
881
|
+
expect(candidates[0].kind).toBe("extension");
|
|
882
|
+
expect(candidates[0].reason).toContain("host-client-42");
|
|
883
|
+
});
|
|
884
|
+
|
|
885
|
+
test("targetClientId: throws transport_error immediately when no Chrome Extension is connected", () => {
|
|
886
|
+
// No extension — local would normally be the fallback, but targeting
|
|
887
|
+
// requires the proxy path and must fail loudly instead of routing elsewhere.
|
|
888
|
+
const ctx = makeContext({ conversationId: "target-no-ext" });
|
|
889
|
+
|
|
890
|
+
expect(() => buildCandidateList(ctx, "host-client-42")).toThrow(
|
|
891
|
+
expect.objectContaining({
|
|
892
|
+
code: "transport_error",
|
|
893
|
+
message: expect.stringContaining("host-client-42"),
|
|
894
|
+
}),
|
|
895
|
+
);
|
|
896
|
+
// Verify we did NOT silently fall through to a local candidate.
|
|
897
|
+
expect(createLocalCdpClientMock).not.toHaveBeenCalled();
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
test("targetClientId: threads targetClientId into the extension candidate's create() call", async () => {
|
|
901
|
+
const fakeProxy = makeAvailableProxy();
|
|
902
|
+
mockSingletonProxy = fakeProxy;
|
|
903
|
+
const ctx = makeContext({
|
|
904
|
+
conversationId: "target-threads-id",
|
|
905
|
+
sourceActorPrincipalId: "actor-1",
|
|
906
|
+
});
|
|
907
|
+
|
|
908
|
+
const candidates = buildCandidateList(ctx, "host-client-99");
|
|
909
|
+
expect(candidates.length).toBe(1);
|
|
910
|
+
|
|
911
|
+
// Clear accumulated calls from prior tests in this describe block before
|
|
912
|
+
// materialising the candidate so the call count is unambiguous.
|
|
913
|
+
createExtensionCdpClientMock.mockClear();
|
|
914
|
+
candidates[0].create();
|
|
915
|
+
|
|
916
|
+
expect(createExtensionCdpClientMock).toHaveBeenCalledTimes(1);
|
|
917
|
+
expect(createExtensionCdpClientMock).toHaveBeenCalledWith(
|
|
918
|
+
fakeProxy,
|
|
919
|
+
"target-threads-id",
|
|
920
|
+
undefined,
|
|
921
|
+
"actor-1",
|
|
922
|
+
"host-client-99",
|
|
923
|
+
);
|
|
924
|
+
});
|
|
751
925
|
});
|
|
752
926
|
|
|
753
927
|
// ── buildChainedClient failover tests ────────────────────────────────────
|
|
@@ -249,18 +249,22 @@ describe("connectCdpWsTransport", () => {
|
|
|
249
249
|
});
|
|
250
250
|
|
|
251
251
|
test("fans out events (frames with no id) to listeners", async () => {
|
|
252
|
+
// The server pushes the unsolicited event in direct response to
|
|
253
|
+
// a client trigger, sending the event frame BEFORE the response
|
|
254
|
+
// ack. WebSocket message ordering then guarantees the event
|
|
255
|
+
// arrives at the client (and is fanned out) before the trigger
|
|
256
|
+
// resolves — no setTimeout race between the server's open
|
|
257
|
+
// callback and the test attaching its listener.
|
|
252
258
|
const server = startFakeWsServer({
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
);
|
|
263
|
-
}, 5);
|
|
259
|
+
onMessage(ws, frame) {
|
|
260
|
+
ws.send(
|
|
261
|
+
JSON.stringify({
|
|
262
|
+
method: "Target.targetCreated",
|
|
263
|
+
params: { targetId: "abc" },
|
|
264
|
+
sessionId: "S1",
|
|
265
|
+
}),
|
|
266
|
+
);
|
|
267
|
+
ws.send(JSON.stringify({ id: frame.id, result: {} }));
|
|
264
268
|
},
|
|
265
269
|
});
|
|
266
270
|
try {
|
|
@@ -273,8 +277,7 @@ describe("connectCdpWsTransport", () => {
|
|
|
273
277
|
transport.addEventListener((ev) => {
|
|
274
278
|
received.push(ev);
|
|
275
279
|
});
|
|
276
|
-
|
|
277
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
280
|
+
await transport.send("Test.trigger");
|
|
278
281
|
expect(received).toEqual([
|
|
279
282
|
{
|
|
280
283
|
method: "Target.targetCreated",
|
|
@@ -44,6 +44,19 @@ export class ExtensionCdpClient implements ScopedCdpClient {
|
|
|
44
44
|
private readonly proxy: HostBrowserProxy,
|
|
45
45
|
public readonly conversationId: string,
|
|
46
46
|
private readonly cdpSessionId?: string,
|
|
47
|
+
/**
|
|
48
|
+
* Caller's actor principal id. When provided, the proxy will refuse to
|
|
49
|
+
* dispatch this CDP command to a host_browser-capable client owned by a
|
|
50
|
+
* different actor — closing the cross-client exposure path's same-user
|
|
51
|
+
* boundary.
|
|
52
|
+
*/
|
|
53
|
+
private readonly sourceActorPrincipalId?: string,
|
|
54
|
+
/**
|
|
55
|
+
* Explicit target client id. When provided, the proxy routes directly
|
|
56
|
+
* to that client instead of auto-resolving to the most-recently-active
|
|
57
|
+
* same-actor host_browser client.
|
|
58
|
+
*/
|
|
59
|
+
private readonly targetClientId?: string,
|
|
47
60
|
) {}
|
|
48
61
|
|
|
49
62
|
async send<T = unknown>(
|
|
@@ -74,6 +87,8 @@ export class ExtensionCdpClient implements ScopedCdpClient {
|
|
|
74
87
|
},
|
|
75
88
|
this.conversationId,
|
|
76
89
|
signal,
|
|
90
|
+
this.sourceActorPrincipalId,
|
|
91
|
+
this.targetClientId,
|
|
77
92
|
);
|
|
78
93
|
} catch (err) {
|
|
79
94
|
throw new CdpError(
|
|
@@ -194,6 +209,14 @@ export function createExtensionCdpClient(
|
|
|
194
209
|
proxy: HostBrowserProxy,
|
|
195
210
|
conversationId: string,
|
|
196
211
|
cdpSessionId?: string,
|
|
212
|
+
sourceActorPrincipalId?: string,
|
|
213
|
+
targetClientId?: string,
|
|
197
214
|
): ExtensionCdpClient {
|
|
198
|
-
return new ExtensionCdpClient(
|
|
215
|
+
return new ExtensionCdpClient(
|
|
216
|
+
proxy,
|
|
217
|
+
conversationId,
|
|
218
|
+
cdpSessionId,
|
|
219
|
+
sourceActorPrincipalId,
|
|
220
|
+
targetClientId,
|
|
221
|
+
);
|
|
199
222
|
}
|