@vellumai/assistant 0.8.2 → 0.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +11 -12
- package/docker-entrypoint.sh +13 -2
- package/docker-init-apt-root.sh +79 -6
- package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
- package/openapi.yaml +945 -36
- package/package.json +1 -1
- package/src/__tests__/agent-loop-exit-reason.test.ts +271 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +195 -0
- package/src/__tests__/agent-loop.test.ts +88 -3
- package/src/__tests__/anthropic-provider.test.ts +272 -0
- package/src/__tests__/approval-cascade.test.ts +1 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
- package/src/__tests__/channel-delivery-store.test.ts +193 -0
- package/src/__tests__/channel-reply-delivery.test.ts +284 -5
- package/src/__tests__/channel-retry-sweep.test.ts +274 -1
- package/src/__tests__/compaction-events.test.ts +1 -1
- package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
- package/src/__tests__/compactor-tail-resolution.test.ts +107 -1
- package/src/__tests__/config-get-vision-flag.test.ts +136 -0
- package/src/__tests__/config-loader-backfill.test.ts +115 -18
- package/src/__tests__/config-watcher.test.ts +1 -1
- package/src/__tests__/context-token-estimator.test.ts +112 -57
- package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +54 -3
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +31 -6
- package/src/__tests__/conversation-agent-loop.test.ts +77 -3
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
- package/src/__tests__/conversation-clean-command.test.ts +137 -0
- package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
- package/src/__tests__/conversation-fork-crud.test.ts +161 -0
- package/src/__tests__/conversation-lifecycle.test.ts +1 -1
- package/src/__tests__/conversation-load-cleaned-at.test.ts +279 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
- package/src/__tests__/conversation-media-retry.test.ts +19 -8
- package/src/__tests__/conversation-pairing.test.ts +2 -2
- package/src/__tests__/conversation-process-callsite.test.ts +1 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -1
- package/src/__tests__/conversation-queue.test.ts +1 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +290 -85
- package/src/__tests__/conversation-seed-composer.test.ts +66 -4
- package/src/__tests__/conversation-slash-commands.test.ts +36 -8
- package/src/__tests__/conversation-slash-queue.test.ts +1 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
- package/src/__tests__/conversation-speed-override.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -1
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
- package/src/__tests__/credential-security-invariants.test.ts +6 -0
- package/src/__tests__/cu-unified-flow.test.ts +10 -1
- package/src/__tests__/date-context.test.ts +45 -0
- package/src/__tests__/dm-backfill.test.ts +64 -0
- package/src/__tests__/dm-persistence.test.ts +33 -0
- package/src/__tests__/document-find-replace.test.ts +501 -0
- package/src/__tests__/external-plugin-loader.test.ts +91 -19
- package/src/__tests__/first-greeting.test.ts +23 -2
- package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +0 -1
- package/src/__tests__/guardian-dispatch.test.ts +1 -0
- package/src/__tests__/headless-browser-navigate.test.ts +172 -0
- package/src/__tests__/heartbeat-service.test.ts +24 -164
- package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
- package/src/__tests__/host-app-control-proxy.test.ts +241 -0
- package/src/__tests__/host-bash-proxy.test.ts +6 -0
- package/src/__tests__/host-browser-proxy.test.ts +10 -0
- package/src/__tests__/host-cu-proxy.test.ts +8 -1
- package/src/__tests__/host-file-proxy.test.ts +8 -1
- package/src/__tests__/host-proxy-preactivation.test.ts +200 -13
- package/src/__tests__/host-transfer-proxy.test.ts +8 -1
- package/src/__tests__/identity-routes.test.ts +57 -0
- package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
- package/src/__tests__/injector-background-turn.test.ts +153 -0
- package/src/__tests__/injector-chain.test.ts +7 -0
- package/src/__tests__/injector-document-comments.test.ts +378 -0
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +9 -2
- package/src/__tests__/list-messages-attachments.test.ts +21 -17
- package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
- package/src/__tests__/list-messages-page-latest.test.ts +130 -14
- package/src/__tests__/list-messages-tool-merge.test.ts +17 -16
- package/src/__tests__/llm-callsite-catalog.test.ts +25 -0
- package/src/__tests__/llm-catalog-parity.test.ts +3 -0
- package/src/__tests__/llm-context-normalization.test.ts +0 -2
- package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +116 -0
- package/src/__tests__/llm-request-log-error-payload.test.ts +138 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +2 -0
- package/src/__tests__/llm-resolver.test.ts +340 -3
- package/src/__tests__/log-export-routes.test.ts +99 -2
- package/src/__tests__/managed-profile-guard.test.ts +10 -0
- package/src/__tests__/message-queue-steer.test.ts +114 -0
- package/src/__tests__/notification-decision-fallback.test.ts +0 -91
- package/src/__tests__/notification-decision-strategy.test.ts +14 -31
- package/src/__tests__/notification-deep-link.test.ts +15 -0
- package/src/__tests__/notification-guardian-path.test.ts +1 -2
- package/src/__tests__/notification-platform-adapter.test.ts +5 -4
- package/src/__tests__/notification-telegram-adapter.test.ts +1 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +113 -0
- package/src/__tests__/openai-provider.test.ts +323 -3
- package/src/__tests__/openai-responses-cutover-guard.test.ts +3 -3
- package/src/__tests__/openai-responses-provider.test.ts +4 -4
- package/src/__tests__/openrouter-provider-only.test.ts +51 -3
- package/src/__tests__/openrouter-token-estimation.test.ts +34 -25
- package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
- package/src/__tests__/pending-interactions-resolved-event.test.ts +190 -0
- package/src/__tests__/platform-proxy-context.test.ts +6 -1
- package/src/__tests__/platform.test.ts +0 -3
- package/src/__tests__/plugin-source-watcher.test.ts +302 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +3 -3
- package/src/__tests__/plugin-types.test.ts +2 -2
- package/src/__tests__/process-message-background-slack.test.ts +1 -51
- package/src/__tests__/process-message-display-content.test.ts +21 -16
- package/src/__tests__/provider-catalog-visibility.test.ts +16 -0
- package/src/__tests__/provider-platform-proxy-integration.test.ts +27 -25
- package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +83 -4
- package/src/__tests__/steer-tool-repair.test.ts +249 -0
- package/src/__tests__/system-prompt.test.ts +57 -101
- package/src/__tests__/terminal-tools.test.ts +11 -1
- package/src/__tests__/thinking-block-replay.test.ts +113 -0
- package/src/__tests__/thread-backfill.test.ts +370 -22
- package/src/__tests__/tool-executor.test.ts +90 -1
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
- package/src/__tests__/twilio-routes.test.ts +1 -1
- package/src/__tests__/web-fetch.test.ts +2 -2
- package/src/__tests__/workspace-git-service.test.ts +88 -5
- package/src/__tests__/workspace-migration-087-memory-router-balanced-profile.test.ts +228 -0
- package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
- package/src/a2a/__tests__/agent-card.test.ts +98 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +597 -0
- package/src/a2a/__tests__/protocol-helpers.test.ts +113 -0
- package/src/a2a/__tests__/task-store.test.ts +246 -0
- package/src/a2a/agent-card.ts +58 -0
- package/src/a2a/feature-gate.ts +8 -0
- package/src/a2a/protocol-constants.ts +21 -0
- package/src/a2a/protocol-errors.ts +50 -0
- package/src/a2a/protocol-types.ts +162 -0
- package/src/a2a/task-store.ts +168 -0
- package/src/agent/attachments.ts +1 -0
- package/src/agent/loop.ts +208 -22
- package/src/background-wake/next-wake.test.ts +289 -0
- package/src/background-wake/next-wake.ts +172 -0
- package/src/browser/operations.ts +15 -0
- package/src/channels/config.ts +9 -0
- package/src/channels/types.ts +14 -0
- package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +9 -12
- package/src/cli/{__tests__ → commands/__tests__}/notifications.test.ts +201 -28
- package/src/cli/commands/__tests__/schedules.test.ts +469 -0
- package/src/cli/commands/conversations.ts +128 -1
- package/src/cli/commands/inference-providers.ts +147 -1
- package/src/cli/commands/memory-v2.ts +308 -0
- package/src/cli/commands/notifications.ts +89 -37
- package/src/cli/commands/plugins.ts +67 -0
- package/src/cli/commands/schedules.ts +297 -5
- package/src/cli/lib/__tests__/search-plugins.test.ts +261 -0
- package/src/cli/lib/install-from-github.ts +8 -9
- package/src/cli/lib/search-plugins.ts +163 -0
- package/src/cli/program.ts +14 -0
- package/src/cli/utils/conversation-id.ts +17 -5
- package/src/config/assistant-feature-flags.ts +24 -54
- package/src/config/bundled-skills/app-builder/SKILL.md +117 -1
- package/src/config/bundled-skills/document-editor/SKILL.md +115 -0
- package/src/config/bundled-skills/document-editor/TOOLS.json +240 -0
- package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
- package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/SKILL.md +8 -0
- package/src/config/bundled-tool-registry.ts +22 -12
- package/src/config/call-site-defaults.ts +124 -0
- package/src/config/feature-flag-registry.json +111 -23
- package/src/config/llm-resolver.ts +66 -1
- package/src/config/schema.ts +2 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +7 -3
- package/src/config/schemas/call-site-catalog.ts +21 -0
- package/src/config/schemas/channels.ts +9 -0
- package/src/config/schemas/conversations.ts +10 -0
- package/src/config/schemas/heartbeat.ts +14 -0
- package/src/config/schemas/llm.ts +4 -3
- package/src/config/schemas/memory-retrospective.ts +1 -1
- package/src/config/schemas/memory-v2.ts +51 -4
- package/src/config/schemas/memory.ts +3 -1
- package/src/config/seed-inference-profiles.ts +99 -29
- package/src/context/compactor.ts +80 -13
- package/src/context/token-estimator.ts +72 -31
- package/src/context/window-manager.ts +25 -0
- package/src/credential-health/credential-health-service.ts +34 -19
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -22
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
- package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +231 -23
- package/src/daemon/conversation-agent-loop.ts +252 -56
- package/src/daemon/conversation-lifecycle.ts +142 -116
- package/src/daemon/conversation-messaging.ts +3 -0
- package/src/daemon/conversation-process.ts +273 -0
- package/src/daemon/conversation-queue-manager.ts +14 -0
- package/src/daemon/conversation-runtime-assembly.ts +144 -75
- package/src/daemon/conversation-slash.ts +37 -5
- package/src/daemon/conversation-surfaces.ts +45 -2
- package/src/daemon/conversation-tool-setup.ts +7 -0
- package/src/daemon/conversation.ts +42 -12
- package/src/daemon/date-context.ts +40 -0
- package/src/daemon/first-greeting.ts +10 -0
- package/src/daemon/guardian-action-generators.ts +1 -125
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +248 -0
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +154 -0
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +133 -0
- package/src/daemon/handlers/__tests__/config-a2a.test.ts +95 -0
- package/src/daemon/handlers/config-a2a.ts +449 -0
- package/src/daemon/handlers/config-model.test.ts +1 -0
- package/src/daemon/handlers/conversations.ts +80 -0
- package/src/daemon/handlers/shared.ts +92 -29
- package/src/daemon/host-app-control-proxy.ts +69 -18
- package/src/daemon/host-bash-proxy.ts +1 -1
- package/src/daemon/host-cu-proxy.ts +1 -1
- package/src/daemon/host-file-proxy.ts +1 -1
- package/src/daemon/host-proxy-preactivation.ts +85 -18
- package/src/daemon/host-transfer-proxy.ts +1 -1
- package/src/daemon/lifecycle.ts +67 -65
- package/src/daemon/memory-v2-startup.ts +49 -13
- package/src/daemon/message-protocol.ts +4 -0
- package/src/daemon/message-types/conversations.ts +8 -0
- package/src/daemon/message-types/document-comments.ts +50 -0
- package/src/daemon/message-types/messages.ts +68 -1
- package/src/daemon/message-types/notifications.ts +21 -0
- package/src/daemon/message-types/surfaces.ts +3 -1
- package/src/daemon/message-types/web-activity.ts +57 -0
- package/src/daemon/pkb-reminder-builder.test.ts +10 -53
- package/src/daemon/pkb-reminder-builder.ts +4 -19
- package/src/daemon/plugin-source-watcher.ts +135 -3
- package/src/daemon/process-message.ts +72 -12
- package/src/daemon/query-complexity-router.ts +75 -0
- package/src/daemon/skill-memory-refresh.ts +5 -1
- package/src/daemon/trust-context.ts +6 -0
- package/src/daemon/wake-target-adapter.ts +2 -0
- package/src/documents/document-comments-store.test.ts +338 -0
- package/src/documents/document-comments-store.ts +237 -0
- package/src/documents/document-store.ts +202 -0
- package/src/export/__tests__/transcript-formatter.test.ts +121 -0
- package/src/export/transcript-formatter.ts +54 -20
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +44 -1
- package/src/heartbeat/heartbeat-service.ts +35 -191
- package/src/home/__tests__/feed-types.test.ts +40 -0
- package/src/home/__tests__/suggested-prompts.test.ts +33 -2
- package/src/home/feed-types.ts +20 -3
- package/src/home/home-content-refresh.ts +52 -0
- package/src/home/home-greeting-cache.ts +69 -0
- package/src/home/home-greeting.ts +94 -0
- package/src/home/suggested-prompts.ts +177 -9
- package/src/ipc/cli-client.ts +147 -45
- package/src/memory/__tests__/conversation-queries.test.ts +220 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +2 -50
- package/src/memory/__tests__/memory-retrospective-job.test.ts +407 -10
- package/src/memory/conversation-crud.ts +133 -43
- package/src/memory/conversation-queries.ts +87 -1
- package/src/memory/conversation-title-service.ts +26 -4
- package/src/memory/db-init.ts +22 -0
- package/src/memory/delivery-crud.ts +41 -0
- package/src/memory/delivery-status.ts +141 -15
- package/src/memory/external-conversation-store.ts +32 -1
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +84 -3
- package/src/memory/graph/conversation-graph-memory.ts +18 -6
- package/src/memory/graph/tools.ts +6 -37
- package/src/memory/invite-store.ts +53 -0
- package/src/memory/jobs-worker.ts +21 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +7 -2
- package/src/memory/llm-request-log-store.ts +92 -1
- package/src/memory/memory-retrospective-constants.ts +28 -0
- package/src/memory/memory-retrospective-enqueue.ts +4 -22
- package/src/memory/memory-retrospective-job.ts +438 -21
- package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
- package/src/memory/memory-v2-activation-log-store.ts +26 -8
- package/src/memory/migrations/100-core-tables.ts +1 -0
- package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
- package/src/memory/migrations/250-provider-connection-base-url-and-models.ts +28 -0
- package/src/memory/migrations/251-a2a-tasks.ts +49 -0
- package/src/memory/migrations/252-llm-request-log-agent-loop-exit-reason.ts +32 -0
- package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
- package/src/memory/migrations/253-document-comments.ts +47 -0
- package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
- package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
- package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
- package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
- package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
- package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
- package/src/memory/migrations/index.ts +20 -0
- package/src/memory/migrations/registry.ts +33 -0
- package/src/memory/onboarding-events-store.ts +7 -0
- package/src/memory/schema/a2a.ts +15 -0
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/conversations.ts +3 -0
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/inference.ts +2 -0
- package/src/memory/schema/infrastructure.ts +2 -0
- package/src/memory/v2/__tests__/activation-store.test.ts +25 -23
- package/src/memory/v2/__tests__/cli-command-store.test.ts +404 -0
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +25 -4
- package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
- package/src/memory/v2/__tests__/injection.test.ts +221 -17
- package/src/memory/v2/__tests__/page-index.test.ts +365 -1
- package/src/memory/v2/__tests__/router.test.ts +489 -1
- package/src/memory/v2/__tests__/static-context.test.ts +12 -1
- package/src/memory/v2/activation-store.ts +14 -16
- package/src/memory/v2/cli-command-content.ts +19 -0
- package/src/memory/v2/cli-command-store.ts +304 -0
- package/src/memory/v2/consolidation-job.ts +14 -0
- package/src/memory/v2/frontmatter-sweep.ts +7 -1
- package/src/memory/v2/injection-events.ts +101 -0
- package/src/memory/v2/injection.ts +69 -29
- package/src/memory/v2/page-index.ts +246 -19
- package/src/memory/v2/page-store.ts +18 -0
- package/src/memory/v2/router.ts +209 -55
- package/src/memory/v2/static-context.ts +4 -4
- package/src/memory/v2/types.ts +23 -0
- package/src/messaging/providers/a2a/__tests__/deliver.test.ts +274 -0
- package/src/messaging/providers/a2a/deliver.ts +156 -0
- package/src/messaging/providers/gmail/client.ts +9 -2
- package/src/messaging/providers/index.ts +18 -3
- package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
- package/src/messaging/providers/slack/adapter.ts +178 -25
- package/src/messaging/providers/slack/api.test.ts +54 -0
- package/src/messaging/providers/slack/api.ts +119 -3
- package/src/messaging/providers/slack/client.ts +12 -0
- package/src/messaging/providers/slack/deep-link.ts +20 -1
- package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
- package/src/messaging/providers/slack/message-metadata.ts +156 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
- package/src/messaging/providers/slack/render-transcript.ts +176 -49
- package/src/messaging/providers/slack/send.test.ts +77 -0
- package/src/messaging/providers/slack/send.ts +8 -2
- package/src/messaging/providers/slack/types.ts +14 -0
- package/src/notifications/__tests__/broadcaster.test.ts +203 -0
- package/src/notifications/__tests__/decision-engine.test.ts +283 -0
- package/src/notifications/__tests__/deterministic-checks.test.ts +286 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +5 -1
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +521 -36
- package/src/notifications/adapters/macos.ts +12 -2
- package/src/notifications/broadcaster.ts +29 -4
- package/src/notifications/conversation-seed-composer.ts +14 -2
- package/src/notifications/copy-composer.ts +17 -64
- package/src/notifications/decision-engine.ts +111 -44
- package/src/notifications/deferred-emit.ts +135 -0
- package/src/notifications/deterministic-checks.ts +96 -0
- package/src/notifications/emit-signal.ts +10 -1
- package/src/notifications/home-feed-side-effect.ts +136 -27
- package/src/notifications/signal.ts +0 -4
- package/src/notifications/types.ts +8 -0
- package/src/oauth/connect-orchestrator.ts +3 -0
- package/src/oauth/credential-token-resolver.ts +2 -0
- package/src/oauth/manual-token-connection.ts +19 -0
- package/src/oauth/oauth-store.ts +12 -0
- package/src/oauth/platform-connection.test.ts +43 -3
- package/src/oauth/platform-connection.ts +13 -4
- package/src/oauth/seed-providers.ts +22 -0
- package/src/permissions/prompter.ts +5 -2
- package/src/permissions/secret-prompter.ts +4 -1
- package/src/plugins/defaults/injectors.ts +118 -26
- package/src/plugins/external-plugin-loader.ts +82 -10
- package/src/plugins/types.ts +16 -7
- package/src/prompts/__tests__/system-prompt.test.ts +44 -45
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +4 -8
- package/src/prompts/normalize-onboarding.ts +40 -0
- package/src/prompts/sections.ts +32 -14
- package/src/prompts/system-prompt.ts +105 -76
- package/src/prompts/template-detection.ts +37 -0
- package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
- package/src/prompts/templates/BOOTSTRAP.md +13 -5
- package/src/prompts/templates/VOICE.md +3 -0
- package/src/prompts/templates/system-sections.ts +51 -10
- package/src/providers/__tests__/inference.test.ts +2 -0
- package/src/providers/anthropic/client.ts +132 -5
- package/src/providers/call-site-routing.ts +24 -6
- package/src/providers/connection-resolution.ts +63 -13
- package/src/providers/fireworks/client.ts +20 -2
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +74 -0
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
- package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
- package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
- package/src/providers/inference/__tests__/connections-openai-compatible.test.ts +175 -0
- package/src/providers/inference/__tests__/connections-status-label.test.ts +15 -0
- package/src/providers/inference/adapter-factory.ts +24 -21
- package/src/providers/inference/auth.ts +15 -3
- package/src/providers/inference/backfill.ts +14 -1
- package/src/providers/inference/codex-token-refresh.ts +128 -0
- package/src/providers/inference/connections.ts +85 -5
- package/src/providers/inference/resolve-auth.ts +50 -5
- package/src/providers/model-catalog.ts +244 -242
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +235 -0
- package/src/providers/openai/chat-completions-provider.ts +215 -25
- package/src/providers/openai/responses-provider.ts +9 -3
- package/src/providers/openrouter/client.ts +46 -4
- package/src/providers/platform-proxy/constants.ts +3 -4
- package/src/providers/provider-catalog-visibility.ts +3 -1
- package/src/providers/provider-send-message.ts +27 -12
- package/src/providers/registry.ts +30 -1
- package/src/providers/types.ts +25 -0
- package/src/runtime/__tests__/agent-wake.test.ts +214 -0
- package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
- package/src/runtime/agent-wake.ts +212 -57
- package/src/runtime/auth/route-policy.ts +20 -3
- package/src/runtime/background-job-runner.ts +26 -0
- package/src/runtime/channel-reply-delivery.ts +182 -47
- package/src/runtime/channel-retry-sweep.ts +141 -16
- package/src/runtime/http-server.ts +7 -16
- package/src/runtime/http-types.ts +7 -51
- package/src/runtime/pending-interactions.ts +51 -8
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +258 -0
- package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +121 -5
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +275 -44
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +12 -0
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +271 -0
- package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
- package/src/runtime/routes/approval-routes.ts +4 -1
- package/src/runtime/routes/channel-availability-routes.ts +5 -0
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
- package/src/runtime/routes/consolidation-routes.ts +100 -0
- package/src/runtime/routes/content-source-routes.ts +78 -0
- package/src/runtime/routes/conversation-cli-routes.ts +146 -1
- package/src/runtime/routes/conversation-query-routes.ts +130 -12
- package/src/runtime/routes/conversation-routes.ts +288 -76
- package/src/runtime/routes/document-comments-routes.ts +287 -0
- package/src/runtime/routes/documents-routes.ts +33 -0
- package/src/runtime/routes/home-feed-routes.ts +6 -3
- package/src/runtime/routes/host-app-control-routes.ts +1 -1
- package/src/runtime/routes/host-browser-routes.ts +8 -1
- package/src/runtime/routes/identity-routes.ts +21 -0
- package/src/runtime/routes/inbound-message-handler.ts +288 -58
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
- package/src/runtime/routes/index.ts +14 -4
- package/src/runtime/routes/inference-provider-connection-routes.ts +192 -3
- package/src/runtime/routes/integrations/a2a.ts +294 -0
- package/src/runtime/routes/llm-call-sites-routes.ts +11 -1
- package/src/runtime/routes/log-export-routes.ts +39 -0
- package/src/runtime/routes/memory-v2-routes.ts +217 -0
- package/src/runtime/routes/notification-routes.ts +19 -2
- package/src/runtime/routes/question-routes.ts +4 -1
- package/src/runtime/routes/sanity-routes.ts +159 -0
- package/src/runtime/routes/slack-channel-routes.ts +187 -0
- package/src/runtime/routes/subagents-routes.ts +41 -0
- package/src/runtime/services/conversation-serializer.ts +30 -4
- package/src/schedule/integration-status.ts +3 -1
- package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
- package/src/security/oauth2-device-code.ts +307 -0
- package/src/security/oauth2.ts +26 -9
- package/src/security/secure-keys.ts +5 -0
- package/src/skills/catalog-install.ts +6 -2
- package/src/subagent/manager.ts +2 -0
- package/src/tools/browser/__tests__/pinned-tabs.test.ts +80 -0
- package/src/tools/browser/browser-execution.ts +93 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +1 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +10 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +15 -1
- package/src/tools/browser/cdp-client/factory.ts +87 -3
- package/src/tools/browser/cdp-client/local-cdp-client.ts +9 -0
- package/src/tools/browser/cdp-client/types.ts +36 -0
- package/src/tools/browser/pinned-tabs.ts +90 -0
- package/src/tools/document/document-comment-tool.test.ts +379 -0
- package/src/tools/document/document-comment-tool.ts +156 -0
- package/src/tools/document/document-tool.ts +128 -2
- package/src/tools/memory/register.ts +1 -9
- package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
- package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
- package/src/tools/network/domain-normalize.ts +17 -0
- package/src/tools/network/web-fetch.ts +213 -64
- package/src/tools/network/web-search.ts +191 -66
- package/src/tools/registry.ts +2 -2
- package/src/tools/terminal/safe-env.ts +3 -2
- package/src/tools/tool-approval-handler.ts +19 -12
- package/src/tools/types.ts +41 -2
- package/src/tools/ui-surface/definitions.ts +3 -1
- package/src/types/onboarding-context.ts +4 -0
- package/src/util/__tests__/favicon.test.ts +84 -0
- package/src/util/favicon.ts +40 -0
- package/src/util/platform.ts +0 -5
- package/src/workspace/git-service.ts +75 -4
- package/src/workspace/migrations/087-memory-router-balanced-profile.ts +91 -0
- package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -441
- package/src/config/bundled-skills/document/SKILL.md +0 -54
- package/src/config/bundled-skills/document/TOOLS.json +0 -106
- package/src/daemon/seed-files.ts +0 -18
- package/src/memory/graph/__tests__/remember-description.test.ts +0 -55
- package/src/runtime/guardian-action-conversation-turn.ts +0 -99
- package/src/runtime/routes/interface-routes.ts +0 -43
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
|
@@ -2382,4 +2382,32 @@ describe("macOS host-browser proxy without extension registry", () => {
|
|
|
2382
2382
|
);
|
|
2383
2383
|
expect(result).toEqual({ ok: true, via: "extension" });
|
|
2384
2384
|
});
|
|
2385
|
+
test("setCdpSessionId is forwarded to the underlying client through buildChainedClient", async () => {
|
|
2386
|
+
// This test exercises the real chained-client path that integrates
|
|
2387
|
+
// the extension CdpClient. Without it, the test suite would only ever
|
|
2388
|
+
// instantiate getCdpClient(), which returns the scopedClient directly.
|
|
2389
|
+
// buildChainedClient (used by the navigator executor) wraps that
|
|
2390
|
+
// client and must forward setCdpSessionId calls to the underlying
|
|
2391
|
+
// extension client — otherwise --new-tab would silently fail to
|
|
2392
|
+
// re-target CDP commands.
|
|
2393
|
+
const fakeProxy = makeAvailableProxy();
|
|
2394
|
+
mockSingletonProxy = fakeProxy;
|
|
2395
|
+
const ctx = makeContext({ conversationId: "set-session-id-test" });
|
|
2396
|
+
const client = getCdpClient(ctx);
|
|
2397
|
+
// The scopedClient should expose setCdpSessionId (which it didn't
|
|
2398
|
+
// before the fix).
|
|
2399
|
+
expect(typeof client.setCdpSessionId).toBe("function");
|
|
2400
|
+
// Call it; it should reach the underlying extension client without error.
|
|
2401
|
+
// (The fake client's setCdpSessionId is a no-op in this test, but in
|
|
2402
|
+
// production ExtensionCdpClient.setCdpSessionId updates cdpSessionId to
|
|
2403
|
+
// re-target follow-on commands at a specific tab.)
|
|
2404
|
+
const newTabId = "12345";
|
|
2405
|
+
client.setCdpSessionId(newTabId);
|
|
2406
|
+
// Verify the client is still functional after the session ID call.
|
|
2407
|
+
const result = await client.send<{ ok: boolean; via: string }>(
|
|
2408
|
+
"Page.navigate",
|
|
2409
|
+
{ url: "https://example.com" },
|
|
2410
|
+
);
|
|
2411
|
+
expect(result).toEqual({ ok: true, via: "extension" });
|
|
2412
|
+
});
|
|
2385
2413
|
});
|
|
@@ -700,6 +700,16 @@ export class CdpInspectClient implements ScopedCdpClient {
|
|
|
700
700
|
}
|
|
701
701
|
}
|
|
702
702
|
|
|
703
|
+
/**
|
|
704
|
+
* CdpInspectClient doesn't support re-targeting to a specific tab/session.
|
|
705
|
+
* It connects directly to a remote CDP endpoint, which manages targets
|
|
706
|
+
* globally. This method is a no-op to satisfy the {@link ScopedCdpClient}
|
|
707
|
+
* interface.
|
|
708
|
+
*/
|
|
709
|
+
setCdpSessionId(): void {
|
|
710
|
+
// no-op
|
|
711
|
+
}
|
|
712
|
+
|
|
703
713
|
dispose(): void {
|
|
704
714
|
if (this.disposed) return;
|
|
705
715
|
this.disposed = true;
|
|
@@ -43,7 +43,7 @@ export class ExtensionCdpClient implements ScopedCdpClient {
|
|
|
43
43
|
constructor(
|
|
44
44
|
private readonly proxy: HostBrowserProxy,
|
|
45
45
|
public readonly conversationId: string,
|
|
46
|
-
private
|
|
46
|
+
private cdpSessionId?: string,
|
|
47
47
|
/**
|
|
48
48
|
* Caller's actor principal id. When provided, the proxy will refuse to
|
|
49
49
|
* dispatch this CDP command to a host_browser-capable client owned by a
|
|
@@ -182,6 +182,20 @@ export class ExtensionCdpClient implements ScopedCdpClient {
|
|
|
182
182
|
// it here. In-flight requests will be cancelled by the AbortSignal
|
|
183
183
|
// the tool passes in, or by conversation teardown.
|
|
184
184
|
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Update the `cdpSessionId` used on subsequent {@link send} calls.
|
|
188
|
+
*
|
|
189
|
+
* Used by the navigate executor after opening a new tab via the
|
|
190
|
+
* `Vellum.createTab` pseudo-CDP method: the returned tabId becomes
|
|
191
|
+
* this client's pinned target so the follow-on `Page.navigate`
|
|
192
|
+
* (and every command on this conversation thereafter) routes to
|
|
193
|
+
* the freshly-created tab instead of the user's currently-active
|
|
194
|
+
* tab.
|
|
195
|
+
*/
|
|
196
|
+
setCdpSessionId(cdpSessionId: string | undefined): void {
|
|
197
|
+
this.cdpSessionId = cdpSessionId;
|
|
198
|
+
}
|
|
185
199
|
}
|
|
186
200
|
|
|
187
201
|
/**
|
|
@@ -11,6 +11,7 @@ import { getConfig } from "../../../config/loader.js";
|
|
|
11
11
|
import { HostBrowserProxy } from "../../../daemon/host-browser-proxy.js";
|
|
12
12
|
import { getLogger } from "../../../util/logger.js";
|
|
13
13
|
import type { ToolContext } from "../../types.js";
|
|
14
|
+
import { getPinnedTab } from "../pinned-tabs.js";
|
|
14
15
|
import { createCdpInspectClient } from "./cdp-inspect-client.js";
|
|
15
16
|
import { CdpError } from "./errors.js";
|
|
16
17
|
import { createExtensionCdpClient } from "./extension-cdp-client.js";
|
|
@@ -222,7 +223,14 @@ export function buildPinnedCandidateList(
|
|
|
222
223
|
const client = createExtensionCdpClient(
|
|
223
224
|
hostBrowserProxy,
|
|
224
225
|
conversationId,
|
|
225
|
-
|
|
226
|
+
// Conversation pins are scoped to "default routing on
|
|
227
|
+
// this conversation". When `target_client_id` is an
|
|
228
|
+
// explicit override, the caller is taking over routing
|
|
229
|
+
// and the pin (which may point at a tab on a different
|
|
230
|
+
// host client) must not be applied — otherwise we'd
|
|
231
|
+
// send tabId from host A to host B and get
|
|
232
|
+
// cdp_session_not_found.
|
|
233
|
+
targetClientId ? undefined : getPinnedTab(conversationId),
|
|
226
234
|
sourceActorPrincipalId,
|
|
227
235
|
targetClientId,
|
|
228
236
|
);
|
|
@@ -330,6 +338,11 @@ export function buildCandidateList(context: ToolContext, targetClientId?: string
|
|
|
330
338
|
kind: "extension",
|
|
331
339
|
reason: `target_client_id override: ${targetClientId}`,
|
|
332
340
|
create() {
|
|
341
|
+
// Explicit target_client_id override → ignore the
|
|
342
|
+
// conversation's pinned tab. Pins are conversation-scoped
|
|
343
|
+
// (not host-client-scoped) and would route a tabId from
|
|
344
|
+
// a different host to this one, producing
|
|
345
|
+
// cdp_session_not_found.
|
|
333
346
|
const client = createExtensionCdpClient(
|
|
334
347
|
hostBrowserProxy,
|
|
335
348
|
conversationId,
|
|
@@ -358,7 +371,9 @@ export function buildCandidateList(context: ToolContext, targetClientId?: string
|
|
|
358
371
|
const client = createExtensionCdpClient(
|
|
359
372
|
hostBrowserProxy,
|
|
360
373
|
conversationId,
|
|
361
|
-
|
|
374
|
+
// See comment above the pinned-mode call site for why pins
|
|
375
|
+
// are skipped under explicit target_client_id override.
|
|
376
|
+
targetClientId ? undefined : getPinnedTab(conversationId),
|
|
362
377
|
sourceActorPrincipalId,
|
|
363
378
|
targetClientId,
|
|
364
379
|
);
|
|
@@ -484,6 +499,16 @@ export function buildChainedClient(
|
|
|
484
499
|
kind: CdpClientKind;
|
|
485
500
|
manager: BrowserSessionManager;
|
|
486
501
|
sessionId: string;
|
|
502
|
+
/**
|
|
503
|
+
* Reference to the underlying CdpClient (returned from
|
|
504
|
+
* `candidate.create()`). Held so callers can reach methods that
|
|
505
|
+
* aren't routed through `manager.send()` — specifically
|
|
506
|
+
* {@link CdpClient.setCdpSessionId}, which re-targets follow-on
|
|
507
|
+
* CDP commands at a specific tab/target. Without this we'd have
|
|
508
|
+
* no way to call setCdpSessionId on the materialised client
|
|
509
|
+
* since `backend` only exposes the send/dispose surface.
|
|
510
|
+
*/
|
|
511
|
+
client: CdpClient;
|
|
487
512
|
} | null = null;
|
|
488
513
|
|
|
489
514
|
/** Set to true after the first successful CDP command. */
|
|
@@ -491,6 +516,17 @@ export function buildChainedClient(
|
|
|
491
516
|
|
|
492
517
|
let disposed = false;
|
|
493
518
|
|
|
519
|
+
/**
|
|
520
|
+
* setCdpSessionId may be called BEFORE the first send (i.e. before
|
|
521
|
+
* `active` is populated). When that happens we stash the value
|
|
522
|
+
* here and apply it to `active.client` as soon as a backend becomes
|
|
523
|
+
* sticky. In the current --new-tab flow this can't trigger (the
|
|
524
|
+
* createTab send establishes sticky first, then setCdpSessionId is
|
|
525
|
+
* called), but supporting the pre-sticky case keeps the contract
|
|
526
|
+
* simple for future callers.
|
|
527
|
+
*/
|
|
528
|
+
let pendingCdpSessionId: string | undefined;
|
|
529
|
+
|
|
494
530
|
/**
|
|
495
531
|
* Track all materialised backends so dispose() can tear them all
|
|
496
532
|
* down, even ones that were tried and failed before the sticky
|
|
@@ -545,6 +581,16 @@ export function buildChainedClient(
|
|
|
545
581
|
active = established;
|
|
546
582
|
sticky = true;
|
|
547
583
|
currentKind = established.kind;
|
|
584
|
+
// Flush any pre-sticky setCdpSessionId call onto the
|
|
585
|
+
// freshly-materialised client. See pendingCdpSessionId
|
|
586
|
+
// comment above for why this exists.
|
|
587
|
+
if (
|
|
588
|
+
pendingCdpSessionId !== undefined &&
|
|
589
|
+
established.client.setCdpSessionId
|
|
590
|
+
) {
|
|
591
|
+
established.client.setCdpSessionId(pendingCdpSessionId);
|
|
592
|
+
pendingCdpSessionId = undefined;
|
|
593
|
+
}
|
|
548
594
|
},
|
|
549
595
|
() => disposed,
|
|
550
596
|
conversationId,
|
|
@@ -561,6 +607,31 @@ export function buildChainedClient(
|
|
|
561
607
|
materialisedManagers.length = 0;
|
|
562
608
|
active = null;
|
|
563
609
|
},
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Re-target follow-on CDP commands at a specific tab/target by
|
|
613
|
+
* updating the underlying client's `cdpSessionId`. The navigate
|
|
614
|
+
* executor calls this after `Vellum.createTab` returns so the
|
|
615
|
+
* subsequent `Page.navigate` (and every command on this
|
|
616
|
+
* conversation thereafter) routes to the new tab instead of the
|
|
617
|
+
* currently-active tab.
|
|
618
|
+
*
|
|
619
|
+
* Behaviour by state:
|
|
620
|
+
* - Sticky backend already established → forward to
|
|
621
|
+
* `active.client.setCdpSessionId` if the underlying client
|
|
622
|
+
* implements it (extension does; local/cdp-inspect don't and
|
|
623
|
+
* the optional chain no-ops).
|
|
624
|
+
* - No sticky backend yet → stash the value; it gets applied
|
|
625
|
+
* in the `onEstablished` callback when the first send walks
|
|
626
|
+
* the candidate list.
|
|
627
|
+
*/
|
|
628
|
+
setCdpSessionId(cdpSessionId: string | undefined): void {
|
|
629
|
+
if (active?.client.setCdpSessionId) {
|
|
630
|
+
active.client.setCdpSessionId(cdpSessionId);
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
pendingCdpSessionId = cdpSessionId;
|
|
634
|
+
},
|
|
564
635
|
};
|
|
565
636
|
|
|
566
637
|
return scopedClient;
|
|
@@ -591,6 +662,7 @@ async function sendWithFailover<T>(
|
|
|
591
662
|
kind: CdpClientKind;
|
|
592
663
|
manager: BrowserSessionManager;
|
|
593
664
|
sessionId: string;
|
|
665
|
+
client: CdpClient;
|
|
594
666
|
}) => void,
|
|
595
667
|
isDisposed: () => boolean,
|
|
596
668
|
conversationId: string,
|
|
@@ -619,9 +691,16 @@ async function sendWithFailover<T>(
|
|
|
619
691
|
);
|
|
620
692
|
|
|
621
693
|
let backend: BrowserBackend;
|
|
694
|
+
let underlyingClient: CdpClient;
|
|
622
695
|
try {
|
|
623
696
|
const created = candidate.create();
|
|
624
697
|
backend = created.backend;
|
|
698
|
+
// Hold the underlying CdpClient so we can forward
|
|
699
|
+
// setCdpSessionId calls to it after the backend becomes
|
|
700
|
+
// sticky. Without this the scopedClient's setCdpSessionId
|
|
701
|
+
// method has no way to reach the materialised client (the
|
|
702
|
+
// BrowserSessionManager only exposes a send/dispose surface).
|
|
703
|
+
underlyingClient = created.client;
|
|
625
704
|
} catch (err) {
|
|
626
705
|
// Backend construction failed -- treat as transport error and
|
|
627
706
|
// try the next candidate.
|
|
@@ -810,7 +889,12 @@ async function sendWithFailover<T>(
|
|
|
810
889
|
{ conversationId, candidateKind: candidate.kind, method },
|
|
811
890
|
"CDP factory: candidate succeeded, backend is now sticky",
|
|
812
891
|
);
|
|
813
|
-
onEstablished({
|
|
892
|
+
onEstablished({
|
|
893
|
+
kind: candidate.kind,
|
|
894
|
+
manager,
|
|
895
|
+
sessionId: session.id,
|
|
896
|
+
client: underlyingClient,
|
|
897
|
+
});
|
|
814
898
|
return envelope.result as T;
|
|
815
899
|
}
|
|
816
900
|
|
|
@@ -156,6 +156,15 @@ export class LocalCdpClient implements ScopedCdpClient {
|
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
+
/**
|
|
160
|
+
* LocalCdpClient doesn't support re-targeting to a specific tab/session.
|
|
161
|
+
* The local Chromium instance manages all tabs globally, not per-client.
|
|
162
|
+
* This method is a no-op to satisfy the {@link ScopedCdpClient} interface.
|
|
163
|
+
*/
|
|
164
|
+
setCdpSessionId(): void {
|
|
165
|
+
// no-op
|
|
166
|
+
}
|
|
167
|
+
|
|
159
168
|
dispose(): void {
|
|
160
169
|
if (this.disposed) return;
|
|
161
170
|
this.disposed = true;
|
|
@@ -34,6 +34,25 @@ export interface CdpClient {
|
|
|
34
34
|
* is allowed but should surface as an error.
|
|
35
35
|
*/
|
|
36
36
|
dispose(): void;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Update the `cdpSessionId` used on subsequent {@link CdpClient.send}
|
|
40
|
+
* calls. Backends that don't multiplex commands across multiple
|
|
41
|
+
* targets (local Playwright, cdp-inspect) may implement this as a
|
|
42
|
+
* no-op. The extension backend uses this after opening a new tab
|
|
43
|
+
* (via the `Vellum.createTab` pseudo-CDP method) to route
|
|
44
|
+
* follow-on commands to the freshly-created tab instead of the
|
|
45
|
+
* currently-active one.
|
|
46
|
+
*
|
|
47
|
+
* Pass `undefined` to clear an existing pinned session and revert
|
|
48
|
+
* to default routing (i.e. dispatcher resolves the active tab).
|
|
49
|
+
* Used in the `Vellum.createTab` no-tabId fallback path to avoid
|
|
50
|
+
* sending follow-on commands to a stale/dead tab when the previous
|
|
51
|
+
* pin is no longer valid.
|
|
52
|
+
*
|
|
53
|
+
* Optional — callers should null-check before invoking.
|
|
54
|
+
*/
|
|
55
|
+
setCdpSessionId?(cdpSessionId: string | undefined): void;
|
|
37
56
|
}
|
|
38
57
|
|
|
39
58
|
/**
|
|
@@ -97,6 +116,23 @@ export interface ScopedCdpClient extends CdpClient {
|
|
|
97
116
|
readonly kind: CdpClientKind;
|
|
98
117
|
/** Stable conversation id this client is bound to. */
|
|
99
118
|
readonly conversationId: string;
|
|
119
|
+
/**
|
|
120
|
+
* Re-target follow-on CDP commands at a specific tab/target. Calling
|
|
121
|
+
* this updates the underlying client's `cdpSessionId`. This is used by
|
|
122
|
+
* the navigator executor after `Vellum.createTab` returns to ensure the
|
|
123
|
+
* subsequent `Page.navigate` and all follow-on commands on this
|
|
124
|
+
* conversation route to the newly-created tab instead of the
|
|
125
|
+
* previously-active tab.
|
|
126
|
+
*
|
|
127
|
+
* Pass `undefined` to clear an existing pinned session on the chained
|
|
128
|
+
* client and on the underlying client (if it supports the method).
|
|
129
|
+
* Used in the `Vellum.createTab` no-tabId fallback path.
|
|
130
|
+
*
|
|
131
|
+
* If the underlying client doesn't implement this method (e.g., local
|
|
132
|
+
* or cdp-inspect clients), the call is silently ignored via optional
|
|
133
|
+
* chaining.
|
|
134
|
+
*/
|
|
135
|
+
setCdpSessionId(cdpSessionId: string | undefined): void;
|
|
100
136
|
}
|
|
101
137
|
|
|
102
138
|
/**
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-conversation pinned-tab store for the Chrome extension browser
|
|
3
|
+
* backend.
|
|
4
|
+
*
|
|
5
|
+
* When a navigate is issued with `new_tab: true`, the executor first
|
|
6
|
+
* asks the extension to open a fresh tab (via the `Vellum.createTab`
|
|
7
|
+
* pseudo-CDP method), then records the returned tabId here against the
|
|
8
|
+
* conversation. Subsequent CDP commands constructed for the same
|
|
9
|
+
* conversation pick up this tabId as the `cdpSessionId` on the
|
|
10
|
+
* outgoing envelope, which causes the extension's
|
|
11
|
+
* `resolveHostBrowserTarget` to route to that specific tab instead of
|
|
12
|
+
* falling back to `chrome.tabs.query({ active: true })`.
|
|
13
|
+
*
|
|
14
|
+
* Persistence is process-lifetime (in-memory only). The daemon is a
|
|
15
|
+
* single process and all CLI invocations land in it via IPC, so a
|
|
16
|
+
* module-level Map is sufficient. A pin is cleared when the extension
|
|
17
|
+
* reports the underlying CDP target as invalidated (see
|
|
18
|
+
* `consumeInvalidatedTargetId` in `browser-session/events.ts`) — that
|
|
19
|
+
* eviction is wired through `BrowserSessionManager.invalidateByTargetId`
|
|
20
|
+
* and the host-browser session-invalidated event route.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { log } from "../../cli/logger.js";
|
|
24
|
+
|
|
25
|
+
const pinnedTabs = new Map<string, string>();
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Record a tabId as the pinned tab for the given conversation. The
|
|
29
|
+
* tabId is stored as a string because it travels on the wire as
|
|
30
|
+
* `cdpSessionId` (a string-typed field on the host-browser envelope).
|
|
31
|
+
*/
|
|
32
|
+
export function setPinnedTab(conversationId: string, tabId: string): void {
|
|
33
|
+
if (!conversationId || !tabId) return;
|
|
34
|
+
pinnedTabs.set(conversationId, tabId);
|
|
35
|
+
log.debug(
|
|
36
|
+
{ conversationId, tabId },
|
|
37
|
+
"Pinned extension tab for conversation",
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Return the tabId pinned to the given conversation, or undefined if
|
|
43
|
+
* no pin exists.
|
|
44
|
+
*/
|
|
45
|
+
export function getPinnedTab(conversationId: string): string | undefined {
|
|
46
|
+
if (!conversationId) return undefined;
|
|
47
|
+
return pinnedTabs.get(conversationId);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Clear the pin for the given conversation. Idempotent — clearing a
|
|
52
|
+
* non-existent pin is a no-op.
|
|
53
|
+
*/
|
|
54
|
+
export function clearPinnedTab(conversationId: string): void {
|
|
55
|
+
if (!conversationId) return;
|
|
56
|
+
if (pinnedTabs.delete(conversationId)) {
|
|
57
|
+
log.debug({ conversationId }, "Cleared pinned extension tab");
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Clear every pin pointing at a given tabId across all conversations.
|
|
63
|
+
* Used when the extension reports a target as invalidated (tab closed,
|
|
64
|
+
* crashed, navigated away from a debuggable URL, etc.) so we don't
|
|
65
|
+
* keep routing to a dead tab.
|
|
66
|
+
*
|
|
67
|
+
* Returns the number of conversations whose pin was cleared.
|
|
68
|
+
*/
|
|
69
|
+
export function clearPinnedTabByTabId(tabId: string): number {
|
|
70
|
+
if (!tabId) return 0;
|
|
71
|
+
let cleared = 0;
|
|
72
|
+
for (const [conversationId, pinned] of pinnedTabs.entries()) {
|
|
73
|
+
if (pinned === tabId) {
|
|
74
|
+
pinnedTabs.delete(conversationId);
|
|
75
|
+
cleared++;
|
|
76
|
+
log.debug(
|
|
77
|
+
{ conversationId, tabId },
|
|
78
|
+
"Cleared pinned extension tab due to invalidation",
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return cleared;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Reset the entire pin store. Test-only.
|
|
87
|
+
*/
|
|
88
|
+
export function __resetPinnedTabsForTests(): void {
|
|
89
|
+
pinnedTabs.clear();
|
|
90
|
+
}
|