@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
|
@@ -39,10 +39,10 @@ function findProxyByTransferId(transferId: string) {
|
|
|
39
39
|
// GET /v1/transfers/:transferId/content
|
|
40
40
|
// ---------------------------------------------------------------------------
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
function handleTransferContentGet({
|
|
43
43
|
pathParams = {},
|
|
44
44
|
headers = {},
|
|
45
|
-
}: RouteHandlerArgs):
|
|
45
|
+
}: RouteHandlerArgs): Uint8Array {
|
|
46
46
|
const transferId = pathParams.transferId;
|
|
47
47
|
if (!transferId) {
|
|
48
48
|
throw new BadRequestError("transferId path parameter is required");
|
|
@@ -72,7 +72,7 @@ async function handleTransferContentGet({
|
|
|
72
72
|
// the value persisted at registration time so a brief reconnect does
|
|
73
73
|
// not 403 a legitimate fetch.
|
|
74
74
|
enforceSameActorOrThrow({
|
|
75
|
-
sourceActorPrincipalId:
|
|
75
|
+
sourceActorPrincipalId: resolveActorPrincipalIdForLocalGuardian(
|
|
76
76
|
headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
|
|
77
77
|
),
|
|
78
78
|
targetActorPrincipalId:
|
|
@@ -151,7 +151,7 @@ async function handleTransferContentPut({
|
|
|
151
151
|
);
|
|
152
152
|
|
|
153
153
|
enforceSameActorOrThrow({
|
|
154
|
-
sourceActorPrincipalId:
|
|
154
|
+
sourceActorPrincipalId: resolveActorPrincipalIdForLocalGuardian(
|
|
155
155
|
headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
|
|
156
156
|
),
|
|
157
157
|
targetActorPrincipalId:
|
|
@@ -181,7 +181,7 @@ async function handleTransferContentPut({
|
|
|
181
181
|
// POST /v1/host-transfer-result
|
|
182
182
|
// ---------------------------------------------------------------------------
|
|
183
183
|
|
|
184
|
-
|
|
184
|
+
function handleTransferResult({ body, headers }: RouteHandlerArgs) {
|
|
185
185
|
if (!body || typeof body !== "object") {
|
|
186
186
|
throw new BadRequestError("Request body is required");
|
|
187
187
|
}
|
|
@@ -222,7 +222,7 @@ async function handleTransferResult({ body, headers }: RouteHandlerArgs) {
|
|
|
222
222
|
);
|
|
223
223
|
|
|
224
224
|
enforceSameActorOrThrow({
|
|
225
|
-
sourceActorPrincipalId:
|
|
225
|
+
sourceActorPrincipalId: resolveActorPrincipalIdForLocalGuardian(
|
|
226
226
|
headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
|
|
227
227
|
),
|
|
228
228
|
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
@@ -51,7 +51,7 @@ export function routeDefinitionsToHTTPRoutes(
|
|
|
51
51
|
handler: async ({ req, url, params, authContext }) => {
|
|
52
52
|
try {
|
|
53
53
|
if (r.requireGuardian) {
|
|
54
|
-
const guardianError =
|
|
54
|
+
const guardianError = requireBoundGuardian(authContext);
|
|
55
55
|
if (guardianError) return guardianError;
|
|
56
56
|
}
|
|
57
57
|
|
|
@@ -10,8 +10,7 @@ import { z } from "zod";
|
|
|
10
10
|
import { getCpuLimit, getIsPlatform } from "../../config/env-registry.js";
|
|
11
11
|
import { parseIdentityFields } from "../../daemon/handlers/identity.js";
|
|
12
12
|
import { getProfilerRuntimeStatus } from "../../daemon/profiler-run-store.js";
|
|
13
|
-
import {
|
|
14
|
-
import { migrationSteps } from "../../memory/steps.js";
|
|
13
|
+
import { getMaxMigrationVersion } from "../../memory/migrations/registry.js";
|
|
15
14
|
import { getCesClient } from "../../security/secure-keys.js";
|
|
16
15
|
import {
|
|
17
16
|
getDiskUsageInfo,
|
|
@@ -336,7 +335,7 @@ function getDetailedHealth() {
|
|
|
336
335
|
memory: getMemoryInfo(),
|
|
337
336
|
cpu: getCpuInfo(),
|
|
338
337
|
migrations: {
|
|
339
|
-
dbVersion:
|
|
338
|
+
dbVersion: getMaxMigrationVersion(),
|
|
340
339
|
lastWorkspaceMigrationId:
|
|
341
340
|
getLastWorkspaceMigrationId(WORKSPACE_MIGRATIONS),
|
|
342
341
|
},
|
|
@@ -680,7 +680,7 @@ export async function handleChannelInbound({
|
|
|
680
680
|
canonicalAssistantId,
|
|
681
681
|
assistantId,
|
|
682
682
|
content,
|
|
683
|
-
channelId: resolvedMember?.
|
|
683
|
+
channelId: resolvedMember?.channel.id,
|
|
684
684
|
});
|
|
685
685
|
}
|
|
686
686
|
|
|
@@ -761,7 +761,7 @@ export async function handleChannelInbound({
|
|
|
761
761
|
: enforceAdmissionPolicy({
|
|
762
762
|
sourceChannel,
|
|
763
763
|
trustClass: trustCtx.trustClass,
|
|
764
|
-
memberStatus: resolvedMember?.status,
|
|
764
|
+
memberStatus: resolvedMember?.channel.status,
|
|
765
765
|
policy: admissionPolicyFromGateway,
|
|
766
766
|
});
|
|
767
767
|
if (!admissionResult.admitted) {
|
|
@@ -801,7 +801,7 @@ export async function handleChannelInbound({
|
|
|
801
801
|
// guardian sees "previously pending" etc.
|
|
802
802
|
let guardianNotified = false;
|
|
803
803
|
try {
|
|
804
|
-
const accessResult =
|
|
804
|
+
const accessResult = notifyGuardianOfAccessRequest({
|
|
805
805
|
canonicalAssistantId,
|
|
806
806
|
sourceChannel,
|
|
807
807
|
conversationExternalId,
|
|
@@ -811,7 +811,7 @@ export async function handleChannelInbound({
|
|
|
811
811
|
...(resolvedMember
|
|
812
812
|
? {
|
|
813
813
|
previousMemberStatus: channelStatusToMemberStatus(
|
|
814
|
-
resolvedMember.status,
|
|
814
|
+
resolvedMember.channel.status,
|
|
815
815
|
),
|
|
816
816
|
}
|
|
817
817
|
: {}),
|
|
@@ -935,7 +935,7 @@ export async function handleChannelInbound({
|
|
|
935
935
|
}
|
|
936
936
|
|
|
937
937
|
// ── Ingress escalation ──
|
|
938
|
-
const escalationResponse =
|
|
938
|
+
const escalationResponse = handleEscalationIntercept({
|
|
939
939
|
resolvedMember,
|
|
940
940
|
canonicalAssistantId,
|
|
941
941
|
sourceChannel,
|
|
@@ -19,28 +19,14 @@ mock.module("../../../util/logger.js", () => ({
|
|
|
19
19
|
}));
|
|
20
20
|
|
|
21
21
|
// Track contact-store reads to prove findContactChannel is NOT used on the
|
|
22
|
-
// verdict path.
|
|
22
|
+
// verdict path. findGuardianForChannel is still called by resolveGuardianLabel.
|
|
23
23
|
const findContactChannelCalls: unknown[] = [];
|
|
24
24
|
mock.module("../../../contacts/contact-store.js", () => ({
|
|
25
25
|
findContactChannel: (params: unknown) => {
|
|
26
26
|
findContactChannelCalls.push(params);
|
|
27
27
|
return null;
|
|
28
28
|
},
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
// resolveGuardianLabel resolves the guardian via the gateway delivery reader.
|
|
32
|
-
let guardianDeliveryList: Array<Record<string, unknown>> = [];
|
|
33
|
-
mock.module("../../../contacts/guardian-delivery-reader.js", () => ({
|
|
34
|
-
getGuardianDelivery: async () => guardianDeliveryList,
|
|
35
|
-
guardianForChannel: (
|
|
36
|
-
list: Array<Record<string, unknown>>,
|
|
37
|
-
channelType: string,
|
|
38
|
-
) => list.find((g) => g.channelType === channelType && g.status === "active"),
|
|
39
|
-
}));
|
|
40
|
-
|
|
41
|
-
mock.module("../../../prompts/user-reference.js", () => ({
|
|
42
|
-
resolveGuardianName: (displayName?: string | null) =>
|
|
43
|
-
displayName && displayName.trim().length > 0 ? displayName.trim() : "my human",
|
|
29
|
+
findGuardianForChannel: () => null,
|
|
44
30
|
}));
|
|
45
31
|
|
|
46
32
|
const deliverReplyCalls: Array<{ url: string; payload: unknown }> = [];
|
|
@@ -140,7 +126,6 @@ beforeEach(() => {
|
|
|
140
126
|
deliverReplyCalls.length = 0;
|
|
141
127
|
accessRequestCalls.length = 0;
|
|
142
128
|
inviteTokenForTest = undefined;
|
|
143
|
-
guardianDeliveryList = [];
|
|
144
129
|
});
|
|
145
130
|
|
|
146
131
|
afterEach(() => {
|
|
@@ -155,8 +140,8 @@ describe("enforceIngressAcl — verdict-sourced member resolution", () => {
|
|
|
155
140
|
|
|
156
141
|
expect(result.earlyResponse).toBeUndefined();
|
|
157
142
|
expect(result.resolvedMember).not.toBeNull();
|
|
158
|
-
expect(result.resolvedMember!.status).toBe("active");
|
|
159
|
-
expect(result.resolvedMember!.policy).toBe("allow");
|
|
143
|
+
expect(result.resolvedMember!.channel.status).toBe("active");
|
|
144
|
+
expect(result.resolvedMember!.channel.policy).toBe("allow");
|
|
160
145
|
// Member came from the verdict, never the local contact store.
|
|
161
146
|
expect(findContactChannelCalls.length).toBe(0);
|
|
162
147
|
});
|
|
@@ -171,8 +156,7 @@ describe("enforceIngressAcl — verdict-sourced member resolution", () => {
|
|
|
171
156
|
);
|
|
172
157
|
|
|
173
158
|
expect(result.earlyResponse).toBeUndefined();
|
|
174
|
-
expect(result.resolvedMember).
|
|
175
|
-
expect(result.resolvedMember!.status).toBe("active");
|
|
159
|
+
expect(result.resolvedMember!.contact.role).toBe("guardian");
|
|
176
160
|
expect(findContactChannelCalls.length).toBe(0);
|
|
177
161
|
});
|
|
178
162
|
});
|
|
@@ -265,82 +249,6 @@ describe("enforceIngressAcl — fail-closed on absent verdict", () => {
|
|
|
265
249
|
});
|
|
266
250
|
});
|
|
267
251
|
|
|
268
|
-
describe("enforceIngressAcl — fail-closed on resolutionFailed verdict", () => {
|
|
269
|
-
test("resolutionFailed verdict → not_a_member deny, does not flow to intercepts", async () => {
|
|
270
|
-
inviteTokenForTest = "iv_token123";
|
|
271
|
-
const result = await enforceIngressAcl(
|
|
272
|
-
makeParams({
|
|
273
|
-
sourceMetadata: withVerdict({
|
|
274
|
-
trustClass: "unknown",
|
|
275
|
-
canonicalSenderId: "sender-1",
|
|
276
|
-
resolutionFailed: true,
|
|
277
|
-
}),
|
|
278
|
-
effectiveAdmissionPolicy: "strangers",
|
|
279
|
-
}),
|
|
280
|
-
);
|
|
281
|
-
|
|
282
|
-
expect(result.earlyResponse).toBeDefined();
|
|
283
|
-
expect(result.earlyResponse!.reason).toBe("not_a_member");
|
|
284
|
-
expect(result.resolvedMember).toBeNull();
|
|
285
|
-
// Distinct from a stranger: no invite redemption, onboarding, or
|
|
286
|
-
// guardian notification fires.
|
|
287
|
-
expect(result.earlyResponse!.inviteRedemption).toBeUndefined();
|
|
288
|
-
expect(deliverReplyCalls.length).toBe(0);
|
|
289
|
-
expect(accessRequestCalls.length).toBe(0);
|
|
290
|
-
expect(findContactChannelCalls.length).toBe(0);
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
test("real unknown stranger (no resolutionFailed) still redeems via intercept", async () => {
|
|
294
|
-
inviteTokenForTest = "iv_token123";
|
|
295
|
-
const result = await enforceIngressAcl(
|
|
296
|
-
makeParams({
|
|
297
|
-
sourceMetadata: withVerdict({
|
|
298
|
-
trustClass: "unknown",
|
|
299
|
-
canonicalSenderId: "sender-1",
|
|
300
|
-
}),
|
|
301
|
-
}),
|
|
302
|
-
);
|
|
303
|
-
|
|
304
|
-
expect(result.earlyResponse!.inviteRedemption).toBe("redeemed");
|
|
305
|
-
expect(result.resolvedMember).toBeNull();
|
|
306
|
-
});
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
describe("enforceIngressAcl — deny copy names the gateway guardian", () => {
|
|
310
|
-
test("non-member deny reply uses the guardian displayName from the gateway list", async () => {
|
|
311
|
-
guardianDeliveryList = [
|
|
312
|
-
{
|
|
313
|
-
channelType: "vellum",
|
|
314
|
-
contactId: "c-1",
|
|
315
|
-
principalId: "p-anchor",
|
|
316
|
-
displayName: "Alice Guardian",
|
|
317
|
-
address: "p-anchor",
|
|
318
|
-
status: "active",
|
|
319
|
-
},
|
|
320
|
-
];
|
|
321
|
-
|
|
322
|
-
const result = await enforceIngressAcl(
|
|
323
|
-
makeParams({
|
|
324
|
-
sourceMetadata: withVerdict({
|
|
325
|
-
trustClass: "unknown",
|
|
326
|
-
canonicalSenderId: "stranger-1",
|
|
327
|
-
}),
|
|
328
|
-
}),
|
|
329
|
-
);
|
|
330
|
-
|
|
331
|
-
expect(result.earlyResponse!.reason).toBe("not_a_member");
|
|
332
|
-
const denyReply = deliverReplyCalls.find((c) =>
|
|
333
|
-
String((c.payload as { text?: string }).text ?? "").includes(
|
|
334
|
-
"tried talking to me",
|
|
335
|
-
),
|
|
336
|
-
);
|
|
337
|
-
expect(denyReply).toBeDefined();
|
|
338
|
-
expect((denyReply!.payload as { text: string }).text).toContain(
|
|
339
|
-
"Alice Guardian",
|
|
340
|
-
);
|
|
341
|
-
});
|
|
342
|
-
});
|
|
343
|
-
|
|
344
252
|
describe("enforceIngressAcl — fail-closed on malformed member verdict", () => {
|
|
345
253
|
test("member identity + unknown policy → not_a_member deny even under strangers", async () => {
|
|
346
254
|
const result = await enforceIngressAcl(
|
|
@@ -7,7 +7,7 @@ import type { AdmissionPolicy, SourceMetadata } from "@vellumai/gateway-client";
|
|
|
7
7
|
|
|
8
8
|
import { isInviteCodeRedemptionEnabled } from "../../../channels/config.js";
|
|
9
9
|
import type { ChannelId } from "../../../channels/types.js";
|
|
10
|
-
import {
|
|
10
|
+
import { findGuardianForChannel } from "../../../contacts/contact-store.js";
|
|
11
11
|
import { channelStatusToMemberStatus } from "../../../contacts/member-status.js";
|
|
12
12
|
import type {
|
|
13
13
|
ContactChannel,
|
|
@@ -25,7 +25,6 @@ import { getLogger } from "../../../util/logger.js";
|
|
|
25
25
|
import { truncate } from "../../../util/truncate.js";
|
|
26
26
|
import { hashVoiceCode } from "../../../util/voice-code.js";
|
|
27
27
|
import { notifyGuardianOfAccessRequest } from "../../access-request-helper.js";
|
|
28
|
-
import { resolveAnchoredGuardian } from "../../anchored-guardian.js";
|
|
29
28
|
import { getInviteAdapterRegistry } from "../../channel-invite-transport.js";
|
|
30
29
|
import {
|
|
31
30
|
createOutboundSession,
|
|
@@ -39,8 +38,7 @@ import {
|
|
|
39
38
|
redeemInviteByCode,
|
|
40
39
|
} from "../../invite-redemption-service.js";
|
|
41
40
|
import { getInviteRedemptionReply } from "../../invite-redemption-templates.js";
|
|
42
|
-
import
|
|
43
|
-
import { verdictMemberFromVerdict } from "../../trust-verdict-consumer.js";
|
|
41
|
+
import { resolvedMemberFromVerdict } from "../../trust-verdict-consumer.js";
|
|
44
42
|
|
|
45
43
|
const log = getLogger("runtime-http");
|
|
46
44
|
|
|
@@ -48,20 +46,28 @@ const log = getLogger("runtime-http");
|
|
|
48
46
|
* Resolve the guardian's display name for use in requester-facing messages.
|
|
49
47
|
*
|
|
50
48
|
* Uses the assistant's anchored vellum principal to validate the guardian
|
|
51
|
-
*
|
|
52
|
-
* This prevents stale or cross-assistant
|
|
53
|
-
* Cosmetic copy, not an admission decision, so a null gateway list degrades
|
|
54
|
-
* gracefully to the default reference.
|
|
49
|
+
* contact, matching the same strategy used by `notifyGuardianOfAccessRequest`.
|
|
50
|
+
* This prevents stale or cross-assistant contacts from leaking a wrong name.
|
|
55
51
|
*/
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
52
|
+
function resolveGuardianLabel(sourceChannel: ChannelId): string {
|
|
53
|
+
const vellumGuardian = findGuardianForChannel("vellum");
|
|
54
|
+
const anchoredPrincipalId = vellumGuardian?.contact.principalId;
|
|
55
|
+
|
|
56
|
+
if (!anchoredPrincipalId) {
|
|
57
|
+
return resolveGuardianName(undefined);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Try source-channel guardian, but only accept it when the principal
|
|
61
|
+
// matches the assistant's anchor.
|
|
62
|
+
const sourceGuardian = findGuardianForChannel(sourceChannel);
|
|
63
|
+
if (
|
|
64
|
+
sourceGuardian &&
|
|
65
|
+
sourceGuardian.contact.principalId === anchoredPrincipalId
|
|
66
|
+
) {
|
|
67
|
+
return resolveGuardianName(sourceGuardian.contact.displayName);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return resolveGuardianName(vellumGuardian.contact.displayName);
|
|
65
71
|
}
|
|
66
72
|
|
|
67
73
|
// ---------------------------------------------------------------------------
|
|
@@ -103,7 +109,7 @@ export type ResolvedMember = {
|
|
|
103
109
|
};
|
|
104
110
|
|
|
105
111
|
export interface AclResult {
|
|
106
|
-
resolvedMember:
|
|
112
|
+
resolvedMember: ResolvedMember | null;
|
|
107
113
|
/** When set, the caller must return this response immediately. */
|
|
108
114
|
earlyResponse?: Record<string, unknown>;
|
|
109
115
|
/**
|
|
@@ -167,27 +173,9 @@ export async function enforceIngressAcl(
|
|
|
167
173
|
};
|
|
168
174
|
}
|
|
169
175
|
|
|
170
|
-
// Gateway attempted resolution but failed (DB error) → fail-closed deny,
|
|
171
|
-
// distinct from an absent verdict and from a real stranger. TEXT does not
|
|
172
|
-
// fall back to local ACL reads; the sender can retry.
|
|
173
|
-
if (verdict.resolutionFailed === true) {
|
|
174
|
-
log.warn(
|
|
175
|
-
{ sourceChannel, externalUserId: canonicalSenderId },
|
|
176
|
-
"Ingress ACL: gateway trust resolution failed, denying fail-closed",
|
|
177
|
-
);
|
|
178
|
-
return {
|
|
179
|
-
resolvedMember: null,
|
|
180
|
-
earlyResponse: {
|
|
181
|
-
accepted: true,
|
|
182
|
-
denied: true,
|
|
183
|
-
reason: "not_a_member",
|
|
184
|
-
},
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
|
|
188
176
|
// Member resolved from the gateway verdict (ACL + identity only); null for a
|
|
189
177
|
// stranger verdict, which falls through to the non-member intercepts.
|
|
190
|
-
const resolvedMember:
|
|
178
|
+
const resolvedMember: ResolvedMember | null = resolvedMemberFromVerdict(verdict);
|
|
191
179
|
|
|
192
180
|
// A verdict carrying member identity but no resolvable member
|
|
193
181
|
// (malformed/unknown ACL) fails closed, not treated as a stranger.
|
|
@@ -341,7 +329,7 @@ export async function enforceIngressAcl(
|
|
|
341
329
|
if (slackVerifyResult.initiated) {
|
|
342
330
|
// Still notify the guardian about the access attempt
|
|
343
331
|
try {
|
|
344
|
-
|
|
332
|
+
notifyGuardianOfAccessRequest({
|
|
345
333
|
canonicalAssistantId,
|
|
346
334
|
sourceChannel,
|
|
347
335
|
conversationExternalId,
|
|
@@ -381,7 +369,7 @@ export async function enforceIngressAcl(
|
|
|
381
369
|
try {
|
|
382
370
|
await deliverChannelReply(dmCallbackUrl, {
|
|
383
371
|
chatId: senderUserId,
|
|
384
|
-
text: `I don't recognize you yet! I've let ${
|
|
372
|
+
text: `I don't recognize you yet! I've let ${resolveGuardianLabel(sourceChannel)} know you're trying to reach me. They'll need to share a 6-digit verification code with you — ask them directly if you know them. Once you have the code, reply here with it.`,
|
|
385
373
|
assistantId,
|
|
386
374
|
});
|
|
387
375
|
} catch (err) {
|
|
@@ -416,7 +404,7 @@ export async function enforceIngressAcl(
|
|
|
416
404
|
|
|
417
405
|
if (emailVerifyResult.initiated) {
|
|
418
406
|
try {
|
|
419
|
-
|
|
407
|
+
notifyGuardianOfAccessRequest({
|
|
420
408
|
canonicalAssistantId,
|
|
421
409
|
sourceChannel,
|
|
422
410
|
conversationExternalId,
|
|
@@ -455,7 +443,7 @@ export async function enforceIngressAcl(
|
|
|
455
443
|
// deduplication, canonical request creation, and notification emission.
|
|
456
444
|
let guardianNotified = false;
|
|
457
445
|
try {
|
|
458
|
-
const accessResult =
|
|
446
|
+
const accessResult = notifyGuardianOfAccessRequest({
|
|
459
447
|
canonicalAssistantId,
|
|
460
448
|
sourceChannel,
|
|
461
449
|
conversationExternalId,
|
|
@@ -479,7 +467,7 @@ export async function enforceIngressAcl(
|
|
|
479
467
|
}
|
|
480
468
|
|
|
481
469
|
const replyText = guardianNotified
|
|
482
|
-
? `Hmm looks like you don't have access to talk to me. I'll let ${
|
|
470
|
+
? `Hmm looks like you don't have access to talk to me. I'll let ${resolveGuardianLabel(sourceChannel)} know you tried talking to me and get back to you.`
|
|
483
471
|
: "Sorry, you haven't been approved to message this assistant.";
|
|
484
472
|
let replyDelivered = false;
|
|
485
473
|
if (replyCallbackUrl) {
|
|
@@ -519,8 +507,8 @@ export async function enforceIngressAcl(
|
|
|
519
507
|
}
|
|
520
508
|
|
|
521
509
|
if (resolvedMember) {
|
|
522
|
-
if (resolvedMember.status !== "active") {
|
|
523
|
-
const isBlockedMember = resolvedMember.status === "blocked";
|
|
510
|
+
if (resolvedMember.channel.status !== "active") {
|
|
511
|
+
const isBlockedMember = resolvedMember.channel.status === "blocked";
|
|
524
512
|
// Bootstrap commands must pass through for re-verifiable states
|
|
525
513
|
// (pending/revoked), but never for blocked members.
|
|
526
514
|
let denyInactiveMember = true;
|
|
@@ -541,7 +529,7 @@ export async function enforceIngressAcl(
|
|
|
541
529
|
log.info(
|
|
542
530
|
{
|
|
543
531
|
sourceChannel,
|
|
544
|
-
channelId: resolvedMember.
|
|
532
|
+
channelId: resolvedMember.channel.id,
|
|
545
533
|
hasValidBootstrapSession: false,
|
|
546
534
|
},
|
|
547
535
|
"Ingress ACL: inactive member bootstrap bypass denied",
|
|
@@ -626,11 +614,11 @@ export async function enforceIngressAcl(
|
|
|
626
614
|
if (!isBlockedMember && denyInactiveMember) {
|
|
627
615
|
if (
|
|
628
616
|
(effectiveAdmissionPolicy === "strangers" &&
|
|
629
|
-
resolvedMember.status !== "revoked") ||
|
|
617
|
+
resolvedMember.channel.status !== "revoked") ||
|
|
630
618
|
((effectiveAdmissionPolicy === "any_contact" ||
|
|
631
619
|
effectiveAdmissionPolicy === "guardian_only") &&
|
|
632
|
-
(resolvedMember.status === "pending" ||
|
|
633
|
-
resolvedMember.status === "unverified"))
|
|
620
|
+
(resolvedMember.channel.status === "pending" ||
|
|
621
|
+
resolvedMember.channel.status === "unverified"))
|
|
634
622
|
) {
|
|
635
623
|
denyInactiveMember = false;
|
|
636
624
|
}
|
|
@@ -640,8 +628,8 @@ export async function enforceIngressAcl(
|
|
|
640
628
|
log.info(
|
|
641
629
|
{
|
|
642
630
|
sourceChannel,
|
|
643
|
-
channelId: resolvedMember.
|
|
644
|
-
status: resolvedMember.status,
|
|
631
|
+
channelId: resolvedMember.channel.id,
|
|
632
|
+
status: resolvedMember.channel.status,
|
|
645
633
|
},
|
|
646
634
|
"Ingress ACL: member not active, denying",
|
|
647
635
|
);
|
|
@@ -651,7 +639,7 @@ export async function enforceIngressAcl(
|
|
|
651
639
|
// the guardian made an explicit decision to block them.
|
|
652
640
|
if (
|
|
653
641
|
sourceChannel === "slack" &&
|
|
654
|
-
resolvedMember.status !== "blocked" &&
|
|
642
|
+
resolvedMember.channel.status !== "blocked" &&
|
|
655
643
|
(canonicalSenderId ?? rawSenderId)
|
|
656
644
|
) {
|
|
657
645
|
const slackVerifyResult = initiateSlackVerificationChallenge({
|
|
@@ -661,7 +649,7 @@ export async function enforceIngressAcl(
|
|
|
661
649
|
|
|
662
650
|
if (slackVerifyResult.initiated) {
|
|
663
651
|
try {
|
|
664
|
-
|
|
652
|
+
notifyGuardianOfAccessRequest({
|
|
665
653
|
canonicalAssistantId,
|
|
666
654
|
sourceChannel,
|
|
667
655
|
conversationExternalId,
|
|
@@ -669,7 +657,7 @@ export async function enforceIngressAcl(
|
|
|
669
657
|
actorDisplayName,
|
|
670
658
|
actorUsername,
|
|
671
659
|
previousMemberStatus: channelStatusToMemberStatus(
|
|
672
|
-
resolvedMember.status,
|
|
660
|
+
resolvedMember.channel.status,
|
|
673
661
|
),
|
|
674
662
|
messagePreview: truncate(
|
|
675
663
|
trimmedContent,
|
|
@@ -700,7 +688,7 @@ export async function enforceIngressAcl(
|
|
|
700
688
|
try {
|
|
701
689
|
await deliverChannelReply(dmCallbackUrl, {
|
|
702
690
|
chatId: senderUserId,
|
|
703
|
-
text: `I don't recognize you yet! I've let ${
|
|
691
|
+
text: `I don't recognize you yet! I've let ${resolveGuardianLabel(sourceChannel)} know you're trying to reach me. They'll need to share a 6-digit verification code with you — ask them directly if you know them. Once you have the code, reply here with it.`,
|
|
704
692
|
assistantId,
|
|
705
693
|
});
|
|
706
694
|
} catch (err) {
|
|
@@ -727,9 +715,9 @@ export async function enforceIngressAcl(
|
|
|
727
715
|
// re-approve. Blocked members are intentionally excluded — the
|
|
728
716
|
// guardian already made an explicit decision to block them.
|
|
729
717
|
let guardianNotified = false;
|
|
730
|
-
if (resolvedMember.status !== "blocked") {
|
|
718
|
+
if (resolvedMember.channel.status !== "blocked") {
|
|
731
719
|
try {
|
|
732
|
-
const accessResult =
|
|
720
|
+
const accessResult = notifyGuardianOfAccessRequest({
|
|
733
721
|
canonicalAssistantId,
|
|
734
722
|
sourceChannel,
|
|
735
723
|
conversationExternalId,
|
|
@@ -737,7 +725,7 @@ export async function enforceIngressAcl(
|
|
|
737
725
|
actorDisplayName,
|
|
738
726
|
actorUsername,
|
|
739
727
|
previousMemberStatus: channelStatusToMemberStatus(
|
|
740
|
-
resolvedMember.status,
|
|
728
|
+
resolvedMember.channel.status,
|
|
741
729
|
),
|
|
742
730
|
messagePreview: truncate(
|
|
743
731
|
trimmedContent,
|
|
@@ -757,7 +745,7 @@ export async function enforceIngressAcl(
|
|
|
757
745
|
}
|
|
758
746
|
|
|
759
747
|
const inactiveReplyText = guardianNotified
|
|
760
|
-
? `Hmm looks like you don't have access to talk to me. I'll let ${
|
|
748
|
+
? `Hmm looks like you don't have access to talk to me. I'll let ${resolveGuardianLabel(sourceChannel)} know you tried talking to me and get back to you.`
|
|
761
749
|
: "Sorry, you haven't been approved to message this assistant.";
|
|
762
750
|
let inactiveReplyDelivered = false;
|
|
763
751
|
if (replyCallbackUrl) {
|
|
@@ -791,16 +779,16 @@ export async function enforceIngressAcl(
|
|
|
791
779
|
earlyResponse: {
|
|
792
780
|
accepted: true,
|
|
793
781
|
denied: true,
|
|
794
|
-
reason: `member_${channelStatusToMemberStatus(resolvedMember.status)}`,
|
|
782
|
+
reason: `member_${channelStatusToMemberStatus(resolvedMember.channel.status)}`,
|
|
795
783
|
...(!inactiveReplyDelivered && { replyText: inactiveReplyText }),
|
|
796
784
|
},
|
|
797
785
|
};
|
|
798
786
|
}
|
|
799
787
|
}
|
|
800
788
|
|
|
801
|
-
if (resolvedMember.policy === "deny") {
|
|
789
|
+
if (resolvedMember.channel.policy === "deny") {
|
|
802
790
|
log.info(
|
|
803
|
-
{ sourceChannel, channelId: resolvedMember.
|
|
791
|
+
{ sourceChannel, channelId: resolvedMember.channel.id },
|
|
804
792
|
"Ingress ACL: member policy deny",
|
|
805
793
|
);
|
|
806
794
|
const denyReplyText =
|
|
@@ -9,10 +9,6 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { ChannelId, InterfaceId } from "../../../channels/types.js";
|
|
11
11
|
import { findGuardianForChannel } from "../../../contacts/contact-store.js";
|
|
12
|
-
import {
|
|
13
|
-
getGuardianDelivery,
|
|
14
|
-
guardianForChannel,
|
|
15
|
-
} from "../../../contacts/guardian-delivery-reader.js";
|
|
16
12
|
import type { ServerMessage } from "../../../daemon/message-protocol.js";
|
|
17
13
|
import type { TrustContext } from "../../../daemon/trust-context.js";
|
|
18
14
|
import {
|
|
@@ -964,18 +960,10 @@ function startTrustedContactApprovalNotifier(params: {
|
|
|
964
960
|
|
|
965
961
|
if (info && !globalNotifiedApprovalRequestIds.has(info.requestId)) {
|
|
966
962
|
globalNotifiedApprovalRequestIds.set(info.requestId, conversationId);
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
});
|
|
972
|
-
const gatewayDisplayName = guardians
|
|
973
|
-
? guardianForChannel(guardians, sourceChannel)?.displayName
|
|
974
|
-
: undefined;
|
|
975
|
-
const displayName =
|
|
976
|
-
gatewayDisplayName ??
|
|
977
|
-
findGuardianForChannel(sourceChannel)?.contact.displayName;
|
|
978
|
-
const guardianName = resolveGuardianName(displayName);
|
|
963
|
+
const guardian = findGuardianForChannel(sourceChannel);
|
|
964
|
+
const guardianName = resolveGuardianName(
|
|
965
|
+
guardian?.contact.displayName,
|
|
966
|
+
);
|
|
979
967
|
const waitingText = `Waiting for ${guardianName}'s approval...`;
|
|
980
968
|
try {
|
|
981
969
|
await deliverChannelReply(replyCallbackUrl, {
|
|
@@ -13,8 +13,8 @@ import { storePayload } from "../../../memory/delivery-crud.js";
|
|
|
13
13
|
import { emitNotificationSignal } from "../../../notifications/emit-signal.js";
|
|
14
14
|
import { getLogger } from "../../../util/logger.js";
|
|
15
15
|
import { getGuardianBinding } from "../../channel-verification-service.js";
|
|
16
|
-
import type { VerdictMember } from "../../trust-verdict-consumer.js";
|
|
17
16
|
import { GUARDIAN_APPROVAL_TTL_MS } from "../channel-route-shared.js";
|
|
17
|
+
import type { ResolvedMember } from "./acl-enforcement.js";
|
|
18
18
|
|
|
19
19
|
const log = getLogger("runtime-http");
|
|
20
20
|
|
|
@@ -23,7 +23,7 @@ const log = getLogger("runtime-http");
|
|
|
23
23
|
// ---------------------------------------------------------------------------
|
|
24
24
|
|
|
25
25
|
export interface EscalationInterceptParams {
|
|
26
|
-
resolvedMember:
|
|
26
|
+
resolvedMember: ResolvedMember | null;
|
|
27
27
|
canonicalAssistantId: string;
|
|
28
28
|
sourceChannel: ChannelId;
|
|
29
29
|
sourceInterface: InterfaceId;
|
|
@@ -49,9 +49,9 @@ export interface EscalationInterceptParams {
|
|
|
49
49
|
* Returns a Response if the escalation was handled (the pipeline should
|
|
50
50
|
* short-circuit), or null to continue the pipeline.
|
|
51
51
|
*/
|
|
52
|
-
export
|
|
52
|
+
export function handleEscalationIntercept(
|
|
53
53
|
params: EscalationInterceptParams,
|
|
54
|
-
):
|
|
54
|
+
): Record<string, unknown> | null {
|
|
55
55
|
const {
|
|
56
56
|
resolvedMember,
|
|
57
57
|
canonicalAssistantId,
|
|
@@ -72,15 +72,15 @@ export async function handleEscalationIntercept(
|
|
|
72
72
|
rawSenderId,
|
|
73
73
|
} = params;
|
|
74
74
|
|
|
75
|
-
if (resolvedMember?.policy !== "escalate") {
|
|
75
|
+
if (resolvedMember?.channel.policy !== "escalate") {
|
|
76
76
|
return null;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
const binding =
|
|
79
|
+
const binding = getGuardianBinding(canonicalAssistantId, sourceChannel);
|
|
80
80
|
if (!binding) {
|
|
81
81
|
// Fail-closed: can't escalate without a guardian to route to
|
|
82
82
|
log.info(
|
|
83
|
-
{ sourceChannel, channelId: resolvedMember.
|
|
83
|
+
{ sourceChannel, channelId: resolvedMember.channel.id },
|
|
84
84
|
"Ingress ACL: escalate policy but no guardian binding, denying",
|
|
85
85
|
);
|
|
86
86
|
return {
|