@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
|
@@ -7,6 +7,8 @@ export const SYNC_TAGS = {
|
|
|
7
7
|
assistantSounds: "assistant:self:sounds",
|
|
8
8
|
assistantSchedules: "assistant:self:schedules",
|
|
9
9
|
conversationsList: "conversations:list",
|
|
10
|
+
featureFlagsClient: "feature-flags:client",
|
|
11
|
+
featureFlagsAssistant: "feature-flags:assistant",
|
|
10
12
|
} as const;
|
|
11
13
|
|
|
12
14
|
export type KnownSyncInvalidationTag =
|
|
@@ -24,6 +26,14 @@ export type SyncInvalidationTag =
|
|
|
24
26
|
export interface SyncChangedMessage {
|
|
25
27
|
type: "sync_changed";
|
|
26
28
|
tags: SyncInvalidationTag[];
|
|
29
|
+
/**
|
|
30
|
+
* Optional identifier of the client that originated the change. When set,
|
|
31
|
+
* the server fan-out and clients themselves can suppress self-echoes so
|
|
32
|
+
* the originating tab/process doesn't reinvalidate its own cache off its
|
|
33
|
+
* own mutation. Daemon-internal emits (agent loop, FS watcher, cron) leave
|
|
34
|
+
* this unset so the event fans out to every subscriber as before.
|
|
35
|
+
*/
|
|
36
|
+
originClientId?: string;
|
|
27
37
|
}
|
|
28
38
|
|
|
29
39
|
export const SyncInvalidationTagSchema = z.string().min(1);
|
|
@@ -32,6 +42,7 @@ export const SyncChangedMessageSchema = z
|
|
|
32
42
|
.object({
|
|
33
43
|
type: z.literal("sync_changed"),
|
|
34
44
|
tags: z.array(SyncInvalidationTagSchema).min(1),
|
|
45
|
+
originClientId: z.string().min(1).optional(),
|
|
35
46
|
})
|
|
36
47
|
.strict();
|
|
37
48
|
|
|
@@ -49,11 +60,14 @@ export function conversationMetadataSyncTag(
|
|
|
49
60
|
|
|
50
61
|
export function buildSyncChangedMessage(
|
|
51
62
|
tags: SyncInvalidationTag[],
|
|
63
|
+
originClientId?: string,
|
|
52
64
|
): SyncChangedMessage {
|
|
53
65
|
const dedupedTags = Array.from(new Set(tags));
|
|
66
|
+
const trimmedOrigin = originClientId?.trim();
|
|
54
67
|
const parsed = SyncChangedMessageSchema.parse({
|
|
55
68
|
type: "sync_changed",
|
|
56
69
|
tags: dedupedTags,
|
|
70
|
+
...(trimmedOrigin ? { originClientId: trimmedOrigin } : {}),
|
|
57
71
|
});
|
|
58
72
|
return parsed as SyncChangedMessage;
|
|
59
73
|
}
|
|
@@ -34,10 +34,9 @@ export function installShutdownHandlers(deps: ShutdownDeps): void {
|
|
|
34
34
|
let shuttingDown = false;
|
|
35
35
|
let exitCode = 0;
|
|
36
36
|
|
|
37
|
-
const shutdown = async () => {
|
|
37
|
+
const shutdown = async (_signal?: NodeJS.Signals) => {
|
|
38
38
|
if (shuttingDown) return;
|
|
39
39
|
shuttingDown = true;
|
|
40
|
-
log.info("Shutting down daemon...");
|
|
41
40
|
|
|
42
41
|
// Force exit if graceful shutdown takes too long.
|
|
43
42
|
// Set this BEFORE awaiting heartbeat stop so it covers all
|
|
@@ -156,9 +155,29 @@ export function installShutdownHandlers(deps: ShutdownDeps): void {
|
|
|
156
155
|
process.exit(exitCode);
|
|
157
156
|
};
|
|
158
157
|
|
|
159
|
-
process.on("SIGTERM",
|
|
160
|
-
|
|
161
|
-
|
|
158
|
+
process.on("SIGTERM", () => {
|
|
159
|
+
log.warn(
|
|
160
|
+
{ signal: "SIGTERM", pid: process.pid, uptime: process.uptime() },
|
|
161
|
+
"Received SIGTERM — process termination requested",
|
|
162
|
+
);
|
|
163
|
+
void shutdown("SIGTERM");
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
process.on("SIGINT", () => {
|
|
167
|
+
log.warn(
|
|
168
|
+
{ signal: "SIGINT", pid: process.pid, uptime: process.uptime() },
|
|
169
|
+
"Received SIGINT — user interrupt",
|
|
170
|
+
);
|
|
171
|
+
void shutdown("SIGINT");
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
process.on("SIGHUP", () => {
|
|
175
|
+
log.warn(
|
|
176
|
+
{ signal: "SIGHUP", pid: process.pid, uptime: process.uptime() },
|
|
177
|
+
"Received SIGHUP — terminal hangup",
|
|
178
|
+
);
|
|
179
|
+
void shutdown("SIGHUP");
|
|
180
|
+
});
|
|
162
181
|
|
|
163
182
|
process.on("unhandledRejection", (reason) => {
|
|
164
183
|
log.error(
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { ProfileEntry } from "../config/schemas/llm.js";
|
|
2
|
+
import type { ToolDefinition } from "../providers/types.js";
|
|
3
|
+
|
|
4
|
+
export const SWITCH_INFERENCE_PROFILE_TOOL_NAME = "switch_inference_profile";
|
|
5
|
+
|
|
6
|
+
const PROFILE_DESCRIPTION_FALLBACKS: Record<string, string> = {
|
|
7
|
+
"quality-optimized":
|
|
8
|
+
"Most capable model for complex reasoning, multi-step analysis, math, and coding",
|
|
9
|
+
balanced: "Good balance of quality, cost, and speed for most tasks",
|
|
10
|
+
"cost-optimized":
|
|
11
|
+
"Fast responses for simple factual questions, short lookups, and casual chat",
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export function buildSwitchInferenceProfileToolDef(
|
|
15
|
+
profiles: Record<string, ProfileEntry>,
|
|
16
|
+
currentProfile?: string,
|
|
17
|
+
): ToolDefinition | null {
|
|
18
|
+
const entries = Object.entries(profiles).filter(
|
|
19
|
+
([, entry]) => entry.status !== "disabled",
|
|
20
|
+
);
|
|
21
|
+
if (entries.length < 2) return null;
|
|
22
|
+
|
|
23
|
+
const profileDescriptions = entries
|
|
24
|
+
.map(([key, entry]) => {
|
|
25
|
+
const label = entry.label ?? key;
|
|
26
|
+
const desc =
|
|
27
|
+
entry.description || PROFILE_DESCRIPTION_FALLBACKS[key] || "";
|
|
28
|
+
const descSuffix = desc ? `: ${desc}` : "";
|
|
29
|
+
const current = key === currentProfile ? " (current)" : "";
|
|
30
|
+
return `- ${key} — ${label}${descSuffix}${current}`;
|
|
31
|
+
})
|
|
32
|
+
.join("\n");
|
|
33
|
+
|
|
34
|
+
const currentEntry = currentProfile ? profiles[currentProfile] : undefined;
|
|
35
|
+
const currentLabel = currentEntry?.label ?? currentProfile ?? "current";
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
name: SWITCH_INFERENCE_PROFILE_TOOL_NAME,
|
|
39
|
+
description: `Switch to a different inference profile BEFORE answering. You MUST call this tool when the user's query requires capabilities beyond what your current profile ("${currentLabel}") provides. Examples of when to switch to a more capable profile: multi-step reasoning or analysis, math proofs or derivations, complex coding tasks, detailed creative writing, or any task requiring deep thought. Examples of when to switch to a faster profile: simple greetings, one-word answers, factual lookups. When in doubt about whether you can handle the query well, switch to a more capable profile.\n\nAvailable profiles:\n${profileDescriptions}`,
|
|
40
|
+
input_schema: {
|
|
41
|
+
type: "object" as const,
|
|
42
|
+
properties: {
|
|
43
|
+
profile: {
|
|
44
|
+
type: "string",
|
|
45
|
+
enum: entries.map(([key]) => key),
|
|
46
|
+
description: "The profile key to switch to.",
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
required: ["profile"],
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -57,4 +57,17 @@ export interface ToolSetupContext extends SurfaceConversationContext {
|
|
|
57
57
|
* return `undefined` for the in-flight (background) subagent.
|
|
58
58
|
*/
|
|
59
59
|
currentTurnOverrideProfile?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Set by the `switch_inference_profile` tool when the model self-selects a
|
|
62
|
+
* different profile mid-turn. Read by `readCurrentOverrideProfile` in the
|
|
63
|
+
* agent loop so the next LLM call uses the switched profile. Reset at
|
|
64
|
+
* turn start.
|
|
65
|
+
*/
|
|
66
|
+
toolRoutedProfile?: string;
|
|
67
|
+
/**
|
|
68
|
+
* True when the user has explicitly selected an inference profile for this
|
|
69
|
+
* conversation (via the composer profile picker). When set, tool-based
|
|
70
|
+
* auto-routing is suppressed — the user's explicit choice takes precedence.
|
|
71
|
+
*/
|
|
72
|
+
hasExplicitProfileOverride?: boolean;
|
|
60
73
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `relationship_state_updated` SSE event.
|
|
3
|
+
*
|
|
4
|
+
* Broadcast by the daemon after a successful write of
|
|
5
|
+
* `relationship-state.json` to disk. Subscribers refetch
|
|
6
|
+
* `GET /v1/home/state` to read the new state — payload here just
|
|
7
|
+
* carries the new `updatedAt` for cache-tag comparison.
|
|
8
|
+
*
|
|
9
|
+
* Canonical wire-contract source. Daemon code imports the type
|
|
10
|
+
* directly from this file; external consumers import via
|
|
11
|
+
* `@vellumai/assistant-api`.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { z } from "zod";
|
|
15
|
+
|
|
16
|
+
export const RelationshipStateUpdatedSchema = z
|
|
17
|
+
.object({
|
|
18
|
+
type: z.literal("relationship_state_updated"),
|
|
19
|
+
updatedAt: z.string(),
|
|
20
|
+
})
|
|
21
|
+
.strict();
|
|
22
|
+
|
|
23
|
+
export type RelationshipStateUpdated = z.infer<
|
|
24
|
+
typeof RelationshipStateUpdatedSchema
|
|
25
|
+
>;
|
|
@@ -14,6 +14,7 @@ mock.module("../../runtime/assistant-event-hub.js", () => ({
|
|
|
14
14
|
publish: publishSpy,
|
|
15
15
|
subscribe: () => () => {},
|
|
16
16
|
},
|
|
17
|
+
broadcastMessage: () => {},
|
|
17
18
|
}));
|
|
18
19
|
|
|
19
20
|
// Stub workspace prompt reads so the heartbeat service doesn't try to
|
|
@@ -99,7 +100,6 @@ mock.module("../../prompts/persona-resolver.js", () => ({
|
|
|
99
100
|
}));
|
|
100
101
|
mock.module("../../prompts/system-prompt.js", () => ({
|
|
101
102
|
isTemplateContent: () => false,
|
|
102
|
-
SYSTEM_PROMPT_CACHE_BOUNDARY: "<<CACHE_BOUNDARY>>",
|
|
103
103
|
buildCoreIdentityContext: () => "",
|
|
104
104
|
buildSystemPrompt: () => "",
|
|
105
105
|
ensurePromptFiles: () => {},
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
|
|
14
14
|
import { resolveCallSiteConfig } from "../config/llm-resolver.js";
|
|
15
15
|
import { getConfig } from "../config/loader.js";
|
|
16
|
-
import { resolvePersonaContext } from "../prompts/persona-resolver.js";
|
|
17
16
|
import { buildSystemPrompt } from "../prompts/system-prompt.js";
|
|
18
17
|
import { getConfiguredProvider } from "../providers/provider-send-message.js";
|
|
19
18
|
import { runBtwSidechain } from "../runtime/btw-sidechain.js";
|
|
@@ -56,17 +55,9 @@ export async function refreshPersonalizedGreeting(): Promise<void> {
|
|
|
56
55
|
return;
|
|
57
56
|
}
|
|
58
57
|
|
|
59
|
-
const { userPersona, userSlug, channelPersona } = resolvePersonaContext(
|
|
60
|
-
undefined,
|
|
61
|
-
undefined,
|
|
62
|
-
);
|
|
63
|
-
|
|
64
58
|
const systemPrompt = buildSystemPrompt({
|
|
65
59
|
excludeBootstrap: true,
|
|
66
60
|
excludeCustomPrefix: true,
|
|
67
|
-
userPersona,
|
|
68
|
-
channelPersona,
|
|
69
|
-
userSlug,
|
|
70
61
|
});
|
|
71
62
|
|
|
72
63
|
const result = await runBtwSidechain({
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
import { resolveCallSiteConfig } from "../config/llm-resolver.js";
|
|
17
17
|
import { getConfig } from "../config/loader.js";
|
|
18
18
|
import { listProviders } from "../oauth/oauth-store.js";
|
|
19
|
-
import { resolvePersonaContext } from "../prompts/persona-resolver.js";
|
|
20
19
|
import { buildSystemPrompt } from "../prompts/system-prompt.js";
|
|
21
20
|
import { getConfiguredProvider } from "../providers/provider-send-message.js";
|
|
22
21
|
import { buildAssistantEvent } from "../runtime/assistant-event.js";
|
|
@@ -234,17 +233,9 @@ async function generateAssistantPrompts(
|
|
|
234
233
|
return [];
|
|
235
234
|
}
|
|
236
235
|
|
|
237
|
-
const { userPersona, userSlug, channelPersona } = resolvePersonaContext(
|
|
238
|
-
undefined,
|
|
239
|
-
undefined,
|
|
240
|
-
);
|
|
241
|
-
|
|
242
236
|
const systemPrompt = buildSystemPrompt({
|
|
243
237
|
excludeBootstrap: true,
|
|
244
238
|
excludeCustomPrefix: true,
|
|
245
|
-
userPersona,
|
|
246
|
-
channelPersona,
|
|
247
|
-
userSlug,
|
|
248
239
|
});
|
|
249
240
|
|
|
250
241
|
const existingLabels = deterministicPrompts.map((p) => p.label).join(", ");
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { connect, type Socket } from "node:net";
|
|
2
|
+
|
|
3
|
+
import { refreshOverridesFromGateway } from "../config/assistant-feature-flags.js";
|
|
4
|
+
import { SYNC_TAGS } from "../daemon/message-types/sync.js";
|
|
5
|
+
import { publishSyncInvalidation } from "../runtime/sync/sync-publisher.js";
|
|
6
|
+
import { getLogger } from "../util/logger.js";
|
|
7
|
+
import { resolveIpcSocketPath } from "./socket-path.js";
|
|
8
|
+
|
|
9
|
+
const log = getLogger("gateway-flag-listener");
|
|
10
|
+
|
|
11
|
+
const MAX_BACKOFF_MS = 30_000;
|
|
12
|
+
const INITIAL_BACKOFF_MS = 1_000;
|
|
13
|
+
|
|
14
|
+
let socket: Socket | null = null;
|
|
15
|
+
let stopped = false;
|
|
16
|
+
let reconnectTimer: ReturnType<typeof setTimeout> | null = null;
|
|
17
|
+
let currentBackoffMs = INITIAL_BACKOFF_MS;
|
|
18
|
+
|
|
19
|
+
function getSocketPath(): string {
|
|
20
|
+
return resolveIpcSocketPath("gateway").path;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function handleData(chunk: Buffer): void {
|
|
24
|
+
const lines = chunk.toString().split("\n");
|
|
25
|
+
for (const line of lines) {
|
|
26
|
+
const trimmed = line.trim();
|
|
27
|
+
if (!trimmed) continue;
|
|
28
|
+
try {
|
|
29
|
+
const msg = JSON.parse(trimmed) as { event?: string };
|
|
30
|
+
if (msg.event === "feature_flags_changed") {
|
|
31
|
+
log.info("Received feature_flags_changed event — refreshing overrides");
|
|
32
|
+
refreshOverridesFromGateway().catch((err) => {
|
|
33
|
+
log.warn({ err }, "Failed to refresh feature flag overrides");
|
|
34
|
+
});
|
|
35
|
+
// Fan out to every connected web client so React Query caches
|
|
36
|
+
// for `/v1/feature-flags/client-flag-values/` and
|
|
37
|
+
// `/v1/assistants/:id/feature-flags` invalidate immediately
|
|
38
|
+
// instead of waiting on a 5s polling tick.
|
|
39
|
+
publishSyncInvalidation([
|
|
40
|
+
SYNC_TAGS.featureFlagsClient,
|
|
41
|
+
SYNC_TAGS.featureFlagsAssistant,
|
|
42
|
+
]).catch((err) => {
|
|
43
|
+
log.warn({ err }, "Failed to broadcast feature-flags sync_changed");
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
} catch {
|
|
47
|
+
// Ignore non-JSON lines (e.g. IPC responses on a shared socket)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function scheduleReconnect(): void {
|
|
53
|
+
if (stopped) return;
|
|
54
|
+
reconnectTimer = setTimeout(() => {
|
|
55
|
+
reconnectTimer = null;
|
|
56
|
+
connectToGateway();
|
|
57
|
+
}, currentBackoffMs);
|
|
58
|
+
currentBackoffMs = Math.min(currentBackoffMs * 2, MAX_BACKOFF_MS);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function connectToGateway(): void {
|
|
62
|
+
if (stopped) return;
|
|
63
|
+
|
|
64
|
+
const socketPath = getSocketPath();
|
|
65
|
+
const conn = connect(socketPath);
|
|
66
|
+
|
|
67
|
+
conn.on("connect", () => {
|
|
68
|
+
if (stopped) {
|
|
69
|
+
conn.destroy();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
log.info("Connected to gateway IPC for flag events");
|
|
73
|
+
currentBackoffMs = INITIAL_BACKOFF_MS;
|
|
74
|
+
socket = conn;
|
|
75
|
+
refreshOverridesFromGateway().catch((err) => {
|
|
76
|
+
log.warn({ err }, "Failed to refresh feature flag overrides on reconnect");
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
let buffer = "";
|
|
81
|
+
conn.on("data", (chunk) => {
|
|
82
|
+
buffer += chunk.toString();
|
|
83
|
+
let newlineIdx: number;
|
|
84
|
+
while ((newlineIdx = buffer.indexOf("\n")) !== -1) {
|
|
85
|
+
const line = buffer.slice(0, newlineIdx);
|
|
86
|
+
buffer = buffer.slice(newlineIdx + 1);
|
|
87
|
+
if (line.trim()) {
|
|
88
|
+
handleData(Buffer.from(line));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
conn.on("close", () => {
|
|
94
|
+
socket = null;
|
|
95
|
+
if (!stopped) {
|
|
96
|
+
log.debug("Gateway IPC connection closed — reconnecting");
|
|
97
|
+
scheduleReconnect();
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
conn.on("error", (err) => {
|
|
102
|
+
log.debug({ err }, "Gateway IPC connection error");
|
|
103
|
+
conn.destroy();
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function startGatewayFlagListener(): void {
|
|
108
|
+
stopped = false;
|
|
109
|
+
currentBackoffMs = INITIAL_BACKOFF_MS;
|
|
110
|
+
connectToGateway();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function stopGatewayFlagListener(): void {
|
|
114
|
+
stopped = true;
|
|
115
|
+
if (reconnectTimer) {
|
|
116
|
+
clearTimeout(reconnectTimer);
|
|
117
|
+
reconnectTimer = null;
|
|
118
|
+
}
|
|
119
|
+
if (socket) {
|
|
120
|
+
socket.destroy();
|
|
121
|
+
socket = null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -22,12 +22,9 @@ import { z } from "zod";
|
|
|
22
22
|
import type { MeetHostSupervisor } from "../../daemon/meet-host-supervisor.js";
|
|
23
23
|
import { registerShutdownHook } from "../../daemon/shutdown-registry.js";
|
|
24
24
|
import { registerSkillRoute } from "../../runtime/skill-route-registry.js";
|
|
25
|
+
import { resolveExecutionTarget } from "../../tools/execution-target.js";
|
|
25
26
|
import { registerSkillTools } from "../../tools/registry.js";
|
|
26
|
-
import type {
|
|
27
|
-
ExecutionTarget,
|
|
28
|
-
Tool,
|
|
29
|
-
ToolDefinition,
|
|
30
|
-
} from "../../tools/types.js";
|
|
27
|
+
import type { ExecutionTarget, Tool } from "../../tools/types.js";
|
|
31
28
|
import { RiskLevel } from "../../tools/types.js";
|
|
32
29
|
import { getLogger } from "../../util/logger.js";
|
|
33
30
|
import type { SkillIpcRoute } from "../skill-ipc-types.js";
|
|
@@ -182,25 +179,24 @@ export function __getActiveSessionCountForTesting(): number {
|
|
|
182
179
|
* exercised end-to-end.
|
|
183
180
|
*/
|
|
184
181
|
function buildProxyTool(manifest: ToolManifest): Tool {
|
|
185
|
-
const definition: ToolDefinition = {
|
|
186
|
-
name: manifest.name,
|
|
187
|
-
description: manifest.description,
|
|
188
|
-
input_schema: manifest.input_schema as object,
|
|
189
|
-
};
|
|
190
182
|
// RiskLevel is a string enum whose values are "low" | "medium" | "high",
|
|
191
183
|
// matching the schema above exactly — the cast is a no-op at runtime.
|
|
192
184
|
return {
|
|
193
185
|
name: manifest.name,
|
|
194
186
|
description: manifest.description,
|
|
187
|
+
input_schema: manifest.input_schema as object,
|
|
195
188
|
category: manifest.category,
|
|
196
189
|
defaultRiskLevel: manifest.defaultRiskLevel as RiskLevel,
|
|
197
190
|
executionMode: manifest.executionMode ?? "proxy",
|
|
198
|
-
executionTarget:
|
|
191
|
+
executionTarget: resolveExecutionTarget({
|
|
192
|
+
name: manifest.name,
|
|
193
|
+
executionTarget: manifest.executionTarget as ExecutionTarget | undefined,
|
|
194
|
+
executionMode: manifest.executionMode ?? "proxy",
|
|
195
|
+
}),
|
|
199
196
|
origin: "skill",
|
|
200
197
|
ownerSkillId: manifest.ownerSkillId,
|
|
201
198
|
ownerSkillBundled: manifest.ownerSkillBundled,
|
|
202
199
|
ownerSkillVersionHash: manifest.ownerSkillVersionHash,
|
|
203
|
-
getDefinition: () => definition,
|
|
204
200
|
execute: async () => {
|
|
205
201
|
// Only reached when no supervisor is attached (tests/boot race);
|
|
206
202
|
// the supervisor short-circuit above replaces this with the
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for `db-async-query.ts` — the runAsyncSqlite abstraction.
|
|
3
|
+
*
|
|
4
|
+
* The contract this PR locks in:
|
|
5
|
+
* 1. **The main event loop keeps ticking while a long SQLite
|
|
6
|
+
* statement is in flight via the sqlite3 CLI backend.** This is
|
|
7
|
+
* the structural anti-block assertion — a recursive `setImmediate`
|
|
8
|
+
* probe counts event-loop iterations during the operation; if
|
|
9
|
+
* anyone moves the slow path back onto the main thread,
|
|
10
|
+
* `bun:sqlite` is synchronous and tick counting collapses to ~0;
|
|
11
|
+
* this test fails loudly.
|
|
12
|
+
* 2. The CLI backend reports `backend: "sqlite3-cli"` and `ok: true`
|
|
13
|
+
* on success.
|
|
14
|
+
* 3. The in-process fallback backend executes the statement
|
|
15
|
+
* synchronously and reports `backend: "in-process-blocking"`.
|
|
16
|
+
* 4. Errors from sqlite3 surface as `ok: false` with the stderr
|
|
17
|
+
* preserved in `error`.
|
|
18
|
+
*/
|
|
19
|
+
import { beforeEach, describe, expect, test } from "bun:test";
|
|
20
|
+
|
|
21
|
+
const { getSqlite } = await import("../db-connection.js");
|
|
22
|
+
const { initializeDb } = await import("../db-init.js");
|
|
23
|
+
const { runAsyncSqlite, _resetFallbackWarning } =
|
|
24
|
+
await import("../db-async-query.js");
|
|
25
|
+
const { findSqlite3 } = await import("../../util/sqlite3-runtime.js");
|
|
26
|
+
|
|
27
|
+
initializeDb();
|
|
28
|
+
|
|
29
|
+
const sqlite3Available = findSqlite3() !== undefined;
|
|
30
|
+
|
|
31
|
+
beforeEach(() => {
|
|
32
|
+
_resetFallbackWarning();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
function inflateAndDelete(byteTarget: number): void {
|
|
36
|
+
const sqlite = getSqlite();
|
|
37
|
+
sqlite.exec(
|
|
38
|
+
"CREATE TABLE IF NOT EXISTS async_bloat (id INTEGER PRIMARY KEY, payload BLOB)",
|
|
39
|
+
);
|
|
40
|
+
const pageSize = (
|
|
41
|
+
sqlite.query("PRAGMA page_size").get() as { page_size: number }
|
|
42
|
+
).page_size;
|
|
43
|
+
const rowsTarget = Math.max(1, Math.ceil(byteTarget / pageSize));
|
|
44
|
+
const payload = new Uint8Array(Math.max(1, pageSize - 64));
|
|
45
|
+
const insert = sqlite.prepare("INSERT INTO async_bloat (payload) VALUES (?)");
|
|
46
|
+
sqlite.exec("BEGIN");
|
|
47
|
+
for (let i = 0; i < rowsTarget; i++) {
|
|
48
|
+
insert.run(payload);
|
|
49
|
+
}
|
|
50
|
+
sqlite.exec("COMMIT");
|
|
51
|
+
sqlite.exec("DELETE FROM async_bloat");
|
|
52
|
+
sqlite.exec("DROP TABLE async_bloat");
|
|
53
|
+
sqlite.exec("PRAGMA wal_checkpoint(TRUNCATE)");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
describe("runAsyncSqlite", () => {
|
|
57
|
+
test("returns ok=true for a trivial statement", async () => {
|
|
58
|
+
const result = await runAsyncSqlite("SELECT 1");
|
|
59
|
+
expect(result.ok).toBe(true);
|
|
60
|
+
expect(result.error).toBeNull();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("in-process fallback reports the right backend", async () => {
|
|
64
|
+
const result = await runAsyncSqlite("SELECT 1", {
|
|
65
|
+
forceBackend: "in-process-blocking",
|
|
66
|
+
});
|
|
67
|
+
expect(result.ok).toBe(true);
|
|
68
|
+
expect(result.backend).toBe("in-process-blocking");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("in-process fallback emits changes() count on stdout after a DELETE", async () => {
|
|
72
|
+
// Regression for Codex P1 on #31894: callers (e.g. prune jobs) rely
|
|
73
|
+
// on reading the row count off `result.stdout`. The CLI backend
|
|
74
|
+
// populates this naturally when the SQL ends with `SELECT changes();`,
|
|
75
|
+
// but `bun:sqlite`'s `exec()` discards SELECT results — so the
|
|
76
|
+
// in-process backend has to synthesize the same line, or the
|
|
77
|
+
// re-enqueue gate in pruneOld*Job silently never fires on hosts
|
|
78
|
+
// without the sqlite3 CLI.
|
|
79
|
+
const sqlite = getSqlite();
|
|
80
|
+
sqlite.exec(
|
|
81
|
+
"CREATE TABLE IF NOT EXISTS async_changes_probe (id INTEGER PRIMARY KEY)",
|
|
82
|
+
);
|
|
83
|
+
sqlite.exec("DELETE FROM async_changes_probe");
|
|
84
|
+
sqlite.exec(
|
|
85
|
+
"INSERT INTO async_changes_probe (id) VALUES (1),(2),(3),(4),(5)",
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const result = await runAsyncSqlite(
|
|
89
|
+
"DELETE FROM async_changes_probe WHERE id <= 3; SELECT changes();",
|
|
90
|
+
{ forceBackend: "in-process-blocking" },
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
expect(result.ok).toBe(true);
|
|
94
|
+
expect(result.backend).toBe("in-process-blocking");
|
|
95
|
+
// The synthesized stdout matches what the CLI backend would emit:
|
|
96
|
+
// a bare integer on its own line. The exact format keeps the
|
|
97
|
+
// parser in cleanup.ts backend-agnostic.
|
|
98
|
+
expect(result.stdout).toBe("3\n");
|
|
99
|
+
|
|
100
|
+
sqlite.exec("DROP TABLE async_changes_probe");
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test.if(sqlite3Available)(
|
|
104
|
+
"sqlite3 CLI backend reports the right backend on success",
|
|
105
|
+
async () => {
|
|
106
|
+
const result = await runAsyncSqlite("SELECT 1");
|
|
107
|
+
expect(result.ok).toBe(true);
|
|
108
|
+
expect(result.backend).toBe("sqlite3-cli");
|
|
109
|
+
},
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
test.if(sqlite3Available)(
|
|
113
|
+
"surfaces sqlite3 errors as ok=false with the message preserved",
|
|
114
|
+
async () => {
|
|
115
|
+
// Intentional SQL syntax error.
|
|
116
|
+
const result = await runAsyncSqlite("THIS IS NOT VALID SQL");
|
|
117
|
+
expect(result.ok).toBe(false);
|
|
118
|
+
expect(result.backend).toBe("sqlite3-cli");
|
|
119
|
+
expect(result.error).toBeTruthy();
|
|
120
|
+
},
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
test.if(sqlite3Available)(
|
|
124
|
+
"VACUUM via sqlite3 CLI keeps the event loop ticking (anti-block)",
|
|
125
|
+
async () => {
|
|
126
|
+
// Inflate the DB so VACUUM has measurable work to do. Without
|
|
127
|
+
// this the subprocess finishes in single-digit ms and the
|
|
128
|
+
// probe has no opportunity to record meaningful ticks.
|
|
129
|
+
inflateAndDelete(8 * 1024 * 1024);
|
|
130
|
+
|
|
131
|
+
// Probe the event loop with recursive setImmediate. This fires
|
|
132
|
+
// on every event-loop iteration with no minimum delay, so on a
|
|
133
|
+
// healthy unblocked loop it produces tens of thousands of ticks
|
|
134
|
+
// per second (vs. setInterval(1) which is capped by the host's
|
|
135
|
+
// timer resolution — observed at ~32 ms on GitHub Actions
|
|
136
|
+
// runners). If anyone moves VACUUM back onto the main thread,
|
|
137
|
+
// `bun:sqlite` is sync and tick count collapses to ~0; the
|
|
138
|
+
// assertion below fails loudly. The signal is intentionally
|
|
139
|
+
// binary: "many" vs "none".
|
|
140
|
+
let tickCount = 0;
|
|
141
|
+
let probing = true;
|
|
142
|
+
const tick = (): void => {
|
|
143
|
+
if (!probing) return;
|
|
144
|
+
tickCount += 1;
|
|
145
|
+
setImmediate(tick);
|
|
146
|
+
};
|
|
147
|
+
setImmediate(tick);
|
|
148
|
+
|
|
149
|
+
let result;
|
|
150
|
+
try {
|
|
151
|
+
result = await runAsyncSqlite("VACUUM");
|
|
152
|
+
} finally {
|
|
153
|
+
probing = false;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
expect(result.ok).toBe(true);
|
|
157
|
+
expect(result.backend).toBe("sqlite3-cli");
|
|
158
|
+
|
|
159
|
+
// Any positive tick count proves the event loop wasn't blocked.
|
|
160
|
+
// A sync in-process VACUUM would collapse this to 0.
|
|
161
|
+
expect(tickCount).toBeGreaterThanOrEqual(1);
|
|
162
|
+
},
|
|
163
|
+
60_000,
|
|
164
|
+
);
|
|
165
|
+
});
|