@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
|
@@ -61,22 +61,43 @@ mock.module("../prompts/user-reference.js", () => ({
|
|
|
61
61
|
resolveUserPronouns: () => null,
|
|
62
62
|
}));
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
// Stub persona-resolver so tests can dictate the slug `buildSystemPrompt`
|
|
65
|
+
// sees without writing contact rows to the test DB. User and channel
|
|
66
|
+
// persona content now flows through bundled sections that read files
|
|
67
|
+
// directly, so tests write the persona file under TEST_DIR rather than
|
|
68
|
+
// stubbing the content here.
|
|
69
|
+
const mockPersona: {
|
|
70
|
+
userSlug: string | null;
|
|
71
|
+
guardianPersona: string | null;
|
|
72
|
+
} = { userSlug: null, guardianPersona: null };
|
|
73
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
74
|
+
const realPersonaResolver = require("../prompts/persona-resolver.js");
|
|
75
|
+
mock.module("../prompts/persona-resolver.js", () => ({
|
|
76
|
+
...realPersonaResolver,
|
|
77
|
+
resolveUserSlug: () => mockPersona.userSlug,
|
|
78
|
+
resolveGuardianPersona: () => mockPersona.guardianPersona,
|
|
79
|
+
}));
|
|
80
|
+
|
|
81
|
+
const { buildSystemPrompt } = await import("../prompts/system-prompt.js");
|
|
66
82
|
|
|
67
83
|
/**
|
|
68
|
-
*
|
|
84
|
+
* Slice the assembled system prompt from the `# First-Run Ritual`
|
|
85
|
+
* marker through the end of the prompt, returning just the
|
|
86
|
+
* `13-bootstrap` section's rendered payload. Returns "" when the
|
|
87
|
+
* section isn't rendered (no BOOTSTRAP.md, `excludeBootstrap: true`,
|
|
88
|
+
* etc.).
|
|
69
89
|
*/
|
|
70
|
-
function
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
: result;
|
|
90
|
+
function bootstrapBlock(result: string): string {
|
|
91
|
+
const ritualIdx = result.indexOf("# First-Run Ritual");
|
|
92
|
+
if (ritualIdx < 0) return "";
|
|
93
|
+
return result.slice(ritualIdx);
|
|
75
94
|
}
|
|
76
95
|
|
|
77
96
|
describe("pre-chat onboarding contract", () => {
|
|
78
97
|
beforeEach(() => {
|
|
79
98
|
mkdirSync(TEST_DIR, { recursive: true });
|
|
99
|
+
mockPersona.userSlug = null;
|
|
100
|
+
mockPersona.guardianPersona = null;
|
|
80
101
|
});
|
|
81
102
|
|
|
82
103
|
afterEach(() => {
|
|
@@ -87,6 +108,8 @@ describe("pre-chat onboarding contract", () => {
|
|
|
87
108
|
"BOOTSTRAP.md",
|
|
88
109
|
"BOOTSTRAP-REFERENCE.md",
|
|
89
110
|
"UPDATES.md",
|
|
111
|
+
"users",
|
|
112
|
+
"channels",
|
|
90
113
|
]) {
|
|
91
114
|
const p = join(TEST_DIR, name);
|
|
92
115
|
if (existsSync(p)) rmSync(p, { recursive: true, force: true });
|
|
@@ -151,20 +174,20 @@ describe("pre-chat onboarding contract", () => {
|
|
|
151
174
|
};
|
|
152
175
|
|
|
153
176
|
const result = buildSystemPrompt({ onboardingContext: context });
|
|
154
|
-
const
|
|
177
|
+
const bootstrap = bootstrapBlock(result);
|
|
155
178
|
|
|
156
|
-
expect(
|
|
157
|
-
expect(
|
|
179
|
+
expect(bootstrap).toContain("## First-Run User Context");
|
|
180
|
+
expect(bootstrap).toContain(
|
|
158
181
|
"The user completed setup before this conversation.",
|
|
159
182
|
);
|
|
160
|
-
expect(
|
|
161
|
-
expect(
|
|
162
|
-
expect(
|
|
163
|
-
expect(
|
|
164
|
-
expect(
|
|
183
|
+
expect(bootstrap).toContain("- Daily tools: Slack, Linear");
|
|
184
|
+
expect(bootstrap).toContain("- Common work: builds code, apps, or tools");
|
|
185
|
+
expect(bootstrap).toContain("- Name: Alex");
|
|
186
|
+
expect(bootstrap).toContain("- Chosen assistant name: Nova");
|
|
187
|
+
expect(bootstrap).toContain("Apply this context quietly.");
|
|
165
188
|
|
|
166
189
|
// Raw JSON must NOT be present
|
|
167
|
-
expect(
|
|
190
|
+
expect(bootstrap).not.toContain("```json");
|
|
168
191
|
});
|
|
169
192
|
|
|
170
193
|
test("does NOT inject onboarding context when BOOTSTRAP.md does not exist", () => {
|
|
@@ -177,11 +200,11 @@ describe("pre-chat onboarding contract", () => {
|
|
|
177
200
|
};
|
|
178
201
|
|
|
179
202
|
const result = buildSystemPrompt({ onboardingContext: context });
|
|
180
|
-
const
|
|
203
|
+
const bootstrap = bootstrapBlock(result);
|
|
181
204
|
|
|
182
|
-
expect(
|
|
183
|
-
expect(
|
|
184
|
-
expect(
|
|
205
|
+
expect(bootstrap).not.toContain("## First-Run User Context");
|
|
206
|
+
expect(bootstrap).not.toContain("First-Run User Context");
|
|
207
|
+
expect(bootstrap).not.toContain("- Daily tools:");
|
|
185
208
|
});
|
|
186
209
|
|
|
187
210
|
test("does NOT inject onboarding context when excludeBootstrap is true", () => {
|
|
@@ -200,10 +223,10 @@ describe("pre-chat onboarding contract", () => {
|
|
|
200
223
|
onboardingContext: context,
|
|
201
224
|
excludeBootstrap: true,
|
|
202
225
|
});
|
|
203
|
-
const
|
|
226
|
+
const bootstrap = bootstrapBlock(result);
|
|
204
227
|
|
|
205
|
-
expect(
|
|
206
|
-
expect(
|
|
228
|
+
expect(bootstrap).not.toContain("## First-Run User Context");
|
|
229
|
+
expect(bootstrap).not.toContain("First-Run Ritual");
|
|
207
230
|
});
|
|
208
231
|
|
|
209
232
|
test("omits onboarding section when context is undefined", () => {
|
|
@@ -213,12 +236,12 @@ describe("pre-chat onboarding contract", () => {
|
|
|
213
236
|
);
|
|
214
237
|
|
|
215
238
|
const result = buildSystemPrompt({ onboardingContext: undefined });
|
|
216
|
-
const
|
|
239
|
+
const bootstrap = bootstrapBlock(result);
|
|
217
240
|
|
|
218
241
|
// Bootstrap should still be present
|
|
219
|
-
expect(
|
|
242
|
+
expect(bootstrap).toContain("First-Run Ritual");
|
|
220
243
|
// But no onboarding context section
|
|
221
|
-
expect(
|
|
244
|
+
expect(bootstrap).not.toContain("## First-Run User Context");
|
|
222
245
|
});
|
|
223
246
|
|
|
224
247
|
test("accepts all four personality tones", () => {
|
|
@@ -238,10 +261,10 @@ describe("pre-chat onboarding contract", () => {
|
|
|
238
261
|
};
|
|
239
262
|
|
|
240
263
|
const result = buildSystemPrompt({ onboardingContext: context });
|
|
241
|
-
const
|
|
264
|
+
const bootstrap = bootstrapBlock(result);
|
|
242
265
|
|
|
243
|
-
expect(
|
|
244
|
-
expect(
|
|
266
|
+
expect(bootstrap).toContain("## First-Run User Context");
|
|
267
|
+
expect(bootstrap).toContain(`- Preferred initial voice: ${tone}`);
|
|
245
268
|
}
|
|
246
269
|
});
|
|
247
270
|
|
|
@@ -260,20 +283,20 @@ describe("pre-chat onboarding contract", () => {
|
|
|
260
283
|
};
|
|
261
284
|
|
|
262
285
|
const result = buildSystemPrompt({ onboardingContext: context });
|
|
263
|
-
const
|
|
286
|
+
const bootstrap = bootstrapBlock(result);
|
|
264
287
|
|
|
265
288
|
// Should contain compact markdown lines
|
|
266
|
-
expect(
|
|
267
|
-
expect(
|
|
268
|
-
expect(
|
|
269
|
-
expect(
|
|
270
|
-
expect(
|
|
271
|
-
expect(
|
|
289
|
+
expect(bootstrap).toContain("## First-Run User Context");
|
|
290
|
+
expect(bootstrap).toContain("- Name: Jane");
|
|
291
|
+
expect(bootstrap).toContain("- Common work: plans and coordinates work");
|
|
292
|
+
expect(bootstrap).toContain("- Daily tools: Notion");
|
|
293
|
+
expect(bootstrap).toContain("- Chosen assistant name: Kit");
|
|
294
|
+
expect(bootstrap).toContain("- Preferred initial voice: warm");
|
|
272
295
|
|
|
273
296
|
// Must NOT contain JSON output
|
|
274
|
-
expect(
|
|
297
|
+
expect(bootstrap).not.toContain("```json");
|
|
275
298
|
const expectedJson = JSON.stringify(context, null, 2);
|
|
276
|
-
expect(
|
|
299
|
+
expect(bootstrap).not.toContain(expectedJson);
|
|
277
300
|
});
|
|
278
301
|
|
|
279
302
|
test("empty tools/tasks arrays result in no Daily tools / Common work lines", () => {
|
|
@@ -290,12 +313,12 @@ describe("pre-chat onboarding contract", () => {
|
|
|
290
313
|
};
|
|
291
314
|
|
|
292
315
|
const result = buildSystemPrompt({ onboardingContext: context });
|
|
293
|
-
const
|
|
316
|
+
const bootstrap = bootstrapBlock(result);
|
|
294
317
|
|
|
295
|
-
expect(
|
|
296
|
-
expect(
|
|
297
|
-
expect(
|
|
298
|
-
expect(
|
|
318
|
+
expect(bootstrap).toContain("## First-Run User Context");
|
|
319
|
+
expect(bootstrap).toContain("- Name: Alex");
|
|
320
|
+
expect(bootstrap).not.toContain("- Daily tools:");
|
|
321
|
+
expect(bootstrap).not.toContain("- Common work:");
|
|
299
322
|
});
|
|
300
323
|
|
|
301
324
|
test("absent userName results in no Name line", () => {
|
|
@@ -311,16 +334,16 @@ describe("pre-chat onboarding contract", () => {
|
|
|
311
334
|
};
|
|
312
335
|
|
|
313
336
|
const result = buildSystemPrompt({ onboardingContext: context });
|
|
314
|
-
const
|
|
337
|
+
const bootstrap = bootstrapBlock(result);
|
|
315
338
|
|
|
316
|
-
expect(
|
|
317
|
-
expect(
|
|
339
|
+
expect(bootstrap).toContain("## First-Run User Context");
|
|
340
|
+
expect(bootstrap).not.toContain("- Name:");
|
|
318
341
|
// Other fields should still be present
|
|
319
|
-
expect(
|
|
320
|
-
expect(
|
|
342
|
+
expect(bootstrap).toContain("- Daily tools: Slack");
|
|
343
|
+
expect(bootstrap).toContain(
|
|
321
344
|
"- Common work: writes docs, emails, or content",
|
|
322
345
|
);
|
|
323
|
-
expect(
|
|
346
|
+
expect(bootstrap).toContain("- Preferred initial voice: warm");
|
|
324
347
|
});
|
|
325
348
|
});
|
|
326
349
|
|
|
@@ -356,26 +379,26 @@ describe("pre-chat onboarding contract", () => {
|
|
|
356
379
|
};
|
|
357
380
|
|
|
358
381
|
const result = buildSystemPrompt({ onboardingContext: context });
|
|
359
|
-
const
|
|
382
|
+
const bootstrap = bootstrapBlock(result);
|
|
360
383
|
|
|
361
384
|
// Heading is present
|
|
362
|
-
expect(
|
|
385
|
+
expect(bootstrap).toContain("## First-Run User Context");
|
|
363
386
|
|
|
364
387
|
// Normalized labels appear (capitalised tool names, human-readable task descriptions)
|
|
365
|
-
expect(
|
|
366
|
-
expect(
|
|
367
|
-
expect(
|
|
368
|
-
expect(
|
|
388
|
+
expect(bootstrap).toContain("- Daily tools: Slack, Notion, Linear");
|
|
389
|
+
expect(bootstrap).toContain("- Name: Alice");
|
|
390
|
+
expect(bootstrap).toContain("- Chosen assistant name: Pax");
|
|
391
|
+
expect(bootstrap).toContain("- Preferred initial voice: grounded");
|
|
369
392
|
// Common work descriptions are normalised from task IDs
|
|
370
|
-
expect(
|
|
371
|
-
|
|
372
|
-
// No raw JSON anywhere in the
|
|
373
|
-
expect(
|
|
374
|
-
expect(
|
|
375
|
-
expect(
|
|
376
|
-
expect(
|
|
377
|
-
expect(
|
|
378
|
-
expect(
|
|
393
|
+
expect(bootstrap).toContain("- Common work:");
|
|
394
|
+
|
|
395
|
+
// No raw JSON anywhere in the bootstrap block
|
|
396
|
+
expect(bootstrap).not.toContain("```json");
|
|
397
|
+
expect(bootstrap).not.toContain('"tools"');
|
|
398
|
+
expect(bootstrap).not.toContain('"tasks"');
|
|
399
|
+
expect(bootstrap).not.toContain('"tone"');
|
|
400
|
+
expect(bootstrap).not.toContain('"userName"');
|
|
401
|
+
expect(bootstrap).not.toContain('"assistantName"');
|
|
379
402
|
});
|
|
380
403
|
|
|
381
404
|
test("without BOOTSTRAP.md, onboarding context does NOT appear in system prompt", () => {
|
|
@@ -389,15 +412,15 @@ describe("pre-chat onboarding contract", () => {
|
|
|
389
412
|
};
|
|
390
413
|
|
|
391
414
|
const result = buildSystemPrompt({ onboardingContext: context });
|
|
392
|
-
const
|
|
415
|
+
const bootstrap = bootstrapBlock(result);
|
|
393
416
|
|
|
394
417
|
// Onboarding section must be absent
|
|
395
|
-
expect(
|
|
396
|
-
expect(
|
|
397
|
-
expect(
|
|
398
|
-
expect(
|
|
399
|
-
expect(
|
|
400
|
-
expect(
|
|
418
|
+
expect(bootstrap).not.toContain("## First-Run User Context");
|
|
419
|
+
expect(bootstrap).not.toContain("First-Run Ritual");
|
|
420
|
+
expect(bootstrap).not.toContain("- Daily tools:");
|
|
421
|
+
expect(bootstrap).not.toContain("- Name: Bob");
|
|
422
|
+
expect(bootstrap).not.toContain("- Chosen assistant name:");
|
|
423
|
+
expect(bootstrap).not.toContain("Apply this context quietly.");
|
|
401
424
|
});
|
|
402
425
|
|
|
403
426
|
test("excludeBootstrap suppresses both bootstrap and onboarding sections", () => {
|
|
@@ -418,34 +441,38 @@ describe("pre-chat onboarding contract", () => {
|
|
|
418
441
|
onboardingContext: context,
|
|
419
442
|
excludeBootstrap: true,
|
|
420
443
|
});
|
|
421
|
-
const
|
|
444
|
+
const bootstrap = bootstrapBlock(result);
|
|
422
445
|
|
|
423
446
|
// Both bootstrap and onboarding must be suppressed
|
|
424
|
-
expect(
|
|
425
|
-
expect(
|
|
426
|
-
expect(
|
|
427
|
-
expect(
|
|
428
|
-
expect(
|
|
447
|
+
expect(bootstrap).not.toContain("First-Run Ritual");
|
|
448
|
+
expect(bootstrap).not.toContain("## First-Run User Context");
|
|
449
|
+
expect(bootstrap).not.toContain("- Daily tools:");
|
|
450
|
+
expect(bootstrap).not.toContain("- Name: Charlie");
|
|
451
|
+
expect(bootstrap).not.toContain("Apply this context quietly.");
|
|
429
452
|
});
|
|
430
453
|
|
|
431
454
|
test("userPersona is included independently of onboarding context", () => {
|
|
432
|
-
// No BOOTSTRAP.md — the durable persona path after bootstrap is deleted
|
|
433
|
-
|
|
434
|
-
|
|
455
|
+
// No BOOTSTRAP.md — the durable persona path after bootstrap is deleted.
|
|
456
|
+
// User persona content now lives in `users/<slug>.md` and renders
|
|
457
|
+
// via the `10-user-persona` bundled section in the static prefix.
|
|
458
|
+
mkdirSync(join(TEST_DIR, "users"), { recursive: true });
|
|
459
|
+
writeFileSync(
|
|
460
|
+
join(TEST_DIR, "users", "default.md"),
|
|
461
|
+
"# User Persona\n\nPrefers concise answers. Works in fintech.",
|
|
462
|
+
);
|
|
435
463
|
|
|
436
464
|
const result = buildSystemPrompt({
|
|
437
|
-
userPersona: personaContent,
|
|
438
465
|
// No onboardingContext — simulates post-onboarding conversation
|
|
439
466
|
});
|
|
440
|
-
const dynamic = dynamicBlock(result);
|
|
441
467
|
|
|
442
468
|
// Persona content appears in prompt even without bootstrap or onboarding
|
|
443
|
-
expect(
|
|
444
|
-
expect(
|
|
469
|
+
expect(result).toContain("# User Persona");
|
|
470
|
+
expect(result).toContain("Prefers concise answers. Works in fintech.");
|
|
445
471
|
|
|
446
472
|
// No onboarding section should be present
|
|
447
|
-
|
|
448
|
-
expect(
|
|
473
|
+
const bootstrap = bootstrapBlock(result);
|
|
474
|
+
expect(bootstrap).not.toContain("## First-Run User Context");
|
|
475
|
+
expect(bootstrap).not.toContain("First-Run Ritual");
|
|
449
476
|
});
|
|
450
477
|
|
|
451
478
|
test("userPersona appears alongside onboarding context during first run", () => {
|
|
@@ -454,8 +481,14 @@ describe("pre-chat onboarding contract", () => {
|
|
|
454
481
|
"# Bootstrap\n\nOnboarding flow.",
|
|
455
482
|
);
|
|
456
483
|
|
|
457
|
-
|
|
458
|
-
|
|
484
|
+
// User persona file renders via the `10-user-persona` section
|
|
485
|
+
// and the First-Run Ritual + onboarding context render via the
|
|
486
|
+
// `13-bootstrap` section — both in the static prefix.
|
|
487
|
+
mkdirSync(join(TEST_DIR, "users"), { recursive: true });
|
|
488
|
+
writeFileSync(
|
|
489
|
+
join(TEST_DIR, "users", "default.md"),
|
|
490
|
+
"# User Persona\n\nEarly-stage startup founder. Likes bullet points.",
|
|
491
|
+
);
|
|
459
492
|
const context: OnboardingContext = {
|
|
460
493
|
tools: ["slack"],
|
|
461
494
|
tasks: ["writing"],
|
|
@@ -464,17 +497,17 @@ describe("pre-chat onboarding contract", () => {
|
|
|
464
497
|
};
|
|
465
498
|
|
|
466
499
|
const result = buildSystemPrompt({
|
|
467
|
-
userPersona: personaContent,
|
|
468
500
|
onboardingContext: context,
|
|
469
501
|
});
|
|
470
|
-
const
|
|
471
|
-
|
|
472
|
-
// Both persona and onboarding context appear
|
|
473
|
-
|
|
474
|
-
expect(
|
|
475
|
-
expect(
|
|
476
|
-
expect(
|
|
477
|
-
expect(
|
|
502
|
+
const bootstrap = bootstrapBlock(result);
|
|
503
|
+
|
|
504
|
+
// Both persona and onboarding context appear in the static prefix
|
|
505
|
+
// (`10-user-persona` and `13-bootstrap` respectively)
|
|
506
|
+
expect(result).toContain("# User Persona");
|
|
507
|
+
expect(result).toContain("Likes bullet points.");
|
|
508
|
+
expect(bootstrap).toContain("## First-Run User Context");
|
|
509
|
+
expect(bootstrap).toContain("- Name: Dana");
|
|
510
|
+
expect(bootstrap).toContain("- Daily tools: Slack");
|
|
478
511
|
});
|
|
479
512
|
});
|
|
480
513
|
});
|
|
@@ -216,6 +216,17 @@ describe("resolvePricing", () => {
|
|
|
216
216
|
expect(result.estimatedCostUsd).toBe(0.25 + 1.5);
|
|
217
217
|
});
|
|
218
218
|
|
|
219
|
+
test("returns priced for gemini-3.1-flash-lite", () => {
|
|
220
|
+
const result = resolvePricing(
|
|
221
|
+
"gemini",
|
|
222
|
+
"gemini-3.1-flash-lite",
|
|
223
|
+
1_000_000,
|
|
224
|
+
1_000_000,
|
|
225
|
+
);
|
|
226
|
+
expect(result.pricingStatus).toBe("priced");
|
|
227
|
+
expect(result.estimatedCostUsd).toBe(0.25 + 1.5);
|
|
228
|
+
});
|
|
229
|
+
|
|
219
230
|
test("prices gemini-2.5-pro at the low-context tier through 200k input tokens", () => {
|
|
220
231
|
const result = resolvePricing(
|
|
221
232
|
"gemini",
|
|
@@ -489,6 +500,7 @@ describe("resolvePricingForUsage", () => {
|
|
|
489
500
|
const cases = [
|
|
490
501
|
["gemini-3-flash-preview", 0.05],
|
|
491
502
|
["gemini-3.1-flash-lite-preview", 0.025],
|
|
503
|
+
["gemini-3.1-flash-lite", 0.025],
|
|
492
504
|
["gemini-2.5-flash", 0.03],
|
|
493
505
|
["gemini-2.5-flash-lite", 0.01],
|
|
494
506
|
["gemini-2.5-pro", 0.625],
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit coverage for the `parseDeletedCount` helper that reads the row
|
|
3
|
+
* count out of the sqlite3 CLI's stdout after a prune DELETE.
|
|
4
|
+
*
|
|
5
|
+
* The shape of the stdout we expect:
|
|
6
|
+
*
|
|
7
|
+
* "<n>\n"
|
|
8
|
+
*
|
|
9
|
+
* — where `<n>` is the `SELECT changes()` value the CLI prints in
|
|
10
|
+
* default output mode after the DELETE statement runs. The helper has
|
|
11
|
+
* to tolerate empty/missing stdout, blank trailing lines, and any
|
|
12
|
+
* incidental log line emitted above the count.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { describe, expect, test } from "bun:test";
|
|
16
|
+
|
|
17
|
+
import { _parseDeletedCount as parseDeletedCount } from "../memory/job-handlers/cleanup.js";
|
|
18
|
+
|
|
19
|
+
describe("parseDeletedCount", () => {
|
|
20
|
+
test("bare integer on its own line", () => {
|
|
21
|
+
expect(parseDeletedCount("100\n")).toBe(100);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("integer with trailing whitespace/blank lines", () => {
|
|
25
|
+
expect(parseDeletedCount("100\n\n")).toBe(100);
|
|
26
|
+
expect(parseDeletedCount(" 42 \n")).toBe(42);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("zero is a valid count", () => {
|
|
30
|
+
expect(parseDeletedCount("0\n")).toBe(0);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("PRUNE_LOG_BATCH_LIMIT value", () => {
|
|
34
|
+
expect(parseDeletedCount("1000\n")).toBe(1000);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("undefined stdout (subprocess never wrote anything)", () => {
|
|
38
|
+
expect(parseDeletedCount(undefined)).toBe(0);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("empty stdout", () => {
|
|
42
|
+
expect(parseDeletedCount("")).toBe(0);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("only whitespace", () => {
|
|
46
|
+
expect(parseDeletedCount(" \n\n ")).toBe(0);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("non-numeric lines are skipped, last numeric line wins", () => {
|
|
50
|
+
// Sample shape if the CLI ever logged an incidental warning above the count
|
|
51
|
+
expect(parseDeletedCount("warning: foo\n250\n")).toBe(250);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("negative values are not accepted (sqlite changes() is unsigned)", () => {
|
|
55
|
+
expect(parseDeletedCount("-1\n")).toBe(0);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("CRLF line endings", () => {
|
|
59
|
+
expect(parseDeletedCount("750\r\n")).toBe(750);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { afterAll, beforeEach, describe, expect, test } from "bun:test";
|
|
2
2
|
|
|
3
3
|
import { RiskLevel } from "../permissions/types.js";
|
|
4
|
-
import type { ToolDefinition } from "../providers/types.js";
|
|
5
4
|
import {
|
|
6
5
|
__clearRegistryForTesting,
|
|
7
6
|
__resetRegistryForTesting,
|
|
@@ -30,13 +29,8 @@ function makeFakeTool(name: string): Tool {
|
|
|
30
29
|
description: `Fake ${name}`,
|
|
31
30
|
category: "test",
|
|
32
31
|
defaultRiskLevel: RiskLevel.Low,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
name,
|
|
36
|
-
description: `Fake ${name}`,
|
|
37
|
-
input_schema: { type: "object", properties: {}, required: [] },
|
|
38
|
-
};
|
|
39
|
-
},
|
|
32
|
+
executionTarget: "sandbox",
|
|
33
|
+
input_schema: { type: "object", properties: {}, required: [] },
|
|
40
34
|
async execute(
|
|
41
35
|
_input: Record<string, unknown>,
|
|
42
36
|
_context: ToolContext,
|
|
@@ -103,7 +103,7 @@ mock.module("../permissions/checker.js", () => ({
|
|
|
103
103
|
mock.module("../memory/tool-usage-store.js", () => ({
|
|
104
104
|
recordToolInvocation: () => {},
|
|
105
105
|
getRecentInvocations: () => [],
|
|
106
|
-
rotateToolInvocations: () => 0,
|
|
106
|
+
rotateToolInvocations: async () => 0,
|
|
107
107
|
}));
|
|
108
108
|
|
|
109
109
|
mock.module("../tools/registry.js", () => ({
|
|
@@ -116,7 +116,7 @@ mock.module("../tools/registry.js", () => ({
|
|
|
116
116
|
category: isGmailTool ? "gmail" : "credential-execution",
|
|
117
117
|
defaultRiskLevel: "high",
|
|
118
118
|
executionTarget: isGmailTool ? ("host" as const) : undefined,
|
|
119
|
-
|
|
119
|
+
input_schema: {},
|
|
120
120
|
execute: async () => fakeToolResult,
|
|
121
121
|
};
|
|
122
122
|
},
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `GET /v1/events` (`handleSubscribeAssistantEvents`) — bilingual scope
|
|
3
|
+
* resolution. Two query params are accepted, with distinct semantics:
|
|
4
|
+
*
|
|
5
|
+
* - `?conversationId=<internal-id>` — looks up the conversation row
|
|
6
|
+
* directly by its assistant-minted id. 404 if not found. Does NOT
|
|
7
|
+
* materialise a new row.
|
|
8
|
+
* - `?conversationKey=<external-key>` — resolves via the
|
|
9
|
+
* `conversation_keys` table; materialises on first use. Ignored when
|
|
10
|
+
* `conversationId` is also supplied.
|
|
11
|
+
*
|
|
12
|
+
* Companion to `runtime-events-sse.test.ts`, which exercises the broader
|
|
13
|
+
* `?conversationKey=` happy/error path.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
17
|
+
|
|
18
|
+
mock.module("../util/logger.js", () => ({
|
|
19
|
+
getLogger: () =>
|
|
20
|
+
new Proxy({} as Record<string, unknown>, {
|
|
21
|
+
get: () => () => {},
|
|
22
|
+
}),
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
mock.module("../config/loader.js", () => ({
|
|
26
|
+
getConfig: () => ({
|
|
27
|
+
ui: {},
|
|
28
|
+
model: "test",
|
|
29
|
+
provider: "test",
|
|
30
|
+
memory: { enabled: false },
|
|
31
|
+
rateLimit: { maxRequestsPerMinute: 0 },
|
|
32
|
+
secretDetection: { enabled: false },
|
|
33
|
+
}),
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
import { getOrCreateConversation } from "../memory/conversation-key-store.js";
|
|
37
|
+
import { getDb } from "../memory/db-connection.js";
|
|
38
|
+
import { initializeDb } from "../memory/db-init.js";
|
|
39
|
+
import { buildAssistantEvent } from "../runtime/assistant-event.js";
|
|
40
|
+
import { AssistantEventHub } from "../runtime/assistant-event-hub.js";
|
|
41
|
+
import {
|
|
42
|
+
BadRequestError,
|
|
43
|
+
NotFoundError,
|
|
44
|
+
} from "../runtime/routes/errors.js";
|
|
45
|
+
import { handleSubscribeAssistantEvents } from "../runtime/routes/events-routes.js";
|
|
46
|
+
|
|
47
|
+
initializeDb();
|
|
48
|
+
|
|
49
|
+
describe("GET /v1/events — bilingual scope query params", () => {
|
|
50
|
+
beforeEach(() => {
|
|
51
|
+
const db = getDb();
|
|
52
|
+
db.run("DELETE FROM conversation_keys");
|
|
53
|
+
db.run("DELETE FROM conversations");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("?conversationId=<existing-id> scopes the stream to that conversation", async () => {
|
|
57
|
+
// Materialise a conversation via the key path, then subscribe to it
|
|
58
|
+
// directly by its internal id.
|
|
59
|
+
const { conversationId } = getOrCreateConversation("sse-id-scope-source");
|
|
60
|
+
|
|
61
|
+
const ac = new AbortController();
|
|
62
|
+
const testHub = new AssistantEventHub();
|
|
63
|
+
|
|
64
|
+
const stream = handleSubscribeAssistantEvents(
|
|
65
|
+
{
|
|
66
|
+
queryParams: { conversationId },
|
|
67
|
+
abortSignal: ac.signal,
|
|
68
|
+
},
|
|
69
|
+
{ hub: testHub },
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const reader = stream.getReader();
|
|
73
|
+
// Consume the initial heartbeat.
|
|
74
|
+
const heartbeat = await reader.read();
|
|
75
|
+
expect(new TextDecoder().decode(heartbeat.value)).toBe(": heartbeat\n\n");
|
|
76
|
+
|
|
77
|
+
// Publish an event scoped to that conversation — should be delivered.
|
|
78
|
+
await testHub.publish(buildAssistantEvent({ type: "pong" }, conversationId));
|
|
79
|
+
|
|
80
|
+
const { value, done } = await reader.read();
|
|
81
|
+
ac.abort();
|
|
82
|
+
|
|
83
|
+
expect(done).toBe(false);
|
|
84
|
+
const frame = new TextDecoder().decode(value);
|
|
85
|
+
expect(frame).toContain("event: assistant_event");
|
|
86
|
+
expect(frame).toContain(`"conversationId":"${conversationId}"`);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("?conversationId=<non-existent-id> throws NotFoundError", () => {
|
|
90
|
+
expect(() =>
|
|
91
|
+
handleSubscribeAssistantEvents({
|
|
92
|
+
queryParams: { conversationId: "does-not-exist" },
|
|
93
|
+
abortSignal: new AbortController().signal,
|
|
94
|
+
}),
|
|
95
|
+
).toThrow(NotFoundError);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test("?conversationId is honored and ?conversationKey is ignored when both are present", async () => {
|
|
99
|
+
// Materialise two distinct conversations: one we'll subscribe to by id,
|
|
100
|
+
// one we'll publish to via the ignored key.
|
|
101
|
+
const { conversationId: idConv } = getOrCreateConversation("sse-id-wins");
|
|
102
|
+
const { conversationId: keyConv } = getOrCreateConversation(
|
|
103
|
+
"sse-key-ignored",
|
|
104
|
+
);
|
|
105
|
+
expect(idConv).not.toBe(keyConv);
|
|
106
|
+
|
|
107
|
+
const ac = new AbortController();
|
|
108
|
+
const testHub = new AssistantEventHub();
|
|
109
|
+
|
|
110
|
+
const stream = handleSubscribeAssistantEvents(
|
|
111
|
+
{
|
|
112
|
+
queryParams: {
|
|
113
|
+
conversationId: idConv,
|
|
114
|
+
conversationKey: "sse-key-ignored",
|
|
115
|
+
},
|
|
116
|
+
abortSignal: ac.signal,
|
|
117
|
+
},
|
|
118
|
+
{ hub: testHub },
|
|
119
|
+
);
|
|
120
|
+
const reader = stream.getReader();
|
|
121
|
+
await reader.read(); // heartbeat
|
|
122
|
+
|
|
123
|
+
// Publish on the "key" conversation — should NOT be delivered (filter
|
|
124
|
+
// is locked to idConv because conversationId wins).
|
|
125
|
+
await testHub.publish(buildAssistantEvent({ type: "pong" }, keyConv));
|
|
126
|
+
// Publish on the "id" conversation — should be delivered.
|
|
127
|
+
await testHub.publish(buildAssistantEvent({ type: "pong" }, idConv));
|
|
128
|
+
|
|
129
|
+
const { value } = await reader.read();
|
|
130
|
+
ac.abort();
|
|
131
|
+
const frame = new TextDecoder().decode(value);
|
|
132
|
+
|
|
133
|
+
expect(frame).toContain(`"conversationId":"${idConv}"`);
|
|
134
|
+
expect(frame).not.toContain(`"conversationId":"${keyConv}"`);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("empty conversationId is rejected with BadRequestError", () => {
|
|
138
|
+
expect(() =>
|
|
139
|
+
handleSubscribeAssistantEvents({
|
|
140
|
+
queryParams: { conversationId: "" },
|
|
141
|
+
abortSignal: new AbortController().signal,
|
|
142
|
+
}),
|
|
143
|
+
).toThrow(BadRequestError);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("empty conversationKey is still rejected (legacy parity)", () => {
|
|
147
|
+
expect(() =>
|
|
148
|
+
handleSubscribeAssistantEvents({
|
|
149
|
+
queryParams: { conversationKey: "" },
|
|
150
|
+
abortSignal: new AbortController().signal,
|
|
151
|
+
}),
|
|
152
|
+
).toThrow(BadRequestError);
|
|
153
|
+
});
|
|
154
|
+
});
|