@vellumai/assistant 0.10.2-dev.202606250318.5e7cfb0 → 0.10.2
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/bun.lock +0 -20
- package/docs/workspace-tools.md +33 -42
- package/eslint-rules/cli-no-daemon-internals.js +0 -6
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +0 -31
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +0 -44
- package/node_modules/@vellumai/gateway-client/src/index.ts +0 -14
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +0 -17
- package/node_modules/@vellumai/service-contracts/package.json +0 -1
- package/node_modules/@vellumai/service-contracts/src/index.ts +0 -1
- package/openapi.yaml +0 -155
- package/package.json +1 -4
- package/scripts/test.sh +15 -36
- package/src/__tests__/actor-token-service.test.ts +14 -36
- package/src/__tests__/agent-loop-override-profile.test.ts +0 -1
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +0 -2
- package/src/__tests__/agent-wake-override-profile.test.ts +0 -2
- package/src/__tests__/annotate-activity-metadata.test.ts +0 -2
- package/src/__tests__/annotate-risk-options.test.ts +0 -2
- package/src/__tests__/approval-cascade.test.ts +0 -2
- package/src/__tests__/assistant-attachments.test.ts +0 -42
- package/src/__tests__/background-workers-disk-pressure.test.ts +0 -2
- package/src/__tests__/btw-routes.test.ts +0 -2
- package/src/__tests__/build-persisted-content.test.ts +0 -2
- package/src/__tests__/call-controller.test.ts +0 -19
- package/src/__tests__/channel-guardian.test.ts +58 -94
- package/src/__tests__/channel-reply-delivery.test.ts +0 -2
- package/src/__tests__/compaction-events.test.ts +0 -2
- package/src/__tests__/compaction.benchmark.test.ts +0 -2
- package/src/__tests__/compactor-call-site-logging.test.ts +0 -2
- package/src/__tests__/compactor-low-watermark-cut.test.ts +0 -2
- package/src/__tests__/compactor-preserved-tail-count.test.ts +0 -2
- package/src/__tests__/compactor-summary-call-truncation.test.ts +0 -2
- package/src/__tests__/compactor-web-search-strip.test.ts +0 -2
- package/src/__tests__/config-loader-backfill.test.ts +10 -123
- package/src/__tests__/config-schema.test.ts +0 -1
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +29 -31
- package/src/__tests__/contacts-relay-reads.test.ts +15 -13
- package/src/__tests__/conversation-abort-tool-results.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop.test.ts +0 -134
- package/src/__tests__/conversation-analysis-routes.test.ts +0 -2
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +0 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +0 -2
- package/src/__tests__/conversation-history-web-search.test.ts +0 -2
- package/src/__tests__/conversation-load-history-repair.test.ts +0 -2
- package/src/__tests__/conversation-load-history-stripped.test.ts +0 -2
- package/src/__tests__/conversation-pairing.test.ts +0 -2
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +0 -2
- package/src/__tests__/conversation-process-callsite.test.ts +0 -2
- package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -2
- package/src/__tests__/conversation-queue.test.ts +0 -91
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -14
- package/src/__tests__/conversation-routes-slash-commands.test.ts +0 -14
- package/src/__tests__/conversation-slash-queue.test.ts +0 -2
- package/src/__tests__/conversation-slash-unknown.test.ts +0 -2
- package/src/__tests__/conversation-speed-override.test.ts +0 -2
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -29
- package/src/__tests__/conversation-title-service.test.ts +0 -2
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -47
- package/src/__tests__/conversation-usage.test.ts +0 -2
- package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -2
- package/src/__tests__/conversation-workspace-injection.test.ts +0 -2
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -2
- package/src/__tests__/credential-security-invariants.test.ts +1 -1
- package/src/__tests__/db-migration-rollback.test.ts +171 -205
- package/src/__tests__/db-test-helpers.ts +4 -5
- package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -4
- package/src/__tests__/disk-pressure-guard.test.ts +0 -41
- package/src/__tests__/dm-persistence.test.ts +0 -2
- package/src/__tests__/emit-signal-routing-intent.test.ts +5 -10
- package/src/__tests__/events-dev-bypass-actor.test.ts +1 -7
- package/src/__tests__/exploration-drift-hook.test.ts +2 -3
- package/src/__tests__/filing-service.test.ts +0 -2
- package/src/__tests__/guardian-binding-drift-heal.test.ts +10 -75
- package/src/__tests__/guardian-dispatch.test.ts +1 -95
- package/src/__tests__/guardian-outbound-http.test.ts +0 -13
- package/src/__tests__/heartbeat-disk-pressure.test.ts +0 -2
- package/src/__tests__/heartbeat-service.test.ts +0 -2
- package/src/__tests__/helpers/channel-test-adapter.ts +7 -1
- package/src/__tests__/host-app-control-routes.test.ts +30 -24
- package/src/__tests__/host-bash-routes.test.ts +41 -31
- package/src/__tests__/host-browser-routes.test.ts +32 -26
- package/src/__tests__/host-cu-routes-targeted.test.ts +33 -25
- package/src/__tests__/host-file-routes-targeted.test.ts +52 -40
- package/src/__tests__/host-transfer-routes-targeted.test.ts +43 -31
- package/src/__tests__/http-user-message-parity.test.ts +8 -290
- package/src/__tests__/inbound-invite-redemption.test.ts +0 -28
- package/src/__tests__/inbound-slack-persistence.test.ts +0 -2
- package/src/__tests__/invite-redemption-service.test.ts +0 -198
- package/src/__tests__/llm-context-normalization.test.ts +0 -105
- package/src/__tests__/llm-request-log-error-payload.test.ts +9 -71
- package/src/__tests__/llm-usage-store.test.ts +0 -25
- package/src/__tests__/mcp-health-check.test.ts +1 -2
- package/src/__tests__/media-stream-server-integration.test.ts +0 -127
- package/src/__tests__/memory-retrieval-hook.test.ts +0 -2
- package/src/__tests__/messaging-send-tool.test.ts +0 -2
- package/src/__tests__/migration-import-from-url.test.ts +2 -2
- package/src/__tests__/mtime-cache.test.ts +5 -146
- package/src/__tests__/native-web-search.test.ts +0 -2
- package/src/__tests__/non-member-access-request.test.ts +17 -189
- package/src/__tests__/notification-broadcaster.test.ts +0 -4
- package/src/__tests__/notification-decision-recipient-context.test.ts +32 -33
- package/src/__tests__/notification-deep-link.test.ts +0 -6
- package/src/__tests__/notification-guardian-path.test.ts +0 -19
- package/src/__tests__/openai-provider.test.ts +12 -22
- package/src/__tests__/openai-responses-provider.test.ts +2 -12
- package/src/__tests__/outbound-slack-persistence.test.ts +0 -2
- package/src/__tests__/pending-interactions-resolved-event.test.ts +4 -7
- package/src/__tests__/persistence-secret-redaction.test.ts +0 -2
- package/src/__tests__/plugin-bootstrap.test.ts +73 -3
- package/src/__tests__/plugin-route-contribution.test.ts +17 -4
- package/src/__tests__/plugin-tool-contribution.test.ts +18 -3
- package/src/__tests__/plugin-types.test.ts +2 -0
- package/src/__tests__/process-message-background-slack.test.ts +0 -2
- package/src/__tests__/process-message-display-content.test.ts +0 -2
- package/src/__tests__/provider-error-scenarios.test.ts +4 -5
- package/src/__tests__/provider-usage-tracking.test.ts +0 -39
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +0 -2
- package/src/__tests__/registry.test.ts +1 -4
- package/src/__tests__/relay-server.test.ts +25 -694
- package/src/__tests__/runtime-attachment-metadata.test.ts +1 -0
- package/src/__tests__/secret-ingress-http.test.ts +0 -14
- package/src/__tests__/send-endpoint-busy.test.ts +8 -30
- package/src/__tests__/skills.test.ts +0 -44
- package/src/__tests__/slack-inbound-verification.test.ts +2 -47
- package/src/__tests__/stt-hints.test.ts +13 -44
- package/src/__tests__/subagent-detail.test.ts +0 -27
- package/src/__tests__/subagent-disposal.test.ts +0 -65
- package/src/__tests__/subagent-notify-parent.test.ts +0 -2
- package/src/__tests__/subagent-role-registry.test.ts +2 -7
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +0 -2
- package/src/__tests__/subagent-tools.test.ts +0 -2
- package/src/__tests__/suggestion-routes.test.ts +0 -2
- package/src/__tests__/title-generate-hook.test.ts +0 -2
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -2
- package/src/__tests__/tool-executor.test.ts +11 -16
- package/src/__tests__/tool-preview-lifecycle.test.ts +0 -2
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +0 -2
- package/src/__tests__/tool-start-timestamp.test.ts +0 -2
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +10 -10
- package/src/__tests__/twilio-routes.test.ts +0 -96
- package/src/__tests__/ui-file-upload-surface.test.ts +0 -86
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
- package/src/__tests__/voice-invite-redemption.test.ts +0 -33
- package/src/__tests__/web-search-backend-failure.test.ts +0 -2
- package/src/__tests__/workspace-migration-remove-hooks.test.ts +35 -14
- package/src/__tests__/workspace-tool-loader.test.ts +2 -195
- package/src/__tests__/workspace-tools-watcher-flag.test.ts +70 -0
- package/src/agent/loop.ts +0 -56
- package/src/api/index.ts +1 -19
- package/src/api/responses/llm-request-log-entry.ts +0 -29
- package/src/api/responses/subagent-detail.ts +0 -17
- package/src/api/surfaces.ts +3 -39
- package/src/approvals/guardian-request-resolvers.ts +11 -1
- package/src/calls/__tests__/relay-setup-router.test.ts +4 -262
- package/src/calls/call-domain.ts +3 -3
- package/src/calls/guardian-dispatch.ts +8 -10
- package/src/calls/inbound-trust-reader.ts +1 -17
- package/src/calls/media-stream-server.ts +0 -21
- package/src/calls/relay-server.ts +50 -167
- package/src/calls/relay-setup-router.ts +7 -37
- package/src/calls/relay-verification.ts +4 -4
- package/src/calls/stt-hints.ts +12 -9
- package/src/calls/twilio-routes.ts +4 -14
- package/src/channels/types.ts +20 -10
- package/src/cli/commands/__tests__/cache.test.ts +1 -8
- package/src/cli/commands/cache.ts +181 -194
- package/src/cli/commands/db/__tests__/repair.test.ts +5 -6
- package/src/cli/commands/db/status.ts +1 -37
- package/src/cli/commands/mcp.ts +218 -252
- package/src/cli/commands/memory/index.ts +0 -2
- package/src/cli/commands/plugins.ts +3 -75
- package/src/cli/lib/__tests__/install-from-github.test.ts +0 -102
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +1 -160
- package/src/cli/lib/list-installed-plugins.ts +1 -179
- package/src/config/__tests__/sync-gated-profiles.test.ts +3 -11
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +17 -27
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +3 -13
- package/src/config/bundled-skills/subagent/SKILL.md +1 -1
- package/src/config/bundled-skills/subagent/TOOLS.json +1 -1
- package/src/config/feature-flag-registry.json +13 -5
- package/src/config/loader.ts +5 -38
- package/src/config/schemas/__tests__/memory-v3.test.ts +0 -1
- package/src/config/schemas/memory-lifecycle.ts +0 -12
- package/src/config/schemas/memory-v3.ts +0 -7
- package/src/config/schemas/memory.ts +0 -4
- package/src/config/schemas/timeouts.ts +0 -8
- package/src/config/seed-inference-profiles.ts +11 -21
- package/src/config/skills.ts +5 -27
- package/src/config/sync-gated-profiles.ts +13 -12
- package/src/contacts/contacts-write.ts +0 -3
- package/src/daemon/assistant-attachments.ts +4 -27
- package/src/daemon/conversation-agent-loop.ts +0 -28
- package/src/daemon/conversation-process.ts +16 -35
- package/src/daemon/conversation-surfaces.ts +38 -111
- package/src/daemon/conversation-tool-setup.ts +16 -50
- package/src/daemon/conversation.ts +1 -13
- package/src/daemon/disk-pressure-guard.ts +2 -12
- package/src/daemon/event-loop-watchdog.ts +1 -28
- package/src/daemon/external-plugins-bootstrap.ts +34 -4
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -25
- package/src/daemon/handlers/config-a2a.ts +14 -6
- package/src/daemon/handlers/config-channels.ts +22 -78
- package/src/daemon/handlers/conversations.ts +0 -77
- package/src/daemon/lifecycle.ts +0 -4
- package/src/daemon/mcp-reload-service.ts +0 -10
- package/src/daemon/memory-v2-startup.test.ts +0 -72
- package/src/daemon/memory-v2-startup.ts +19 -87
- package/src/daemon/message-types/conversations.ts +0 -2
- package/src/daemon/message-types/surfaces.ts +12 -12
- package/src/daemon/server.ts +4 -0
- package/src/daemon/shutdown-handlers.ts +0 -20
- package/src/daemon/tool-setup-types.ts +0 -9
- package/src/daemon/workspace-tools-watcher.ts +328 -0
- package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
- package/src/ipc/assistant-server.ts +2 -2
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
- package/src/mcp/client.ts +1 -15
- package/src/mcp/mcp-auth-orchestrator.ts +1 -6
- package/src/mcp/mcp-oauth-provider.ts +8 -19
- package/src/memory/__tests__/memory-retrospective-job.test.ts +0 -8
- package/src/memory/conversation-crud.ts +0 -38
- package/src/memory/db-connection.ts +3 -22
- package/src/memory/db-init.ts +502 -36
- package/src/memory/db-singleton.ts +4 -6
- package/src/memory/jobs-worker.ts +0 -58
- package/src/memory/llm-request-log-store.ts +1 -26
- package/src/memory/llm-usage-store.ts +20 -48
- package/src/memory/memory-retrospective-job.ts +8 -9
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +56 -130
- package/src/memory/migrations/__tests__/run-migrations.test.ts +2 -2
- package/src/memory/migrations/registry.ts +573 -0
- package/src/memory/migrations/run-migrations.ts +6 -90
- package/src/memory/migrations/validate-migration-state.ts +66 -101
- package/src/memory/schema/conversations.ts +0 -9
- package/src/memory/schema/infrastructure.ts +0 -20
- package/src/memory/v2/__tests__/cli-command-store.test.ts +0 -25
- package/src/memory/v2/__tests__/skill-store.test.ts +0 -80
- package/src/memory/v2/cli-command-store.ts +38 -75
- package/src/memory/v2/prompts/consolidation.ts +82 -13
- package/src/memory/v2/prompts/router.ts +93 -21
- package/src/memory/v2/skill-store.ts +31 -68
- package/src/notifications/__tests__/broadcaster.test.ts +8 -16
- package/src/notifications/__tests__/decision-engine.test.ts +9 -78
- package/src/notifications/broadcaster.ts +1 -8
- package/src/notifications/decision-engine.ts +7 -15
- package/src/notifications/destination-resolver.ts +24 -68
- package/src/notifications/emit-signal.ts +14 -39
- package/src/permissions/question-prompter.test.ts +1 -1
- package/src/permissions/question-prompter.ts +4 -7
- package/src/plugin-api/index.ts +6 -6
- package/src/plugin-api/types.ts +5 -3
- package/src/plugin-api/vision-support.test.ts +4 -28
- package/src/plugin-api/vision-support.ts +31 -66
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +0 -161
- package/src/plugins/defaults/advisor/consult.ts +6 -110
- package/src/plugins/defaults/advisor/steering.ts +2 -14
- package/src/plugins/defaults/advisor/tools/advisor.ts +5 -32
- package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +1 -2
- package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +7 -47
- package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +11 -10
- package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +20 -12
- package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +11 -42
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +3 -33
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +4 -48
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +8 -4
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +15 -43
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +2 -11
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +13 -77
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +11 -12
- package/src/plugins/mtime-cache.ts +291 -76
- package/src/plugins/pipeline.ts +13 -111
- package/src/plugins/types.ts +2 -0
- package/src/providers/anthropic/client.ts +0 -5
- package/src/providers/call-site-routing.ts +0 -4
- package/src/providers/model-catalog.ts +0 -16
- package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
- package/src/providers/openai/chat-completions-provider.ts +83 -37
- package/src/providers/openai/responses-provider.ts +46 -50
- package/src/providers/openrouter/client.ts +0 -5
- package/src/providers/provider-send-message.ts +0 -4
- package/src/providers/ratelimit.ts +0 -4
- package/src/providers/retry.ts +0 -4
- package/src/providers/types.ts +0 -9
- package/src/providers/usage-tracking.ts +0 -4
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +3 -335
- package/src/runtime/access-request-helper.ts +39 -19
- package/src/runtime/actor-trust-resolver.ts +2 -2
- package/src/runtime/assistant-event-hub.ts +1 -1
- package/src/runtime/assistant-stream-state.ts +2 -9
- package/src/runtime/auth/require-bound-guardian.ts +11 -21
- package/src/runtime/channel-verification-service.ts +31 -56
- package/src/runtime/confirmation-request-guardian-bridge.ts +3 -3
- package/src/runtime/guardian-vellum-migration.ts +7 -66
- package/src/runtime/invite-redemption-service.ts +187 -198
- package/src/runtime/local-actor-identity.ts +11 -76
- package/src/runtime/pending-interactions.ts +1 -11
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +5 -56
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +0 -187
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +5 -13
- package/src/runtime/routes/channel-verification-routes.ts +3 -3
- package/src/runtime/routes/contact-routes.ts +32 -8
- package/src/runtime/routes/conversation-cli-routes.ts +5 -4
- package/src/runtime/routes/conversation-list-routes.ts +7 -4
- package/src/runtime/routes/conversation-query-routes.ts +0 -72
- package/src/runtime/routes/conversation-routes.ts +85 -84
- package/src/runtime/routes/events-routes.ts +2 -2
- package/src/runtime/routes/global-search-routes.ts +1 -3
- package/src/runtime/routes/guardian-action-routes.ts +5 -4
- package/src/runtime/routes/host-app-control-routes.ts +4 -5
- package/src/runtime/routes/host-bash-routes.ts +4 -5
- package/src/runtime/routes/host-browser-routes.ts +11 -9
- package/src/runtime/routes/host-cu-routes.ts +4 -5
- package/src/runtime/routes/host-file-routes.ts +4 -5
- package/src/runtime/routes/host-transfer-routes.ts +6 -6
- package/src/runtime/routes/http-adapter.ts +1 -1
- package/src/runtime/routes/identity-routes.ts +2 -3
- package/src/runtime/routes/inbound-message-handler.ts +5 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +5 -97
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +49 -61
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -16
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +7 -7
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +8 -21
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +3 -14
- package/src/runtime/routes/index.ts +0 -2
- package/src/runtime/routes/llm-context-normalization.ts +0 -83
- package/src/runtime/routes/mcp-auth-routes.ts +19 -171
- package/src/runtime/routes/migration-rollback-routes.ts +3 -4
- package/src/runtime/routes/migration-routes.ts +1 -4
- package/src/runtime/routes/subagents-routes.ts +0 -5
- package/src/runtime/routes/surface-action-routes.ts +56 -42
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -1
- package/src/runtime/services/conversation-serializer.ts +9 -7
- package/src/runtime/tool-grant-request-helper.ts +3 -3
- package/src/runtime/trust-verdict-consumer.ts +9 -85
- package/src/runtime/verification-outbound-actions.ts +18 -18
- package/src/signals/user-message.ts +0 -16
- package/src/subagent/manager.ts +0 -9
- package/src/subagent/types.ts +3 -3
- package/src/telemetry/types.ts +1 -34
- package/src/telemetry/usage-telemetry-reporter.test.ts +2 -3
- package/src/telemetry/usage-telemetry-reporter.ts +3 -87
- package/src/tools/ask-question/ask-question-tool.test.ts +0 -29
- package/src/tools/ask-question/ask-question-tool.ts +0 -13
- package/src/tools/executor.ts +4 -4
- package/src/tools/registry.ts +0 -18
- package/src/tools/shared/filesystem/path-policy.ts +5 -12
- package/src/tools/tool-approval-handler.ts +1 -1
- package/src/tools/tool-defaults.ts +2 -9
- package/src/tools/tool-manifest.ts +0 -3
- package/src/tools/types.ts +2 -17
- package/src/tools/workspace-tools/loader.ts +244 -348
- package/src/util/errors.ts +1 -26
- package/src/util/platform.ts +0 -5
- package/src/workflows/library.test.ts +0 -140
- package/src/workflows/library.ts +28 -82
- package/src/workspace/migrations/017-seed-persona-dirs.ts +34 -3
- package/src/workspace/migrations/019-scope-journal-to-guardian.ts +24 -3
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +66 -14
- package/src/workspace/migrations/registry.ts +0 -2
- package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +0 -91
- package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +0 -48
- package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +0 -28
- package/node_modules/@vellumai/service-contracts/src/channels.ts +0 -41
- package/src/__tests__/code-search-tool.test.ts +0 -585
- package/src/__tests__/guardian-expiry-notifier.test.ts +0 -282
- package/src/__tests__/mcp-config-secret-boundary.test.ts +0 -390
- package/src/__tests__/plugin-pipeline.test.ts +0 -96
- package/src/__tests__/sse-actor-principal-guardian-source.test.ts +0 -102
- package/src/__tests__/steer-on-enqueue-question.test.ts +0 -181
- package/src/__tests__/workspace-migration-111-prune-seeded-callsite-defaults.test.ts +0 -208
- package/src/agent/loop-exclusive-tool.test.ts +0 -150
- package/src/api/constants/sse-replay.ts +0 -41
- package/src/api/events/conversation-notice.ts +0 -26
- package/src/approvals/guardian-channel-delivery.ts +0 -30
- package/src/approvals/guardian-expiry-notifier.ts +0 -148
- package/src/cli/commands/memory/__tests__/worker.test.ts +0 -302
- package/src/cli/commands/memory/worker.ts +0 -175
- package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +0 -143
- package/src/config/prune-seeded-callsite-defaults.ts +0 -110
- package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +0 -129
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +0 -312
- package/src/contacts/__tests__/member-write-relay.test.ts +0 -202
- package/src/contacts/guardian-delivery-reader.ts +0 -223
- package/src/contacts/member-write-relay.ts +0 -189
- package/src/daemon/conversation-notices.ts +0 -60
- package/src/daemon/handlers/__tests__/config-channels.test.ts +0 -225
- package/src/hooks/hook-loader.ts +0 -341
- package/src/mcp/mcp-header-store.ts +0 -134
- package/src/memory/__tests__/301-create-watchdog-events.test.ts +0 -110
- package/src/memory/__tests__/prompt-override.test.ts +0 -192
- package/src/memory/__tests__/watchdog-events-store.test.ts +0 -161
- package/src/memory/migrations/300-add-processing-started-at.ts +0 -30
- package/src/memory/migrations/301-create-watchdog-events.ts +0 -45
- package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +0 -224
- package/src/memory/prompt-override.ts +0 -129
- package/src/memory/steps.ts +0 -573
- package/src/memory/watchdog-events-store.ts +0 -87
- package/src/memory/worker-control.ts +0 -118
- package/src/memory/worker-process.ts +0 -72
- package/src/notifications/__tests__/connected-channels.test.ts +0 -114
- package/src/notifications/__tests__/destination-resolver.test.ts +0 -256
- package/src/onboarding/checkin-event.test.ts +0 -222
- package/src/onboarding/checkin-event.ts +0 -321
- package/src/onboarding/schedule-checkin.ts +0 -190
- package/src/plugins/defaults/advisor/__tests__/context-pack-gating.test.ts +0 -106
- package/src/plugins/defaults/advisor/__tests__/context-pack.test.ts +0 -60
- package/src/plugins/defaults/advisor/context-pack.ts +0 -288
- package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +0 -146
- package/src/plugins/surface-import.ts +0 -121
- package/src/providers/openai/__tests__/api-error-normalization.test.ts +0 -321
- package/src/providers/openai/api-error-normalization.ts +0 -270
- package/src/runtime/__tests__/channel-verification-service.test.ts +0 -133
- package/src/runtime/__tests__/guardian-vellum-migration.test.ts +0 -181
- package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +0 -66
- package/src/runtime/__tests__/local-principal-trust.test.ts +0 -164
- package/src/runtime/anchored-guardian.test.ts +0 -156
- package/src/runtime/anchored-guardian.ts +0 -135
- package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +0 -99
- package/src/runtime/local-principal-trust.ts +0 -52
- package/src/runtime/routes/__tests__/contact-routes.test.ts +0 -212
- package/src/runtime/routes/__tests__/global-search-routes.test.ts +0 -93
- package/src/runtime/routes/onboarding-checkin-routes.ts +0 -86
- package/src/tools/filesystem/search.ts +0 -543
- package/src/util/telemetry-db-path.ts +0 -24
- package/src/workspace/migrations/111-prune-seeded-callsite-defaults.ts +0 -134
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for the shared prompt-override loader
|
|
3
|
-
* (`assistant/src/memory/prompt-override.ts`) and the memory-v3
|
|
4
|
-
* `resolveSelectorPrompt` built on it. Mirrors the v2 router/consolidation
|
|
5
|
-
* prompt-path suites: a configured file replaces the bundled prompt, and any
|
|
6
|
-
* missing / empty / oversized / non-regular / unreadable file degrades to the
|
|
7
|
-
* bundled prompt with a diagnostic warning.
|
|
8
|
-
*/
|
|
9
|
-
import { execFileSync } from "node:child_process";
|
|
10
|
-
import { mkdtempSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
|
|
11
|
-
import { homedir, tmpdir } from "node:os";
|
|
12
|
-
import { join } from "node:path";
|
|
13
|
-
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
14
|
-
|
|
15
|
-
import { resolveSelectorPrompt } from "../../plugins/defaults/memory-v3-shadow/pool-select.js";
|
|
16
|
-
import {
|
|
17
|
-
loadPromptOverride,
|
|
18
|
-
MAX_PROMPT_OVERRIDE_BYTES,
|
|
19
|
-
resolveOverridePath,
|
|
20
|
-
} from "../prompt-override.js";
|
|
21
|
-
|
|
22
|
-
const warnCalls: Array<{ data: Record<string, unknown>; msg: string }> = [];
|
|
23
|
-
const recordingLogger = {
|
|
24
|
-
warn: (data: object, msg: string) => {
|
|
25
|
-
warnCalls.push({ data: data as Record<string, unknown>, msg });
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
let tmpDir: string;
|
|
30
|
-
|
|
31
|
-
beforeEach(() => {
|
|
32
|
-
warnCalls.length = 0;
|
|
33
|
-
tmpDir = mkdtempSync(join(tmpdir(), "prompt-override-"));
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
afterEach(() => {
|
|
37
|
-
rmSync(tmpDir, { recursive: true, force: true });
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
/** Load against the per-test temp dir with the recording logger. */
|
|
41
|
-
const load = (
|
|
42
|
-
overridePath: string | null | undefined,
|
|
43
|
-
label = "test prompt",
|
|
44
|
-
): string | null =>
|
|
45
|
-
loadPromptOverride({
|
|
46
|
-
overridePath,
|
|
47
|
-
workspaceDir: tmpDir,
|
|
48
|
-
log: recordingLogger,
|
|
49
|
-
label,
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
describe("resolveOverridePath", () => {
|
|
53
|
-
test("expands a leading ~/ to the home directory", () => {
|
|
54
|
-
expect(resolveOverridePath("~/sub/x.md", tmpDir)).toBe(
|
|
55
|
-
join(homedir(), "sub/x.md"),
|
|
56
|
-
);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
test("uses an absolute path as-is", () => {
|
|
60
|
-
expect(resolveOverridePath("/abs/x.md", tmpDir)).toBe("/abs/x.md");
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
test("resolves a relative path under the workspace dir", () => {
|
|
64
|
-
expect(resolveOverridePath("rel/x.md", tmpDir)).toBe(
|
|
65
|
-
join(tmpDir, "rel/x.md"),
|
|
66
|
-
);
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
describe("loadPromptOverride — usable override", () => {
|
|
71
|
-
test("null overridePath returns null without touching the filesystem", () => {
|
|
72
|
-
expect(load(null)).toBeNull();
|
|
73
|
-
expect(warnCalls).toHaveLength(0);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
test("undefined overridePath (unset config field) returns null without throwing", () => {
|
|
77
|
-
expect(load(undefined)).toBeNull();
|
|
78
|
-
expect(warnCalls).toHaveLength(0);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test("returns an absolute-path file's contents verbatim", () => {
|
|
82
|
-
const p = join(tmpDir, "abs.md");
|
|
83
|
-
writeFileSync(p, "absolute body\n");
|
|
84
|
-
expect(load(p)).toBe("absolute body\n");
|
|
85
|
-
expect(warnCalls).toHaveLength(0);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
test("resolves a relative path under the workspace dir", () => {
|
|
89
|
-
writeFileSync(join(tmpDir, "rel.md"), "relative body\n");
|
|
90
|
-
expect(load("rel.md")).toBe("relative body\n");
|
|
91
|
-
expect(warnCalls).toHaveLength(0);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
test("expands a leading ~/ to the home directory", () => {
|
|
95
|
-
const filename = `.vellum-prompt-override-test-${process.pid}.md`;
|
|
96
|
-
const p = join(homedir(), filename);
|
|
97
|
-
writeFileSync(p, "home body\n");
|
|
98
|
-
try {
|
|
99
|
-
expect(load(`~/${filename}`)).toBe("home body\n");
|
|
100
|
-
expect(warnCalls).toHaveLength(0);
|
|
101
|
-
} finally {
|
|
102
|
-
rmSync(p, { force: true });
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
describe("loadPromptOverride — fallback to null with a diagnostic warning", () => {
|
|
108
|
-
test("missing file logs ENOENT and returns null", () => {
|
|
109
|
-
expect(load(join(tmpDir, "missing.md"))).toBeNull();
|
|
110
|
-
expect(warnCalls).toHaveLength(1);
|
|
111
|
-
expect(warnCalls[0].data.code).toBe("ENOENT");
|
|
112
|
-
expect(warnCalls[0].data.fallback).toBe("bundled");
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
test("empty file is rejected", () => {
|
|
116
|
-
const p = join(tmpDir, "empty.md");
|
|
117
|
-
writeFileSync(p, "");
|
|
118
|
-
expect(load(p)).toBeNull();
|
|
119
|
-
expect(warnCalls[0].data.reason).toBe("empty_override");
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
test("whitespace-only file is rejected", () => {
|
|
123
|
-
const p = join(tmpDir, "ws.md");
|
|
124
|
-
writeFileSync(p, " \n\t\n");
|
|
125
|
-
expect(load(p)).toBeNull();
|
|
126
|
-
expect(warnCalls[0].data.reason).toBe("empty_override");
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
test("oversized file is rejected with its size", () => {
|
|
130
|
-
const p = join(tmpDir, "huge.md");
|
|
131
|
-
// 1 MiB + 1 byte — just over the cap so we don't waste test memory.
|
|
132
|
-
writeFileSync(p, Buffer.alloc(MAX_PROMPT_OVERRIDE_BYTES + 1, 0x61));
|
|
133
|
-
expect(load(p)).toBeNull();
|
|
134
|
-
expect(warnCalls[0].data.reason).toBe("oversized_override");
|
|
135
|
-
expect(warnCalls[0].data.size).toBe(MAX_PROMPT_OVERRIDE_BYTES + 1);
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
test("a directory is not a regular file", () => {
|
|
139
|
-
expect(load(tmpDir)).toBeNull();
|
|
140
|
-
expect(warnCalls[0].data.reason).toBe("not_regular_file");
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
test("a symlink is not a regular file (lstat does not follow it)", () => {
|
|
144
|
-
const target = join(tmpDir, "target.md");
|
|
145
|
-
writeFileSync(target, "real body\n");
|
|
146
|
-
const link = join(tmpDir, "link.md");
|
|
147
|
-
symlinkSync(target, link);
|
|
148
|
-
expect(load(link)).toBeNull();
|
|
149
|
-
expect(warnCalls[0].data.reason).toBe("not_regular_file");
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
test("a FIFO is not a regular file", () => {
|
|
153
|
-
const fifoPath = join(tmpDir, "fifo");
|
|
154
|
-
try {
|
|
155
|
-
execFileSync("mkfifo", [fifoPath]);
|
|
156
|
-
} catch {
|
|
157
|
-
// mkfifo unavailable on this platform — skip without failing.
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
expect(load(fifoPath)).toBeNull();
|
|
161
|
-
expect(warnCalls[0].data.reason).toBe("not_regular_file");
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
test("the label names the prompt in the warning message", () => {
|
|
165
|
-
load(join(tmpDir, "missing.md"), "router prompt");
|
|
166
|
-
expect(warnCalls[0].msg).toContain("router prompt override");
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
describe("resolveSelectorPrompt", () => {
|
|
171
|
-
// A stable phrase from the bundled selector prompt (`SYSTEM_PROMPT`).
|
|
172
|
-
const BUNDLED_PHRASE =
|
|
173
|
-
"Select EVERY candidate whose content the upcoming reply would draw on";
|
|
174
|
-
|
|
175
|
-
test("null path returns the bundled selector prompt", () => {
|
|
176
|
-
expect(resolveSelectorPrompt(null, tmpDir)).toContain(BUNDLED_PHRASE);
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
test("a configured file replaces the bundled prompt verbatim — no placeholder substitution", () => {
|
|
180
|
-
const body = "Custom selector instructions {{NOT_A_PLACEHOLDER}}\n";
|
|
181
|
-
writeFileSync(join(tmpDir, "selector.md"), body);
|
|
182
|
-
const out = resolveSelectorPrompt("selector.md", tmpDir);
|
|
183
|
-
expect(out).toBe(body);
|
|
184
|
-
expect(out).not.toContain(BUNDLED_PHRASE);
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
test("a missing override falls back to the bundled prompt", () => {
|
|
188
|
-
expect(resolveSelectorPrompt(join(tmpDir, "nope.md"), tmpDir)).toContain(
|
|
189
|
-
BUNDLED_PHRASE,
|
|
190
|
-
);
|
|
191
|
-
});
|
|
192
|
-
});
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
|
-
|
|
3
|
-
// Silence the logger.
|
|
4
|
-
mock.module("../../util/logger.js", () => ({
|
|
5
|
-
getLogger: () =>
|
|
6
|
-
new Proxy({} as Record<string, unknown>, {
|
|
7
|
-
get: () => () => {},
|
|
8
|
-
}),
|
|
9
|
-
}));
|
|
10
|
-
|
|
11
|
-
let shareAnalytics = true;
|
|
12
|
-
|
|
13
|
-
mock.module("../../platform/consent-cache.js", () => ({
|
|
14
|
-
getCachedShareAnalytics: () => shareAnalytics,
|
|
15
|
-
}));
|
|
16
|
-
|
|
17
|
-
import { getTelemetryDb } from "../db-connection.js";
|
|
18
|
-
import { initializeDb } from "../db-init.js";
|
|
19
|
-
import { watchdogEvents } from "../schema.js";
|
|
20
|
-
import {
|
|
21
|
-
queryUnreportedWatchdogEvents,
|
|
22
|
-
recordWatchdogEvent,
|
|
23
|
-
} from "../watchdog-events-store.js";
|
|
24
|
-
|
|
25
|
-
await initializeDb();
|
|
26
|
-
|
|
27
|
-
function insertEvent(
|
|
28
|
-
id: string,
|
|
29
|
-
createdAt: number,
|
|
30
|
-
checkName = "event_loop_blocked",
|
|
31
|
-
): void {
|
|
32
|
-
const db = getTelemetryDb();
|
|
33
|
-
if (!db) throw new Error("telemetry DB unavailable in test");
|
|
34
|
-
db.insert(watchdogEvents).values({ id, createdAt, checkName }).run();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function clearEvents(): void {
|
|
38
|
-
const db = getTelemetryDb();
|
|
39
|
-
if (!db) throw new Error("telemetry DB unavailable in test");
|
|
40
|
-
db.delete(watchdogEvents).run();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
describe("watchdog-events-store", () => {
|
|
44
|
-
beforeEach(() => {
|
|
45
|
-
shareAnalytics = true;
|
|
46
|
-
clearEvents();
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test("honors the share_analytics opt-out (records nothing)", () => {
|
|
50
|
-
shareAnalytics = false;
|
|
51
|
-
recordWatchdogEvent({ checkName: "event_loop_blocked", value: 60000 });
|
|
52
|
-
expect(queryUnreportedWatchdogEvents(0, undefined, 10)).toHaveLength(0);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
test("record + query round-trips all fields", () => {
|
|
56
|
-
recordWatchdogEvent({
|
|
57
|
-
checkName: "event_loop_blocked",
|
|
58
|
-
value: 12345,
|
|
59
|
-
detail: { reason: "no_bytes_60s", threshold_ms: 5000 },
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
const rows = queryUnreportedWatchdogEvents(0, undefined, 10);
|
|
63
|
-
expect(rows).toHaveLength(1);
|
|
64
|
-
const row = rows[0]!;
|
|
65
|
-
expect(row.id).toBeString();
|
|
66
|
-
expect(row.createdAt).toBeGreaterThan(0);
|
|
67
|
-
expect(row.checkName).toBe("event_loop_blocked");
|
|
68
|
-
expect(row.value).toBe(12345);
|
|
69
|
-
expect(row.detail).toBe(
|
|
70
|
-
JSON.stringify({ reason: "no_bytes_60s", threshold_ms: 5000 }),
|
|
71
|
-
);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
test("optional fields persist as null", () => {
|
|
75
|
-
recordWatchdogEvent({ checkName: "stream_idle" });
|
|
76
|
-
|
|
77
|
-
const rows = queryUnreportedWatchdogEvents(0, undefined, 10);
|
|
78
|
-
expect(rows).toHaveLength(1);
|
|
79
|
-
expect(rows[0]).toMatchObject({
|
|
80
|
-
checkName: "stream_idle",
|
|
81
|
-
value: null,
|
|
82
|
-
detail: null,
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
test("explicit null value and detail persist as null", () => {
|
|
87
|
-
recordWatchdogEvent({
|
|
88
|
-
checkName: "restart",
|
|
89
|
-
value: null,
|
|
90
|
-
detail: null,
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
const rows = queryUnreportedWatchdogEvents(0, undefined, 10);
|
|
94
|
-
expect(rows).toHaveLength(1);
|
|
95
|
-
expect(rows[0]?.value).toBeNull();
|
|
96
|
-
expect(rows[0]?.detail).toBeNull();
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
test("returns rows in (createdAt, id) order", () => {
|
|
100
|
-
insertEvent("wd-b", 2000);
|
|
101
|
-
insertEvent("wd-a", 1000);
|
|
102
|
-
|
|
103
|
-
const rows = queryUnreportedWatchdogEvents(0, undefined, 100);
|
|
104
|
-
expect(rows.map((r) => r.id)).toEqual(["wd-a", "wd-b"]);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
test("query advances past the compound (createdAt, id) cursor", () => {
|
|
108
|
-
// Two rows in the same millisecond: pagination must use the id
|
|
109
|
-
// tiebreaker to make forward progress, not loop.
|
|
110
|
-
insertEvent("wd-1", 5000);
|
|
111
|
-
insertEvent("wd-2", 5000);
|
|
112
|
-
insertEvent("wd-3", 6000);
|
|
113
|
-
|
|
114
|
-
const first = queryUnreportedWatchdogEvents(0, undefined, 1);
|
|
115
|
-
expect(first.map((r) => r.id)).toEqual(["wd-1"]);
|
|
116
|
-
|
|
117
|
-
const second = queryUnreportedWatchdogEvents(
|
|
118
|
-
first[0]!.createdAt,
|
|
119
|
-
first[0]!.id,
|
|
120
|
-
100,
|
|
121
|
-
);
|
|
122
|
-
expect(second.map((r) => r.id)).toEqual(["wd-2", "wd-3"]);
|
|
123
|
-
|
|
124
|
-
// Without an id cursor the timestamp-only branch is used.
|
|
125
|
-
expect(
|
|
126
|
-
queryUnreportedWatchdogEvents(5000, undefined, 100).map((r) => r.id),
|
|
127
|
-
).toEqual(["wd-3"]);
|
|
128
|
-
|
|
129
|
-
// Cursor past the last row returns nothing.
|
|
130
|
-
const last = second[second.length - 1]!;
|
|
131
|
-
expect(
|
|
132
|
-
queryUnreportedWatchdogEvents(last.createdAt, last.id, 100).length,
|
|
133
|
-
).toBe(0);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
test("resumes from a persisted watermark without re-reporting", () => {
|
|
137
|
-
insertEvent("wd-w1", 1000);
|
|
138
|
-
insertEvent("wd-w2", 2000);
|
|
139
|
-
|
|
140
|
-
const batch = queryUnreportedWatchdogEvents(0, undefined, 100);
|
|
141
|
-
const watermark = batch[batch.length - 1]!;
|
|
142
|
-
|
|
143
|
-
insertEvent("wd-w3", 3000);
|
|
144
|
-
|
|
145
|
-
const resumed = queryUnreportedWatchdogEvents(
|
|
146
|
-
watermark.createdAt,
|
|
147
|
-
watermark.id,
|
|
148
|
-
100,
|
|
149
|
-
);
|
|
150
|
-
expect(resumed.map((r) => r.id)).toEqual(["wd-w3"]);
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
test("honors the limit", () => {
|
|
154
|
-
insertEvent("wd-l1", 1000);
|
|
155
|
-
insertEvent("wd-l2", 2000);
|
|
156
|
-
insertEvent("wd-l3", 3000);
|
|
157
|
-
|
|
158
|
-
const rows = queryUnreportedWatchdogEvents(0, undefined, 2);
|
|
159
|
-
expect(rows.map((r) => r.id)).toEqual(["wd-l1", "wd-l2"]);
|
|
160
|
-
});
|
|
161
|
-
});
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
-
import { tableHasColumn } from "./schema-introspection.js";
|
|
3
|
-
|
|
4
|
-
const COLUMN_NAME = "processing_started_at";
|
|
5
|
-
const COLUMN_DEFINITION = "processing_started_at INTEGER";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Add `processing_started_at` column to the `conversations` table.
|
|
9
|
-
*
|
|
10
|
-
* The column is a nullable epoch-ms timestamp: non-NULL means the agent loop
|
|
11
|
-
* is mid-turn for this conversation, NULL means idle. This is the
|
|
12
|
-
* cross-process source of truth for processing state — the in-memory
|
|
13
|
-
* `Conversation._processing` flag is the hot-path read for resident
|
|
14
|
-
* conversations, but out-of-process callers (e.g. the retrospective CLI)
|
|
15
|
-
* read this column directly via `isConversationProcessing()`.
|
|
16
|
-
*
|
|
17
|
-
* No backfill is needed — all existing rows default to NULL (not processing),
|
|
18
|
-
* which is correct for any conversation that isn't actively mid-turn at
|
|
19
|
-
* migration time.
|
|
20
|
-
*
|
|
21
|
-
* Idempotent: guarded with `tableHasColumn` so a crash between the `ALTER
|
|
22
|
-
* TABLE` and the checkpoint write doesn't cause a duplicate-column error on
|
|
23
|
-
* the next boot.
|
|
24
|
-
*/
|
|
25
|
-
export function migrateAddProcessingStartedAt(database: DrizzleDb): void {
|
|
26
|
-
if (tableHasColumn(database, "conversations", COLUMN_NAME)) {
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
database.run(`ALTER TABLE conversations ADD COLUMN ${COLUMN_DEFINITION}`);
|
|
30
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { Database } from "bun:sqlite";
|
|
2
|
-
|
|
3
|
-
import { getTelemetryDbPath } from "../../util/telemetry-db-path.js";
|
|
4
|
-
import {
|
|
5
|
-
type DrizzleDb,
|
|
6
|
-
getTelemetrySqlite,
|
|
7
|
-
} from "../db-connection.js";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Create the `watchdog_events` table on the dedicated telemetry database
|
|
11
|
-
* (`assistant-telemetry.db`), not the main DB. The migration runner passes the
|
|
12
|
-
* main DrizzleDb, but this table lives on the telemetry connection, so we open
|
|
13
|
-
* that connection and run DDL against it directly. The dedicated connection
|
|
14
|
-
* itself performs no DDL on open, so this migration owns the schema.
|
|
15
|
-
*
|
|
16
|
-
* Idempotent (`IF NOT EXISTS`). Writes are gated on `share_analytics`
|
|
17
|
-
* consent at the store level, so opted-out rows never exist and the
|
|
18
|
-
* reporter's standard 0 watermark default is safe. The index backs the
|
|
19
|
-
* telemetry reporter's compound `(created_at, id)` watermark cursor.
|
|
20
|
-
*
|
|
21
|
-
* The `mainDb` parameter is accepted to satisfy the migration-step signature but
|
|
22
|
-
* is not used — this migration operates exclusively on the telemetry DB.
|
|
23
|
-
*/
|
|
24
|
-
export function createWatchdogEventsTable(_mainDb: DrizzleDb): void {
|
|
25
|
-
let raw: Database | null = getTelemetrySqlite();
|
|
26
|
-
if (!raw) {
|
|
27
|
-
// The dedicated connection failed to open (logged by openDedicatedDb).
|
|
28
|
-
// Fall back to opening the file directly so the migration still runs —
|
|
29
|
-
// the singleton will pick it up on a later access. This mirrors the
|
|
30
|
-
// fail-soft pattern of the other dedicated-DB migrations.
|
|
31
|
-
raw = new Database(getTelemetryDbPath());
|
|
32
|
-
}
|
|
33
|
-
raw.exec(/*sql*/ `
|
|
34
|
-
CREATE TABLE IF NOT EXISTS watchdog_events (
|
|
35
|
-
id TEXT PRIMARY KEY,
|
|
36
|
-
created_at INTEGER NOT NULL,
|
|
37
|
-
check_name TEXT NOT NULL,
|
|
38
|
-
value REAL,
|
|
39
|
-
detail TEXT
|
|
40
|
-
)
|
|
41
|
-
`);
|
|
42
|
-
raw.exec(
|
|
43
|
-
/*sql*/ `CREATE INDEX IF NOT EXISTS idx_watchdog_events_created_at_id ON watchdog_events (created_at, id)`,
|
|
44
|
-
);
|
|
45
|
-
}
|
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for migration 209 — stripping thinking / redacted_thinking blocks from
|
|
3
|
-
* persisted assistant messages.
|
|
4
|
-
*
|
|
5
|
-
* The migration rewrites content entirely inside SQLite (JSON1), dispatched a
|
|
6
|
-
* rowid window at a time through `runAsyncSqlite`. These tests drive the step
|
|
7
|
-
* directly against a real DB and assert the at-rest content, idempotency,
|
|
8
|
-
* scoping (assistant rows only), tolerance of malformed content, and that the
|
|
9
|
-
* persisted rowid watermark is honored for resume.
|
|
10
|
-
*/
|
|
11
|
-
import { describe, expect, test } from "bun:test";
|
|
12
|
-
|
|
13
|
-
const { getDb, getSqlite } = await import("../../db-connection.js");
|
|
14
|
-
const { initializeDb } = await import("../../db-init.js");
|
|
15
|
-
const { migrateStripThinkingFromConsolidated } =
|
|
16
|
-
await import("../209-strip-thinking-from-consolidated.js");
|
|
17
|
-
|
|
18
|
-
await initializeDb();
|
|
19
|
-
|
|
20
|
-
const CONV = "conv-209";
|
|
21
|
-
getSqlite()
|
|
22
|
-
.query(
|
|
23
|
-
`INSERT OR IGNORE INTO conversations (id, created_at, updated_at) VALUES (?, ?, ?)`,
|
|
24
|
-
)
|
|
25
|
-
.run(CONV, Date.now(), Date.now());
|
|
26
|
-
|
|
27
|
-
let seq = 0;
|
|
28
|
-
function insert(role: string, content: string): { id: string; rowid: number } {
|
|
29
|
-
const id = `m209-${seq++}`;
|
|
30
|
-
getSqlite()
|
|
31
|
-
.query(
|
|
32
|
-
`INSERT INTO messages (id, conversation_id, role, content, created_at) VALUES (?, ?, ?, ?, ?)`,
|
|
33
|
-
)
|
|
34
|
-
.run(id, CONV, role, content, Date.now());
|
|
35
|
-
const rowid = (
|
|
36
|
-
getSqlite()
|
|
37
|
-
.query(`SELECT rowid AS r FROM messages WHERE id = ?`)
|
|
38
|
-
.get(id) as { r: number }
|
|
39
|
-
).r;
|
|
40
|
-
return { id, rowid };
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function content(id: string): string {
|
|
44
|
-
return (
|
|
45
|
-
getSqlite().query(`SELECT content FROM messages WHERE id = ?`).get(id) as {
|
|
46
|
-
content: string;
|
|
47
|
-
}
|
|
48
|
-
).content;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function blocks(id: string): Array<Record<string, unknown>> {
|
|
52
|
-
return JSON.parse(content(id));
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
describe("migration 209 — strip thinking from consolidated assistant messages", () => {
|
|
56
|
-
test("strips thinking blocks but keeps text and tool_use, preserving order", async () => {
|
|
57
|
-
const { id } = insert(
|
|
58
|
-
"assistant",
|
|
59
|
-
JSON.stringify([
|
|
60
|
-
{ type: "thinking", thinking: "secret", signature: "sig" },
|
|
61
|
-
{ type: "text", text: "hello" },
|
|
62
|
-
{ type: "tool_use", id: "t1", name: "x", input: { a: 1 } },
|
|
63
|
-
]),
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
await migrateStripThinkingFromConsolidated(getDb());
|
|
67
|
-
|
|
68
|
-
expect(blocks(id)).toEqual([
|
|
69
|
-
{ type: "text", text: "hello" },
|
|
70
|
-
{ type: "tool_use", id: "t1", name: "x", input: { a: 1 } },
|
|
71
|
-
]);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
test("strips redacted_thinking blocks", async () => {
|
|
75
|
-
const { id } = insert(
|
|
76
|
-
"assistant",
|
|
77
|
-
JSON.stringify([
|
|
78
|
-
{ type: "redacted_thinking", data: "blob" },
|
|
79
|
-
{ type: "text", text: "world" },
|
|
80
|
-
]),
|
|
81
|
-
);
|
|
82
|
-
|
|
83
|
-
await migrateStripThinkingFromConsolidated(getDb());
|
|
84
|
-
|
|
85
|
-
expect(blocks(id)).toEqual([{ type: "text", text: "world" }]);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
test("all-thinking message becomes the null-byte placeholder sentinel", async () => {
|
|
89
|
-
const { id } = insert(
|
|
90
|
-
"assistant",
|
|
91
|
-
JSON.stringify([
|
|
92
|
-
{ type: "thinking", thinking: "a", signature: "s1" },
|
|
93
|
-
{ type: "redacted_thinking", data: "b" },
|
|
94
|
-
]),
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
await migrateStripThinkingFromConsolidated(getDb());
|
|
98
|
-
|
|
99
|
-
const result = blocks(id);
|
|
100
|
-
expect(result).toHaveLength(1);
|
|
101
|
-
expect(result[0].type).toBe("text");
|
|
102
|
-
expect(result[0].text).toBe("\x00__PLACEHOLDER__[internal blocks omitted]");
|
|
103
|
-
// The leading byte must be a literal NUL, produced by SQLite's char(0).
|
|
104
|
-
expect((result[0].text as string).charCodeAt(0)).toBe(0);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
test("preserves blocks with a missing/null type", async () => {
|
|
108
|
-
const { id } = insert(
|
|
109
|
-
"assistant",
|
|
110
|
-
JSON.stringify([
|
|
111
|
-
{ type: "thinking", thinking: "x", signature: "s" },
|
|
112
|
-
{ foo: "bar" },
|
|
113
|
-
{ type: "text", text: "kept" },
|
|
114
|
-
]),
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
await migrateStripThinkingFromConsolidated(getDb());
|
|
118
|
-
|
|
119
|
-
expect(blocks(id)).toEqual([
|
|
120
|
-
{ foo: "bar" },
|
|
121
|
-
{ type: "text", text: "kept" },
|
|
122
|
-
]);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
test("leaves thinking-free assistant messages untouched", async () => {
|
|
126
|
-
const original = JSON.stringify([
|
|
127
|
-
{ type: "text", text: "I was thinking about lunch" },
|
|
128
|
-
]);
|
|
129
|
-
const { id } = insert("assistant", original);
|
|
130
|
-
|
|
131
|
-
await migrateStripThinkingFromConsolidated(getDb());
|
|
132
|
-
|
|
133
|
-
// Substring 'thinking' appears in the text but no block is of thinking type.
|
|
134
|
-
expect(content(id)).toBe(original);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
test("does not touch non-assistant roles", async () => {
|
|
138
|
-
const original = JSON.stringify([
|
|
139
|
-
{ type: "thinking", thinking: "x", signature: "s" },
|
|
140
|
-
{ type: "text", text: "u" },
|
|
141
|
-
]);
|
|
142
|
-
const { id } = insert("user", original);
|
|
143
|
-
|
|
144
|
-
await migrateStripThinkingFromConsolidated(getDb());
|
|
145
|
-
|
|
146
|
-
expect(content(id)).toBe(original);
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
test("tolerates non-array and invalid JSON content", async () => {
|
|
150
|
-
const obj = insert(
|
|
151
|
-
"assistant",
|
|
152
|
-
JSON.stringify({ type: "thinking", thinking: "x" }),
|
|
153
|
-
);
|
|
154
|
-
const invalid = insert("assistant", "{not json with thinking");
|
|
155
|
-
|
|
156
|
-
await migrateStripThinkingFromConsolidated(getDb());
|
|
157
|
-
|
|
158
|
-
expect(content(obj.id)).toBe(
|
|
159
|
-
JSON.stringify({ type: "thinking", thinking: "x" }),
|
|
160
|
-
);
|
|
161
|
-
expect(content(invalid.id)).toBe("{not json with thinking");
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
test("is idempotent across repeated runs", async () => {
|
|
165
|
-
const { id } = insert(
|
|
166
|
-
"assistant",
|
|
167
|
-
JSON.stringify([
|
|
168
|
-
{ type: "thinking", thinking: "x", signature: "s" },
|
|
169
|
-
{ type: "text", text: "stable" },
|
|
170
|
-
]),
|
|
171
|
-
);
|
|
172
|
-
|
|
173
|
-
await migrateStripThinkingFromConsolidated(getDb());
|
|
174
|
-
const once = content(id);
|
|
175
|
-
await migrateStripThinkingFromConsolidated(getDb());
|
|
176
|
-
const twice = content(id);
|
|
177
|
-
|
|
178
|
-
expect(twice).toBe(once);
|
|
179
|
-
expect(blocks(id)).toEqual([{ type: "text", text: "stable" }]);
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
test("honors the persisted rowid watermark and resumes above it", async () => {
|
|
183
|
-
const below = insert(
|
|
184
|
-
"assistant",
|
|
185
|
-
JSON.stringify([
|
|
186
|
-
{ type: "thinking", thinking: "x", signature: "s" },
|
|
187
|
-
{ type: "text", text: "below" },
|
|
188
|
-
]),
|
|
189
|
-
);
|
|
190
|
-
const above = insert(
|
|
191
|
-
"assistant",
|
|
192
|
-
JSON.stringify([
|
|
193
|
-
{ type: "thinking", thinking: "y", signature: "s" },
|
|
194
|
-
{ type: "text", text: "above" },
|
|
195
|
-
]),
|
|
196
|
-
);
|
|
197
|
-
|
|
198
|
-
// Pretend a prior run already swept through `below`'s rowid: the sweep must
|
|
199
|
-
// resume strictly above it, leaving `below` untouched and cleaning `above`.
|
|
200
|
-
getSqlite()
|
|
201
|
-
.query(
|
|
202
|
-
`INSERT OR REPLACE INTO memory_checkpoints (key, value, updated_at) VALUES (?, ?, ?)`,
|
|
203
|
-
)
|
|
204
|
-
.run(
|
|
205
|
-
"migration_209_strip_thinking_watermark",
|
|
206
|
-
String(below.rowid),
|
|
207
|
-
Date.now(),
|
|
208
|
-
);
|
|
209
|
-
|
|
210
|
-
await migrateStripThinkingFromConsolidated(getDb());
|
|
211
|
-
|
|
212
|
-
expect(blocks(below.id)).toEqual([
|
|
213
|
-
{ type: "thinking", thinking: "x", signature: "s" },
|
|
214
|
-
{ type: "text", text: "below" },
|
|
215
|
-
]);
|
|
216
|
-
expect(blocks(above.id)).toEqual([{ type: "text", text: "above" }]);
|
|
217
|
-
|
|
218
|
-
// The watermark is cleared once the sweep reaches the end of the table.
|
|
219
|
-
const wm = getSqlite()
|
|
220
|
-
.query(`SELECT value FROM memory_checkpoints WHERE key = ?`)
|
|
221
|
-
.get("migration_209_strip_thinking_watermark");
|
|
222
|
-
expect(wm).toBeNull();
|
|
223
|
-
});
|
|
224
|
-
});
|