@vellumai/assistant 0.8.3 → 0.8.5
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 +2 -2
- package/docker-entrypoint.sh +0 -1
- package/docs/browser-use-architecture-phase2.md +1 -1
- package/knip.json +2 -1
- package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
- package/openapi.yaml +1492 -100
- package/package.json +1 -1
- package/src/__tests__/agent-loop-exit-reason.test.ts +4 -5
- package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
- package/src/__tests__/agent-loop.test.ts +88 -3
- package/src/__tests__/anthropic-provider.test.ts +302 -33
- package/src/__tests__/approval-cascade.test.ts +1 -1
- package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +3 -3
- package/src/__tests__/audit-log-rotation.test.ts +70 -16
- package/src/__tests__/background-workers-disk-pressure.test.ts +4 -3
- package/src/__tests__/btw-routes.test.ts +2 -3
- package/src/__tests__/call-controller.test.ts +0 -1
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
- package/src/__tests__/channel-delivery-store.test.ts +193 -0
- package/src/__tests__/channel-guardian.test.ts +3 -3
- package/src/__tests__/channel-reply-delivery.test.ts +284 -5
- package/src/__tests__/channel-retry-sweep.test.ts +274 -1
- package/src/__tests__/checker.test.ts +6 -15
- package/src/__tests__/compaction-events.test.ts +2 -1
- package/src/__tests__/compactor-call-site-logging.test.ts +214 -0
- package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +5 -11
- package/src/__tests__/computer-use-tools.test.ts +2 -4
- package/src/__tests__/config-watcher.test.ts +1 -1
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
- package/src/__tests__/context-token-estimator.test.ts +91 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +55 -4
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +228 -8
- package/src/__tests__/conversation-agent-loop.test.ts +188 -129
- package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -5
- 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-clear-safety.test.ts +25 -25
- package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
- package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
- package/src/__tests__/conversation-error.test.ts +31 -0
- package/src/__tests__/conversation-fork-crud.test.ts +324 -0
- package/src/__tests__/conversation-lifecycle.test.ts +53 -12
- package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
- package/src/__tests__/conversation-load-history-stripped.test.ts +279 -0
- 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 +2 -1
- package/src/__tests__/conversation-queue.test.ts +1 -1
- package/src/__tests__/conversation-routes-disk-view.test.ts +109 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +35 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +264 -81
- package/src/__tests__/conversation-seed-composer.test.ts +66 -4
- package/src/__tests__/conversation-skill-tools.test.ts +2 -5
- 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-store.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
- package/src/__tests__/conversation-sync-tags.test.ts +99 -32
- package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -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-execution-feature-gates.test.ts +9 -7
- package/src/__tests__/credential-execution-tools.test.ts +6 -6
- package/src/__tests__/credential-security-invariants.test.ts +7 -0
- package/src/__tests__/credential-vault-unit.test.ts +2 -2
- package/src/__tests__/cu-unified-flow.test.ts +10 -1
- 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__/dynamic-page-surface.test.ts +2 -2
- package/src/__tests__/email-html-renderer.test.ts +12 -0
- package/src/__tests__/first-greeting.test.ts +23 -2
- package/src/__tests__/gateway-flag-listener.test.ts +237 -0
- package/src/__tests__/gemini-provider.test.ts +78 -0
- package/src/__tests__/guardian-dispatch.test.ts +0 -1
- package/src/__tests__/guardian-outbound-http.test.ts +7 -5
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/headless-browser-navigate.test.ts +172 -0
- package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
- package/src/__tests__/heartbeat-service.test.ts +4 -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-shell-tool.test.ts +1 -1
- 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__/init-feature-flag-overrides.test.ts +5 -6
- package/src/__tests__/injector-chain.test.ts +2 -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__/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 +77 -17
- package/src/__tests__/llm-context-normalization.test.ts +0 -2
- package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
- package/src/__tests__/llm-resolver.test.ts +161 -9
- package/src/__tests__/llm-usage-store.test.ts +66 -0
- package/src/__tests__/log-export-routes.test.ts +99 -2
- package/src/__tests__/logger.test.ts +89 -0
- package/src/__tests__/mcp-abort-signal.test.ts +2 -2
- package/src/__tests__/media-generate-image.test.ts +31 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
- package/src/__tests__/message-queue-steer.test.ts +114 -0
- package/src/__tests__/model-intents.test.ts +2 -4
- package/src/__tests__/notification-guardian-path.test.ts +0 -1
- package/src/__tests__/onboarding-template-contract.test.ts +1 -1
- package/src/__tests__/openai-provider.test.ts +151 -0
- package/src/__tests__/openai-responses-provider.test.ts +118 -16
- package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
- package/src/__tests__/pending-interactions-resolved-event.test.ts +189 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
- package/src/__tests__/platform.test.ts +2 -5
- package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
- package/src/__tests__/plugin-bootstrap.test.ts +2 -2
- package/src/__tests__/plugin-source-watcher.test.ts +302 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +13 -6
- package/src/__tests__/plugin-types.test.ts +3 -2
- package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
- package/src/__tests__/pricing.test.ts +12 -0
- 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__/prune-jobs-changes-parser.test.ts +61 -0
- package/src/__tests__/registry.test.ts +2 -8
- package/src/__tests__/require-fresh-approval.test.ts +2 -2
- package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
- package/src/__tests__/server-history-render.test.ts +83 -4
- package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/skill-projection-feature-flag.test.ts +4 -7
- package/src/__tests__/skill-projection.benchmark.test.ts +2 -6
- package/src/__tests__/skill-tool-factory.test.ts +1 -1
- package/src/__tests__/steer-tool-repair.test.ts +249 -0
- package/src/__tests__/subagent-notify-parent.test.ts +1 -1
- package/src/__tests__/suggestion-routes.test.ts +1 -0
- package/src/__tests__/sync-message-contract.test.ts +59 -0
- package/src/__tests__/system-prompt.test.ts +161 -124
- package/src/__tests__/terminal-tools.test.ts +12 -2
- package/src/__tests__/thinking-block-replay.test.ts +113 -0
- package/src/__tests__/thread-backfill.test.ts +370 -22
- package/src/__tests__/tool-approval-handler.test.ts +1 -5
- package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +15 -5
- package/src/__tests__/tool-executor.test.ts +89 -53
- package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
- package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
- package/src/__tests__/twilio-routes.test.ts +1 -1
- package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
- package/src/__tests__/usage-routes.test.ts +3 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
- package/src/__tests__/web-fetch.test.ts +2 -2
- package/src/__tests__/workspace-git-service.test.ts +94 -10
- package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
- package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +146 -0
- package/src/acp/prepare-agent-env.ts +78 -0
- package/src/acp/session-manager.ts +1 -1
- package/src/agent/attachments.ts +1 -0
- package/src/agent/loop.ts +65 -20
- package/src/api/README.md +5 -0
- package/src/api/index.ts +4 -0
- package/src/api/package.json +10 -0
- package/src/background-wake/background-wake-routes.test.ts +233 -0
- package/src/background-wake/next-wake.test.ts +289 -0
- package/src/background-wake/next-wake.ts +172 -0
- package/src/background-wake/runtime-registry.ts +24 -0
- package/src/browser/operations.ts +15 -0
- package/src/cli/commands/__tests__/browser.test.ts +23 -5
- package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
- package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
- package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
- package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +10 -12
- package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
- package/src/cli/commands/browser.ts +247 -0
- package/src/cli/commands/conversations.ts +128 -1
- package/src/cli/commands/domain.ts +91 -41
- package/src/cli/commands/inference-providers.ts +147 -1
- package/src/cli/commands/inference.ts +93 -40
- package/src/cli/commands/memory-v2-compare-render.ts +115 -0
- package/src/cli/commands/memory-v2.ts +483 -0
- package/src/cli/commands/memory-v3-render.ts +344 -0
- package/src/cli/commands/memory-v3.ts +316 -0
- package/src/cli/commands/notifications.ts +24 -2
- package/src/cli/program.ts +2 -0
- package/src/cli/utils/conversation-id.ts +17 -5
- package/src/config/assistant-feature-flags.ts +21 -9
- package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
- package/src/config/bundled-skills/document-editor/SKILL.md +124 -0
- package/src/config/bundled-skills/document-editor/TOOLS.json +258 -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-open.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
- package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
- package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
- package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
- package/src/config/bundled-skills/schedule/SKILL.md +8 -0
- package/src/config/bundled-tool-registry.ts +24 -12
- package/src/config/call-site-defaults.ts +20 -0
- package/src/config/feature-flag-registry.json +115 -3
- package/src/config/llm-resolver.ts +16 -2
- package/src/config/schemas/__tests__/memory-v2.test.ts +217 -1
- package/src/config/schemas/call-site-catalog.ts +35 -0
- package/src/config/schemas/llm.ts +14 -0
- package/src/config/schemas/memory-v2.ts +294 -1
- package/src/config/schemas/memory.ts +2 -1
- package/src/context/compactor.ts +60 -1
- package/src/context/token-estimator.ts +47 -4
- package/src/context/window-manager.ts +25 -0
- package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
- package/src/conversations/message-consolidation.ts +404 -0
- package/src/credential-health/credential-health-service.ts +34 -19
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -1
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +1 -1
- 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 +155 -36
- package/src/daemon/conversation-agent-loop.ts +307 -88
- package/src/daemon/conversation-error.ts +31 -1
- package/src/daemon/conversation-lifecycle.ts +149 -118
- 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 +145 -84
- package/src/daemon/conversation-slash.ts +37 -5
- package/src/daemon/conversation-surfaces.ts +45 -2
- package/src/daemon/conversation-tool-setup.ts +70 -3
- package/src/daemon/conversation-usage.ts +2 -0
- package/src/daemon/conversation.ts +54 -32
- package/src/daemon/disk-pressure-guard.ts +14 -2
- package/src/daemon/first-greeting.ts +10 -0
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
- package/src/daemon/handlers/config-a2a.ts +160 -0
- package/src/daemon/handlers/config-model.test.ts +2 -0
- package/src/daemon/handlers/conversations.ts +90 -3
- package/src/daemon/handlers/shared.ts +92 -29
- package/src/daemon/host-bash-proxy.ts +1 -1
- package/src/daemon/host-browser-proxy.ts +5 -5
- package/src/daemon/host-cu-proxy.ts +5 -5
- package/src/daemon/host-file-proxy.ts +5 -5
- package/src/daemon/host-proxy-base.ts +4 -4
- package/src/daemon/host-transfer-proxy.ts +11 -11
- package/src/daemon/lifecycle.ts +40 -23
- package/src/daemon/meet-manifest-loader.ts +1 -7
- package/src/daemon/message-protocol.ts +4 -0
- package/src/daemon/message-types/conversations.ts +14 -9
- package/src/daemon/message-types/document-comments.ts +50 -0
- package/src/daemon/message-types/home.ts +1 -13
- package/src/daemon/message-types/messages.ts +66 -7
- package/src/daemon/message-types/surfaces.ts +3 -1
- package/src/daemon/message-types/sync.ts +14 -0
- package/src/daemon/message-types/web-activity.ts +57 -0
- package/src/daemon/plugin-source-watcher.ts +135 -3
- package/src/daemon/process-message.ts +69 -12
- package/src/daemon/shutdown-handlers.ts +24 -5
- package/src/daemon/switch-inference-profile-tool.ts +52 -0
- package/src/daemon/tool-setup-types.ts +13 -0
- package/src/daemon/trust-context.ts +6 -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/events/relationship-state-updated.ts +25 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -2
- package/src/heartbeat/heartbeat-service.ts +1 -0
- package/src/home/__tests__/suggested-prompts.test.ts +33 -2
- package/src/home/feed-types.ts +6 -1
- package/src/home/home-content-refresh.ts +52 -0
- package/src/home/home-greeting-cache.ts +69 -0
- package/src/home/home-greeting.ts +85 -0
- package/src/home/suggested-prompts.ts +168 -9
- package/src/ipc/gateway-flag-listener.ts +123 -0
- package/src/ipc/skill-routes/registries.ts +8 -12
- package/src/memory/__tests__/db-async-query.test.ts +165 -0
- package/src/memory/__tests__/db-maintenance.test.ts +115 -0
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +241 -0
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
- package/src/memory/__tests__/memory-retrospective-job.test.ts +327 -6
- package/src/memory/auto-analysis-enqueue.ts +5 -1
- package/src/memory/conversation-crud.ts +191 -100
- package/src/memory/conversation-starters-cadence.ts +3 -1
- package/src/memory/conversation-title-service.ts +19 -3
- package/src/memory/db-async-query.ts +214 -0
- package/src/memory/db-init.ts +26 -0
- package/src/memory/db-maintenance.ts +30 -21
- 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/bootstrap.ts +8 -1
- package/src/memory/graph/capability-seed.ts +7 -3
- package/src/memory/graph/conversation-graph-memory.ts +100 -17
- package/src/memory/graph/extraction.ts +1 -5
- package/src/memory/graph/graph-search.ts +7 -1
- package/src/memory/indexer.ts +28 -18
- package/src/memory/job-handlers/cleanup.ts +76 -18
- package/src/memory/job-handlers/conversation-starters.ts +1 -4
- package/src/memory/jobs/embed-pkb-file.ts +6 -1
- package/src/memory/jobs-store.ts +14 -0
- package/src/memory/jobs-worker.ts +68 -15
- package/src/memory/llm-request-log-source-clickhouse.ts +42 -2
- package/src/memory/llm-request-log-source-local.ts +7 -0
- package/src/memory/llm-request-log-source.ts +9 -2
- package/src/memory/llm-request-log-store.ts +43 -1
- package/src/memory/llm-usage-store.ts +24 -0
- package/src/memory/memory-retrospective-constants.ts +28 -0
- package/src/memory/memory-retrospective-enqueue.ts +11 -3
- package/src/memory/memory-retrospective-job.ts +413 -18
- package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
- package/src/memory/memory-v2-activation-log-store.ts +41 -14
- 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/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/260-rename-cleaned-at.ts +44 -0
- package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
- package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
- package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
- package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
- package/src/memory/migrations/index.ts +34 -0
- package/src/memory/migrations/registry.ts +58 -0
- package/src/memory/onboarding-events-store.ts +7 -0
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/conversations.ts +3 -0
- package/src/memory/schema/infrastructure.ts +22 -0
- package/src/memory/tool-usage-store.ts +36 -8
- package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
- package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
- package/src/memory/v2/__tests__/harness-metrics.test.ts +74 -0
- package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +225 -0
- package/src/memory/v2/__tests__/harness-runner.test.ts +109 -0
- package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
- package/src/memory/v2/__tests__/injection.test.ts +158 -112
- package/src/memory/v2/__tests__/page-index.test.ts +365 -1
- package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
- package/src/memory/v2/__tests__/router.test.ts +660 -4
- package/src/memory/v2/consolidation-job.ts +14 -0
- package/src/memory/v2/harness/compare.ts +57 -0
- package/src/memory/v2/harness/metrics.ts +124 -0
- package/src/memory/v2/harness/oracle.ts +145 -0
- package/src/memory/v2/harness/replay-input.ts +224 -0
- package/src/memory/v2/harness/retriever.ts +74 -0
- package/src/memory/v2/harness/router-retriever.ts +43 -0
- package/src/memory/v2/harness/runner.ts +106 -0
- package/src/memory/v2/harness/trace.ts +58 -0
- package/src/memory/v2/injection-events.ts +101 -0
- package/src/memory/v2/injection.ts +42 -25
- package/src/memory/v2/page-index.ts +209 -7
- package/src/memory/v2/page-store.ts +18 -0
- package/src/memory/v2/prompts/router.ts +26 -1
- package/src/memory/v2/qdrant.ts +14 -2
- package/src/memory/v2/router.ts +369 -62
- package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
- package/src/memory/v3/__tests__/consolidation-job.test.ts +468 -0
- package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
- package/src/memory/v3/__tests__/edges.test.ts +563 -0
- package/src/memory/v3/__tests__/filter.test.ts +512 -0
- package/src/memory/v3/__tests__/gate.test.ts +574 -0
- package/src/memory/v3/__tests__/index-composition.test.ts +233 -0
- package/src/memory/v3/__tests__/loop.test.ts +530 -0
- package/src/memory/v3/__tests__/retriever.test.ts +226 -0
- package/src/memory/v3/__tests__/scouts.test.ts +440 -0
- package/src/memory/v3/__tests__/shadow-middleware.test.ts +312 -0
- package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
- package/src/memory/v3/__tests__/traversal.test.ts +469 -0
- package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
- package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
- package/src/memory/v3/__tests__/tree-walk.test.ts +707 -0
- package/src/memory/v3/__tests__/validate.test.ts +245 -0
- package/src/memory/v3/auto-edges.ts +223 -0
- package/src/memory/v3/coactivation-store.ts +124 -0
- package/src/memory/v3/consolidation-job.ts +323 -0
- package/src/memory/v3/edge-learning-job.ts +160 -0
- package/src/memory/v3/edges.ts +249 -0
- package/src/memory/v3/filter.ts +281 -0
- package/src/memory/v3/gate.ts +334 -0
- package/src/memory/v3/index-composition.ts +113 -0
- package/src/memory/v3/llm-capture.ts +46 -0
- package/src/memory/v3/loop.ts +382 -0
- package/src/memory/v3/maintenance.ts +144 -0
- package/src/memory/v3/prompt-context.ts +33 -0
- package/src/memory/v3/prompts/consolidation.ts +458 -0
- package/src/memory/v3/prompts/system-prompts.ts +196 -0
- package/src/memory/v3/retriever.ts +33 -0
- package/src/memory/v3/scouts.ts +420 -0
- package/src/memory/v3/shadow-middleware.ts +305 -0
- package/src/memory/v3/traversal.ts +206 -0
- package/src/memory/v3/tree-index.ts +237 -0
- package/src/memory/v3/tree-store.ts +394 -0
- package/src/memory/v3/tree-walk.ts +351 -0
- package/src/memory/v3/types.ts +65 -0
- package/src/memory/v3/validate.ts +300 -0
- package/src/messaging/providers/index.ts +7 -1
- 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__/emit-signal-home-feed.test.ts +4 -1
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +116 -54
- package/src/notifications/adapters/macos.ts +18 -1
- package/src/notifications/adapters/platform.ts +1 -1
- package/src/notifications/conversation-seed-composer.ts +14 -2
- package/src/notifications/decision-engine.ts +1 -4
- package/src/notifications/deferred-emit.ts +135 -0
- package/src/notifications/emit-signal.ts +38 -50
- package/src/notifications/home-feed-side-effect.ts +60 -30
- 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/seed-providers.ts +22 -0
- package/src/permissions/prompter.ts +8 -5
- package/src/permissions/question-prompter.ts +5 -2
- package/src/permissions/secret-prompter.ts +6 -3
- package/src/plugin-api/index.ts +4 -0
- package/src/plugin-api/types.ts +7 -33
- package/src/plugins/defaults/index.ts +6 -0
- package/src/plugins/defaults/injectors.ts +100 -20
- package/src/plugins/external-plugin-loader.ts +5 -68
- package/src/plugins/types.ts +11 -16
- package/src/proactive-artifact/aux-message-injector.ts +17 -4
- package/src/prompts/__tests__/system-prompt.test.ts +46 -2
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
- package/src/prompts/normalize-onboarding.ts +40 -0
- package/src/prompts/persona-resolver.ts +36 -21
- package/src/prompts/sections.ts +69 -19
- package/src/prompts/system-prompt.ts +118 -216
- package/src/prompts/template-detection.ts +37 -0
- package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
- package/src/prompts/templates/BOOTSTRAP.md +10 -2
- package/src/prompts/templates/VOICE.md +3 -0
- package/src/prompts/templates/system-sections.ts +281 -9
- package/src/providers/__tests__/connection-model-compat.test.ts +234 -0
- package/src/providers/__tests__/retry-callsite.test.ts +85 -5
- package/src/providers/anthropic/client.ts +159 -66
- package/src/providers/call-site-routing.ts +14 -2
- package/src/providers/connection-model-compat.ts +38 -0
- package/src/providers/connection-resolution.ts +16 -2
- package/src/providers/fireworks/client.ts +20 -2
- package/src/providers/gemini/client.ts +49 -6
- 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/adapter-factory.ts +18 -1
- package/src/providers/inference/auth.ts +3 -3
- package/src/providers/inference/codex-token-refresh.ts +128 -0
- package/src/providers/inference/resolve-auth.ts +49 -6
- package/src/providers/minimax/client.ts +106 -0
- package/src/providers/model-catalog.ts +91 -1
- package/src/providers/model-intents.ts +1 -1
- package/src/providers/openai/chat-completions-provider.ts +63 -23
- package/src/providers/openai/codex-models.ts +18 -0
- package/src/providers/openai/responses-provider.ts +86 -23
- package/src/providers/openrouter/client.ts +5 -1
- package/src/providers/provider-send-message.ts +7 -1
- package/src/providers/retry.ts +34 -3
- package/src/providers/thinking-config.ts +26 -1
- package/src/providers/types.ts +25 -0
- package/src/providers/usage-tracking.ts +2 -0
- package/src/runtime/AGENTS.md +2 -2
- 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 +152 -56
- package/src/runtime/assistant-event-hub.ts +76 -6
- package/src/runtime/auth/route-policy.ts +43 -3
- package/src/runtime/background-job-runner.ts +26 -0
- package/src/runtime/btw-sidechain.ts +0 -6
- package/src/runtime/channel-reply-delivery.ts +182 -47
- package/src/runtime/channel-retry-sweep.ts +141 -16
- package/src/runtime/http-types.ts +7 -6
- package/src/runtime/migrations/vbundle-builder.ts +10 -3
- package/src/runtime/pending-interactions.ts +50 -8
- package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +161 -1
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +290 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -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/acp-routes.test.ts +255 -6
- package/src/runtime/routes/acp-routes.ts +8 -1
- package/src/runtime/routes/approval-routes.ts +4 -1
- package/src/runtime/routes/avatar-routes.ts +10 -10
- package/src/runtime/routes/background-wake-routes.ts +188 -0
- package/src/runtime/routes/browser-tabs-routes.ts +200 -0
- package/src/runtime/routes/btw-routes.ts +0 -6
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
- package/src/runtime/routes/content-source-routes.ts +78 -0
- package/src/runtime/routes/conversation-cli-routes.ts +147 -2
- package/src/runtime/routes/conversation-list-routes.ts +12 -4
- package/src/runtime/routes/conversation-management-routes.ts +77 -20
- package/src/runtime/routes/conversation-query-routes.ts +196 -31
- package/src/runtime/routes/conversation-routes.ts +472 -425
- package/src/runtime/routes/conversation-starter-routes.ts +6 -3
- package/src/runtime/routes/disk-pressure-routes.ts +1 -1
- package/src/runtime/routes/document-comments-routes.ts +287 -0
- package/src/runtime/routes/documents-routes.ts +33 -0
- package/src/runtime/routes/domain-routes.ts +60 -10
- package/src/runtime/routes/email-routes.ts +5 -2
- package/src/runtime/routes/events-routes.ts +54 -10
- package/src/runtime/routes/group-routes.ts +24 -8
- 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 +17 -2
- package/src/runtime/routes/host-cu-routes.ts +2 -2
- 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/acl-enforcement.ts +96 -3
- 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 +20 -4
- package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
- package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
- package/src/runtime/routes/inference-provider-connection-routes.ts +63 -7
- package/src/runtime/routes/integrations/a2a.ts +60 -1
- package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
- package/src/runtime/routes/log-export-routes.ts +39 -0
- package/src/runtime/routes/memory-item-routes.ts +8 -3
- package/src/runtime/routes/memory-v2-routes.ts +427 -0
- package/src/runtime/routes/memory-v3-routes.ts +316 -0
- package/src/runtime/routes/migration-routes.ts +21 -24
- package/src/runtime/routes/notification-routes.ts +19 -2
- package/src/runtime/routes/plugins-routes.ts +337 -0
- package/src/runtime/routes/question-routes.ts +4 -1
- package/src/runtime/routes/rename-conversation-routes.ts +6 -2
- package/src/runtime/routes/sanity-routes.ts +159 -0
- package/src/runtime/routes/secret-routes.ts +25 -5
- package/src/runtime/routes/settings-routes.ts +12 -11
- package/src/runtime/routes/slack-channel-routes.ts +188 -0
- package/src/runtime/routes/workspace-routes.ts +25 -10
- package/src/runtime/services/conversation-serializer.ts +30 -4
- package/src/runtime/sync/resource-sync-events.ts +106 -38
- package/src/runtime/sync/sync-publisher.test.ts +49 -0
- package/src/runtime/sync/sync-publisher.ts +2 -1
- package/src/runtime/verification-outbound-actions.ts +73 -1
- 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/telemetry/types.ts +12 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
- package/src/telemetry/usage-telemetry-reporter.ts +1 -0
- package/src/tools/acp/spawn.test.ts +119 -0
- package/src/tools/acp/spawn.ts +15 -2
- package/src/tools/apps/definitions.ts +2 -8
- package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
- package/src/tools/ask-question/ask-question-tool.ts +38 -45
- package/src/tools/browser/__tests__/pinned-tabs.test.ts +150 -0
- package/src/tools/browser/browser-execution.ts +106 -0
- package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +4 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +22 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +42 -2
- package/src/tools/browser/cdp-client/factory.ts +171 -4
- package/src/tools/browser/cdp-client/local-cdp-client.ts +21 -0
- package/src/tools/browser/cdp-client/types.ts +101 -0
- package/src/tools/browser/pinned-tabs.ts +146 -0
- package/src/tools/computer-use/definitions.ts +22 -78
- package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
- package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
- package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
- package/src/tools/credentials/vault.ts +3 -9
- 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 +187 -2
- package/src/tools/execution-target.ts +21 -23
- package/src/tools/executor.ts +6 -1
- package/src/tools/filesystem/edit.ts +3 -9
- package/src/tools/filesystem/list.ts +3 -9
- package/src/tools/filesystem/read.ts +3 -9
- package/src/tools/filesystem/write.ts +3 -9
- package/src/tools/host-filesystem/edit.ts +3 -9
- package/src/tools/host-filesystem/read.ts +3 -9
- package/src/tools/host-filesystem/transfer.ts +3 -9
- package/src/tools/host-filesystem/write.ts +3 -9
- package/src/tools/host-terminal/host-shell.ts +3 -9
- package/src/tools/mcp/mcp-tool-factory.ts +1 -8
- package/src/tools/memory/register.test.ts +1 -1
- package/src/tools/memory/register.ts +4 -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 +216 -73
- package/src/tools/network/web-search.ts +216 -98
- package/src/tools/registry.ts +7 -23
- package/src/tools/schema-transforms.ts +1 -1
- package/src/tools/skills/execute.ts +3 -9
- package/src/tools/skills/load.ts +3 -9
- package/src/tools/skills/skill-tool-factory.ts +1 -8
- package/src/tools/subagent/notify-parent.ts +3 -9
- package/src/tools/system/request-permission.ts +3 -9
- package/src/tools/terminal/safe-env.ts +3 -2
- package/src/tools/terminal/shell.ts +3 -9
- package/src/tools/tool-approval-handler.ts +19 -12
- package/src/tools/tool-defaults.ts +94 -0
- package/src/tools/types.ts +31 -98
- package/src/tools/ui-surface/definitions.ts +9 -23
- package/src/types/onboarding-context.ts +4 -0
- package/src/usage/pricing.ts +23 -0
- package/src/usage/types.ts +12 -0
- package/src/util/__tests__/favicon.test.ts +84 -0
- package/src/util/favicon.ts +40 -0
- package/src/util/logger.ts +16 -7
- package/src/util/platform.ts +7 -7
- package/src/util/sqlite3-runtime.ts +65 -0
- package/src/workspace/git-service.ts +75 -4
- package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
- package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
- package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
- package/src/__tests__/message-complete-display-id.test.ts +0 -175
- 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/prompts/cache-boundary.ts +0 -8
- 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
|
@@ -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";
|
|
@@ -22,6 +23,7 @@ import type {
|
|
|
22
23
|
CdpClient,
|
|
23
24
|
CdpClientKind,
|
|
24
25
|
ScopedCdpClient,
|
|
26
|
+
TabInfo,
|
|
25
27
|
} from "./types.js";
|
|
26
28
|
|
|
27
29
|
const log = getLogger("cdp-factory");
|
|
@@ -222,7 +224,12 @@ export function buildPinnedCandidateList(
|
|
|
222
224
|
const client = createExtensionCdpClient(
|
|
223
225
|
hostBrowserProxy,
|
|
224
226
|
conversationId,
|
|
225
|
-
|
|
227
|
+
// Pass clientId to scope the pin lookup to this specific
|
|
228
|
+
// extension install. When a targetClientId is provided
|
|
229
|
+
// the pin is fetched for that client; otherwise falls back
|
|
230
|
+
// to the __default__ slot which is set by older callers
|
|
231
|
+
// without clientId awareness.
|
|
232
|
+
getPinnedTab(conversationId, targetClientId),
|
|
226
233
|
sourceActorPrincipalId,
|
|
227
234
|
targetClientId,
|
|
228
235
|
);
|
|
@@ -330,10 +337,13 @@ export function buildCandidateList(context: ToolContext, targetClientId?: string
|
|
|
330
337
|
kind: "extension",
|
|
331
338
|
reason: `target_client_id override: ${targetClientId}`,
|
|
332
339
|
create() {
|
|
340
|
+
// Explicit target_client_id override → look up the pin scoped
|
|
341
|
+
// to this specific client. This is safe because targetClientId
|
|
342
|
+
// and the pin were both recorded for the same extension install.
|
|
333
343
|
const client = createExtensionCdpClient(
|
|
334
344
|
hostBrowserProxy,
|
|
335
345
|
conversationId,
|
|
336
|
-
|
|
346
|
+
getPinnedTab(conversationId, targetClientId),
|
|
337
347
|
sourceActorPrincipalId,
|
|
338
348
|
targetClientId,
|
|
339
349
|
);
|
|
@@ -358,7 +368,11 @@ export function buildCandidateList(context: ToolContext, targetClientId?: string
|
|
|
358
368
|
const client = createExtensionCdpClient(
|
|
359
369
|
hostBrowserProxy,
|
|
360
370
|
conversationId,
|
|
361
|
-
undefined
|
|
371
|
+
// targetClientId is always undefined here — this code path
|
|
372
|
+
// only runs when targetClientId is null (the early-return
|
|
373
|
+
// above handles the non-null case). Use the no-clientId
|
|
374
|
+
// lookup which returns the first pin for auto-routing.
|
|
375
|
+
getPinnedTab(conversationId),
|
|
362
376
|
sourceActorPrincipalId,
|
|
363
377
|
targetClientId,
|
|
364
378
|
);
|
|
@@ -484,6 +498,16 @@ export function buildChainedClient(
|
|
|
484
498
|
kind: CdpClientKind;
|
|
485
499
|
manager: BrowserSessionManager;
|
|
486
500
|
sessionId: string;
|
|
501
|
+
/**
|
|
502
|
+
* Reference to the underlying CdpClient (returned from
|
|
503
|
+
* `candidate.create()`). Held so callers can reach methods that
|
|
504
|
+
* aren't routed through `manager.send()` — specifically
|
|
505
|
+
* {@link CdpClient.setCdpSessionId}, which re-targets follow-on
|
|
506
|
+
* CDP commands at a specific tab/target. Without this we'd have
|
|
507
|
+
* no way to call setCdpSessionId on the materialised client
|
|
508
|
+
* since `backend` only exposes the send/dispose surface.
|
|
509
|
+
*/
|
|
510
|
+
client: CdpClient;
|
|
487
511
|
} | null = null;
|
|
488
512
|
|
|
489
513
|
/** Set to true after the first successful CDP command. */
|
|
@@ -491,6 +515,17 @@ export function buildChainedClient(
|
|
|
491
515
|
|
|
492
516
|
let disposed = false;
|
|
493
517
|
|
|
518
|
+
/**
|
|
519
|
+
* setCdpSessionId may be called BEFORE the first send (i.e. before
|
|
520
|
+
* `active` is populated). When that happens we stash the value
|
|
521
|
+
* here and apply it to `active.client` as soon as a backend becomes
|
|
522
|
+
* sticky. In the current --new-tab flow this can't trigger (the
|
|
523
|
+
* createTab send establishes sticky first, then setCdpSessionId is
|
|
524
|
+
* called), but supporting the pre-sticky case keeps the contract
|
|
525
|
+
* simple for future callers.
|
|
526
|
+
*/
|
|
527
|
+
let pendingCdpSessionId: string | undefined;
|
|
528
|
+
|
|
494
529
|
/**
|
|
495
530
|
* Track all materialised backends so dispose() can tear them all
|
|
496
531
|
* down, even ones that were tried and failed before the sticky
|
|
@@ -545,6 +580,16 @@ export function buildChainedClient(
|
|
|
545
580
|
active = established;
|
|
546
581
|
sticky = true;
|
|
547
582
|
currentKind = established.kind;
|
|
583
|
+
// Flush any pre-sticky setCdpSessionId call onto the
|
|
584
|
+
// freshly-materialised client. See pendingCdpSessionId
|
|
585
|
+
// comment above for why this exists.
|
|
586
|
+
if (
|
|
587
|
+
pendingCdpSessionId !== undefined &&
|
|
588
|
+
established.client.setCdpSessionId
|
|
589
|
+
) {
|
|
590
|
+
established.client.setCdpSessionId(pendingCdpSessionId);
|
|
591
|
+
pendingCdpSessionId = undefined;
|
|
592
|
+
}
|
|
548
593
|
},
|
|
549
594
|
() => disposed,
|
|
550
595
|
conversationId,
|
|
@@ -561,6 +606,115 @@ export function buildChainedClient(
|
|
|
561
606
|
materialisedManagers.length = 0;
|
|
562
607
|
active = null;
|
|
563
608
|
},
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* Re-target follow-on CDP commands at a specific tab/target by
|
|
612
|
+
* updating the underlying client's `cdpSessionId`. The navigate
|
|
613
|
+
* executor calls this after `Vellum.createTab` returns so the
|
|
614
|
+
* subsequent `Page.navigate` (and every command on this
|
|
615
|
+
* conversation thereafter) routes to the new tab instead of the
|
|
616
|
+
* currently-active tab.
|
|
617
|
+
*
|
|
618
|
+
* Behaviour by state:
|
|
619
|
+
* - Sticky backend already established → forward to
|
|
620
|
+
* `active.client.setCdpSessionId` if the underlying client
|
|
621
|
+
* implements it (extension does; local/cdp-inspect don't and
|
|
622
|
+
* the optional chain no-ops).
|
|
623
|
+
* - No sticky backend yet → stash the value; it gets applied
|
|
624
|
+
* in the `onEstablished` callback when the first send walks
|
|
625
|
+
* the candidate list.
|
|
626
|
+
*/
|
|
627
|
+
setCdpSessionId(cdpSessionId: string | undefined): void {
|
|
628
|
+
if (active?.client.setCdpSessionId) {
|
|
629
|
+
active.client.setCdpSessionId(cdpSessionId);
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
pendingCdpSessionId = cdpSessionId;
|
|
633
|
+
},
|
|
634
|
+
|
|
635
|
+
async listTabs(): Promise<TabInfo[]> {
|
|
636
|
+
if (sticky && active?.client.listTabs) {
|
|
637
|
+
return active.client.listTabs();
|
|
638
|
+
}
|
|
639
|
+
if (sticky) {
|
|
640
|
+
throw new CdpError(
|
|
641
|
+
"transport_error",
|
|
642
|
+
"listTabs is not supported by the current backend (extension backend required)",
|
|
643
|
+
);
|
|
644
|
+
}
|
|
645
|
+
// Fresh client: route through the failover walk so the extension
|
|
646
|
+
// backend is selected automatically. The Vellum.listTabs pseudo-method
|
|
647
|
+
// is handled by the extension dispatcher before chrome.debugger.sendCommand.
|
|
648
|
+
const result = await scopedClient.send<{ tabs?: TabInfo[] }>("Vellum.listTabs", {});
|
|
649
|
+
if (!active?.client.listTabs) {
|
|
650
|
+
// Backend became sticky but isn't an extension client — not supported.
|
|
651
|
+
throw new CdpError(
|
|
652
|
+
"transport_error",
|
|
653
|
+
"listTabs is not supported by the current backend (extension backend required)",
|
|
654
|
+
);
|
|
655
|
+
}
|
|
656
|
+
return Array.isArray(result?.tabs) ? result.tabs : [];
|
|
657
|
+
},
|
|
658
|
+
|
|
659
|
+
async selectTab(tabId: number): Promise<{
|
|
660
|
+
tabId?: number;
|
|
661
|
+
windowId?: number;
|
|
662
|
+
url?: string;
|
|
663
|
+
title?: string;
|
|
664
|
+
clientId?: string;
|
|
665
|
+
}> {
|
|
666
|
+
if (sticky && active?.client.selectTab) {
|
|
667
|
+
return active.client.selectTab(tabId);
|
|
668
|
+
}
|
|
669
|
+
if (sticky) {
|
|
670
|
+
throw new CdpError(
|
|
671
|
+
"transport_error",
|
|
672
|
+
"selectTab is not supported by the current backend (extension backend required)",
|
|
673
|
+
);
|
|
674
|
+
}
|
|
675
|
+
const result = await scopedClient.send<{
|
|
676
|
+
tabId?: number;
|
|
677
|
+
windowId?: number;
|
|
678
|
+
url?: string;
|
|
679
|
+
title?: string;
|
|
680
|
+
clientId?: string;
|
|
681
|
+
}>("Vellum.selectTab", { tabId });
|
|
682
|
+
if (!active?.client.selectTab) {
|
|
683
|
+
throw new CdpError(
|
|
684
|
+
"transport_error",
|
|
685
|
+
"selectTab is not supported by the current backend (extension backend required)",
|
|
686
|
+
);
|
|
687
|
+
}
|
|
688
|
+
return result;
|
|
689
|
+
},
|
|
690
|
+
|
|
691
|
+
async closeTab(tabId: number): Promise<{
|
|
692
|
+
closed: boolean;
|
|
693
|
+
tabId: number;
|
|
694
|
+
clientId?: string;
|
|
695
|
+
}> {
|
|
696
|
+
if (sticky && active?.client.closeTab) {
|
|
697
|
+
return active.client.closeTab(tabId);
|
|
698
|
+
}
|
|
699
|
+
if (sticky) {
|
|
700
|
+
throw new CdpError(
|
|
701
|
+
"transport_error",
|
|
702
|
+
"closeTab is not supported by the current backend (extension backend required)",
|
|
703
|
+
);
|
|
704
|
+
}
|
|
705
|
+
const result = await scopedClient.send<{
|
|
706
|
+
closed: boolean;
|
|
707
|
+
tabId: number;
|
|
708
|
+
clientId?: string;
|
|
709
|
+
}>("Vellum.closeTab", { tabId });
|
|
710
|
+
if (!active?.client.closeTab) {
|
|
711
|
+
throw new CdpError(
|
|
712
|
+
"transport_error",
|
|
713
|
+
"closeTab is not supported by the current backend (extension backend required)",
|
|
714
|
+
);
|
|
715
|
+
}
|
|
716
|
+
return result;
|
|
717
|
+
},
|
|
564
718
|
};
|
|
565
719
|
|
|
566
720
|
return scopedClient;
|
|
@@ -591,6 +745,7 @@ async function sendWithFailover<T>(
|
|
|
591
745
|
kind: CdpClientKind;
|
|
592
746
|
manager: BrowserSessionManager;
|
|
593
747
|
sessionId: string;
|
|
748
|
+
client: CdpClient;
|
|
594
749
|
}) => void,
|
|
595
750
|
isDisposed: () => boolean,
|
|
596
751
|
conversationId: string,
|
|
@@ -619,9 +774,16 @@ async function sendWithFailover<T>(
|
|
|
619
774
|
);
|
|
620
775
|
|
|
621
776
|
let backend: BrowserBackend;
|
|
777
|
+
let underlyingClient: CdpClient;
|
|
622
778
|
try {
|
|
623
779
|
const created = candidate.create();
|
|
624
780
|
backend = created.backend;
|
|
781
|
+
// Hold the underlying CdpClient so we can forward
|
|
782
|
+
// setCdpSessionId calls to it after the backend becomes
|
|
783
|
+
// sticky. Without this the scopedClient's setCdpSessionId
|
|
784
|
+
// method has no way to reach the materialised client (the
|
|
785
|
+
// BrowserSessionManager only exposes a send/dispose surface).
|
|
786
|
+
underlyingClient = created.client;
|
|
625
787
|
} catch (err) {
|
|
626
788
|
// Backend construction failed -- treat as transport error and
|
|
627
789
|
// try the next candidate.
|
|
@@ -810,7 +972,12 @@ async function sendWithFailover<T>(
|
|
|
810
972
|
{ conversationId, candidateKind: candidate.kind, method },
|
|
811
973
|
"CDP factory: candidate succeeded, backend is now sticky",
|
|
812
974
|
);
|
|
813
|
-
onEstablished({
|
|
975
|
+
onEstablished({
|
|
976
|
+
kind: candidate.kind,
|
|
977
|
+
manager,
|
|
978
|
+
sessionId: session.id,
|
|
979
|
+
client: underlyingClient,
|
|
980
|
+
});
|
|
814
981
|
return envelope.result as T;
|
|
815
982
|
}
|
|
816
983
|
|
|
@@ -156,6 +156,27 @@ 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
|
+
|
|
168
|
+
async listTabs(): Promise<never> {
|
|
169
|
+
throw new CdpError("transport_error", "listTabs is not supported by the local backend (extension backend required)");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async selectTab(_tabId: number): Promise<never> {
|
|
173
|
+
throw new CdpError("transport_error", "selectTab is not supported by the local backend (extension backend required)");
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async closeTab(_tabId: number): Promise<never> {
|
|
177
|
+
throw new CdpError("transport_error", "closeTab is not supported by the local backend (extension backend required)");
|
|
178
|
+
}
|
|
179
|
+
|
|
159
180
|
dispose(): void {
|
|
160
181
|
if (this.disposed) return;
|
|
161
182
|
this.disposed = true;
|
|
@@ -10,6 +10,16 @@
|
|
|
10
10
|
|
|
11
11
|
import type { BrowserBackend } from "../../../browser-session/types.js";
|
|
12
12
|
|
|
13
|
+
/** Shape of a single Chrome tab as returned by Vellum.listTabs. */
|
|
14
|
+
export interface TabInfo {
|
|
15
|
+
tabId?: number;
|
|
16
|
+
windowId?: number;
|
|
17
|
+
url?: string;
|
|
18
|
+
title?: string;
|
|
19
|
+
active: boolean;
|
|
20
|
+
pinned: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
13
23
|
export interface CdpClient {
|
|
14
24
|
/**
|
|
15
25
|
* Send a CDP command and await the result. `method` must be a
|
|
@@ -34,6 +44,52 @@ export interface CdpClient {
|
|
|
34
44
|
* is allowed but should surface as an error.
|
|
35
45
|
*/
|
|
36
46
|
dispose(): void;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Update the `cdpSessionId` used on subsequent {@link CdpClient.send}
|
|
50
|
+
* calls. Backends that don't multiplex commands across multiple
|
|
51
|
+
* targets (local Playwright, cdp-inspect) may implement this as a
|
|
52
|
+
* no-op. The extension backend uses this after opening a new tab
|
|
53
|
+
* (via the `Vellum.createTab` pseudo-CDP method) to route
|
|
54
|
+
* follow-on commands to the freshly-created tab instead of the
|
|
55
|
+
* currently-active one.
|
|
56
|
+
*
|
|
57
|
+
* Pass `undefined` to clear an existing pinned session and revert
|
|
58
|
+
* to default routing (i.e. dispatcher resolves the active tab).
|
|
59
|
+
* Used in the `Vellum.createTab` no-tabId fallback path to avoid
|
|
60
|
+
* sending follow-on commands to a stale/dead tab when the previous
|
|
61
|
+
* pin is no longer valid.
|
|
62
|
+
*
|
|
63
|
+
* Optional — callers should null-check before invoking.
|
|
64
|
+
*/
|
|
65
|
+
setCdpSessionId?(cdpSessionId: string | undefined): void;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* List all open browser tabs. Extension backend only — returns
|
|
69
|
+
* `{ tabId, windowId, url, title, active, pinned }[]`.
|
|
70
|
+
* Optional — callers must null-check before invoking.
|
|
71
|
+
*/
|
|
72
|
+
listTabs?(): Promise<TabInfo[]>;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Select (activate) an existing tab. Extension backend only. Optional.
|
|
76
|
+
*/
|
|
77
|
+
selectTab?(tabId: number): Promise<{
|
|
78
|
+
tabId?: number;
|
|
79
|
+
windowId?: number;
|
|
80
|
+
url?: string;
|
|
81
|
+
title?: string;
|
|
82
|
+
clientId?: string;
|
|
83
|
+
}>;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Close a browser tab by ID. Extension backend only. Optional.
|
|
87
|
+
*/
|
|
88
|
+
closeTab?(tabId: number): Promise<{
|
|
89
|
+
closed: boolean;
|
|
90
|
+
tabId: number;
|
|
91
|
+
clientId?: string;
|
|
92
|
+
}>;
|
|
37
93
|
}
|
|
38
94
|
|
|
39
95
|
/**
|
|
@@ -97,6 +153,51 @@ export interface ScopedCdpClient extends CdpClient {
|
|
|
97
153
|
readonly kind: CdpClientKind;
|
|
98
154
|
/** Stable conversation id this client is bound to. */
|
|
99
155
|
readonly conversationId: string;
|
|
156
|
+
/**
|
|
157
|
+
* Re-target follow-on CDP commands at a specific tab/target. Calling
|
|
158
|
+
* this updates the underlying client's `cdpSessionId`. This is used by
|
|
159
|
+
* the navigator executor after `Vellum.createTab` returns to ensure the
|
|
160
|
+
* subsequent `Page.navigate` and all follow-on commands on this
|
|
161
|
+
* conversation route to the newly-created tab instead of the
|
|
162
|
+
* previously-active tab.
|
|
163
|
+
*
|
|
164
|
+
* Pass `undefined` to clear an existing pinned session on the chained
|
|
165
|
+
* client and on the underlying client (if it supports the method).
|
|
166
|
+
* Used in the `Vellum.createTab` no-tabId fallback path.
|
|
167
|
+
*
|
|
168
|
+
* If the underlying client doesn't implement this method (e.g., local
|
|
169
|
+
* or cdp-inspect clients), the call is silently ignored via optional
|
|
170
|
+
* chaining.
|
|
171
|
+
*/
|
|
172
|
+
setCdpSessionId(cdpSessionId: string | undefined): void;
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* List all open browser tabs. Throws with code "transport_error" if
|
|
176
|
+
* the current backend does not support tab listing.
|
|
177
|
+
*/
|
|
178
|
+
listTabs(): Promise<TabInfo[]>;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Select (activate) an existing tab. Throws if backend doesn't support it.
|
|
182
|
+
*/
|
|
183
|
+
selectTab(tabId: number): Promise<{
|
|
184
|
+
tabId?: number;
|
|
185
|
+
windowId?: number;
|
|
186
|
+
url?: string;
|
|
187
|
+
title?: string;
|
|
188
|
+
clientId?: string;
|
|
189
|
+
}>;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Close a browser tab by ID. Throws if backend doesn't support it.
|
|
193
|
+
* The optional `clientId` identifies which extension client actually
|
|
194
|
+
* closed the tab — used to scope pin cleanup in multi-client setups.
|
|
195
|
+
*/
|
|
196
|
+
closeTab(tabId: number): Promise<{
|
|
197
|
+
closed: boolean;
|
|
198
|
+
tabId: number;
|
|
199
|
+
clientId?: string;
|
|
200
|
+
}>;
|
|
100
201
|
}
|
|
101
202
|
|
|
102
203
|
/**
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-conversation, per-client pinned-tab store for the Chrome extension
|
|
3
|
+
* browser backend.
|
|
4
|
+
*
|
|
5
|
+
* Pin store key is (conversationId, clientId) → tabId. This scopes pins
|
|
6
|
+
* to a specific extension instance so that closing a tab on clientA does
|
|
7
|
+
* not clear clientB's pin to a tab with the same numeric ID on a
|
|
8
|
+
* different Chrome instance (issue #31361).
|
|
9
|
+
*
|
|
10
|
+
* Persistence is process-lifetime (in-memory only). The daemon is a
|
|
11
|
+
* single process and all CLI invocations land in it via IPC, so a
|
|
12
|
+
* module-level Map is sufficient. A pin is cleared when the extension
|
|
13
|
+
* reports the underlying CDP target as invalidated via
|
|
14
|
+
* `host_browser_session_invalidated`.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { log } from "../../cli/logger.js";
|
|
18
|
+
|
|
19
|
+
const pinnedTabs = new Map<string, Map<string, string>>();
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Record a tabId as the pinned tab for the given conversation and optional
|
|
23
|
+
* client. The tabId is stored as a string because it travels on the wire
|
|
24
|
+
* as `cdpSessionId` (a string-typed field on the host-browser envelope).
|
|
25
|
+
*/
|
|
26
|
+
export function setPinnedTab(
|
|
27
|
+
conversationId: string,
|
|
28
|
+
tabId: string,
|
|
29
|
+
clientId?: string,
|
|
30
|
+
): void {
|
|
31
|
+
if (!conversationId || !tabId) return;
|
|
32
|
+
const key = clientId ?? "__default__";
|
|
33
|
+
let inner = pinnedTabs.get(conversationId);
|
|
34
|
+
if (!inner) {
|
|
35
|
+
inner = new Map();
|
|
36
|
+
pinnedTabs.set(conversationId, inner);
|
|
37
|
+
}
|
|
38
|
+
inner.set(key, tabId);
|
|
39
|
+
log.debug(
|
|
40
|
+
{ conversationId, clientId, tabId },
|
|
41
|
+
"Pinned extension tab for conversation",
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Return the tabId pinned to the given conversation and optional client,
|
|
47
|
+
* or undefined if no pin exists.
|
|
48
|
+
*
|
|
49
|
+
* When `clientId` is provided, returns the pin for that client first,
|
|
50
|
+
* falling back to the `__default__` slot. When no `clientId` is given,
|
|
51
|
+
* returns the first entry (best-guess for auto-routing).
|
|
52
|
+
*/
|
|
53
|
+
export function getPinnedTab(
|
|
54
|
+
conversationId: string,
|
|
55
|
+
clientId?: string,
|
|
56
|
+
): string | undefined {
|
|
57
|
+
if (!conversationId) return undefined;
|
|
58
|
+
const inner = pinnedTabs.get(conversationId);
|
|
59
|
+
if (!inner) return undefined;
|
|
60
|
+
if (clientId !== undefined) {
|
|
61
|
+
return inner.get(clientId) ?? inner.get("__default__");
|
|
62
|
+
}
|
|
63
|
+
// No clientId: return the first entry (best-guess for auto-routing)
|
|
64
|
+
const first = inner.values().next();
|
|
65
|
+
return first.done ? undefined : first.value;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Clear the pin for the given conversation and optional client. Idempotent
|
|
70
|
+
* — clearing a non-existent pin is a no-op.
|
|
71
|
+
*
|
|
72
|
+
* When `clientId` is provided, only clears that client's slot. When
|
|
73
|
+
* omitted, clears all client slots for the conversation.
|
|
74
|
+
*/
|
|
75
|
+
export function clearPinnedTab(
|
|
76
|
+
conversationId: string,
|
|
77
|
+
clientId?: string,
|
|
78
|
+
): void {
|
|
79
|
+
if (!conversationId) return;
|
|
80
|
+
const inner = pinnedTabs.get(conversationId);
|
|
81
|
+
if (!inner) return;
|
|
82
|
+
if (clientId !== undefined) {
|
|
83
|
+
if (inner.delete(clientId)) {
|
|
84
|
+
log.debug({ conversationId, clientId }, "Cleared pinned extension tab");
|
|
85
|
+
}
|
|
86
|
+
if (inner.size === 0) pinnedTabs.delete(conversationId);
|
|
87
|
+
} else {
|
|
88
|
+
// Clear all clients for this conversation
|
|
89
|
+
if (pinnedTabs.delete(conversationId)) {
|
|
90
|
+
log.debug(
|
|
91
|
+
{ conversationId },
|
|
92
|
+
"Cleared all pinned extension tabs for conversation",
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Clear every pin pointing at a given tabId across all conversations.
|
|
100
|
+
* Used when the extension reports a target as invalidated (tab closed,
|
|
101
|
+
* crashed, navigated away from a debuggable URL, etc.) so we don't
|
|
102
|
+
* keep routing to a dead tab.
|
|
103
|
+
*
|
|
104
|
+
* When `clientId` is provided, only clears the slot for that client.
|
|
105
|
+
* When omitted, clears all entries pointing at this tabId (backward compat).
|
|
106
|
+
*
|
|
107
|
+
* Returns the number of slots cleared.
|
|
108
|
+
*/
|
|
109
|
+
export function clearPinnedTabByTabId(tabId: string, clientId?: string): number {
|
|
110
|
+
if (!tabId) return 0;
|
|
111
|
+
let cleared = 0;
|
|
112
|
+
for (const [conversationId, inner] of pinnedTabs.entries()) {
|
|
113
|
+
if (clientId !== undefined) {
|
|
114
|
+
// Only clear the specific client's slot if its tabId matches
|
|
115
|
+
if (inner.get(clientId) === tabId) {
|
|
116
|
+
inner.delete(clientId);
|
|
117
|
+
cleared++;
|
|
118
|
+
log.debug(
|
|
119
|
+
{ conversationId, clientId, tabId },
|
|
120
|
+
"Cleared pinned extension tab due to invalidation",
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
// Backward compat: clear all entries pointing at this tabId
|
|
125
|
+
for (const [cid, pinned] of inner.entries()) {
|
|
126
|
+
if (pinned === tabId) {
|
|
127
|
+
inner.delete(cid);
|
|
128
|
+
cleared++;
|
|
129
|
+
log.debug(
|
|
130
|
+
{ conversationId, clientId: cid, tabId },
|
|
131
|
+
"Cleared pinned extension tab due to invalidation",
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (inner.size === 0) pinnedTabs.delete(conversationId);
|
|
137
|
+
}
|
|
138
|
+
return cleared;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Reset the entire pin store. Test-only.
|
|
143
|
+
*/
|
|
144
|
+
export function __resetPinnedTabsForTests(): void {
|
|
145
|
+
pinnedTabs.clear();
|
|
146
|
+
}
|