@vellumai/assistant 0.8.4 → 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/docs/browser-use-architecture-phase2.md +1 -1
- package/knip.json +2 -1
- package/openapi.yaml +809 -11
- package/package.json +1 -1
- package/src/__tests__/anthropic-provider.test.ts +34 -37
- 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 +3 -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-guardian.test.ts +3 -3
- package/src/__tests__/checker.test.ts +6 -15
- package/src/__tests__/compaction-events.test.ts +1 -0
- package/src/__tests__/compactor-call-site-logging.test.ts +214 -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__/confirmation-request-guardian-bridge.test.ts +0 -1
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +197 -2
- package/src/__tests__/conversation-agent-loop.test.ts +163 -122
- package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -5
- package/src/__tests__/conversation-clear-safety.test.ts +25 -25
- 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 +178 -15
- package/src/__tests__/conversation-lifecycle.test.ts +52 -11
- package/src/__tests__/{conversation-load-cleaned-at.test.ts → conversation-load-history-stripped.test.ts} +13 -13
- package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -0
- 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-skill-tools.test.ts +2 -5
- package/src/__tests__/conversation-store.test.ts +1 -1
- package/src/__tests__/conversation-sync-tags.test.ts +99 -32
- package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +1 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -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 +1 -0
- package/src/__tests__/credential-vault-unit.test.ts +2 -2
- package/src/__tests__/dynamic-page-surface.test.ts +2 -2
- package/src/__tests__/email-html-renderer.test.ts +12 -0
- 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__/heartbeat-disk-pressure.test.ts +4 -0
- package/src/__tests__/heartbeat-service.test.ts +4 -0
- package/src/__tests__/host-shell-tool.test.ts +1 -1
- package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
- package/src/__tests__/list-messages-tool-merge.test.ts +70 -11
- 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 +77 -9
- package/src/__tests__/llm-usage-store.test.ts +66 -0
- 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__/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 +46 -0
- package/src/__tests__/openai-responses-provider.test.ts +114 -12
- package/src/__tests__/pending-interactions-resolved-event.test.ts +0 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
- package/src/__tests__/platform.test.ts +2 -2
- package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
- package/src/__tests__/plugin-bootstrap.test.ts +2 -2
- 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__/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__/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__/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 +145 -131
- package/src/__tests__/terminal-tools.test.ts +1 -1
- 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 +9 -62
- package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
- 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__/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__/workspace-git-service.test.ts +6 -5
- 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/loop.ts +8 -0
- 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/runtime-registry.ts +24 -0
- package/src/cli/commands/__tests__/browser.test.ts +23 -5
- 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 +1 -0
- package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
- package/src/cli/commands/browser.ts +247 -0
- package/src/cli/commands/domain.ts +91 -41
- 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 +176 -1
- package/src/cli/commands/memory-v3-render.ts +344 -0
- package/src/cli/commands/memory-v3.ts +316 -0
- package/src/cli/program.ts +2 -0
- package/src/config/assistant-feature-flags.ts +21 -9
- package/src/config/bundled-skills/document-editor/SKILL.md +11 -2
- package/src/config/bundled-skills/document-editor/TOOLS.json +18 -0
- package/src/config/bundled-skills/document-editor/tools/document-open.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/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-tool-registry.ts +2 -0
- package/src/config/call-site-defaults.ts +7 -6
- package/src/config/feature-flag-registry.json +16 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +213 -1
- package/src/config/schemas/call-site-catalog.ts +21 -7
- package/src/config/schemas/llm.ts +12 -1
- package/src/config/schemas/memory-v2.ts +246 -0
- package/src/config/schemas/memory.ts +2 -1
- package/src/context/compactor.ts +52 -0
- package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
- package/src/conversations/message-consolidation.ts +404 -0
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -1
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +1 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +2 -13
- package/src/daemon/conversation-agent-loop.ts +126 -76
- package/src/daemon/conversation-error.ts +31 -1
- package/src/daemon/conversation-lifecycle.ts +27 -22
- package/src/daemon/conversation-runtime-assembly.ts +10 -9
- package/src/daemon/conversation-tool-setup.ts +63 -3
- package/src/daemon/conversation-usage.ts +2 -0
- package/src/daemon/conversation.ts +14 -29
- package/src/daemon/disk-pressure-guard.ts +14 -2
- package/src/daemon/handlers/config-model.test.ts +1 -0
- package/src/daemon/handlers/conversations.ts +11 -3
- package/src/daemon/host-browser-proxy.ts +5 -5
- package/src/daemon/host-cu-proxy.ts +4 -4
- package/src/daemon/host-file-proxy.ts +4 -4
- package/src/daemon/host-proxy-base.ts +4 -4
- package/src/daemon/host-transfer-proxy.ts +10 -10
- package/src/daemon/lifecycle.ts +23 -20
- package/src/daemon/meet-manifest-loader.ts +1 -7
- package/src/daemon/message-types/conversations.ts +6 -9
- package/src/daemon/message-types/home.ts +1 -13
- package/src/daemon/message-types/messages.ts +6 -14
- package/src/daemon/message-types/sync.ts +14 -0
- 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/events/relationship-state-updated.ts +25 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -1
- package/src/home/home-greeting.ts +0 -9
- package/src/home/suggested-prompts.ts +0 -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__/memory-retrospective-job.test.ts +7 -0
- package/src/memory/auto-analysis-enqueue.ts +5 -1
- package/src/memory/conversation-crud.ts +71 -70
- 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 +10 -0
- package/src/memory/db-maintenance.ts +30 -21
- 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 +55 -22
- 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-enqueue.ts +8 -1
- package/src/memory/memory-retrospective-job.ts +5 -0
- package/src/memory/memory-v2-activation-log-store.ts +15 -6
- 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 +17 -0
- package/src/memory/migrations/registry.ts +33 -0
- package/src/memory/schema/conversations.ts +1 -1
- package/src/memory/schema/infrastructure.ts +21 -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.test.ts +127 -98
- package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
- package/src/memory/v2/__tests__/router.test.ts +171 -3
- 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.ts +21 -15
- package/src/memory/v2/prompts/router.ts +26 -1
- package/src/memory/v2/qdrant.ts +14 -2
- package/src/memory/v2/router.ts +171 -18
- 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/notifications/adapters/macos.ts +18 -1
- package/src/notifications/adapters/platform.ts +1 -1
- package/src/notifications/decision-engine.ts +1 -4
- package/src/notifications/emit-signal.ts +29 -49
- package/src/permissions/prompter.ts +3 -3
- package/src/permissions/question-prompter.ts +5 -2
- package/src/permissions/secret-prompter.ts +2 -2
- 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 +18 -11
- 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__/task-progress-hint-section.test.ts +3 -9
- package/src/prompts/persona-resolver.ts +36 -21
- package/src/prompts/sections.ts +39 -7
- package/src/prompts/system-prompt.ts +50 -185
- package/src/prompts/templates/BOOTSTRAP.md +2 -2
- package/src/prompts/templates/system-sections.ts +230 -8
- 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 +32 -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/gemini/client.ts +49 -6
- package/src/providers/inference/adapter-factory.ts +3 -0
- package/src/providers/minimax/client.ts +106 -0
- package/src/providers/model-catalog.ts +43 -0
- package/src/providers/model-intents.ts +1 -1
- package/src/providers/openai/chat-completions-provider.ts +6 -3
- package/src/providers/openai/codex-models.ts +18 -0
- package/src/providers/openai/responses-provider.ts +78 -21
- 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/usage-tracking.ts +2 -0
- package/src/runtime/AGENTS.md +2 -2
- package/src/runtime/agent-wake.ts +1 -0
- package/src/runtime/assistant-event-hub.ts +76 -6
- package/src/runtime/auth/route-policy.ts +36 -0
- package/src/runtime/btw-sidechain.ts +0 -6
- package/src/runtime/http-types.ts +0 -2
- package/src/runtime/migrations/vbundle-builder.ts +10 -3
- package/src/runtime/pending-interactions.ts +0 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +106 -0
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +25 -6
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
- package/src/runtime/routes/acp-routes.test.ts +255 -6
- package/src/runtime/routes/acp-routes.ts +8 -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/conversation-cli-routes.ts +1 -1
- 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 +142 -36
- package/src/runtime/routes/conversation-routes.ts +252 -410
- package/src/runtime/routes/conversation-starter-routes.ts +6 -3
- package/src/runtime/routes/disk-pressure-routes.ts +1 -1
- 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/host-browser-routes.ts +10 -2
- package/src/runtime/routes/host-cu-routes.ts +2 -2
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
- package/src/runtime/routes/index.ts +8 -0
- 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/llm-call-sites-routes.ts +32 -5
- package/src/runtime/routes/memory-item-routes.ts +8 -3
- package/src/runtime/routes/memory-v2-routes.ts +215 -5
- package/src/runtime/routes/memory-v3-routes.ts +316 -0
- package/src/runtime/routes/migration-routes.ts +21 -24
- package/src/runtime/routes/plugins-routes.ts +337 -0
- package/src/runtime/routes/rename-conversation-routes.ts +6 -2
- 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 +5 -4
- package/src/runtime/routes/workspace-routes.ts +25 -10
- 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/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 +70 -0
- package/src/tools/browser/browser-execution.ts +16 -3
- package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +3 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +12 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +27 -1
- package/src/tools/browser/cdp-client/factory.ts +100 -17
- package/src/tools/browser/cdp-client/local-cdp-client.ts +12 -0
- package/src/tools/browser/cdp-client/types.ts +65 -0
- package/src/tools/browser/pinned-tabs.ts +96 -40
- 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-tool.ts +59 -0
- 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/web-fetch.ts +3 -9
- package/src/tools/network/web-search.ts +25 -32
- 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/shell.ts +3 -9
- package/src/tools/tool-defaults.ts +94 -0
- package/src/tools/types.ts +27 -98
- package/src/tools/ui-surface/definitions.ts +6 -22
- package/src/usage/pricing.ts +23 -0
- package/src/usage/types.ts +12 -0
- package/src/util/logger.ts +16 -7
- package/src/util/platform.ts +7 -2
- package/src/util/sqlite3-runtime.ts +65 -0
- package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
- package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
- package/src/workspace/migrations/registry.ts +2 -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/daemon/query-complexity-router.ts +0 -75
- package/src/prompts/cache-boundary.ts +0 -8
|
@@ -2,7 +2,7 @@ import type { HostBrowserProxy } from "../../../daemon/host-browser-proxy.js";
|
|
|
2
2
|
import { getLogger } from "../../../util/logger.js";
|
|
3
3
|
import type { CdpErrorCode } from "./errors.js";
|
|
4
4
|
import { CdpError } from "./errors.js";
|
|
5
|
-
import type { CdpClientKind, ScopedCdpClient } from "./types.js";
|
|
5
|
+
import type { CdpClientKind, ScopedCdpClient, TabInfo } from "./types.js";
|
|
6
6
|
|
|
7
7
|
const log = getLogger("extension-cdp-client");
|
|
8
8
|
|
|
@@ -196,6 +196,32 @@ export class ExtensionCdpClient implements ScopedCdpClient {
|
|
|
196
196
|
setCdpSessionId(cdpSessionId: string | undefined): void {
|
|
197
197
|
this.cdpSessionId = cdpSessionId;
|
|
198
198
|
}
|
|
199
|
+
|
|
200
|
+
/** List all open browser tabs via `Vellum.listTabs`. */
|
|
201
|
+
async listTabs(): Promise<TabInfo[]> {
|
|
202
|
+
const result = await this.send<{ tabs: TabInfo[] }>("Vellum.listTabs", {});
|
|
203
|
+
return Array.isArray(result?.tabs) ? result.tabs : [];
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** Select (activate) an existing tab via `Vellum.selectTab`. */
|
|
207
|
+
async selectTab(tabId: number): Promise<{
|
|
208
|
+
tabId?: number;
|
|
209
|
+
windowId?: number;
|
|
210
|
+
url?: string;
|
|
211
|
+
title?: string;
|
|
212
|
+
clientId?: string;
|
|
213
|
+
}> {
|
|
214
|
+
return this.send("Vellum.selectTab", { tabId });
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** Close a browser tab via `Vellum.closeTab`. */
|
|
218
|
+
async closeTab(tabId: number): Promise<{
|
|
219
|
+
closed: boolean;
|
|
220
|
+
tabId: number;
|
|
221
|
+
clientId?: string;
|
|
222
|
+
}> {
|
|
223
|
+
return this.send("Vellum.closeTab", { tabId });
|
|
224
|
+
}
|
|
199
225
|
}
|
|
200
226
|
|
|
201
227
|
/**
|
|
@@ -23,6 +23,7 @@ import type {
|
|
|
23
23
|
CdpClient,
|
|
24
24
|
CdpClientKind,
|
|
25
25
|
ScopedCdpClient,
|
|
26
|
+
TabInfo,
|
|
26
27
|
} from "./types.js";
|
|
27
28
|
|
|
28
29
|
const log = getLogger("cdp-factory");
|
|
@@ -223,14 +224,12 @@ export function buildPinnedCandidateList(
|
|
|
223
224
|
const client = createExtensionCdpClient(
|
|
224
225
|
hostBrowserProxy,
|
|
225
226
|
conversationId,
|
|
226
|
-
//
|
|
227
|
-
//
|
|
228
|
-
//
|
|
229
|
-
//
|
|
230
|
-
//
|
|
231
|
-
|
|
232
|
-
// cdp_session_not_found.
|
|
233
|
-
targetClientId ? undefined : getPinnedTab(conversationId),
|
|
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),
|
|
234
233
|
sourceActorPrincipalId,
|
|
235
234
|
targetClientId,
|
|
236
235
|
);
|
|
@@ -338,15 +337,13 @@ export function buildCandidateList(context: ToolContext, targetClientId?: string
|
|
|
338
337
|
kind: "extension",
|
|
339
338
|
reason: `target_client_id override: ${targetClientId}`,
|
|
340
339
|
create() {
|
|
341
|
-
// Explicit target_client_id override →
|
|
342
|
-
//
|
|
343
|
-
//
|
|
344
|
-
// a different host to this one, producing
|
|
345
|
-
// cdp_session_not_found.
|
|
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.
|
|
346
343
|
const client = createExtensionCdpClient(
|
|
347
344
|
hostBrowserProxy,
|
|
348
345
|
conversationId,
|
|
349
|
-
|
|
346
|
+
getPinnedTab(conversationId, targetClientId),
|
|
350
347
|
sourceActorPrincipalId,
|
|
351
348
|
targetClientId,
|
|
352
349
|
);
|
|
@@ -371,9 +368,11 @@ export function buildCandidateList(context: ToolContext, targetClientId?: string
|
|
|
371
368
|
const client = createExtensionCdpClient(
|
|
372
369
|
hostBrowserProxy,
|
|
373
370
|
conversationId,
|
|
374
|
-
//
|
|
375
|
-
//
|
|
376
|
-
|
|
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),
|
|
377
376
|
sourceActorPrincipalId,
|
|
378
377
|
targetClientId,
|
|
379
378
|
);
|
|
@@ -632,6 +631,90 @@ export function buildChainedClient(
|
|
|
632
631
|
}
|
|
633
632
|
pendingCdpSessionId = cdpSessionId;
|
|
634
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
|
+
},
|
|
635
718
|
};
|
|
636
719
|
|
|
637
720
|
return scopedClient;
|
|
@@ -165,6 +165,18 @@ export class LocalCdpClient implements ScopedCdpClient {
|
|
|
165
165
|
// no-op
|
|
166
166
|
}
|
|
167
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
|
+
|
|
168
180
|
dispose(): void {
|
|
169
181
|
if (this.disposed) return;
|
|
170
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
|
|
@@ -53,6 +63,33 @@ export interface CdpClient {
|
|
|
53
63
|
* Optional — callers should null-check before invoking.
|
|
54
64
|
*/
|
|
55
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
|
+
}>;
|
|
56
93
|
}
|
|
57
94
|
|
|
58
95
|
/**
|
|
@@ -133,6 +170,34 @@ export interface ScopedCdpClient extends CdpClient {
|
|
|
133
170
|
* chaining.
|
|
134
171
|
*/
|
|
135
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
|
+
}>;
|
|
136
201
|
}
|
|
137
202
|
|
|
138
203
|
/**
|
|
@@ -1,60 +1,97 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Per-conversation pinned-tab store for the Chrome extension
|
|
3
|
-
* backend.
|
|
2
|
+
* Per-conversation, per-client pinned-tab store for the Chrome extension
|
|
3
|
+
* browser backend.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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 })`.
|
|
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).
|
|
13
9
|
*
|
|
14
10
|
* Persistence is process-lifetime (in-memory only). The daemon is a
|
|
15
11
|
* single process and all CLI invocations land in it via IPC, so a
|
|
16
12
|
* module-level Map is sufficient. A pin is cleared when the extension
|
|
17
|
-
* reports the underlying CDP target as invalidated
|
|
18
|
-
* `
|
|
19
|
-
* eviction is wired through `BrowserSessionManager.invalidateByTargetId`
|
|
20
|
-
* and the host-browser session-invalidated event route.
|
|
13
|
+
* reports the underlying CDP target as invalidated via
|
|
14
|
+
* `host_browser_session_invalidated`.
|
|
21
15
|
*/
|
|
22
16
|
|
|
23
17
|
import { log } from "../../cli/logger.js";
|
|
24
18
|
|
|
25
|
-
const pinnedTabs = new Map<string, string
|
|
19
|
+
const pinnedTabs = new Map<string, Map<string, string>>();
|
|
26
20
|
|
|
27
21
|
/**
|
|
28
|
-
* Record a tabId as the pinned tab for the given conversation
|
|
29
|
-
* tabId is stored as a string because it travels on the wire
|
|
30
|
-
* `cdpSessionId` (a string-typed field on the host-browser envelope).
|
|
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).
|
|
31
25
|
*/
|
|
32
|
-
export function setPinnedTab(
|
|
26
|
+
export function setPinnedTab(
|
|
27
|
+
conversationId: string,
|
|
28
|
+
tabId: string,
|
|
29
|
+
clientId?: string,
|
|
30
|
+
): void {
|
|
33
31
|
if (!conversationId || !tabId) return;
|
|
34
|
-
|
|
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);
|
|
35
39
|
log.debug(
|
|
36
|
-
{ conversationId, tabId },
|
|
40
|
+
{ conversationId, clientId, tabId },
|
|
37
41
|
"Pinned extension tab for conversation",
|
|
38
42
|
);
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
/**
|
|
42
|
-
* Return the tabId pinned to the given conversation
|
|
43
|
-
* no pin exists.
|
|
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).
|
|
44
52
|
*/
|
|
45
|
-
export function getPinnedTab(
|
|
53
|
+
export function getPinnedTab(
|
|
54
|
+
conversationId: string,
|
|
55
|
+
clientId?: string,
|
|
56
|
+
): string | undefined {
|
|
46
57
|
if (!conversationId) return undefined;
|
|
47
|
-
|
|
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;
|
|
48
66
|
}
|
|
49
67
|
|
|
50
68
|
/**
|
|
51
|
-
* Clear the pin for the given conversation
|
|
52
|
-
* non-existent pin is a no-op.
|
|
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.
|
|
53
74
|
*/
|
|
54
|
-
export function clearPinnedTab(
|
|
75
|
+
export function clearPinnedTab(
|
|
76
|
+
conversationId: string,
|
|
77
|
+
clientId?: string,
|
|
78
|
+
): void {
|
|
55
79
|
if (!conversationId) return;
|
|
56
|
-
|
|
57
|
-
|
|
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
|
+
}
|
|
58
95
|
}
|
|
59
96
|
}
|
|
60
97
|
|
|
@@ -64,20 +101,39 @@ export function clearPinnedTab(conversationId: string): void {
|
|
|
64
101
|
* crashed, navigated away from a debuggable URL, etc.) so we don't
|
|
65
102
|
* keep routing to a dead tab.
|
|
66
103
|
*
|
|
67
|
-
*
|
|
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.
|
|
68
108
|
*/
|
|
69
|
-
export function clearPinnedTabByTabId(tabId: string): number {
|
|
109
|
+
export function clearPinnedTabByTabId(tabId: string, clientId?: string): number {
|
|
70
110
|
if (!tabId) return 0;
|
|
71
111
|
let cleared = 0;
|
|
72
|
-
for (const [conversationId,
|
|
73
|
-
if (
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
+
}
|
|
80
135
|
}
|
|
136
|
+
if (inner.size === 0) pinnedTabs.delete(conversationId);
|
|
81
137
|
}
|
|
82
138
|
return cleared;
|
|
83
139
|
}
|