@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
|
@@ -2,7 +2,6 @@ import { describe, expect, test } from "bun:test";
|
|
|
2
2
|
|
|
3
3
|
import type { TrustVerdict } from "@vellumai/gateway-client";
|
|
4
4
|
|
|
5
|
-
import { channelStatusToMemberStatus } from "../../contacts/member-status.js";
|
|
6
5
|
import type {
|
|
7
6
|
ContactChannel,
|
|
8
7
|
ContactWithChannels,
|
|
@@ -10,12 +9,8 @@ import type {
|
|
|
10
9
|
import type { ActorTrustContext } from "../actor-trust-resolver.js";
|
|
11
10
|
import { toTrustContext } from "../actor-trust-resolver.js";
|
|
12
11
|
import {
|
|
13
|
-
actorTrustContextFromVerdict,
|
|
14
12
|
resolvedMemberFromVerdict,
|
|
15
13
|
trustContextFromVerdict,
|
|
16
|
-
verdictHasMemberIdentity,
|
|
17
|
-
verdictMemberFromVerdict,
|
|
18
|
-
verdictMemberUnresolvable,
|
|
19
14
|
} from "../trust-verdict-consumer.js";
|
|
20
15
|
|
|
21
16
|
const CONV = "conv-123";
|
|
@@ -168,195 +163,6 @@ describe("trustContextFromVerdict", () => {
|
|
|
168
163
|
});
|
|
169
164
|
});
|
|
170
165
|
|
|
171
|
-
describe("actorTrustContextFromVerdict", () => {
|
|
172
|
-
test("maps guardian verdict fields", () => {
|
|
173
|
-
const verdict = {
|
|
174
|
-
trustClass: "guardian",
|
|
175
|
-
canonicalSenderId: "+15550100",
|
|
176
|
-
guardianExternalUserId: "+15550100",
|
|
177
|
-
guardianDeliveryChatId: "chat-9",
|
|
178
|
-
guardianPrincipalId: "vellum-principal-abc",
|
|
179
|
-
memberDisplayName: "Alice",
|
|
180
|
-
} satisfies TrustVerdict;
|
|
181
|
-
|
|
182
|
-
const ctx = actorTrustContextFromVerdict(verdict, {
|
|
183
|
-
sourceChannel: "phone",
|
|
184
|
-
conversationExternalId: CONV,
|
|
185
|
-
actorUsername: "alice",
|
|
186
|
-
actorDisplayName: "Alice Sender",
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
expect(ctx).toEqual({
|
|
190
|
-
canonicalSenderId: "+15550100",
|
|
191
|
-
guardianBindingMatch: {
|
|
192
|
-
guardianExternalUserId: "+15550100",
|
|
193
|
-
guardianDeliveryChatId: "chat-9",
|
|
194
|
-
},
|
|
195
|
-
guardianPrincipalId: "vellum-principal-abc",
|
|
196
|
-
memberRecord: null,
|
|
197
|
-
trustClass: "guardian",
|
|
198
|
-
actorMetadata: {
|
|
199
|
-
identifier: "@alice",
|
|
200
|
-
displayName: "Alice",
|
|
201
|
-
senderDisplayName: "Alice Sender",
|
|
202
|
-
memberDisplayName: "Alice",
|
|
203
|
-
username: "alice",
|
|
204
|
-
channel: "phone",
|
|
205
|
-
trustStatus: "guardian",
|
|
206
|
-
},
|
|
207
|
-
});
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
test("guardianBindingMatch is null without guardianExternalUserId", () => {
|
|
211
|
-
const verdict = {
|
|
212
|
-
trustClass: "trusted_contact",
|
|
213
|
-
canonicalSenderId: "+15550101",
|
|
214
|
-
memberDisplayName: "Bob",
|
|
215
|
-
} satisfies TrustVerdict;
|
|
216
|
-
|
|
217
|
-
const ctx = actorTrustContextFromVerdict(verdict, {
|
|
218
|
-
sourceChannel: "phone",
|
|
219
|
-
conversationExternalId: CONV,
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
expect(ctx.guardianBindingMatch).toBeNull();
|
|
223
|
-
expect(ctx.trustClass).toBe("trusted_contact");
|
|
224
|
-
// identifier falls back to canonicalSenderId when no username.
|
|
225
|
-
expect(ctx.actorMetadata.identifier).toBe("+15550101");
|
|
226
|
-
// displayName uses memberDisplayName when present.
|
|
227
|
-
expect(ctx.actorMetadata.displayName).toBe("Bob");
|
|
228
|
-
expect(ctx.actorMetadata.channel).toBe("phone");
|
|
229
|
-
expect(ctx.memberRecord).toBeNull();
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
test("displayName falls back to actorDisplayName; identifier uses @username", () => {
|
|
233
|
-
const verdict = {
|
|
234
|
-
trustClass: "unverified_contact",
|
|
235
|
-
canonicalSenderId: "u-1",
|
|
236
|
-
} satisfies TrustVerdict;
|
|
237
|
-
|
|
238
|
-
const ctx = actorTrustContextFromVerdict(verdict, {
|
|
239
|
-
sourceChannel: "slack",
|
|
240
|
-
conversationExternalId: CONV,
|
|
241
|
-
actorUsername: "carol",
|
|
242
|
-
actorDisplayName: "Carol Display",
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
expect(ctx.trustClass).toBe("unverified_contact");
|
|
246
|
-
expect(ctx.actorMetadata.identifier).toBe("@carol");
|
|
247
|
-
expect(ctx.actorMetadata.displayName).toBe("Carol Display");
|
|
248
|
-
expect(ctx.actorMetadata.memberDisplayName).toBeUndefined();
|
|
249
|
-
expect(ctx.actorMetadata.trustStatus).toBe("unverified_contact");
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
test("maps unknown verdict with no identity overrides", () => {
|
|
253
|
-
const verdict = {
|
|
254
|
-
trustClass: "unknown",
|
|
255
|
-
canonicalSenderId: "u-2",
|
|
256
|
-
} satisfies TrustVerdict;
|
|
257
|
-
|
|
258
|
-
const ctx = actorTrustContextFromVerdict(verdict, {
|
|
259
|
-
sourceChannel: "slack",
|
|
260
|
-
conversationExternalId: CONV,
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
expect(ctx.trustClass).toBe("unknown");
|
|
264
|
-
expect(ctx.guardianBindingMatch).toBeNull();
|
|
265
|
-
expect(ctx.guardianPrincipalId).toBeUndefined();
|
|
266
|
-
expect(ctx.memberRecord).toBeNull();
|
|
267
|
-
expect(ctx.actorMetadata.identifier).toBe("u-2");
|
|
268
|
-
expect(ctx.actorMetadata.displayName).toBeUndefined();
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
test("member verdict populates memberRecord from the verdict (voice ACL)", () => {
|
|
272
|
-
const verdict = {
|
|
273
|
-
trustClass: "trusted_contact",
|
|
274
|
-
canonicalSenderId: "u-1",
|
|
275
|
-
contactId: "contact-1",
|
|
276
|
-
channelId: "channel-1",
|
|
277
|
-
type: "slack",
|
|
278
|
-
address: "u-1",
|
|
279
|
-
status: "blocked",
|
|
280
|
-
policy: "deny",
|
|
281
|
-
} satisfies TrustVerdict;
|
|
282
|
-
|
|
283
|
-
const ctx = actorTrustContextFromVerdict(verdict, {
|
|
284
|
-
sourceChannel: "slack",
|
|
285
|
-
conversationExternalId: CONV,
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
expect(ctx.memberRecord).not.toBeNull();
|
|
289
|
-
expect(ctx.memberRecord!.contact.id).toBe("contact-1");
|
|
290
|
-
expect(ctx.memberRecord!.channel.id).toBe("channel-1");
|
|
291
|
-
expect(ctx.memberRecord!.channel.status).toBe("blocked");
|
|
292
|
-
expect(ctx.memberRecord!.channel.policy).toBe("deny");
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
test("stranger verdict (no contactId/channelId) leaves memberRecord null", () => {
|
|
296
|
-
const verdict = {
|
|
297
|
-
trustClass: "unknown",
|
|
298
|
-
canonicalSenderId: "u-9",
|
|
299
|
-
} satisfies TrustVerdict;
|
|
300
|
-
|
|
301
|
-
const ctx = actorTrustContextFromVerdict(verdict, {
|
|
302
|
-
sourceChannel: "slack",
|
|
303
|
-
conversationExternalId: CONV,
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
expect(ctx.memberRecord).toBeNull();
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
test("malformed member verdict (unknown status) leaves memberRecord null (fail-closed)", () => {
|
|
310
|
-
const verdict = {
|
|
311
|
-
trustClass: "trusted_contact",
|
|
312
|
-
canonicalSenderId: "u-10",
|
|
313
|
-
contactId: "contact-10",
|
|
314
|
-
channelId: "channel-10",
|
|
315
|
-
status: "quarantined",
|
|
316
|
-
policy: "allow",
|
|
317
|
-
} satisfies TrustVerdict;
|
|
318
|
-
|
|
319
|
-
const ctx = actorTrustContextFromVerdict(verdict, {
|
|
320
|
-
sourceChannel: "slack",
|
|
321
|
-
conversationExternalId: CONV,
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
expect(ctx.memberRecord).toBeNull();
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
test("trustContextFromVerdict equals member stamp applied to toTrustContext(actorTrustContextFromVerdict)", () => {
|
|
328
|
-
const verdict = {
|
|
329
|
-
trustClass: "trusted_contact",
|
|
330
|
-
canonicalSenderId: "u-1",
|
|
331
|
-
contactId: "contact-1",
|
|
332
|
-
channelId: "channel-1",
|
|
333
|
-
type: "slack",
|
|
334
|
-
address: "u-1",
|
|
335
|
-
status: "unverified",
|
|
336
|
-
policy: "escalate",
|
|
337
|
-
memberDisplayName: "Dora",
|
|
338
|
-
} satisfies TrustVerdict;
|
|
339
|
-
const input = {
|
|
340
|
-
sourceChannel: "slack",
|
|
341
|
-
conversationExternalId: CONV,
|
|
342
|
-
actorUsername: "dora",
|
|
343
|
-
actorDisplayName: "Dora Display",
|
|
344
|
-
} as const;
|
|
345
|
-
|
|
346
|
-
const expected = toTrustContext(
|
|
347
|
-
actorTrustContextFromVerdict(verdict, input),
|
|
348
|
-
input.conversationExternalId,
|
|
349
|
-
);
|
|
350
|
-
const member = resolvedMemberFromVerdict(verdict);
|
|
351
|
-
expect(member).not.toBeNull();
|
|
352
|
-
expected.requesterContactId = member!.contact.id;
|
|
353
|
-
expected.memberStatus = channelStatusToMemberStatus(member!.channel.status);
|
|
354
|
-
expected.memberPolicy = member!.channel.policy;
|
|
355
|
-
|
|
356
|
-
expect(trustContextFromVerdict(verdict, input)).toEqual(expected);
|
|
357
|
-
});
|
|
358
|
-
});
|
|
359
|
-
|
|
360
166
|
describe("toTrustContext member grounding", () => {
|
|
361
167
|
function memberChannel(
|
|
362
168
|
overrides: Partial<ContactChannel> = {},
|
|
@@ -401,7 +207,9 @@ describe("toTrustContext member grounding", () => {
|
|
|
401
207
|
};
|
|
402
208
|
}
|
|
403
209
|
|
|
404
|
-
function ctxWithMember(
|
|
210
|
+
function ctxWithMember(
|
|
211
|
+
channel: ContactChannel,
|
|
212
|
+
): ActorTrustContext {
|
|
405
213
|
return {
|
|
406
214
|
canonicalSenderId: "+15550100",
|
|
407
215
|
guardianBindingMatch: null,
|
|
@@ -607,143 +415,3 @@ describe("resolvedMemberFromVerdict", () => {
|
|
|
607
415
|
}
|
|
608
416
|
});
|
|
609
417
|
});
|
|
610
|
-
|
|
611
|
-
describe("verdictMemberFromVerdict", () => {
|
|
612
|
-
test("active member verdict yields the narrow ACL view", () => {
|
|
613
|
-
const verdict = {
|
|
614
|
-
trustClass: "trusted_contact",
|
|
615
|
-
canonicalSenderId: "u-1",
|
|
616
|
-
contactId: "contact-1",
|
|
617
|
-
channelId: "channel-1",
|
|
618
|
-
type: "slack",
|
|
619
|
-
address: "u-1",
|
|
620
|
-
status: "active",
|
|
621
|
-
policy: "allow",
|
|
622
|
-
verifiedAt: 1700000000,
|
|
623
|
-
memberDisplayName: "Dora",
|
|
624
|
-
} satisfies TrustVerdict;
|
|
625
|
-
|
|
626
|
-
expect(verdictMemberFromVerdict(verdict)).toEqual({
|
|
627
|
-
contactId: "contact-1",
|
|
628
|
-
channelId: "channel-1",
|
|
629
|
-
status: "active",
|
|
630
|
-
policy: "allow",
|
|
631
|
-
verifiedAt: 1700000000,
|
|
632
|
-
displayName: "Dora",
|
|
633
|
-
});
|
|
634
|
-
});
|
|
635
|
-
|
|
636
|
-
test("blocked member verdict surfaces status/policy verbatim, null defaults", () => {
|
|
637
|
-
const verdict = {
|
|
638
|
-
trustClass: "unknown",
|
|
639
|
-
canonicalSenderId: "u-3",
|
|
640
|
-
contactId: "contact-3",
|
|
641
|
-
channelId: "channel-3",
|
|
642
|
-
status: "blocked",
|
|
643
|
-
policy: "deny",
|
|
644
|
-
} satisfies TrustVerdict;
|
|
645
|
-
|
|
646
|
-
expect(verdictMemberFromVerdict(verdict)).toEqual({
|
|
647
|
-
contactId: "contact-3",
|
|
648
|
-
channelId: "channel-3",
|
|
649
|
-
status: "blocked",
|
|
650
|
-
policy: "deny",
|
|
651
|
-
verifiedAt: null,
|
|
652
|
-
displayName: null,
|
|
653
|
-
});
|
|
654
|
-
});
|
|
655
|
-
|
|
656
|
-
test("memberless verdict (no contactId/channelId) returns null", () => {
|
|
657
|
-
expect(
|
|
658
|
-
verdictMemberFromVerdict({
|
|
659
|
-
trustClass: "unknown",
|
|
660
|
-
canonicalSenderId: "u-2",
|
|
661
|
-
} satisfies TrustVerdict),
|
|
662
|
-
).toBeNull();
|
|
663
|
-
});
|
|
664
|
-
|
|
665
|
-
test("invalid enum (unknown status/policy) returns null (fail-closed)", () => {
|
|
666
|
-
expect(
|
|
667
|
-
verdictMemberFromVerdict({
|
|
668
|
-
trustClass: "trusted_contact",
|
|
669
|
-
canonicalSenderId: "u-7",
|
|
670
|
-
contactId: "contact-7",
|
|
671
|
-
channelId: "channel-7",
|
|
672
|
-
status: "quarantined",
|
|
673
|
-
policy: "allow",
|
|
674
|
-
} satisfies TrustVerdict),
|
|
675
|
-
).toBeNull();
|
|
676
|
-
expect(
|
|
677
|
-
verdictMemberFromVerdict({
|
|
678
|
-
trustClass: "trusted_contact",
|
|
679
|
-
canonicalSenderId: "u-6",
|
|
680
|
-
contactId: "contact-6",
|
|
681
|
-
channelId: "channel-6",
|
|
682
|
-
status: "active",
|
|
683
|
-
policy: "bogus",
|
|
684
|
-
} satisfies TrustVerdict),
|
|
685
|
-
).toBeNull();
|
|
686
|
-
});
|
|
687
|
-
});
|
|
688
|
-
|
|
689
|
-
describe("verdict predicates", () => {
|
|
690
|
-
test("verdictHasMemberIdentity is true with contactId or channelId", () => {
|
|
691
|
-
expect(
|
|
692
|
-
verdictHasMemberIdentity({
|
|
693
|
-
trustClass: "unknown",
|
|
694
|
-
canonicalSenderId: "u-1",
|
|
695
|
-
contactId: "contact-1",
|
|
696
|
-
} satisfies TrustVerdict),
|
|
697
|
-
).toBe(true);
|
|
698
|
-
expect(
|
|
699
|
-
verdictHasMemberIdentity({
|
|
700
|
-
trustClass: "unknown",
|
|
701
|
-
canonicalSenderId: "u-1",
|
|
702
|
-
channelId: "channel-1",
|
|
703
|
-
} satisfies TrustVerdict),
|
|
704
|
-
).toBe(true);
|
|
705
|
-
});
|
|
706
|
-
|
|
707
|
-
test("verdictHasMemberIdentity is false for a memberless verdict", () => {
|
|
708
|
-
expect(
|
|
709
|
-
verdictHasMemberIdentity({
|
|
710
|
-
trustClass: "unknown",
|
|
711
|
-
canonicalSenderId: "u-1",
|
|
712
|
-
} satisfies TrustVerdict),
|
|
713
|
-
).toBe(false);
|
|
714
|
-
});
|
|
715
|
-
|
|
716
|
-
test("verdictMemberUnresolvable is true when member identity present but ACL unsynthesizable", () => {
|
|
717
|
-
expect(
|
|
718
|
-
verdictMemberUnresolvable({
|
|
719
|
-
trustClass: "trusted_contact",
|
|
720
|
-
canonicalSenderId: "u-1",
|
|
721
|
-
contactId: "contact-1",
|
|
722
|
-
channelId: "channel-1",
|
|
723
|
-
policy: "allow",
|
|
724
|
-
} satisfies TrustVerdict),
|
|
725
|
-
).toBe(true);
|
|
726
|
-
});
|
|
727
|
-
|
|
728
|
-
test("verdictMemberUnresolvable is false for a usable member verdict", () => {
|
|
729
|
-
expect(
|
|
730
|
-
verdictMemberUnresolvable({
|
|
731
|
-
trustClass: "trusted_contact",
|
|
732
|
-
canonicalSenderId: "u-1",
|
|
733
|
-
contactId: "contact-1",
|
|
734
|
-
channelId: "channel-1",
|
|
735
|
-
status: "active",
|
|
736
|
-
policy: "allow",
|
|
737
|
-
} satisfies TrustVerdict),
|
|
738
|
-
).toBe(false);
|
|
739
|
-
});
|
|
740
|
-
|
|
741
|
-
test("verdictMemberUnresolvable is false for a memberless verdict", () => {
|
|
742
|
-
expect(
|
|
743
|
-
verdictMemberUnresolvable({
|
|
744
|
-
trustClass: "unknown",
|
|
745
|
-
canonicalSenderId: "u-1",
|
|
746
|
-
} satisfies TrustVerdict),
|
|
747
|
-
).toBe(false);
|
|
748
|
-
});
|
|
749
|
-
});
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import type { ChannelId } from "../channels/types.js";
|
|
15
|
-
import {
|
|
15
|
+
import { findGuardianForChannel } from "../contacts/contact-store.js";
|
|
16
16
|
import type { ChannelStatus } from "../contacts/types.js";
|
|
17
17
|
import {
|
|
18
18
|
createCanonicalGuardianRequest,
|
|
@@ -25,7 +25,6 @@ import {
|
|
|
25
25
|
import { emitNotificationSignal } from "../notifications/emit-signal.js";
|
|
26
26
|
import type { GuardianResolutionSource } from "../notifications/signal.js";
|
|
27
27
|
import { getLogger } from "../util/logger.js";
|
|
28
|
-
import { resolveAnchoredGuardian } from "./anchored-guardian.js";
|
|
29
28
|
import { GUARDIAN_APPROVAL_TTL_MS } from "./routes/channel-route-shared.js";
|
|
30
29
|
|
|
31
30
|
const log = getLogger("access-request-helper");
|
|
@@ -71,12 +70,12 @@ export type AccessRequestResult =
|
|
|
71
70
|
* trust anchor and only accepts source-channel contacts that match it. This
|
|
72
71
|
* prevents stale or cross-assistant contacts from being bound to the request.
|
|
73
72
|
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
73
|
+
* This is intentionally synchronous with respect to the canonical store writes
|
|
74
|
+
* and fire-and-forget for the notification signal emission.
|
|
76
75
|
*/
|
|
77
|
-
export
|
|
76
|
+
export function notifyGuardianOfAccessRequest(
|
|
78
77
|
params: AccessRequestParams,
|
|
79
|
-
):
|
|
78
|
+
): AccessRequestResult {
|
|
80
79
|
const {
|
|
81
80
|
canonicalAssistantId,
|
|
82
81
|
sourceChannel,
|
|
@@ -95,19 +94,40 @@ export async function notifyGuardianOfAccessRequest(
|
|
|
95
94
|
return { notified: false, reason: "no_sender_id" };
|
|
96
95
|
}
|
|
97
96
|
|
|
98
|
-
// Resolve guardian identity with
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
97
|
+
// Resolve guardian identity with assistant-anchored strategy:
|
|
98
|
+
// 1. Ensure the assistant has a vellum guardian principal (trust anchor)
|
|
99
|
+
// 2. Use source-channel guardian only when principal matches anchor
|
|
100
|
+
// 3. Fallback to vellum guardian identity for this assistant principal
|
|
101
|
+
let guardianExternalUserId: string | null = null;
|
|
102
|
+
let guardianPrincipalId: string | null = null;
|
|
103
|
+
let guardianBindingChannel: string | null = null;
|
|
104
|
+
let guardianResolutionSource: GuardianResolutionSource = "none";
|
|
105
|
+
|
|
106
|
+
const vellumGuardian = findGuardianForChannel("vellum");
|
|
107
|
+
const assistantGuardianPrincipalId = vellumGuardian?.contact.principalId;
|
|
108
|
+
|
|
109
|
+
// Try source-channel guardian, but only if it maps to the assistant's
|
|
110
|
+
// anchored principal. This blocks cross-assistant/stale contact selection.
|
|
111
|
+
const sourceGuardian = findGuardianForChannel(sourceChannel);
|
|
112
|
+
if (
|
|
113
|
+
assistantGuardianPrincipalId &&
|
|
114
|
+
sourceGuardian &&
|
|
115
|
+
sourceGuardian.contact.principalId === assistantGuardianPrincipalId
|
|
116
|
+
) {
|
|
117
|
+
guardianExternalUserId = sourceGuardian.channel.address;
|
|
118
|
+
guardianPrincipalId = sourceGuardian.contact.principalId;
|
|
119
|
+
guardianBindingChannel = sourceGuardian.channel.type;
|
|
120
|
+
guardianResolutionSource = "source-channel-contact";
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Access requests always require a principal. If source-channel resolution
|
|
124
|
+
// did not match the assistant anchor, use the anchored vellum identity.
|
|
125
|
+
if (!guardianPrincipalId && vellumGuardian) {
|
|
126
|
+
guardianExternalUserId = vellumGuardian.channel.address;
|
|
127
|
+
guardianPrincipalId = assistantGuardianPrincipalId ?? null;
|
|
128
|
+
guardianBindingChannel = guardianBindingChannel ?? "vellum";
|
|
129
|
+
guardianResolutionSource = "vellum-anchor";
|
|
130
|
+
}
|
|
111
131
|
|
|
112
132
|
log.debug(
|
|
113
133
|
{
|
|
@@ -323,8 +323,8 @@ export function toTrustContext(
|
|
|
323
323
|
requesterMemberDisplayName: ctx.actorMetadata.memberDisplayName,
|
|
324
324
|
requesterExternalUserId: ctx.canonicalSenderId ?? undefined,
|
|
325
325
|
requesterChatId: conversationExternalId,
|
|
326
|
-
// Member grounding from
|
|
327
|
-
//
|
|
326
|
+
// Member grounding from a real memberRecord (voice path); the verdict path
|
|
327
|
+
// (memberRecord=null) stamps these from the verdict instead.
|
|
328
328
|
requesterContactId: ctx.memberRecord?.contact.id,
|
|
329
329
|
memberStatus: ctx.memberRecord
|
|
330
330
|
? channelStatusToMemberStatus(ctx.memberRecord.channel.status)
|
|
@@ -749,7 +749,7 @@ async function createCanonicalRequestForConfirmation(
|
|
|
749
749
|
});
|
|
750
750
|
|
|
751
751
|
if (trustContext && conversation) {
|
|
752
|
-
|
|
752
|
+
bridgeConfirmationRequestToGuardian({
|
|
753
753
|
canonicalRequest,
|
|
754
754
|
trustContext,
|
|
755
755
|
conversationId,
|
|
@@ -50,21 +50,14 @@
|
|
|
50
50
|
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
51
51
|
import { dirname, join } from "node:path";
|
|
52
52
|
|
|
53
|
-
import {
|
|
54
|
-
SSE_REPLAY_RING_AGE_LIMIT_MS,
|
|
55
|
-
SSE_REPLAY_RING_COUNT_LIMIT,
|
|
56
|
-
} from "../api/constants/sse-replay.js";
|
|
57
53
|
import { getWorkspaceDir } from "../util/platform.js";
|
|
58
54
|
import type { AssistantEvent } from "./assistant-event.js";
|
|
59
55
|
|
|
60
56
|
// ── Tunables ─────────────────────────────────────────────────────────
|
|
61
57
|
|
|
62
|
-
|
|
63
|
-
// (via `@vellumai/assistant-api`) so its seq-gap tolerance is sized
|
|
64
|
-
// against the same numbers the daemon buffers against.
|
|
65
|
-
const RING_COUNT_LIMIT = SSE_REPLAY_RING_COUNT_LIMIT;
|
|
58
|
+
const RING_COUNT_LIMIT = 200;
|
|
66
59
|
const RING_SIZE_LIMIT_BYTES = 256 * 1024;
|
|
67
|
-
const RING_AGE_LIMIT_MS =
|
|
60
|
+
const RING_AGE_LIMIT_MS = 30_000;
|
|
68
61
|
|
|
69
62
|
/**
|
|
70
63
|
* Cap on how many conversations retain a persisted-seq entry. Unlike the
|
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
import { isHttpAuthDisabled } from "../../config/env.js";
|
|
2
|
-
import {
|
|
3
|
-
getGuardianDelivery,
|
|
4
|
-
guardianForChannel,
|
|
5
|
-
} from "../../contacts/guardian-delivery-reader.js";
|
|
2
|
+
import { findGuardianForChannel } from "../../contacts/contact-store.js";
|
|
6
3
|
import { httpError } from "../http-errors.js";
|
|
7
4
|
import type { AuthContext } from "./types.js";
|
|
8
5
|
|
|
9
6
|
/**
|
|
10
7
|
* Verify the actor from AuthContext is the bound guardian for the vellum channel.
|
|
11
|
-
*
|
|
12
|
-
* gateway is unreachable (null list). Returns an error Response if not
|
|
13
|
-
* authorized, or null if allowed.
|
|
8
|
+
* Returns an error Response if not, or null if allowed.
|
|
14
9
|
*/
|
|
15
|
-
export
|
|
10
|
+
export function requireBoundGuardian(
|
|
16
11
|
authContext: AuthContext,
|
|
17
|
-
):
|
|
12
|
+
): Response | null {
|
|
18
13
|
// Dev bypass: when auth is disabled, skip guardian binding check
|
|
19
14
|
// (mirrors enforcePolicy dev bypass in route-policy.ts)
|
|
20
15
|
if (isHttpAuthDisabled()) {
|
|
@@ -27,22 +22,17 @@ export async function requireBoundGuardian(
|
|
|
27
22
|
403,
|
|
28
23
|
);
|
|
29
24
|
}
|
|
30
|
-
const
|
|
31
|
-
if (!
|
|
32
|
-
//
|
|
25
|
+
const guardianResult = findGuardianForChannel("vellum");
|
|
26
|
+
if (!guardianResult) {
|
|
27
|
+
// No guardian yet — in pre-bootstrap state, allow through
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
if (guardianResult.channel.address !== authContext.actorPrincipalId) {
|
|
33
31
|
return httpError(
|
|
34
32
|
"FORBIDDEN",
|
|
35
33
|
"Actor is not the bound guardian for this channel",
|
|
36
34
|
403,
|
|
37
35
|
);
|
|
38
36
|
}
|
|
39
|
-
|
|
40
|
-
if (guardian && guardian.principalId === authContext.actorPrincipalId) {
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
return httpError(
|
|
44
|
-
"FORBIDDEN",
|
|
45
|
-
"Actor is not the bound guardian for this channel",
|
|
46
|
-
403,
|
|
47
|
-
);
|
|
37
|
+
return null;
|
|
48
38
|
}
|
|
@@ -9,12 +9,8 @@
|
|
|
9
9
|
import { createHash, randomBytes } from "crypto";
|
|
10
10
|
import { v4 as uuid } from "uuid";
|
|
11
11
|
|
|
12
|
+
import { findGuardianForChannel } from "../contacts/contact-store.js";
|
|
12
13
|
import { revokeGuardianBinding } from "../contacts/contacts-write.js";
|
|
13
|
-
import {
|
|
14
|
-
getGuardianDelivery,
|
|
15
|
-
getGuardianDeliveryFresh,
|
|
16
|
-
guardianForChannel,
|
|
17
|
-
} from "../contacts/guardian-delivery-reader.js";
|
|
18
14
|
import type {
|
|
19
15
|
GuardianBinding,
|
|
20
16
|
IdentityBindingStatus,
|
|
@@ -323,71 +319,50 @@ export function validateAndConsumeVerification(
|
|
|
323
319
|
|
|
324
320
|
/**
|
|
325
321
|
* Look up the active guardian binding for a given assistant and channel.
|
|
326
|
-
* Reads the
|
|
327
|
-
* GuardianBinding-shaped object.
|
|
328
|
-
*
|
|
322
|
+
* Reads from the contacts table via findGuardianForChannel and
|
|
323
|
+
* synthesizes a GuardianBinding-shaped object.
|
|
324
|
+
* Returns null when no contacts match.
|
|
329
325
|
*/
|
|
330
|
-
export
|
|
326
|
+
export function getGuardianBinding(
|
|
331
327
|
assistantId: string,
|
|
332
328
|
channel: string,
|
|
333
|
-
):
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
metadataJson: null,
|
|
352
|
-
createdAt: now,
|
|
353
|
-
updatedAt: now,
|
|
354
|
-
};
|
|
355
|
-
}
|
|
329
|
+
): GuardianBinding | null {
|
|
330
|
+
const result = findGuardianForChannel(channel);
|
|
331
|
+
if (result) {
|
|
332
|
+
return {
|
|
333
|
+
id: result.channel.id,
|
|
334
|
+
assistantId,
|
|
335
|
+
channel,
|
|
336
|
+
guardianExternalUserId: result.channel.address,
|
|
337
|
+
guardianDeliveryChatId: result.channel.externalChatId ?? "",
|
|
338
|
+
guardianPrincipalId: result.contact.principalId ?? "",
|
|
339
|
+
status: "active" as const,
|
|
340
|
+
verifiedAt: result.channel.verifiedAt ?? 0,
|
|
341
|
+
verifiedVia: result.channel.verifiedVia ?? "",
|
|
342
|
+
metadataJson: null,
|
|
343
|
+
createdAt: result.channel.createdAt,
|
|
344
|
+
updatedAt: result.channel.updatedAt ?? result.channel.createdAt,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
356
347
|
|
|
357
|
-
|
|
358
|
-
* Gateway-backed guardian-existence check: is a guardian already bound for
|
|
359
|
-
* this channel? Presence-only idempotency guard, NOT an ACL-field read.
|
|
360
|
-
*
|
|
361
|
-
* Null-list fail direction: a `null` from the gateway (unreachable / malformed)
|
|
362
|
-
* is "unknown" — returns `true` so an unreachable gateway is treated as
|
|
363
|
-
* already-bound. Callers gate session creation on a falsy result, so this
|
|
364
|
-
* blocks a new binding on a transient miss rather than spuriously creating a
|
|
365
|
-
* second one.
|
|
366
|
-
*/
|
|
367
|
-
export async function isGuardianBoundForChannel(
|
|
368
|
-
channel: string,
|
|
369
|
-
): Promise<boolean> {
|
|
370
|
-
// Existence guards read fresh because gateway-side binding writes don't
|
|
371
|
-
// invalidate the daemon cache.
|
|
372
|
-
const list = await getGuardianDeliveryFresh({ channelTypes: [channel] });
|
|
373
|
-
if (list === null) return true;
|
|
374
|
-
return !!guardianForChannel(list, channel);
|
|
348
|
+
return null;
|
|
375
349
|
}
|
|
376
350
|
|
|
377
351
|
/**
|
|
378
352
|
* Check whether the given external user is the active guardian for
|
|
379
353
|
* the specified assistant and channel.
|
|
380
354
|
*/
|
|
381
|
-
export
|
|
355
|
+
export function isGuardian(
|
|
382
356
|
assistantId: string,
|
|
383
357
|
channel: string,
|
|
384
358
|
address: string,
|
|
385
|
-
):
|
|
386
|
-
const
|
|
387
|
-
|
|
388
|
-
|
|
359
|
+
): boolean {
|
|
360
|
+
const result = findGuardianForChannel(channel);
|
|
361
|
+
if (result) {
|
|
362
|
+
return result.channel.address.toLowerCase() === address.toLowerCase();
|
|
363
|
+
}
|
|
389
364
|
|
|
390
|
-
return
|
|
365
|
+
return false;
|
|
391
366
|
}
|
|
392
367
|
|
|
393
368
|
/**
|