@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
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { mkdirSync, mkdtempSync, rmSync } from "node:fs";
|
|
2
|
+
import { createServer, type Server, type Socket } from "node:net";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { afterEach,beforeEach, describe, expect, mock, test } from "bun:test";
|
|
6
|
+
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Isolated temp directory for the IPC socket
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
const testRoot = mkdtempSync(join(tmpdir(), "flag-listener-test-"));
|
|
11
|
+
const socketPath = join(testRoot, "gateway.sock");
|
|
12
|
+
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Mock socket-path resolution to use our test socket
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
mock.module("../ipc/socket-path.js", () => ({
|
|
17
|
+
resolveIpcSocketPath: (_name: string) => ({
|
|
18
|
+
path: socketPath,
|
|
19
|
+
source: "workspace" as const,
|
|
20
|
+
}),
|
|
21
|
+
getAssistantSocketPath: () => join(testRoot, "assistant.sock"),
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Track calls to refreshOverridesFromGateway
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
let refreshCallCount = 0;
|
|
28
|
+
|
|
29
|
+
mock.module("../config/assistant-feature-flags.js", () => ({
|
|
30
|
+
refreshOverridesFromGateway: async () => {
|
|
31
|
+
refreshCallCount++;
|
|
32
|
+
},
|
|
33
|
+
initFeatureFlagOverrides: async () => {},
|
|
34
|
+
clearFeatureFlagOverridesCache: () => {},
|
|
35
|
+
isAssistantFeatureFlagEnabled: () => true,
|
|
36
|
+
_setOverridesForTesting: () => {},
|
|
37
|
+
}));
|
|
38
|
+
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Track calls to publishSyncInvalidation so we can assert the listener
|
|
41
|
+
// fans flag changes out onto the SSE hub.
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
let publishedTagSets: string[][] = [];
|
|
44
|
+
|
|
45
|
+
mock.module("../runtime/sync/sync-publisher.js", () => ({
|
|
46
|
+
publishSyncInvalidation: async (tags: string[]) => {
|
|
47
|
+
publishedTagSets.push([...tags]);
|
|
48
|
+
return { type: "sync_changed", tags };
|
|
49
|
+
},
|
|
50
|
+
}));
|
|
51
|
+
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Dynamic imports (after mock.module)
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
const { startGatewayFlagListener, stopGatewayFlagListener } = await import(
|
|
56
|
+
"../ipc/gateway-flag-listener.js"
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
// Helpers
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
function createTestServer(): {
|
|
64
|
+
server: Server;
|
|
65
|
+
clients: Set<Socket>;
|
|
66
|
+
emit: (event: string, data?: unknown) => void;
|
|
67
|
+
waitForClient: () => Promise<Socket>;
|
|
68
|
+
} {
|
|
69
|
+
const clients = new Set<Socket>();
|
|
70
|
+
const clientWaiters: Array<(socket: Socket) => void> = [];
|
|
71
|
+
|
|
72
|
+
const server = createServer((socket) => {
|
|
73
|
+
clients.add(socket);
|
|
74
|
+
socket.on("close", () => clients.delete(socket));
|
|
75
|
+
const waiter = clientWaiters.shift();
|
|
76
|
+
if (waiter) waiter(socket);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
server,
|
|
81
|
+
clients,
|
|
82
|
+
emit: (event: string, data?: unknown) => {
|
|
83
|
+
const payload = JSON.stringify({ event, data }) + "\n";
|
|
84
|
+
for (const client of clients) {
|
|
85
|
+
if (!client.destroyed) client.write(payload);
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
waitForClient: () =>
|
|
89
|
+
new Promise((resolve) => {
|
|
90
|
+
if (clients.size > 0) {
|
|
91
|
+
resolve(clients.values().next().value!);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
clientWaiters.push(resolve);
|
|
95
|
+
}),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
// Tests
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
describe("gateway-flag-listener", () => {
|
|
103
|
+
let testServer: ReturnType<typeof createTestServer>;
|
|
104
|
+
|
|
105
|
+
beforeEach(() => {
|
|
106
|
+
mkdirSync(testRoot, { recursive: true });
|
|
107
|
+
refreshCallCount = 0;
|
|
108
|
+
publishedTagSets = [];
|
|
109
|
+
testServer = createTestServer();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
afterEach(async () => {
|
|
113
|
+
stopGatewayFlagListener();
|
|
114
|
+
await new Promise<void>((resolve) => {
|
|
115
|
+
for (const client of testServer.clients) {
|
|
116
|
+
if (!client.destroyed) client.destroy();
|
|
117
|
+
}
|
|
118
|
+
testServer.server.close(() => resolve());
|
|
119
|
+
});
|
|
120
|
+
try {
|
|
121
|
+
rmSync(socketPath, { force: true });
|
|
122
|
+
} catch {
|
|
123
|
+
// best effort
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("refreshes flag cache on connect and on feature_flags_changed event", async () => {
|
|
128
|
+
await new Promise<void>((resolve) => {
|
|
129
|
+
testServer.server.listen(socketPath, resolve);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
startGatewayFlagListener();
|
|
133
|
+
await testServer.waitForClient();
|
|
134
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
135
|
+
|
|
136
|
+
expect(refreshCallCount).toBe(1);
|
|
137
|
+
|
|
138
|
+
testServer.emit("feature_flags_changed");
|
|
139
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
140
|
+
|
|
141
|
+
expect(refreshCallCount).toBe(2);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test("broadcasts feature-flags sync_changed when flags change", async () => {
|
|
145
|
+
await new Promise<void>((resolve) => {
|
|
146
|
+
testServer.server.listen(socketPath, resolve);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
startGatewayFlagListener();
|
|
150
|
+
await testServer.waitForClient();
|
|
151
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
152
|
+
|
|
153
|
+
// Connect refresh should not broadcast — only an actual change does.
|
|
154
|
+
expect(publishedTagSets.length).toBe(0);
|
|
155
|
+
|
|
156
|
+
testServer.emit("feature_flags_changed");
|
|
157
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
158
|
+
|
|
159
|
+
expect(publishedTagSets.length).toBe(1);
|
|
160
|
+
expect(publishedTagSets[0]).toEqual([
|
|
161
|
+
"feature-flags:client",
|
|
162
|
+
"feature-flags:assistant",
|
|
163
|
+
]);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test("ignores non-flag events", async () => {
|
|
167
|
+
await new Promise<void>((resolve) => {
|
|
168
|
+
testServer.server.listen(socketPath, resolve);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
startGatewayFlagListener();
|
|
172
|
+
await testServer.waitForClient();
|
|
173
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
174
|
+
|
|
175
|
+
const countAfterConnect = refreshCallCount;
|
|
176
|
+
|
|
177
|
+
testServer.emit("some_other_event");
|
|
178
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
179
|
+
|
|
180
|
+
expect(refreshCallCount).toBe(countAfterConnect);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test("reconnects on disconnect and handles events on new connection", async () => {
|
|
184
|
+
await new Promise<void>((resolve) => {
|
|
185
|
+
testServer.server.listen(socketPath, resolve);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
startGatewayFlagListener();
|
|
189
|
+
const firstClient = await testServer.waitForClient();
|
|
190
|
+
|
|
191
|
+
// Wait for the close event to propagate back to the server before
|
|
192
|
+
// setting up the next waitForClient — otherwise waitForClient might
|
|
193
|
+
// resolve with the old (now-destroyed) socket that is still in the set.
|
|
194
|
+
await new Promise<void>((resolve) => {
|
|
195
|
+
firstClient.on("close", resolve);
|
|
196
|
+
firstClient.destroy();
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// Wait for reconnect (initial backoff is 1s)
|
|
200
|
+
const secondClient = await Promise.race([
|
|
201
|
+
testServer.waitForClient(),
|
|
202
|
+
new Promise<null>((r) => setTimeout(() => r(null), 3000)),
|
|
203
|
+
]);
|
|
204
|
+
|
|
205
|
+
expect(secondClient).not.toBeNull();
|
|
206
|
+
|
|
207
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
208
|
+
const countAfterReconnect = refreshCallCount;
|
|
209
|
+
expect(countAfterReconnect).toBeGreaterThan(0);
|
|
210
|
+
|
|
211
|
+
const payload =
|
|
212
|
+
JSON.stringify({ event: "feature_flags_changed" }) + "\n";
|
|
213
|
+
secondClient!.write(payload);
|
|
214
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
215
|
+
|
|
216
|
+
expect(refreshCallCount).toBe(countAfterReconnect + 1);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
test("stopGatewayFlagListener cleans up and does not reconnect", async () => {
|
|
220
|
+
await new Promise<void>((resolve) => {
|
|
221
|
+
testServer.server.listen(socketPath, resolve);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
startGatewayFlagListener();
|
|
225
|
+
await testServer.waitForClient();
|
|
226
|
+
|
|
227
|
+
stopGatewayFlagListener();
|
|
228
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
229
|
+
|
|
230
|
+
const initialClientCount = testServer.clients.size;
|
|
231
|
+
|
|
232
|
+
// Wait past reconnect backoff — should not reconnect
|
|
233
|
+
await new Promise((r) => setTimeout(r, 1500));
|
|
234
|
+
|
|
235
|
+
expect(testServer.clients.size).toBeLessThanOrEqual(initialClientCount);
|
|
236
|
+
});
|
|
237
|
+
});
|
|
@@ -75,6 +75,12 @@ mock.module("@google/genai", () => ({
|
|
|
75
75
|
};
|
|
76
76
|
},
|
|
77
77
|
ApiError: FakeApiError,
|
|
78
|
+
ThinkingLevel: {
|
|
79
|
+
MINIMAL: "MINIMAL",
|
|
80
|
+
LOW: "LOW",
|
|
81
|
+
MEDIUM: "MEDIUM",
|
|
82
|
+
HIGH: "HIGH",
|
|
83
|
+
},
|
|
78
84
|
}));
|
|
79
85
|
|
|
80
86
|
// Import after mocking
|
|
@@ -223,6 +229,78 @@ describe("GeminiProvider", () => {
|
|
|
223
229
|
expect(config.systemInstruction).toBe("You are a helpful assistant.");
|
|
224
230
|
});
|
|
225
231
|
|
|
232
|
+
// -----------------------------------------------------------------------
|
|
233
|
+
// Thinking config
|
|
234
|
+
// -----------------------------------------------------------------------
|
|
235
|
+
test("omits thinkingConfig when no thinking config is supplied", async () => {
|
|
236
|
+
fakeChunks = [textChunk("OK"), finishChunk("STOP", 10, 2)];
|
|
237
|
+
|
|
238
|
+
await provider.sendMessage([
|
|
239
|
+
{ role: "user", content: [{ type: "text", text: "Hi" }] },
|
|
240
|
+
]);
|
|
241
|
+
|
|
242
|
+
const config = lastStreamParams!.config as Record<string, unknown>;
|
|
243
|
+
expect(config.thinkingConfig).toBeUndefined();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
test("maps wire { type: 'adaptive', level, streamThinking } to Gemini thinkingConfig", async () => {
|
|
247
|
+
fakeChunks = [textChunk("OK"), finishChunk("STOP", 10, 2)];
|
|
248
|
+
|
|
249
|
+
await provider.sendMessage(
|
|
250
|
+
[{ role: "user", content: [{ type: "text", text: "Hi" }] }],
|
|
251
|
+
undefined,
|
|
252
|
+
undefined,
|
|
253
|
+
{
|
|
254
|
+
config: {
|
|
255
|
+
thinking: {
|
|
256
|
+
type: "adaptive",
|
|
257
|
+
level: "high",
|
|
258
|
+
streamThinking: false,
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
const config = lastStreamParams!.config as Record<string, unknown>;
|
|
265
|
+
expect(config.thinkingConfig).toEqual({
|
|
266
|
+
thinkingLevel: "HIGH",
|
|
267
|
+
includeThoughts: false,
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
test("maps wire { type: 'disabled' } to MINIMAL thinking level", async () => {
|
|
272
|
+
fakeChunks = [textChunk("OK"), finishChunk("STOP", 10, 2)];
|
|
273
|
+
|
|
274
|
+
await provider.sendMessage(
|
|
275
|
+
[{ role: "user", content: [{ type: "text", text: "Hi" }] }],
|
|
276
|
+
undefined,
|
|
277
|
+
undefined,
|
|
278
|
+
{ config: { thinking: { type: "disabled" } } },
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
const config = lastStreamParams!.config as Record<string, unknown>;
|
|
282
|
+
expect(config.thinkingConfig).toEqual({
|
|
283
|
+
thinkingLevel: "MINIMAL",
|
|
284
|
+
includeThoughts: false,
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
test("omits thinkingConfig when wire shape is adaptive with no extras", async () => {
|
|
289
|
+
fakeChunks = [textChunk("OK"), finishChunk("STOP", 10, 2)];
|
|
290
|
+
|
|
291
|
+
await provider.sendMessage(
|
|
292
|
+
[{ role: "user", content: [{ type: "text", text: "Hi" }] }],
|
|
293
|
+
undefined,
|
|
294
|
+
undefined,
|
|
295
|
+
{ config: { thinking: { type: "adaptive" } } },
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
const config = lastStreamParams!.config as Record<string, unknown>;
|
|
299
|
+
// No level/streamThinking → omit so Google's per-model default applies
|
|
300
|
+
// (Gemini 3.x defaults to "medium" with dynamic thinking).
|
|
301
|
+
expect(config.thinkingConfig).toBeUndefined();
|
|
302
|
+
});
|
|
303
|
+
|
|
226
304
|
// -----------------------------------------------------------------------
|
|
227
305
|
// Tool definitions
|
|
228
306
|
// -----------------------------------------------------------------------
|
|
@@ -280,11 +280,13 @@ describe("startOutbound", () => {
|
|
|
280
280
|
expect(voiceCallInitCalls.length).toBe(1);
|
|
281
281
|
});
|
|
282
282
|
|
|
283
|
-
test("
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
283
|
+
test("email channel creates outbound session", async () => {
|
|
284
|
+
const result = await startOutbound({
|
|
285
|
+
channel: "email",
|
|
286
|
+
destination: "user@example.com",
|
|
287
|
+
});
|
|
288
|
+
expect(result.success).toBe(true);
|
|
289
|
+
expect(result.channel).toBe("email");
|
|
288
290
|
});
|
|
289
291
|
});
|
|
290
292
|
|
|
@@ -193,6 +193,6 @@ describe("handleConfirmationResponse canonical status sync", () => {
|
|
|
193
193
|
// Canonical status sync is now handled inside Conversation.handleConfirmationResponse,
|
|
194
194
|
// which this test mocks out — so the handler itself no longer calls resolveCanonicalGuardianRequest.
|
|
195
195
|
expect(resolveCanonicalGuardianRequestMock).not.toHaveBeenCalled();
|
|
196
|
-
expect(resolveMock).toHaveBeenCalledWith("req-confirm-allow");
|
|
196
|
+
expect(resolveMock).toHaveBeenCalledWith("req-confirm-allow", "approved");
|
|
197
197
|
});
|
|
198
198
|
});
|
|
@@ -27,6 +27,7 @@ let cdpSendHandler: (
|
|
|
27
27
|
params?: Record<string, unknown>,
|
|
28
28
|
) => unknown = () => ({});
|
|
29
29
|
let cdpDisposed = false;
|
|
30
|
+
let cdpSetSessionIdCalls: Array<string | undefined> = [];
|
|
30
31
|
|
|
31
32
|
function makeFakeCdp(kind: "local" | "extension", conversationId: string) {
|
|
32
33
|
return {
|
|
@@ -43,6 +44,12 @@ function makeFakeCdp(kind: "local" | "extension", conversationId: string) {
|
|
|
43
44
|
dispose() {
|
|
44
45
|
cdpDisposed = true;
|
|
45
46
|
},
|
|
47
|
+
// Mirrors the optional method on the real CdpClient interface so
|
|
48
|
+
// the --new-tab path can be exercised end-to-end. Recorded for
|
|
49
|
+
// per-test assertions.
|
|
50
|
+
setCdpSessionId(cdpSessionId: string | undefined) {
|
|
51
|
+
cdpSetSessionIdCalls.push(cdpSessionId);
|
|
52
|
+
},
|
|
46
53
|
};
|
|
47
54
|
}
|
|
48
55
|
|
|
@@ -135,6 +142,7 @@ mock.module("../tools/network/url-safety.js", () => ({
|
|
|
135
142
|
}));
|
|
136
143
|
|
|
137
144
|
import { executeBrowserNavigate } from "../tools/browser/browser-execution.js";
|
|
145
|
+
import { __resetPinnedTabsForTests } from "../tools/browser/pinned-tabs.js";
|
|
138
146
|
import type { ToolContext } from "../tools/types.js";
|
|
139
147
|
|
|
140
148
|
const ctx: ToolContext = {
|
|
@@ -212,6 +220,7 @@ function resetCdp() {
|
|
|
212
220
|
cdpSendCalls = [];
|
|
213
221
|
cdpDisposed = false;
|
|
214
222
|
cdpSendHandler = defaultCdpHandler;
|
|
223
|
+
cdpSetSessionIdCalls = [];
|
|
215
224
|
}
|
|
216
225
|
|
|
217
226
|
describe("executeBrowserNavigate", () => {
|
|
@@ -223,6 +232,7 @@ describe("executeBrowserNavigate", () => {
|
|
|
223
232
|
resolveResult = {};
|
|
224
233
|
resetMockPage();
|
|
225
234
|
resetCdp();
|
|
235
|
+
__resetPinnedTabsForTests();
|
|
226
236
|
});
|
|
227
237
|
|
|
228
238
|
// ── Input validation ───────────────────────────────────────────
|
|
@@ -664,6 +674,168 @@ describe("executeBrowserNavigate", () => {
|
|
|
664
674
|
expect(cdpDisposed).toBe(true);
|
|
665
675
|
});
|
|
666
676
|
|
|
677
|
+
// ── --new-tab flag (extension path only) ──────────────────────
|
|
678
|
+
|
|
679
|
+
test("extension path with new_tab: true opens a fresh tab and pins it before Page.navigate", async () => {
|
|
680
|
+
parseUrlResult = new URL("https://example.com/page");
|
|
681
|
+
mockExtensionAvailable = true;
|
|
682
|
+
|
|
683
|
+
cdpSendHandler = (method, params) => {
|
|
684
|
+
if (method === "Vellum.createTab") return { tabId: "999" };
|
|
685
|
+
return defaultCdpHandler(method, params);
|
|
686
|
+
};
|
|
687
|
+
|
|
688
|
+
const result = await executeBrowserNavigate(
|
|
689
|
+
{ url: "https://example.com/page", new_tab: true },
|
|
690
|
+
{ ...ctx },
|
|
691
|
+
);
|
|
692
|
+
|
|
693
|
+
expect(result.isError).toBe(false);
|
|
694
|
+
|
|
695
|
+
// Vellum.createTab fired and fired BEFORE Page.navigate.
|
|
696
|
+
const createIdx = cdpSendCalls.findIndex(
|
|
697
|
+
(c) => c.method === "Vellum.createTab",
|
|
698
|
+
);
|
|
699
|
+
const navIdx = cdpSendCalls.findIndex((c) => c.method === "Page.navigate");
|
|
700
|
+
expect(createIdx).toBeGreaterThanOrEqual(0);
|
|
701
|
+
expect(navIdx).toBeGreaterThanOrEqual(0);
|
|
702
|
+
expect(createIdx).toBeLessThan(navIdx);
|
|
703
|
+
|
|
704
|
+
// setCdpSessionId was invoked with the returned tabId so the
|
|
705
|
+
// follow-on commands on this client route to the new tab.
|
|
706
|
+
expect(cdpSetSessionIdCalls).toContain("999");
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
test("new_tab: true on extension path with createTab failure aborts with a clear error", async () => {
|
|
710
|
+
parseUrlResult = new URL("https://example.com/page");
|
|
711
|
+
mockExtensionAvailable = true;
|
|
712
|
+
|
|
713
|
+
cdpSendHandler = (method, params) => {
|
|
714
|
+
if (method === "Vellum.createTab") {
|
|
715
|
+
throw new Error("createTab returned no tabId");
|
|
716
|
+
}
|
|
717
|
+
return defaultCdpHandler(method, params);
|
|
718
|
+
};
|
|
719
|
+
|
|
720
|
+
const result = await executeBrowserNavigate(
|
|
721
|
+
{ url: "https://example.com/page", new_tab: true },
|
|
722
|
+
{ ...ctx },
|
|
723
|
+
);
|
|
724
|
+
|
|
725
|
+
expect(result.isError).toBe(true);
|
|
726
|
+
expect(result.content).toContain("Failed to open a new tab");
|
|
727
|
+
// Page.navigate must NOT fire — that's exactly what --new-tab is
|
|
728
|
+
// supposed to prevent in the failure case (silent fallback to
|
|
729
|
+
// active-tab clobbering would defeat the purpose of the flag).
|
|
730
|
+
expect(cdpSendCalls.some((c) => c.method === "Page.navigate")).toBe(false);
|
|
731
|
+
// The createTab-failure path early-returns BEFORE the main
|
|
732
|
+
// try/finally that wraps the navigate flow, so the executor has to
|
|
733
|
+
// dispose the CDP client manually. Verifying here so future edits
|
|
734
|
+
// to that early-return don't silently regress the cleanup.
|
|
735
|
+
expect(cdpDisposed).toBe(true);
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
test("new_tab: true on extension path with no tabId in response clears live session and still continues", async () => {
|
|
739
|
+
// Defensive: dispatcher returns success but no tabId. The
|
|
740
|
+
// executor logs a warn, resets the live cdp session to undefined
|
|
741
|
+
// (so the follow-on Page.navigate routes to the active tab
|
|
742
|
+
// instead of any stale pin the cdp instance was constructed
|
|
743
|
+
// with), and proceeds. The navigate still runs (degraded
|
|
744
|
+
// behaviour but not a hard failure).
|
|
745
|
+
parseUrlResult = new URL("https://example.com/page");
|
|
746
|
+
mockExtensionAvailable = true;
|
|
747
|
+
|
|
748
|
+
cdpSendHandler = (method, params) => {
|
|
749
|
+
if (method === "Vellum.createTab") return {}; // no tabId
|
|
750
|
+
return defaultCdpHandler(method, params);
|
|
751
|
+
};
|
|
752
|
+
|
|
753
|
+
const result = await executeBrowserNavigate(
|
|
754
|
+
{ url: "https://example.com/page", new_tab: true },
|
|
755
|
+
{ ...ctx },
|
|
756
|
+
);
|
|
757
|
+
|
|
758
|
+
expect(result.isError).toBe(false);
|
|
759
|
+
// No new pin was set, BUT the live session was reset to undefined
|
|
760
|
+
// so the follow-on Page.navigate falls back to active-tab routing
|
|
761
|
+
// instead of any stale pin the cdp instance held at construction.
|
|
762
|
+
expect(cdpSetSessionIdCalls).toEqual([undefined]);
|
|
763
|
+
// Page.navigate still ran.
|
|
764
|
+
expect(cdpSendCalls.some((c) => c.method === "Page.navigate")).toBe(true);
|
|
765
|
+
});
|
|
766
|
+
|
|
767
|
+
test("new_tab: true with no tabId in response clears a pre-existing stale pin AND live session (regression)", async () => {
|
|
768
|
+
// Regression for the Codex round-2 findings (P2 + round-3 P1):
|
|
769
|
+
// when Vellum.createTab returns a malformed response with no
|
|
770
|
+
// tabId, the executor falls back to active-tab routing — but
|
|
771
|
+
// (a) the pin store still held the stale pin (round-2 P2 fix
|
|
772
|
+
// added clearPinnedTab), and (b) the LIVE cdp instance was
|
|
773
|
+
// already constructed with that stale cdpSessionId, so the
|
|
774
|
+
// follow-on Page.navigate would still route to the dead tab
|
|
775
|
+
// unless we reset the session on the cdp instance too (round-3
|
|
776
|
+
// P1 fix added cdp.setCdpSessionId(undefined)).
|
|
777
|
+
const { setPinnedTab, getPinnedTab } = await import(
|
|
778
|
+
"../tools/browser/pinned-tabs.js"
|
|
779
|
+
);
|
|
780
|
+
setPinnedTab(ctx.conversationId, "stale-pinned-tab-id");
|
|
781
|
+
expect(getPinnedTab(ctx.conversationId)).toBe("stale-pinned-tab-id");
|
|
782
|
+
|
|
783
|
+
parseUrlResult = new URL("https://example.com/page");
|
|
784
|
+
mockExtensionAvailable = true;
|
|
785
|
+
|
|
786
|
+
cdpSendHandler = (method, params) => {
|
|
787
|
+
if (method === "Vellum.createTab") return {}; // no tabId
|
|
788
|
+
return defaultCdpHandler(method, params);
|
|
789
|
+
};
|
|
790
|
+
|
|
791
|
+
const result = await executeBrowserNavigate(
|
|
792
|
+
{ url: "https://example.com/page", new_tab: true },
|
|
793
|
+
{ ...ctx },
|
|
794
|
+
);
|
|
795
|
+
|
|
796
|
+
expect(result.isError).toBe(false);
|
|
797
|
+
// (a) Pin store cleared.
|
|
798
|
+
expect(getPinnedTab(ctx.conversationId)).toBeUndefined();
|
|
799
|
+
// (b) Live cdp session reset (the fake records every
|
|
800
|
+
// setCdpSessionId arg; expect exactly one call with undefined).
|
|
801
|
+
expect(cdpSetSessionIdCalls).toEqual([undefined]);
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
test("new_tab: true on LOCAL path is a no-op (Playwright manages its own isolated browser)", async () => {
|
|
805
|
+
parseUrlResult = new URL("https://example.com/page");
|
|
806
|
+
mockExtensionAvailable = false; // local path
|
|
807
|
+
|
|
808
|
+
const result = await executeBrowserNavigate(
|
|
809
|
+
{ url: "https://example.com/page", new_tab: true },
|
|
810
|
+
{ ...ctx },
|
|
811
|
+
);
|
|
812
|
+
|
|
813
|
+
expect(result.isError).toBe(false);
|
|
814
|
+
// No Vellum.createTab was issued on the local path — the flag is
|
|
815
|
+
// silently ignored because Playwright opens its own browser and
|
|
816
|
+
// there's no user-tab to disturb.
|
|
817
|
+
expect(cdpSendCalls.some((c) => c.method === "Vellum.createTab")).toBe(
|
|
818
|
+
false,
|
|
819
|
+
);
|
|
820
|
+
expect(cdpSetSessionIdCalls).toEqual([]);
|
|
821
|
+
});
|
|
822
|
+
|
|
823
|
+
test("absence of new_tab leaves extension path untouched (no Vellum.createTab)", async () => {
|
|
824
|
+
parseUrlResult = new URL("https://example.com/page");
|
|
825
|
+
mockExtensionAvailable = true;
|
|
826
|
+
|
|
827
|
+
const result = await executeBrowserNavigate(
|
|
828
|
+
{ url: "https://example.com/page" }, // no new_tab key at all
|
|
829
|
+
{ ...ctx },
|
|
830
|
+
);
|
|
831
|
+
|
|
832
|
+
expect(result.isError).toBe(false);
|
|
833
|
+
expect(cdpSendCalls.some((c) => c.method === "Vellum.createTab")).toBe(
|
|
834
|
+
false,
|
|
835
|
+
);
|
|
836
|
+
expect(cdpSetSessionIdCalls).toEqual([]);
|
|
837
|
+
});
|
|
838
|
+
|
|
667
839
|
// ── Defense-in-depth: post-navigation final URL check ─────────
|
|
668
840
|
|
|
669
841
|
test("post-nav check blocks when final URL resolves to private target", async () => {
|
|
@@ -91,6 +91,10 @@ mock.module("../notifications/emit-signal.js", () => ({
|
|
|
91
91
|
mock.module("../prompts/persona-resolver.js", () => ({
|
|
92
92
|
GUARDIAN_PERSONA_TEMPLATE: "# User Profile\n",
|
|
93
93
|
resolveGuardianPersona: () => "# User Profile\n",
|
|
94
|
+
// buildSystemPrompt now uses resolveUserSlug (for ctx) instead of
|
|
95
|
+
// resolvePersonaContext — give the mock a noop so the import
|
|
96
|
+
// doesn't fail.
|
|
97
|
+
resolveUserSlug: () => null,
|
|
94
98
|
}));
|
|
95
99
|
|
|
96
100
|
mock.module("../memory/conversation-title-service.js", () => ({
|
|
@@ -112,6 +112,10 @@ let mockGuardianPersona: string | null = null;
|
|
|
112
112
|
mock.module("../prompts/persona-resolver.js", () => ({
|
|
113
113
|
GUARDIAN_PERSONA_TEMPLATE,
|
|
114
114
|
resolveGuardianPersona: () => mockGuardianPersona,
|
|
115
|
+
// buildSystemPrompt now uses resolveUserSlug (for ctx) instead of
|
|
116
|
+
// resolvePersonaContext — give the mock a noop so the import
|
|
117
|
+
// doesn't fail.
|
|
118
|
+
resolveUserSlug: () => null,
|
|
115
119
|
}));
|
|
116
120
|
|
|
117
121
|
// Mock conversation store
|
|
@@ -31,6 +31,12 @@ mock.module("../runtime/assistant-event-hub.js", () => ({
|
|
|
31
31
|
_conversationId?: string,
|
|
32
32
|
options?: unknown,
|
|
33
33
|
) => {
|
|
34
|
+
// `interaction_resolved` envelopes are emitted by the pending-interactions
|
|
35
|
+
// tracker for every resolution. They are orthogonal to the host-proxy
|
|
36
|
+
// wire messages these tests assert on, so swallow them here.
|
|
37
|
+
if ((msg as { type?: string } | null)?.type === "interaction_resolved") {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
34
40
|
sentMessages.push(msg);
|
|
35
41
|
sentMessageOptions.push(options);
|
|
36
42
|
},
|
|
@@ -31,6 +31,13 @@ let mockClients: MockClient[] = [];
|
|
|
31
31
|
mock.module("../runtime/assistant-event-hub.js", () => ({
|
|
32
32
|
assistantEventHub: {
|
|
33
33
|
publish: async (event: unknown, _options?: unknown) => {
|
|
34
|
+
// `interaction_resolved` envelopes are emitted by the
|
|
35
|
+
// pending-interactions tracker for every resolution. They are
|
|
36
|
+
// orthogonal to the host-browser wire messages these tests assert
|
|
37
|
+
// on, so swallow them here.
|
|
38
|
+
if ((event as { type?: string } | null)?.type === "interaction_resolved") {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
34
41
|
publishedEvents.push(event);
|
|
35
42
|
},
|
|
36
43
|
getMostRecentClientByCapability: (cap: string) =>
|
|
@@ -41,6 +48,9 @@ mock.module("../runtime/assistant-event-hub.js", () => ({
|
|
|
41
48
|
mockClients.find((c) => c.clientId === clientId)?.actorPrincipalId,
|
|
42
49
|
},
|
|
43
50
|
broadcastMessage: (msg: unknown) => {
|
|
51
|
+
if ((msg as { type?: string } | null)?.type === "interaction_resolved") {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
44
54
|
publishedEvents.push(msg);
|
|
45
55
|
},
|
|
46
56
|
}));
|
|
@@ -10,7 +10,14 @@ type MockClient = {
|
|
|
10
10
|
let mockClients: MockClient[] = [];
|
|
11
11
|
|
|
12
12
|
mock.module("../runtime/assistant-event-hub.js", () => ({
|
|
13
|
-
broadcastMessage: (msg: unknown) =>
|
|
13
|
+
broadcastMessage: (msg: unknown) => {
|
|
14
|
+
// Skip `interaction_resolved` envelopes — pending-interactions emits one
|
|
15
|
+
// on every resolve and these tests assert on host-proxy wire messages.
|
|
16
|
+
if ((msg as { type?: string } | null)?.type === "interaction_resolved") {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
sentMessages.push(msg);
|
|
20
|
+
},
|
|
14
21
|
assistantEventHub: {
|
|
15
22
|
getMostRecentClientByCapability: (cap: string) =>
|
|
16
23
|
cap === "host_cu" && mockHasClient ? { id: "mock-client" } : null,
|
|
@@ -12,7 +12,14 @@ interface MockClient {
|
|
|
12
12
|
let mockClients: MockClient[] = [];
|
|
13
13
|
|
|
14
14
|
mock.module("../runtime/assistant-event-hub.js", () => ({
|
|
15
|
-
broadcastMessage: (msg: unknown) =>
|
|
15
|
+
broadcastMessage: (msg: unknown) => {
|
|
16
|
+
// Skip `interaction_resolved` envelopes — pending-interactions emits one
|
|
17
|
+
// on every resolve and these tests assert on host-proxy wire messages.
|
|
18
|
+
if ((msg as { type?: string } | null)?.type === "interaction_resolved") {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
sentMessages.push(msg);
|
|
22
|
+
},
|
|
16
23
|
assistantEventHub: {
|
|
17
24
|
getMostRecentClientByCapability: (cap: string) => {
|
|
18
25
|
if (mockClients.length > 0) {
|
|
@@ -264,7 +264,7 @@ describe("host_bash — baseline: no sandbox isolation", () => {
|
|
|
264
264
|
// These tests lock that boundary so any accidental addition is caught.
|
|
265
265
|
|
|
266
266
|
describe("host_bash — regression: no proxied-mode additions", () => {
|
|
267
|
-
const definition = hostShellTool
|
|
267
|
+
const definition = hostShellTool;
|
|
268
268
|
const schemaProps = (definition.input_schema as Record<string, unknown>)
|
|
269
269
|
.properties as Record<string, unknown>;
|
|
270
270
|
|