@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
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem watcher for `<workspaceDir>/tools/`.
|
|
3
|
+
*
|
|
4
|
+
* Watches the workspace-tools directory non-recursively using fs.watch.
|
|
5
|
+
* On any add/change/delete event, debounces per filename stem (= tool
|
|
6
|
+
* name) and reconciles registry state against on-disk state: registers
|
|
7
|
+
* newly added tools, re-imports changed tools (cache-busting via the
|
|
8
|
+
* loader's per-import URL query string), unregisters deleted tools,
|
|
9
|
+
* strips core tools when a `.removed` sentinel appears, restores them
|
|
10
|
+
* when the sentinel disappears.
|
|
11
|
+
*
|
|
12
|
+
* No assistant restart is required — the file watcher closes the
|
|
13
|
+
* "edit a file, see the change" loop the same way the apps watcher and
|
|
14
|
+
* plugin source watcher do for their respective directories.
|
|
15
|
+
*
|
|
16
|
+
* ## Why per-stem reconciliation
|
|
17
|
+
*
|
|
18
|
+
* The watcher receives `(eventType, filename)` from fs.watch but the
|
|
19
|
+
* eventType ("rename" vs "change") is unreliable across editors and
|
|
20
|
+
* platforms — vim atomic-save shows as a rename of the original file
|
|
21
|
+
* plus an add of a new file, VS Code shows as a change in place, etc.
|
|
22
|
+
* Rather than route on eventType, we debounce per stem and re-derive
|
|
23
|
+
* the world: "given what's on disk right now for `<stem>.*`, what
|
|
24
|
+
* registry state should the assistant be in?"
|
|
25
|
+
*
|
|
26
|
+
* This is the same eventual-consistency pattern the plugin mtime cache
|
|
27
|
+
* uses — the watcher exists to KICK the reconciler, not to be the
|
|
28
|
+
* source of truth about what changed.
|
|
29
|
+
*
|
|
30
|
+
* ## Lifecycle position
|
|
31
|
+
*
|
|
32
|
+
* Started after the initial `loadWorkspaceTools()` scan completes
|
|
33
|
+
* during daemon startup, gated on the `workspace-tools-watcher` feature
|
|
34
|
+
* flag — when the flag is off the initial scan still runs but no watch
|
|
35
|
+
* loop is mounted, so workspace tools load from disk once and live edits
|
|
36
|
+
* need a restart. Stopped on assistant shutdown alongside the
|
|
37
|
+
* other long-lived watchers. Stoppage during shutdown does not
|
|
38
|
+
* unregister tools — those go away with the process; the watcher's
|
|
39
|
+
* only job is to keep the registry fresh while the assistant is up.
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
import { existsSync, type FSWatcher, watch } from "node:fs";
|
|
43
|
+
|
|
44
|
+
import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
|
|
45
|
+
import { getConfig } from "../config/loader.js";
|
|
46
|
+
import {
|
|
47
|
+
getCoreToolOverride,
|
|
48
|
+
getTool,
|
|
49
|
+
getToolOwner,
|
|
50
|
+
removeCoreToolViaWorkspace,
|
|
51
|
+
restoreStrippedCoreTool,
|
|
52
|
+
unregisterWorkspaceTool,
|
|
53
|
+
} from "../tools/registry.js";
|
|
54
|
+
import {
|
|
55
|
+
classifyWorkspaceToolEntry,
|
|
56
|
+
findWinningWorkspaceToolPath,
|
|
57
|
+
loadSingleWorkspaceTool,
|
|
58
|
+
} from "../tools/workspace-tools/loader.js";
|
|
59
|
+
import { DebouncerMap } from "../util/debounce.js";
|
|
60
|
+
import { attachFsWatcherErrorHandler } from "../util/fs-watcher-error.js";
|
|
61
|
+
import { getLogger } from "../util/logger.js";
|
|
62
|
+
import { getWorkspaceToolsDir } from "../util/platform.js";
|
|
63
|
+
|
|
64
|
+
const log = getLogger("workspace-tools-watcher");
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Gates the dynamic hot-reload path. When disabled, workspace tools still
|
|
68
|
+
* load from disk once at daemon startup via {@link loadWorkspaceTools}; only
|
|
69
|
+
* the live watch → re-registration loop is suppressed. Read at its point of
|
|
70
|
+
* use in {@link WorkspaceToolsWatcher.start} so a daemon restart picks up a
|
|
71
|
+
* changed value.
|
|
72
|
+
*/
|
|
73
|
+
const WORKSPACE_TOOLS_WATCHER_FLAG = "workspace-tools-watcher" as const;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Wait this long after the last fs event for a given stem before
|
|
77
|
+
* reconciling. Editor saves often emit a burst of 2–4 events; the
|
|
78
|
+
* debounce collapses them into a single load.
|
|
79
|
+
*/
|
|
80
|
+
const RECONCILE_DEBOUNCE_MS = 250;
|
|
81
|
+
|
|
82
|
+
export class WorkspaceToolsWatcher {
|
|
83
|
+
/**
|
|
84
|
+
* Process-wide singleton. Callers reach the watcher via
|
|
85
|
+
* {@link WorkspaceToolsWatcher.getInstance} rather than instantiating
|
|
86
|
+
* directly so the daemon `start()`/`stop()` lifecycle and any future
|
|
87
|
+
* "trigger a manual reconcile" code paths share one watcher across the
|
|
88
|
+
* assistant process lifetime.
|
|
89
|
+
*/
|
|
90
|
+
private static singleton: WorkspaceToolsWatcher | null = null;
|
|
91
|
+
|
|
92
|
+
static getInstance(): WorkspaceToolsWatcher {
|
|
93
|
+
WorkspaceToolsWatcher.singleton ??= new WorkspaceToolsWatcher();
|
|
94
|
+
return WorkspaceToolsWatcher.singleton;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Test-only — drops the singleton so the next `getInstance()` rebuilds. */
|
|
98
|
+
static resetForTests(): void {
|
|
99
|
+
WorkspaceToolsWatcher.singleton?.stop();
|
|
100
|
+
WorkspaceToolsWatcher.singleton = null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Test-only — whether a live `fs.watch` loop is currently mounted. */
|
|
104
|
+
isWatchingForTests(): boolean {
|
|
105
|
+
return this.watcher !== null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private watcher: FSWatcher | null = null;
|
|
109
|
+
private debouncer = new DebouncerMap({
|
|
110
|
+
defaultDelayMs: RECONCILE_DEBOUNCE_MS,
|
|
111
|
+
maxEntries: 100,
|
|
112
|
+
});
|
|
113
|
+
/**
|
|
114
|
+
* Promise queue per stem — guarantees that two events for the same
|
|
115
|
+
* stem can't run concurrently and corrupt the unregister/load
|
|
116
|
+
* sequence. The queue is single-deep (the chained promise simply
|
|
117
|
+
* awaits the in-flight one before running its own work), so the
|
|
118
|
+
* debouncer's collapsing already does most of the deduplication; this
|
|
119
|
+
* queue exists for the case where a second event lands during the
|
|
120
|
+
* in-flight reconcile's `await loadSingleWorkspaceTool`.
|
|
121
|
+
*/
|
|
122
|
+
private inflight = new Map<string, Promise<void>>();
|
|
123
|
+
|
|
124
|
+
start(): void {
|
|
125
|
+
if (this.watcher) return;
|
|
126
|
+
if (
|
|
127
|
+
!isAssistantFeatureFlagEnabled(WORKSPACE_TOOLS_WATCHER_FLAG, getConfig())
|
|
128
|
+
) {
|
|
129
|
+
log.debug(
|
|
130
|
+
"Workspace tools watcher disabled by feature flag; workspace tools load from disk at startup only (restart required to pick up edits)",
|
|
131
|
+
);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const toolsDir = getWorkspaceToolsDir();
|
|
135
|
+
if (!existsSync(toolsDir)) {
|
|
136
|
+
log.debug(
|
|
137
|
+
{ toolsDir },
|
|
138
|
+
"Workspace tools directory does not exist; watcher not started (will not auto-start on directory creation — restart required)",
|
|
139
|
+
);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
this.watcher = watch(
|
|
144
|
+
toolsDir,
|
|
145
|
+
{ recursive: false },
|
|
146
|
+
(_eventType, filename) => {
|
|
147
|
+
if (!filename) return;
|
|
148
|
+
const classified = classifyWorkspaceToolEntry(filename);
|
|
149
|
+
if (!classified) {
|
|
150
|
+
// Not a workspace-tool file — ignore (README.md, .DS_Store, etc.)
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
this.debouncer.schedule(`stem:${classified.stem}`, () => {
|
|
154
|
+
this.scheduleReconcile(classified.stem);
|
|
155
|
+
});
|
|
156
|
+
},
|
|
157
|
+
);
|
|
158
|
+
// Async FSWatcher errors (e.g. ENOSPC, ENXIO) arrive as an 'error' event;
|
|
159
|
+
// without a listener they crash the daemon. Degrade to a dead watcher.
|
|
160
|
+
attachFsWatcherErrorHandler(this.watcher, log, toolsDir);
|
|
161
|
+
log.info({ toolsDir }, "Workspace tools watcher started");
|
|
162
|
+
} catch (err) {
|
|
163
|
+
log.warn(
|
|
164
|
+
{ err, toolsDir },
|
|
165
|
+
"Failed to start workspace tools watcher — workspace tools will only register at startup",
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
stop(): void {
|
|
171
|
+
this.debouncer.cancelAll();
|
|
172
|
+
if (this.watcher) {
|
|
173
|
+
this.watcher.close();
|
|
174
|
+
this.watcher = null;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Chain `reconcileStem(stem)` after any in-flight reconcile for the
|
|
180
|
+
* same stem so we never run two `loadSingleWorkspaceTool` calls
|
|
181
|
+
* concurrently for the same name.
|
|
182
|
+
*/
|
|
183
|
+
private scheduleReconcile(stem: string): void {
|
|
184
|
+
const prev = this.inflight.get(stem) ?? Promise.resolve();
|
|
185
|
+
const next = prev
|
|
186
|
+
.catch(() => {
|
|
187
|
+
/* swallow — error already logged in the prior tick */
|
|
188
|
+
})
|
|
189
|
+
.then(() => this.reconcileStem(stem))
|
|
190
|
+
.catch((err) => {
|
|
191
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
192
|
+
log.error(
|
|
193
|
+
{ err, stem },
|
|
194
|
+
`workspace-tools-watcher: reconcile for "${stem}" threw: ${message}`,
|
|
195
|
+
);
|
|
196
|
+
})
|
|
197
|
+
.finally(() => {
|
|
198
|
+
// Only clear if we're still the current in-flight promise.
|
|
199
|
+
if (this.inflight.get(stem) === next) {
|
|
200
|
+
this.inflight.delete(stem);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
this.inflight.set(stem, next);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Reconcile a single stem (= tool name) with on-disk state.
|
|
208
|
+
*
|
|
209
|
+
* Possible (live, removed) tuples and their resolution:
|
|
210
|
+
*
|
|
211
|
+
* - `(present, absent)` → ensure workspace tool is registered using
|
|
212
|
+
* the winning live file; re-import if a previous registration
|
|
213
|
+
* pointed at a different path
|
|
214
|
+
* - `(absent, present)` → ensure core tool is stripped (and any
|
|
215
|
+
* previous workspace registration torn down first)
|
|
216
|
+
* - `(absent, absent)` → ensure neither stripped state nor live
|
|
217
|
+
* registration remains
|
|
218
|
+
* - `(present, present)` → ambiguous; tear down both so neither
|
|
219
|
+
* state survives (matches the initial-scan contract)
|
|
220
|
+
*/
|
|
221
|
+
private async reconcileStem(stem: string): Promise<void> {
|
|
222
|
+
const toolsDir = getWorkspaceToolsDir();
|
|
223
|
+
if (!existsSync(toolsDir)) {
|
|
224
|
+
this.teardownStem(stem);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const { livePath, hasRemovedSentinel } = findWinningWorkspaceToolPath(
|
|
229
|
+
toolsDir,
|
|
230
|
+
stem,
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
// Ambiguous: tear down everything for this stem.
|
|
234
|
+
if (hasRemovedSentinel && livePath !== null) {
|
|
235
|
+
log.error(
|
|
236
|
+
{ stem, toolsDir, livePath },
|
|
237
|
+
`workspace-tools-watcher: "${stem}" has both a live file and a .removed sentinel — tearing down both`,
|
|
238
|
+
);
|
|
239
|
+
this.teardownStem(stem);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Neither: tear down anything we own.
|
|
244
|
+
if (!hasRemovedSentinel && livePath === null) {
|
|
245
|
+
this.teardownStem(stem);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (hasRemovedSentinel) {
|
|
250
|
+
// Strip the core tool. Unregister any prior workspace registration
|
|
251
|
+
// first so removeCoreToolViaWorkspace doesn't throw on the
|
|
252
|
+
// workspace-owned-name check.
|
|
253
|
+
if (getToolOwner(stem)?.kind === "workspace") {
|
|
254
|
+
unregisterWorkspaceTool(stem);
|
|
255
|
+
}
|
|
256
|
+
try {
|
|
257
|
+
removeCoreToolViaWorkspace(stem);
|
|
258
|
+
} catch (err) {
|
|
259
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
260
|
+
log.error(
|
|
261
|
+
{ err, stem },
|
|
262
|
+
`workspace-tools-watcher: failed to strip "${stem}": ${message}`,
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (livePath !== null) {
|
|
269
|
+
// If we previously stripped this core tool, restore it before the
|
|
270
|
+
// workspace registration runs so the override path sees the
|
|
271
|
+
// expected baseline (core tool present → stash + replace).
|
|
272
|
+
if (getCoreToolOverride(stem) && !getTool(stem)) {
|
|
273
|
+
restoreStrippedCoreTool(stem);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// If a workspace tool is already registered under this name,
|
|
277
|
+
// unregister it so the loader can re-import cleanly. This covers
|
|
278
|
+
// file-change events (same path, new contents) as well as
|
|
279
|
+
// extension-precedence flips (e.g. user added foo.js next to
|
|
280
|
+
// foo.ts — now .js wins and the registration must update).
|
|
281
|
+
if (getToolOwner(stem)?.kind === "workspace") {
|
|
282
|
+
unregisterWorkspaceTool(stem);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const registered = await loadSingleWorkspaceTool(livePath);
|
|
286
|
+
if (registered) {
|
|
287
|
+
log.info(
|
|
288
|
+
{ stem, livePath },
|
|
289
|
+
`Workspace tool "${stem}" registered via watcher`,
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
// loadSingleWorkspaceTool already logs failures with attribution.
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Tear down any workspace-tool state we own for `stem`: unregister a
|
|
298
|
+
* live workspace tool, restore a core tool we stripped. Both no-ops
|
|
299
|
+
* when there's nothing to undo.
|
|
300
|
+
*/
|
|
301
|
+
private teardownStem(stem: string): void {
|
|
302
|
+
if (getToolOwner(stem)?.kind === "workspace") {
|
|
303
|
+
unregisterWorkspaceTool(stem);
|
|
304
|
+
log.info(
|
|
305
|
+
{ stem },
|
|
306
|
+
`Workspace tool "${stem}" unregistered via watcher (file removed)`,
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
if (getCoreToolOverride(stem) && !getTool(stem)) {
|
|
310
|
+
restoreStrippedCoreTool(stem);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// ── Test affordances ────────────────────────────────────────────────
|
|
315
|
+
//
|
|
316
|
+
// These are intentionally narrow — exposed for the watcher tests so
|
|
317
|
+
// they can drive reconcile() deterministically without waiting on the
|
|
318
|
+
// debouncer, and inspect whether an in-flight promise is settled.
|
|
319
|
+
// Not part of the public lifecycle API.
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Run a reconcile for `stem` synchronously (well, asynchronously, but
|
|
323
|
+
* without going through the debouncer). For tests.
|
|
324
|
+
*/
|
|
325
|
+
async _testReconcile(stem: string): Promise<void> {
|
|
326
|
+
await this.reconcileStem(stem);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
@@ -36,7 +36,7 @@ mock.module("../../config/env.js", () => ({
|
|
|
36
36
|
}));
|
|
37
37
|
|
|
38
38
|
mock.module("../../runtime/local-actor-identity.js", () => ({
|
|
39
|
-
|
|
39
|
+
findLocalGuardianPrincipalId: () => fakeLocalPrincipalId,
|
|
40
40
|
}));
|
|
41
41
|
|
|
42
42
|
// ── Real imports (after mocks) ────────────────────────────────────────────
|
|
@@ -33,7 +33,7 @@ import { createServer, type Server, type Socket } from "node:net";
|
|
|
33
33
|
|
|
34
34
|
import { ensureSocketDir, SocketWatchdog } from "@vellumai/ipc-server-utils";
|
|
35
35
|
|
|
36
|
-
import {
|
|
36
|
+
import { findLocalGuardianPrincipalId } from "../runtime/local-actor-identity.js";
|
|
37
37
|
import { RouteError } from "../runtime/routes/errors.js";
|
|
38
38
|
import { ROUTES } from "../runtime/routes/index.js";
|
|
39
39
|
import type {
|
|
@@ -637,7 +637,7 @@ function injectLocalActorHeader(
|
|
|
637
637
|
// that require the header will fail-closed on their own.
|
|
638
638
|
let localActor: string | undefined;
|
|
639
639
|
try {
|
|
640
|
-
localActor =
|
|
640
|
+
localActor = findLocalGuardianPrincipalId();
|
|
641
641
|
} catch (err) {
|
|
642
642
|
log.debug(
|
|
643
643
|
{ err },
|
package/src/mcp/client.ts
CHANGED
|
@@ -8,7 +8,6 @@ import { getIsPlatform } from "../config/env-registry.js";
|
|
|
8
8
|
import type { McpTransport } from "../config/schemas/mcp.js";
|
|
9
9
|
import { getSecureKeyAsync } from "../security/secure-keys.js";
|
|
10
10
|
import { getLogger } from "../util/logger.js";
|
|
11
|
-
import { getMcpHeaders } from "./mcp-header-store.js";
|
|
12
11
|
import { McpOAuthProvider } from "./mcp-oauth-provider.js";
|
|
13
12
|
|
|
14
13
|
const log = getLogger("mcp-client");
|
|
@@ -109,21 +108,8 @@ export class McpClient {
|
|
|
109
108
|
}
|
|
110
109
|
}
|
|
111
110
|
|
|
112
|
-
// Resolve static auth headers from credential store, falling back to
|
|
113
|
-
// any legacy headers in the transport config for backward compatibility.
|
|
114
|
-
let effectiveConfig = transportConfig;
|
|
115
|
-
if (isHttpTransport) {
|
|
116
|
-
const storedHeaders = await getMcpHeaders(this.serverId);
|
|
117
|
-
if (storedHeaders) {
|
|
118
|
-
effectiveConfig = {
|
|
119
|
-
...transportConfig,
|
|
120
|
-
headers: { ...transportConfig.headers, ...storedHeaders },
|
|
121
|
-
} as McpTransport;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
111
|
log.info({ serverId: this.serverId }, "Connecting to MCP server");
|
|
126
|
-
this.transport = this.createTransport(
|
|
112
|
+
this.transport = this.createTransport(transportConfig);
|
|
127
113
|
|
|
128
114
|
try {
|
|
129
115
|
await Promise.race([
|
|
@@ -21,7 +21,6 @@ import {
|
|
|
21
21
|
setMcpAuthError,
|
|
22
22
|
setMcpAuthPending,
|
|
23
23
|
} from "./mcp-auth-state.js";
|
|
24
|
-
import { getMcpHeaders } from "./mcp-header-store.js";
|
|
25
24
|
import {
|
|
26
25
|
type McpOAuthCallbackTransport,
|
|
27
26
|
McpOAuthProvider,
|
|
@@ -81,10 +80,6 @@ export async function orchestrateMcpOAuthConnect(args: {
|
|
|
81
80
|
// Register the pending callback in the daemon heap
|
|
82
81
|
const { codePromise } = await provider.startCallbackServer();
|
|
83
82
|
|
|
84
|
-
// Resolve effective headers: credential store takes precedence, then config
|
|
85
|
-
const storedHeaders = await getMcpHeaders(serverId);
|
|
86
|
-
const effectiveHeaders = storedHeaders ?? transport.headers;
|
|
87
|
-
|
|
88
83
|
// Build the MCP transport and client
|
|
89
84
|
const serverUrl = new URL(transport.url);
|
|
90
85
|
const TransportClass =
|
|
@@ -93,7 +88,7 @@ export async function orchestrateMcpOAuthConnect(args: {
|
|
|
93
88
|
: StreamableHTTPClientTransport;
|
|
94
89
|
const mcpTransport = new TransportClass(serverUrl, {
|
|
95
90
|
authProvider: provider,
|
|
96
|
-
requestInit:
|
|
91
|
+
requestInit: transport.headers ? { headers: transport.headers } : undefined,
|
|
97
92
|
});
|
|
98
93
|
const client = new Client({ name: "vellum-assistant", version: "1.0.0" });
|
|
99
94
|
|
|
@@ -569,21 +569,13 @@ export class McpOAuthProvider implements OAuthClientProvider {
|
|
|
569
569
|
|
|
570
570
|
// --- Static helpers ---
|
|
571
571
|
|
|
572
|
-
/**
|
|
573
|
-
* Check whether OAuth tokens exist in the credential store for a server.
|
|
574
|
-
*/
|
|
575
|
-
export async function hasMcpOAuthTokens(serverId: string): Promise<boolean> {
|
|
576
|
-
const raw = await getSecureKeyAsync(tokensKey(serverId));
|
|
577
|
-
return raw != null && raw.length > 0;
|
|
578
|
-
}
|
|
579
|
-
|
|
580
572
|
/**
|
|
581
573
|
* Delete all OAuth credentials for a given MCP server.
|
|
582
574
|
* Used by `mcp remove` for cleanup.
|
|
583
575
|
*/
|
|
584
576
|
export async function deleteMcpOAuthCredentials(
|
|
585
577
|
serverId: string,
|
|
586
|
-
): Promise<
|
|
578
|
+
): Promise<void> {
|
|
587
579
|
const [tokensResult, clientResult, discoveryResult] = await Promise.all([
|
|
588
580
|
deleteSecureKeyAsync(tokensKey(serverId)),
|
|
589
581
|
deleteSecureKeyAsync(clientInfoKey(serverId)),
|
|
@@ -594,23 +586,20 @@ export async function deleteMcpOAuthCredentials(
|
|
|
594
586
|
{ key: "client_info", result: clientResult },
|
|
595
587
|
{ key: "discovery", result: discoveryResult },
|
|
596
588
|
];
|
|
597
|
-
const
|
|
598
|
-
|
|
599
|
-
.map((r) => r.key);
|
|
600
|
-
if (failedKeys.length > 0) {
|
|
589
|
+
const errors = results.filter((r) => r.result === "error").map((r) => r.key);
|
|
590
|
+
if (errors.length > 0) {
|
|
601
591
|
log.warn(
|
|
602
|
-
{ serverId, failedKeys },
|
|
592
|
+
{ serverId, failedKeys: errors },
|
|
603
593
|
"Some OAuth credentials could not be deleted from secure storage",
|
|
604
594
|
);
|
|
605
595
|
}
|
|
606
|
-
const
|
|
596
|
+
const hasErrors = errors.length > 0;
|
|
607
597
|
log.info(
|
|
608
598
|
{ serverId },
|
|
609
|
-
|
|
610
|
-
? "OAuth
|
|
611
|
-
: "OAuth
|
|
599
|
+
hasErrors
|
|
600
|
+
? "OAuth credential deletion completed with errors"
|
|
601
|
+
: "OAuth credentials deleted",
|
|
612
602
|
);
|
|
613
|
-
return { ok, failedKeys };
|
|
614
603
|
}
|
|
615
604
|
|
|
616
605
|
// --- HTML rendering ---
|
|
@@ -161,14 +161,6 @@ mock.module("../conversation-crud.js", () => ({
|
|
|
161
161
|
title: "Source conversation",
|
|
162
162
|
};
|
|
163
163
|
},
|
|
164
|
-
// Mirrors the real `isConversationProcessing` which reads the persisted
|
|
165
|
-
// `processing_started_at` column. In tests, the mock registry
|
|
166
|
-
// (`loadedConversations`) is the source of truth — a conversation id
|
|
167
|
-
// present with `processing: true` simulates a mid-turn conversation.
|
|
168
|
-
isConversationProcessing: (id: string) => {
|
|
169
|
-
const entry = loadedConversations[id];
|
|
170
|
-
return entry?.processing ?? false;
|
|
171
|
-
},
|
|
172
164
|
forkConversationForRetrospective: async (params: {
|
|
173
165
|
conversationId: string;
|
|
174
166
|
throughMessageId?: string;
|
|
@@ -25,7 +25,6 @@ import { parseChannelId, parseInterfaceId } from "../channels/types.js";
|
|
|
25
25
|
import { CHANNEL_IDS, isChannelId } from "../channels/types.js";
|
|
26
26
|
import { getConfig } from "../config/loader.js";
|
|
27
27
|
import { findDisplayTurnEndIndex } from "../conversations/message-consolidation.js";
|
|
28
|
-
import { findConversation } from "../daemon/conversation-registry.js";
|
|
29
28
|
import { conversationMetadataSyncTag } from "../daemon/message-types/sync.js";
|
|
30
29
|
import type { TrustContext } from "../daemon/trust-context.js";
|
|
31
30
|
import { clearAllConversationIds } from "../home/feed-writer.js";
|
|
@@ -305,7 +304,6 @@ export interface ConversationRow {
|
|
|
305
304
|
inferenceProfileSessionId: string | null;
|
|
306
305
|
inferenceProfileExpiresAt: number | null;
|
|
307
306
|
lastNotifiedInferenceProfile: string | null;
|
|
308
|
-
processingStartedAt: number | null;
|
|
309
307
|
}
|
|
310
308
|
|
|
311
309
|
export const parseConversation = createRowMapper<
|
|
@@ -341,7 +339,6 @@ export const parseConversation = createRowMapper<
|
|
|
341
339
|
inferenceProfileSessionId: "inferenceProfileSessionId",
|
|
342
340
|
inferenceProfileExpiresAt: "inferenceProfileExpiresAt",
|
|
343
341
|
lastNotifiedInferenceProfile: "lastNotifiedInferenceProfile",
|
|
344
|
-
processingStartedAt: "processingStartedAt",
|
|
345
342
|
});
|
|
346
343
|
|
|
347
344
|
/** Allowed values for the `role` column on `messages`. */
|
|
@@ -2183,41 +2180,6 @@ export function unarchiveConversation(id: string): boolean {
|
|
|
2183
2180
|
return true;
|
|
2184
2181
|
}
|
|
2185
2182
|
|
|
2186
|
-
/**
|
|
2187
|
-
* Persist the processing-start timestamp for a conversation. Called by
|
|
2188
|
-
* `Conversation.setProcessing(true)` so out-of-process callers can detect
|
|
2189
|
-
* mid-turn state by reading the `conversations` row directly. Pass `null`
|
|
2190
|
-
* to clear (turn ended).
|
|
2191
|
-
*/
|
|
2192
|
-
export function setConversationProcessingStartedAt(
|
|
2193
|
-
id: string,
|
|
2194
|
-
startedAt: number | null,
|
|
2195
|
-
): void {
|
|
2196
|
-
rawRun(
|
|
2197
|
-
"UPDATE conversations SET processing_started_at = ? WHERE id = ?",
|
|
2198
|
-
startedAt,
|
|
2199
|
-
id,
|
|
2200
|
-
);
|
|
2201
|
-
}
|
|
2202
|
-
|
|
2203
|
-
/**
|
|
2204
|
-
* Read whether a conversation is currently processing. Checks the in-memory
|
|
2205
|
-
* `Conversation._processing` flag first (hot path for resident conversations),
|
|
2206
|
-
* falling back to the persisted `processing_started_at` column for cold
|
|
2207
|
-
* (evicted / never-loaded) conversations. This is the single entry point for
|
|
2208
|
-
* processing state — callers don't need to layer `findConversation` themselves.
|
|
2209
|
-
* Returns `false` when the conversation row doesn't exist.
|
|
2210
|
-
*/
|
|
2211
|
-
export function isConversationProcessing(id: string): boolean {
|
|
2212
|
-
const inMemory = findConversation(id)?.isProcessing();
|
|
2213
|
-
if (inMemory != null) return inMemory;
|
|
2214
|
-
const row = rawGet<{ processing_started_at: number | null }>(
|
|
2215
|
-
"SELECT processing_started_at FROM conversations WHERE id = ?",
|
|
2216
|
-
id,
|
|
2217
|
-
);
|
|
2218
|
-
return row?.processing_started_at != null;
|
|
2219
|
-
}
|
|
2220
|
-
|
|
2221
2183
|
/**
|
|
2222
2184
|
* Set or clear the `surfaced_at` promotion marker for a conversation.
|
|
2223
2185
|
*
|
|
@@ -8,7 +8,6 @@ import { drizzle } from "drizzle-orm/bun-sqlite";
|
|
|
8
8
|
import { getLogsDbPath } from "../util/logs-db-path.js";
|
|
9
9
|
import { getMemoryDbPath } from "../util/memory-db-path.js";
|
|
10
10
|
import { ensureDataDir, getDbPath } from "../util/platform.js";
|
|
11
|
-
import { getTelemetryDbPath } from "../util/telemetry-db-path.js";
|
|
12
11
|
import { clearStoredDb, getStoredDb, setStoredDb } from "./db-singleton.js";
|
|
13
12
|
import * as schema from "./schema.js";
|
|
14
13
|
|
|
@@ -137,7 +136,7 @@ export function getSqliteFrom(drizzleDb: DrizzleDb): Database {
|
|
|
137
136
|
* path so this file stays import-light. Callers tolerate a `null` result.
|
|
138
137
|
*/
|
|
139
138
|
function openDedicatedDb(
|
|
140
|
-
key: "logs" | "memory"
|
|
139
|
+
key: "logs" | "memory",
|
|
141
140
|
dbPath: string,
|
|
142
141
|
): DrizzleDb | null {
|
|
143
142
|
assertTestDbIsIsolated();
|
|
@@ -193,28 +192,11 @@ export function getMemorySqlite(): Database | null {
|
|
|
193
192
|
return db ? getSqliteFrom(db) : null;
|
|
194
193
|
}
|
|
195
194
|
|
|
196
|
-
/**
|
|
197
|
-
* The telemetry database (`assistant-telemetry.db`), opened lazily as its own
|
|
198
|
-
* connection. Houses telemetry event tables (starting with `watchdog_events`).
|
|
199
|
-
* Returns `null` if the file cannot be opened (logged; the daemon stays up).
|
|
200
|
-
*/
|
|
201
|
-
export function getTelemetryDb(): DrizzleDb | null {
|
|
202
|
-
const existing = getStoredDb<DrizzleDb>("telemetry");
|
|
203
|
-
if (existing) return existing;
|
|
204
|
-
return openDedicatedDb("telemetry", getTelemetryDbPath());
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/** Underlying bun:sqlite Database for the telemetry connection, or `null`. */
|
|
208
|
-
export function getTelemetrySqlite(): Database | null {
|
|
209
|
-
const db = getTelemetryDb();
|
|
210
|
-
return db ? getSqliteFrom(db) : null;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
195
|
/**
|
|
214
196
|
* Reset all DB singletons. Used by production callers that need to close the
|
|
215
197
|
* live connections so the files can be replaced (post-migration, post-restore,
|
|
216
|
-
* post-vbundle-import) and on graceful shutdown. Clears the main, logs,
|
|
217
|
-
*
|
|
198
|
+
* post-vbundle-import) and on graceful shutdown. Clears the main, logs, and
|
|
199
|
+
* memory slots together so none lingers open against a swapped-out file.
|
|
218
200
|
*
|
|
219
201
|
* Tests should use `resetDbForTesting()` from
|
|
220
202
|
* `__tests__/db-test-helpers.ts` instead so they don't depend on this
|
|
@@ -224,5 +206,4 @@ export function resetDb(): void {
|
|
|
224
206
|
clearStoredDb("main");
|
|
225
207
|
clearStoredDb("logs");
|
|
226
208
|
clearStoredDb("memory");
|
|
227
|
-
clearStoredDb("telemetry");
|
|
228
209
|
}
|