@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
|
@@ -14,11 +14,6 @@
|
|
|
14
14
|
import type { ChannelId } from "../channels/types.js";
|
|
15
15
|
import { isHttpAuthDisabled } from "../config/env.js";
|
|
16
16
|
import { findGuardianForChannel } from "../contacts/contact-store.js";
|
|
17
|
-
import {
|
|
18
|
-
getGuardianDelivery,
|
|
19
|
-
guardianForChannel,
|
|
20
|
-
peekCachedGuardianDelivery,
|
|
21
|
-
} from "../contacts/guardian-delivery-reader.js";
|
|
22
17
|
import type { TrustContext } from "../daemon/trust-context.js";
|
|
23
18
|
import { getLogger } from "../util/logger.js";
|
|
24
19
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "./assistant-scope.js";
|
|
@@ -50,48 +45,13 @@ export function buildLocalAuthContext(conversationId: string): AuthContext {
|
|
|
50
45
|
}
|
|
51
46
|
|
|
52
47
|
/**
|
|
53
|
-
*
|
|
48
|
+
* Look up the local vellum guardian's principalId from the contacts table.
|
|
54
49
|
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* storm the IPC. Falls back to the local contacts table for the bootstrap /
|
|
58
|
-
* first-run window where the gateway has no guardian yet or is unreachable
|
|
59
|
-
* (the reader returns `null`).
|
|
60
|
-
*
|
|
61
|
-
* Returns `undefined` when no vellum guardian binding exists in either source
|
|
62
|
-
* (e.g. fresh install before bootstrap). Callers should treat that case as
|
|
50
|
+
* Returns `undefined` when no vellum guardian binding exists (e.g. fresh
|
|
51
|
+
* install before bootstrap). Callers should treat that case as
|
|
63
52
|
* "not yet available" and either fall back or proceed without a principalId.
|
|
64
53
|
*/
|
|
65
|
-
export
|
|
66
|
-
string | undefined
|
|
67
|
-
> {
|
|
68
|
-
const list = await getGuardianDelivery({ channelTypes: ["vellum"] });
|
|
69
|
-
if (list) {
|
|
70
|
-
const principalId = guardianForChannel(list, "vellum")?.principalId;
|
|
71
|
-
if (principalId) return principalId;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return findLocalGuardianPrincipalIdFromStore();
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Synchronous read of the vellum guardian's principalId for paths that cannot
|
|
79
|
-
* await {@link findLocalGuardianPrincipalId} — namely the SSE eager-subscribe
|
|
80
|
-
* path (`events-routes`), which registers before the stream is created.
|
|
81
|
-
*
|
|
82
|
-
* Reads the same gateway-owned binding as the async path via a sync, IO-free
|
|
83
|
-
* snapshot of the guardian-delivery cache (kept fresh by the async hot paths
|
|
84
|
-
* and event-driven invalidation), so SSE registers the SAME principal the
|
|
85
|
-
* send/result routes resolve. Falls back to the local store when the cache is
|
|
86
|
-
* cold — the same fallback the async path lands on during bootstrap.
|
|
87
|
-
*/
|
|
88
|
-
export function findLocalGuardianPrincipalIdFromStore(): string | undefined {
|
|
89
|
-
const cached = peekCachedGuardianDelivery({ channelTypes: ["vellum"] });
|
|
90
|
-
if (cached) {
|
|
91
|
-
const principalId = guardianForChannel(cached, "vellum")?.principalId;
|
|
92
|
-
if (principalId) return principalId;
|
|
93
|
-
}
|
|
94
|
-
|
|
54
|
+
export function findLocalGuardianPrincipalId(): string | undefined {
|
|
95
55
|
return findGuardianForChannel("vellum")?.contact.principalId ?? undefined;
|
|
96
56
|
}
|
|
97
57
|
|
|
@@ -116,35 +76,12 @@ export function findLocalGuardianPrincipalIdFromStore(): string | undefined {
|
|
|
116
76
|
* yet (e.g. fresh install before bootstrap); callers must treat this the
|
|
117
77
|
* same as a missing principal.
|
|
118
78
|
*/
|
|
119
|
-
export
|
|
120
|
-
rawHeader: string | undefined,
|
|
121
|
-
): Promise<string | undefined> {
|
|
122
|
-
if (rawHeader !== "dev-bypass" || !isHttpAuthDisabled()) return rawHeader;
|
|
123
|
-
|
|
124
|
-
const guardianPrincipalId = await findLocalGuardianPrincipalId();
|
|
125
|
-
if (guardianPrincipalId) return guardianPrincipalId;
|
|
126
|
-
|
|
127
|
-
log.warn(
|
|
128
|
-
"dev-bypass actor principal received but no vellum guardian binding found; returning undefined",
|
|
129
|
-
);
|
|
130
|
-
return undefined;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Synchronous variant of {@link resolveActorPrincipalIdForLocalGuardian} for
|
|
135
|
-
* the SSE eager-subscribe path, which registers before the response stream is
|
|
136
|
-
* created and cannot await. Resolves the guardian from the IO-free gateway
|
|
137
|
-
* cache snapshot first (same source the async path reads), falling back to the
|
|
138
|
-
* local store when the cache is cold — so SSE registers the SAME principal the
|
|
139
|
-
* send/result routes resolve and host-proxy targeting matches the same-user
|
|
140
|
-
* client even when the local contact row is stale.
|
|
141
|
-
*/
|
|
142
|
-
export function resolveActorPrincipalIdForLocalGuardianSync(
|
|
79
|
+
export function resolveActorPrincipalIdForLocalGuardian(
|
|
143
80
|
rawHeader: string | undefined,
|
|
144
81
|
): string | undefined {
|
|
145
82
|
if (rawHeader !== "dev-bypass" || !isHttpAuthDisabled()) return rawHeader;
|
|
146
83
|
|
|
147
|
-
const guardianPrincipalId =
|
|
84
|
+
const guardianPrincipalId = findLocalGuardianPrincipalId();
|
|
148
85
|
if (guardianPrincipalId) return guardianPrincipalId;
|
|
149
86
|
|
|
150
87
|
log.warn(
|
|
@@ -165,12 +102,12 @@ export function resolveActorPrincipalIdForLocalGuardianSync(
|
|
|
165
102
|
* bootstrap), falls back to a minimal guardian context so the local
|
|
166
103
|
* user is not incorrectly denied.
|
|
167
104
|
*/
|
|
168
|
-
export
|
|
105
|
+
export function resolveLocalTrustContext(
|
|
169
106
|
sourceChannel: ChannelId = "vellum",
|
|
170
|
-
):
|
|
107
|
+
): TrustContext {
|
|
171
108
|
const assistantId = DAEMON_INTERNAL_ASSISTANT_ID;
|
|
172
109
|
|
|
173
|
-
const guardianPrincipalId =
|
|
110
|
+
const guardianPrincipalId = findLocalGuardianPrincipalId();
|
|
174
111
|
if (guardianPrincipalId) {
|
|
175
112
|
const trustCtx = resolveTrustContext({
|
|
176
113
|
assistantId,
|
|
@@ -202,12 +139,10 @@ export async function resolveLocalTrustContext(
|
|
|
202
139
|
* downstream code to resolve guardian context using the same
|
|
203
140
|
* `authContext.actorPrincipalId` path as HTTP sessions.
|
|
204
141
|
*/
|
|
205
|
-
export
|
|
206
|
-
conversationId: string,
|
|
207
|
-
): Promise<AuthContext> {
|
|
142
|
+
export function resolveLocalAuthContext(conversationId: string): AuthContext {
|
|
208
143
|
const authContext = buildLocalAuthContext(conversationId);
|
|
209
144
|
|
|
210
|
-
const guardianPrincipalId =
|
|
145
|
+
const guardianPrincipalId = findLocalGuardianPrincipalId();
|
|
211
146
|
if (guardianPrincipalId) {
|
|
212
147
|
return { ...authContext, actorPrincipalId: guardianPrincipalId };
|
|
213
148
|
}
|
|
@@ -229,15 +229,6 @@ export function getByConversation(
|
|
|
229
229
|
* /v1/host-browser-result, /v1/host-app-control-result, or
|
|
230
230
|
* /v1/host-transfer-result after completing the operation, get a 404, and the
|
|
231
231
|
* proxy timer would fire with a spurious timeout error.
|
|
232
|
-
*
|
|
233
|
-
* `question` interactions are also skipped: a new message supersedes an open
|
|
234
|
-
* ask_question by steering to it (see the enqueue path in
|
|
235
|
-
* conversation-routes.ts), which aborts the parked turn and settles the
|
|
236
|
-
* question via its abort signal. Clearing the entry here instead would drop it
|
|
237
|
-
* without settling the prompt's Promise (questions carry no `rpcResolve`
|
|
238
|
-
* fallback like secrets do) and would strip the steer of the entry it needs to
|
|
239
|
-
* fire — which can co-occur with a confirmation, since one model response can
|
|
240
|
-
* open both tools concurrently.
|
|
241
232
|
*/
|
|
242
233
|
export function removeByConversation(
|
|
243
234
|
conversationId: string,
|
|
@@ -253,8 +244,7 @@ export function removeByConversation(
|
|
|
253
244
|
interaction.kind !== "host_browser" &&
|
|
254
245
|
interaction.kind !== "host_app_control" &&
|
|
255
246
|
interaction.kind !== "host_transfer" &&
|
|
256
|
-
interaction.kind !== "acp_confirmation"
|
|
257
|
-
interaction.kind !== "question"
|
|
247
|
+
interaction.kind !== "acp_confirmation"
|
|
258
248
|
) {
|
|
259
249
|
// resolve() clears the stored timer and detaches abort listeners.
|
|
260
250
|
resolve(requestId, state);
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
|
|
11
11
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
12
12
|
|
|
13
|
-
import type { GuardianDelivery } from "@vellumai/gateway-client";
|
|
14
13
|
import { IpcCallError } from "@vellumai/gateway-client/ipc-client";
|
|
15
14
|
|
|
16
15
|
type IpcCall = { method: string; params?: Record<string, unknown> };
|
|
@@ -74,16 +73,8 @@ mock.module("../../channel-verification-service.js", () => ({
|
|
|
74
73
|
getGuardianBinding: mock(() => guardianBinding),
|
|
75
74
|
}));
|
|
76
75
|
|
|
77
|
-
// Contact-store lookup that resolves the guardian's channel to downgrade.
|
|
78
|
-
|
|
79
|
-
// matched against (see deliveryForChannel).
|
|
80
|
-
let contactChannel: {
|
|
81
|
-
id: string;
|
|
82
|
-
status: string;
|
|
83
|
-
type: string;
|
|
84
|
-
address: string;
|
|
85
|
-
externalChatId: string;
|
|
86
|
-
} | null = null;
|
|
76
|
+
// Contact-store lookup that resolves the guardian's channel to downgrade.
|
|
77
|
+
let contactChannel: { id: string; status: string } | null = null;
|
|
87
78
|
const actualContactStore = await import("../../../contacts/contact-store.js");
|
|
88
79
|
mock.module("../../../contacts/contact-store.js", () => ({
|
|
89
80
|
...actualContactStore,
|
|
@@ -92,20 +83,6 @@ mock.module("../../../contacts/contact-store.js", () => ({
|
|
|
92
83
|
),
|
|
93
84
|
}));
|
|
94
85
|
|
|
95
|
-
// Gateway delivery (ACL source of truth). The revoke gate relays only when the
|
|
96
|
-
// matching delivery is live (active/pending/unverified); already-revoked or a
|
|
97
|
-
// missing delivery short-circuits the relay.
|
|
98
|
-
let guardianDeliveries: GuardianDelivery[] | null = null;
|
|
99
|
-
mock.module("../../../contacts/guardian-delivery-reader.js", () => ({
|
|
100
|
-
getGuardianDelivery: mock(async (input?: { channelTypes?: string[] }) => {
|
|
101
|
-
if (guardianDeliveries == null) return null;
|
|
102
|
-
if (!input?.channelTypes) return guardianDeliveries;
|
|
103
|
-
return guardianDeliveries.filter((g) =>
|
|
104
|
-
input.channelTypes!.includes(g.channelType),
|
|
105
|
-
);
|
|
106
|
-
}),
|
|
107
|
-
}));
|
|
108
|
-
|
|
109
86
|
// Guard: the contact-channel ACL write moves to the gateway relay and must
|
|
110
87
|
// never run locally. The assistant-owned guardian-binding teardown
|
|
111
88
|
// (revokeGuardianBinding) still runs locally — assert it is invoked.
|
|
@@ -145,24 +122,7 @@ describe("verification revoke relay", () => {
|
|
|
145
122
|
guardianExternalUserId: "guardian-user",
|
|
146
123
|
guardianDeliveryChatId: "chat-1",
|
|
147
124
|
};
|
|
148
|
-
contactChannel = {
|
|
149
|
-
id: "ch1",
|
|
150
|
-
status: "active",
|
|
151
|
-
type: "telegram",
|
|
152
|
-
address: "guardian-user",
|
|
153
|
-
externalChatId: "chat-1",
|
|
154
|
-
};
|
|
155
|
-
// Gateway delivery is live by default, so the revoke relay fires.
|
|
156
|
-
guardianDeliveries = [
|
|
157
|
-
{
|
|
158
|
-
channelType: "telegram",
|
|
159
|
-
contactId: "c1",
|
|
160
|
-
address: "guardian-user",
|
|
161
|
-
externalChatId: "chat-1",
|
|
162
|
-
status: "active",
|
|
163
|
-
verifiedAt: 1700000000,
|
|
164
|
-
},
|
|
165
|
-
];
|
|
125
|
+
contactChannel = { id: "ch1", status: "active" };
|
|
166
126
|
ipcCallPersistentMock.mockClear();
|
|
167
127
|
cancelOutboundMock.mockClear();
|
|
168
128
|
revokePendingSessionsMock.mockClear();
|
|
@@ -303,19 +263,8 @@ describe("verification revoke relay", () => {
|
|
|
303
263
|
expect(result.bound).toBe(false);
|
|
304
264
|
});
|
|
305
265
|
|
|
306
|
-
test("skips the relay when the
|
|
307
|
-
|
|
308
|
-
// redundant relay is skipped even though session/binding teardown runs.
|
|
309
|
-
guardianDeliveries = [
|
|
310
|
-
{
|
|
311
|
-
channelType: "telegram",
|
|
312
|
-
contactId: "c1",
|
|
313
|
-
address: "guardian-user",
|
|
314
|
-
externalChatId: "chat-1",
|
|
315
|
-
status: "revoked",
|
|
316
|
-
verifiedAt: 1700000000,
|
|
317
|
-
},
|
|
318
|
-
];
|
|
266
|
+
test("skips the relay when the resolved channel is already revoked", async () => {
|
|
267
|
+
contactChannel = { id: "ch1", status: "revoked" };
|
|
319
268
|
|
|
320
269
|
await revokeHandler({ body: { channel: "telegram" } });
|
|
321
270
|
|
|
@@ -24,7 +24,7 @@ mock.module("../../../daemon/handlers/config-channels.js", () => ({
|
|
|
24
24
|
verifyTrustedContactCalls.push([contactChannelId, assistantId]);
|
|
25
25
|
return verifyTrustedContactImpl(contactChannelId, assistantId);
|
|
26
26
|
},
|
|
27
|
-
createInboundChallenge:
|
|
27
|
+
createInboundChallenge: () => ({ success: true }),
|
|
28
28
|
getVerificationStatus: () => ({ success: true }),
|
|
29
29
|
revokeVerificationForChannel: () => ({ success: true }),
|
|
30
30
|
}));
|
|
@@ -25,7 +25,6 @@ interface StubConversation {
|
|
|
25
25
|
handleSurfaceActionThrows?: Error;
|
|
26
26
|
handleSurfaceUndoCalled?: boolean;
|
|
27
27
|
handleSurfaceUndoThrows?: Error;
|
|
28
|
-
trustContext?: { trustClass: string; sourceChannel: string };
|
|
29
28
|
surfaceActionCalls: Array<{
|
|
30
29
|
surfaceId: string;
|
|
31
30
|
actionId: string;
|
|
@@ -44,47 +43,6 @@ const findBySurfaceCalls: string[] = [];
|
|
|
44
43
|
const getOrCreateCalls: string[] = [];
|
|
45
44
|
const rawGetCalls: Array<{ sql: string; params: unknown[] }> = [];
|
|
46
45
|
|
|
47
|
-
// Gateway guardian-delivery list (shared by the route's dev-bypass lookup and
|
|
48
|
-
// the local-principal-trust mapper): null = unreachable, [] = no guardian.
|
|
49
|
-
let mockGuardianList: Array<Record<string, unknown>> | null = [];
|
|
50
|
-
let httpAuthDisabled = false;
|
|
51
|
-
|
|
52
|
-
// Stub for the shared reset-drift helper. The route under test only consumes
|
|
53
|
-
// its result (a guardian TrustContext or null); the gate itself is covered in
|
|
54
|
-
// runtime/__tests__/guardian-vellum-migration.test.ts. Tests set
|
|
55
|
-
// `mockReResolve` per case and read `reResolveCalls` to assert routing.
|
|
56
|
-
const reResolveCalls: string[] = [];
|
|
57
|
-
let mockReResolve: { trustClass: string; sourceChannel: string } | null = null;
|
|
58
|
-
|
|
59
|
-
mock.module("../../../contacts/guardian-delivery-reader.js", () => ({
|
|
60
|
-
getGuardianDelivery: (_input?: { channelTypes?: string[] }) =>
|
|
61
|
-
Promise.resolve(mockGuardianList),
|
|
62
|
-
peekCachedGuardianDelivery: () => mockGuardianList ?? undefined,
|
|
63
|
-
guardianForChannel: (
|
|
64
|
-
list: Array<Record<string, unknown>>,
|
|
65
|
-
channelType: string,
|
|
66
|
-
) => list.find((g) => g.channelType === channelType && g.status === "active"),
|
|
67
|
-
}));
|
|
68
|
-
|
|
69
|
-
mock.module("../../../contacts/contact-store.js", () => ({
|
|
70
|
-
findGuardianForChannel: (_channelType: string) => null,
|
|
71
|
-
findContactByAddress: () => null,
|
|
72
|
-
}));
|
|
73
|
-
|
|
74
|
-
mock.module("../../../config/env.js", () => ({
|
|
75
|
-
isHttpAuthDisabled: () => httpAuthDisabled,
|
|
76
|
-
}));
|
|
77
|
-
|
|
78
|
-
mock.module("../../guardian-vellum-migration.js", () => ({
|
|
79
|
-
reResolveTrustOnResetDrift: async (
|
|
80
|
-
incomingPrincipalId: string,
|
|
81
|
-
_sourceChannel: string,
|
|
82
|
-
) => {
|
|
83
|
-
reResolveCalls.push(incomingPrincipalId);
|
|
84
|
-
return mockReResolve;
|
|
85
|
-
},
|
|
86
|
-
}));
|
|
87
|
-
|
|
88
46
|
mock.module("../../../daemon/conversation-registry.js", () => ({
|
|
89
47
|
findConversation: (id: string) => {
|
|
90
48
|
findConvCalls.push(id);
|
|
@@ -164,9 +122,6 @@ function makeStub(id: string): StubConversation {
|
|
|
164
122
|
stub.handleSurfaceUndoCalled = true;
|
|
165
123
|
if (stub.handleSurfaceUndoThrows) throw stub.handleSurfaceUndoThrows;
|
|
166
124
|
},
|
|
167
|
-
setTrustContext: (ctx: { trustClass: string; sourceChannel: string }) => {
|
|
168
|
-
stub.trustContext = ctx;
|
|
169
|
-
},
|
|
170
125
|
});
|
|
171
126
|
return stub;
|
|
172
127
|
}
|
|
@@ -184,10 +139,6 @@ beforeEach(() => {
|
|
|
184
139
|
findBySurfaceCalls.length = 0;
|
|
185
140
|
getOrCreateCalls.length = 0;
|
|
186
141
|
rawGetCalls.length = 0;
|
|
187
|
-
mockGuardianList = [];
|
|
188
|
-
httpAuthDisabled = false;
|
|
189
|
-
reResolveCalls.length = 0;
|
|
190
|
-
mockReResolve = null;
|
|
191
142
|
});
|
|
192
143
|
|
|
193
144
|
// ---------------------------------------------------------------------------
|
|
@@ -386,30 +337,6 @@ describe("triggerSurfaceAction handler", () => {
|
|
|
386
337
|
]);
|
|
387
338
|
});
|
|
388
339
|
|
|
389
|
-
test("resolves dev-bypass to the guardian principal before threading the turn", async () => {
|
|
390
|
-
httpAuthDisabled = true;
|
|
391
|
-
mockGuardianList = [guardianDelivery(GUARDIAN_PRINCIPAL)];
|
|
392
|
-
const live = makeStub("conv-dev-thread");
|
|
393
|
-
memoryBySurface = live;
|
|
394
|
-
|
|
395
|
-
const handler = findHandler("triggerSurfaceAction");
|
|
396
|
-
await handler({
|
|
397
|
-
body: { surfaceId: "surf-dt", actionId: "act-dt" },
|
|
398
|
-
headers: { "x-vellum-actor-principal-id": "dev-bypass" },
|
|
399
|
-
});
|
|
400
|
-
|
|
401
|
-
// dev-bypass is translated so the surface turn matches the SSE host-proxy
|
|
402
|
-
// client's registered guardian principal (CU/app-control same-actor check).
|
|
403
|
-
expect(live.surfaceActionCalls).toEqual([
|
|
404
|
-
{
|
|
405
|
-
surfaceId: "surf-dt",
|
|
406
|
-
actionId: "act-dt",
|
|
407
|
-
data: undefined,
|
|
408
|
-
sourceActorPrincipalId: GUARDIAN_PRINCIPAL,
|
|
409
|
-
},
|
|
410
|
-
]);
|
|
411
|
-
});
|
|
412
|
-
|
|
413
340
|
test("propagates accepted=false rejection as BadRequestError", async () => {
|
|
414
341
|
const live = makeStub("conv-reject");
|
|
415
342
|
live.handleSurfaceActionResult = {
|
|
@@ -435,120 +362,6 @@ describe("triggerSurfaceAction handler", () => {
|
|
|
435
362
|
});
|
|
436
363
|
});
|
|
437
364
|
|
|
438
|
-
// ---------------------------------------------------------------------------
|
|
439
|
-
// Trust context resolution
|
|
440
|
-
// ---------------------------------------------------------------------------
|
|
441
|
-
|
|
442
|
-
const GUARDIAN_PRINCIPAL = "principal-guardian";
|
|
443
|
-
// Daemon-minted vellum-principal-* ids: the DB-reset drift signature. The
|
|
444
|
-
// gateway rebinds to a fresh id while the client still holds a JWT for the old.
|
|
445
|
-
const VELLUM_PRINCIPAL_OLD = "vellum-principal-old";
|
|
446
|
-
const VELLUM_PRINCIPAL_NEW = "vellum-principal-new";
|
|
447
|
-
|
|
448
|
-
function guardianDelivery(principalId: string): Record<string, unknown> {
|
|
449
|
-
return {
|
|
450
|
-
channelType: "vellum",
|
|
451
|
-
contactId: "contact-1",
|
|
452
|
-
principalId,
|
|
453
|
-
address: "guardian-address",
|
|
454
|
-
externalChatId: "guardian-chat",
|
|
455
|
-
status: "active",
|
|
456
|
-
};
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
// A guardian TrustContext the stubbed helper hands back on a recovered drift.
|
|
460
|
-
function guardianCtx(): { trustClass: string; sourceChannel: string } {
|
|
461
|
-
return { trustClass: "guardian", sourceChannel: "vellum" };
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
describe("triggerSurfaceAction trust context", () => {
|
|
465
|
-
test("guardian principal → guardian from the gateway binding, helper not called", async () => {
|
|
466
|
-
mockGuardianList = [guardianDelivery(GUARDIAN_PRINCIPAL)];
|
|
467
|
-
const live = makeStub("conv-guardian");
|
|
468
|
-
memoryBySurface = live;
|
|
469
|
-
|
|
470
|
-
const handler = findHandler("triggerSurfaceAction");
|
|
471
|
-
await handler({
|
|
472
|
-
body: { surfaceId: "surf-g", actionId: "act-g" },
|
|
473
|
-
headers: { "x-vellum-actor-principal-id": GUARDIAN_PRINCIPAL },
|
|
474
|
-
});
|
|
475
|
-
|
|
476
|
-
expect(live.trustContext?.trustClass).toBe("guardian");
|
|
477
|
-
expect(live.trustContext?.sourceChannel).toBe("vellum");
|
|
478
|
-
// First-pass resolve already granted guardian, so the drift helper is skipped.
|
|
479
|
-
expect(reResolveCalls).toEqual([]);
|
|
480
|
-
});
|
|
481
|
-
|
|
482
|
-
test("unknown principal: helper consulted, null result stays unknown (fail closed)", async () => {
|
|
483
|
-
mockGuardianList = [guardianDelivery(GUARDIAN_PRINCIPAL)];
|
|
484
|
-
mockReResolve = null;
|
|
485
|
-
const live = makeStub("conv-unknown");
|
|
486
|
-
memoryBySurface = live;
|
|
487
|
-
|
|
488
|
-
const handler = findHandler("triggerSurfaceAction");
|
|
489
|
-
await handler({
|
|
490
|
-
body: { surfaceId: "surf-u", actionId: "act-u" },
|
|
491
|
-
headers: { "x-vellum-actor-principal-id": VELLUM_PRINCIPAL_OLD },
|
|
492
|
-
});
|
|
493
|
-
|
|
494
|
-
expect(reResolveCalls).toEqual([VELLUM_PRINCIPAL_OLD]);
|
|
495
|
-
expect(live.trustContext?.trustClass).toBe("unknown");
|
|
496
|
-
});
|
|
497
|
-
|
|
498
|
-
test("reset drift: helper returns guardian → route adopts it", async () => {
|
|
499
|
-
mockGuardianList = [guardianDelivery(VELLUM_PRINCIPAL_NEW)];
|
|
500
|
-
mockReResolve = guardianCtx();
|
|
501
|
-
const live = makeStub("conv-drift");
|
|
502
|
-
memoryBySurface = live;
|
|
503
|
-
|
|
504
|
-
const handler = findHandler("triggerSurfaceAction");
|
|
505
|
-
await handler({
|
|
506
|
-
body: { surfaceId: "surf-d", actionId: "act-d" },
|
|
507
|
-
headers: { "x-vellum-actor-principal-id": VELLUM_PRINCIPAL_OLD },
|
|
508
|
-
});
|
|
509
|
-
|
|
510
|
-
expect(reResolveCalls).toEqual([VELLUM_PRINCIPAL_OLD]);
|
|
511
|
-
expect(live.trustContext?.trustClass).toBe("guardian");
|
|
512
|
-
});
|
|
513
|
-
|
|
514
|
-
test("dev-bypass resolves the real guardian principal from the gateway, helper not called", async () => {
|
|
515
|
-
httpAuthDisabled = true;
|
|
516
|
-
mockGuardianList = [guardianDelivery(GUARDIAN_PRINCIPAL)];
|
|
517
|
-
const live = makeStub("conv-dev");
|
|
518
|
-
memoryBySurface = live;
|
|
519
|
-
|
|
520
|
-
const handler = findHandler("triggerSurfaceAction");
|
|
521
|
-
await handler({
|
|
522
|
-
body: { surfaceId: "surf-dev", actionId: "act-dev" },
|
|
523
|
-
headers: { "x-vellum-actor-principal-id": "dev-bypass" },
|
|
524
|
-
});
|
|
525
|
-
|
|
526
|
-
// The synthetic dev-bypass principal is translated to the real guardian,
|
|
527
|
-
// yielding a guardian trust context without consulting the drift helper.
|
|
528
|
-
expect(live.trustContext?.trustClass).toBe("guardian");
|
|
529
|
-
expect(reResolveCalls).toEqual([]);
|
|
530
|
-
});
|
|
531
|
-
|
|
532
|
-
test("dev-bypass with an empty gateway: helper null result → unknown (fail closed)", async () => {
|
|
533
|
-
httpAuthDisabled = true;
|
|
534
|
-
// The gateway has no active binding, so dev-bypass cannot translate to a
|
|
535
|
-
// real guardian; the first-pass resolve is unknown and the helper, returning
|
|
536
|
-
// null, leaves trust unknown.
|
|
537
|
-
mockGuardianList = [];
|
|
538
|
-
mockReResolve = null;
|
|
539
|
-
const live = makeStub("conv-dev-fallback");
|
|
540
|
-
memoryBySurface = live;
|
|
541
|
-
|
|
542
|
-
const handler = findHandler("triggerSurfaceAction");
|
|
543
|
-
await handler({
|
|
544
|
-
body: { surfaceId: "surf-devf", actionId: "act-devf" },
|
|
545
|
-
headers: { "x-vellum-actor-principal-id": "dev-bypass" },
|
|
546
|
-
});
|
|
547
|
-
|
|
548
|
-
expect(live.trustContext?.trustClass).toBe("unknown");
|
|
549
|
-
});
|
|
550
|
-
});
|
|
551
|
-
|
|
552
365
|
// ---------------------------------------------------------------------------
|
|
553
366
|
// undoSurfaceAction
|
|
554
367
|
// ---------------------------------------------------------------------------
|
|
@@ -92,7 +92,7 @@ async function handleBrowserExecute({
|
|
|
92
92
|
// register with (dev-bypass otherwise mismatches).
|
|
93
93
|
const headerActor =
|
|
94
94
|
headers["x-vellum-actor-principal-id"]?.trim() || undefined;
|
|
95
|
-
const sourceActorPrincipalId =
|
|
95
|
+
const sourceActorPrincipalId = resolveActorPrincipalIdForLocalGuardian(
|
|
96
96
|
conversation?.getTurnActorPrincipalId() ?? headerActor,
|
|
97
97
|
);
|
|
98
98
|
|
|
@@ -8,16 +8,13 @@
|
|
|
8
8
|
* requester.
|
|
9
9
|
*
|
|
10
10
|
* This sweep operates on the unified canonical domain
|
|
11
|
-
* (`canonical_guardian_requests`)
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* requester's channel — not the guardian-facing notification pipeline — and the
|
|
16
|
-
* guardian stays passive, since the withdrawn card already reflects expiry.
|
|
11
|
+
* (`canonical_guardian_requests`) and does not auto-deny pending interactions
|
|
12
|
+
* or deliver channel notices — the canonical request status transition is the
|
|
13
|
+
* single source of truth, and consumers (resolvers, clients polling prompts)
|
|
14
|
+
* observe the expired status directly.
|
|
17
15
|
*/
|
|
18
16
|
|
|
19
17
|
import { withdrawGuardianRequestCards } from "../../approvals/guardian-card-withdrawal.js";
|
|
20
|
-
import { notifyExpiredGuardianRequest } from "../../approvals/guardian-expiry-notifier.js";
|
|
21
18
|
import {
|
|
22
19
|
listCanonicalGuardianRequests,
|
|
23
20
|
resolveCanonicalGuardianRequest,
|
|
@@ -42,7 +39,7 @@ let sweepInProgress = false;
|
|
|
42
39
|
* concurrent decision that wins the race is never overwritten by the
|
|
43
40
|
* sweep. Returns the count of requests transitioned to expired.
|
|
44
41
|
*/
|
|
45
|
-
|
|
42
|
+
async function sweepExpiredCanonicalGuardianRequests(): Promise<number> {
|
|
46
43
|
const pending = listCanonicalGuardianRequests({ status: "pending" });
|
|
47
44
|
const now = Date.now();
|
|
48
45
|
let expiredCount = 0;
|
|
@@ -79,11 +76,6 @@ export async function sweepExpiredCanonicalGuardianRequests(): Promise<number> {
|
|
|
79
76
|
request: resolved,
|
|
80
77
|
status: "expired",
|
|
81
78
|
});
|
|
82
|
-
|
|
83
|
-
// Notify the requester their request expired and release any in-memory
|
|
84
|
-
// pending interaction. Best-effort and non-throwing, like the card
|
|
85
|
-
// withdrawal above.
|
|
86
|
-
await notifyExpiredGuardianRequest(resolved);
|
|
87
79
|
}
|
|
88
80
|
}
|
|
89
81
|
|
|
@@ -179,7 +179,7 @@ export async function handleCreateVerificationSession({
|
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
// Inbound challenge path
|
|
182
|
-
const result =
|
|
182
|
+
const result = createInboundChallenge(channel, rebind, conversationId);
|
|
183
183
|
if (!result.success) {
|
|
184
184
|
throw new BadRequestError(
|
|
185
185
|
(result as { message?: string }).message ??
|
|
@@ -192,12 +192,12 @@ export async function handleCreateVerificationSession({
|
|
|
192
192
|
/**
|
|
193
193
|
* GET /v1/channel-verification-sessions/status
|
|
194
194
|
*/
|
|
195
|
-
|
|
195
|
+
function handleGetVerificationStatus({
|
|
196
196
|
queryParams = {},
|
|
197
197
|
body = {},
|
|
198
198
|
}: RouteHandlerArgs) {
|
|
199
199
|
const channel = (queryParams.channel ?? (body as Record<string, unknown>).channel) as ChannelId | undefined;
|
|
200
|
-
return
|
|
200
|
+
return getVerificationStatus(channel);
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
/**
|
|
@@ -17,6 +17,8 @@ import { IpcCallError } from "@vellumai/gateway-client/ipc-client";
|
|
|
17
17
|
import { z } from "zod";
|
|
18
18
|
|
|
19
19
|
import {
|
|
20
|
+
getAssistantContactMetadata,
|
|
21
|
+
getContact,
|
|
20
22
|
listContacts,
|
|
21
23
|
mergeContacts,
|
|
22
24
|
searchContacts,
|
|
@@ -137,10 +139,9 @@ const contactSchema = z.object({
|
|
|
137
139
|
|
|
138
140
|
/**
|
|
139
141
|
* Relay a non-search contact list read to the gateway (source of truth for ACL
|
|
140
|
-
* fields)
|
|
141
|
-
* no-filter case so both serve
|
|
142
|
-
*
|
|
143
|
-
* assistant DB.
|
|
142
|
+
* fields), falling back to the assistant DB on IPC failure. Shared by the GET
|
|
143
|
+
* `contacts` list and the `search_contacts` no-filter case so both serve
|
|
144
|
+
* gateway-sourced data consistently.
|
|
144
145
|
*/
|
|
145
146
|
async function relayListContacts(
|
|
146
147
|
limit: number,
|
|
@@ -157,7 +158,15 @@ async function relayListContacts(
|
|
|
157
158
|
contacts: contacts.map(prepareContactResponse),
|
|
158
159
|
};
|
|
159
160
|
} catch (err) {
|
|
160
|
-
|
|
161
|
+
log.warn(
|
|
162
|
+
{ err },
|
|
163
|
+
"relayListContacts: gateway relay failed; falling back to assistant DB",
|
|
164
|
+
);
|
|
165
|
+
const contacts = listContacts(limit, role);
|
|
166
|
+
return {
|
|
167
|
+
ok: true,
|
|
168
|
+
contacts: contacts.map(prepareContactResponse),
|
|
169
|
+
};
|
|
161
170
|
}
|
|
162
171
|
}
|
|
163
172
|
|
|
@@ -231,10 +240,25 @@ export async function handleGetContact(contactId: string) {
|
|
|
231
240
|
assistantMetadata: assistantMetadata ?? undefined,
|
|
232
241
|
};
|
|
233
242
|
} catch (err) {
|
|
234
|
-
// A clean not-found is a real 404
|
|
235
|
-
// rather than reading ACL from the assistant DB.
|
|
243
|
+
// A clean not-found is a real 404 — don't fall back or mask it.
|
|
236
244
|
if (err instanceof NotFoundError) throw err;
|
|
237
|
-
|
|
245
|
+
log.warn(
|
|
246
|
+
{ err, contactId },
|
|
247
|
+
"handleGetContact: gateway relay failed; falling back to assistant DB",
|
|
248
|
+
);
|
|
249
|
+
const contact = getContact(contactId);
|
|
250
|
+
if (!contact) {
|
|
251
|
+
throw new NotFoundError(`Contact "${contactId}" not found`);
|
|
252
|
+
}
|
|
253
|
+
const assistantMeta =
|
|
254
|
+
contact.contactType === "assistant"
|
|
255
|
+
? getAssistantContactMetadata(contact.id)
|
|
256
|
+
: undefined;
|
|
257
|
+
return {
|
|
258
|
+
ok: true,
|
|
259
|
+
contact: prepareContactResponse(contact),
|
|
260
|
+
assistantMetadata: assistantMeta ?? undefined,
|
|
261
|
+
};
|
|
238
262
|
}
|
|
239
263
|
}
|
|
240
264
|
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
import { v4 as uuid } from "uuid";
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
|
|
12
|
+
import { findConversation } from "../../daemon/conversation-registry.js";
|
|
12
13
|
import { clearAllConversations as clearAllActive } from "../../daemon/handlers/conversations.js";
|
|
13
14
|
import { formatJson, formatMarkdown } from "../../export/formatter.js";
|
|
14
15
|
import { ipcCall as ipcCallGateway } from "../../ipc/gateway-client.js";
|
|
15
|
-
import { isConversationProcessing } from "../../memory/conversation-crud.js";
|
|
16
16
|
import {
|
|
17
17
|
addMessage,
|
|
18
18
|
createConversation,
|
|
@@ -53,9 +53,10 @@ function handleListCli({ body = {} }: RouteHandlerArgs) {
|
|
|
53
53
|
id: c.id,
|
|
54
54
|
title: c.title,
|
|
55
55
|
updatedAt: c.updatedAt,
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
|
|
56
|
+
// `isProcessing` mirrors `Conversation.isProcessing()` from the
|
|
57
|
+
// in-memory daemon store — true when the agent loop is mid-turn.
|
|
58
|
+
// Rows not currently in memory (cold / evicted) report `false`.
|
|
59
|
+
isProcessing: findConversation(c.id)?.isProcessing() ?? false,
|
|
59
60
|
})),
|
|
60
61
|
};
|
|
61
62
|
}
|