@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
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
|
|
13
|
+
import { findConversation } from "../../daemon/conversation-registry.js";
|
|
13
14
|
import {
|
|
14
15
|
type Confidence,
|
|
15
16
|
getAttentionStateByConversationIds,
|
|
@@ -17,7 +18,6 @@ import {
|
|
|
17
18
|
recordConversationSeenSignal,
|
|
18
19
|
type SignalType,
|
|
19
20
|
} from "../../memory/conversation-attention-store.js";
|
|
20
|
-
import { isConversationProcessing } from "../../memory/conversation-crud.js";
|
|
21
21
|
import {
|
|
22
22
|
type ConversationRow,
|
|
23
23
|
getDisplayMetaForConversations,
|
|
@@ -270,9 +270,12 @@ function handleListConversations({ queryParams = {} }: RouteHandlerArgs) {
|
|
|
270
270
|
attentionState: attentionStates.get(conversation.id),
|
|
271
271
|
displayMeta: displayMeta.get(conversation.id),
|
|
272
272
|
parentCache,
|
|
273
|
-
//
|
|
274
|
-
//
|
|
275
|
-
isProcessing:
|
|
273
|
+
// Cold (evicted / never-loaded) rows aren't in the in-memory
|
|
274
|
+
// store, so `findConversation` returns `undefined` and they
|
|
275
|
+
// report `isProcessing: false` — by definition they aren't
|
|
276
|
+
// mid-turn since the agent loop only runs on resident convs.
|
|
277
|
+
isProcessing:
|
|
278
|
+
findConversation(conversation.id)?.isProcessing() ?? false,
|
|
276
279
|
}),
|
|
277
280
|
),
|
|
278
281
|
nextOffset,
|
|
@@ -486,74 +486,6 @@ function readPlainObject(value: unknown): Record<string, unknown> | undefined {
|
|
|
486
486
|
return value as Record<string, unknown>;
|
|
487
487
|
}
|
|
488
488
|
|
|
489
|
-
function stripTransportHeadersRecursively(value: unknown): void {
|
|
490
|
-
if (Array.isArray(value)) {
|
|
491
|
-
for (const item of value) {
|
|
492
|
-
stripTransportHeadersRecursively(item);
|
|
493
|
-
}
|
|
494
|
-
return;
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
const object = readPlainObject(value);
|
|
498
|
-
if (!object) return;
|
|
499
|
-
const transport = readPlainObject(object.transport);
|
|
500
|
-
if (transport) delete transport.headers;
|
|
501
|
-
for (const child of Object.values(object)) {
|
|
502
|
-
stripTransportHeadersRecursively(child);
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
function containsTransportHeadersRecursively(value: unknown): boolean {
|
|
507
|
-
if (Array.isArray(value)) {
|
|
508
|
-
return value.some((item) => containsTransportHeadersRecursively(item));
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
const object = readPlainObject(value);
|
|
512
|
-
if (!object) return false;
|
|
513
|
-
const transport = readPlainObject(object.transport);
|
|
514
|
-
if (transport && Object.hasOwn(transport, "headers")) return true;
|
|
515
|
-
return Object.values(object).some((child) =>
|
|
516
|
-
containsTransportHeadersRecursively(child),
|
|
517
|
-
);
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
function sanitizeMcpTransportHeadersForSettingsRead(config: unknown): void {
|
|
521
|
-
const root = readPlainObject(config);
|
|
522
|
-
if (!root) return;
|
|
523
|
-
const mcp = readPlainObject(root.mcp);
|
|
524
|
-
if (!mcp || !Object.hasOwn(mcp, "servers")) return;
|
|
525
|
-
if (Array.isArray(mcp.servers)) {
|
|
526
|
-
stripTransportHeadersRecursively(mcp.servers);
|
|
527
|
-
return;
|
|
528
|
-
}
|
|
529
|
-
const servers = readPlainObject(mcp.servers);
|
|
530
|
-
if (!servers) return;
|
|
531
|
-
for (const server of Object.values(servers)) {
|
|
532
|
-
stripTransportHeadersRecursively(server);
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
function patchContainsMcpTransportHeaders(patch: unknown): boolean {
|
|
537
|
-
const root = readPlainObject(patch);
|
|
538
|
-
const mcp = readPlainObject(root?.mcp);
|
|
539
|
-
if (!mcp || !Object.hasOwn(mcp, "servers")) return false;
|
|
540
|
-
if (Array.isArray(mcp.servers)) {
|
|
541
|
-
return containsTransportHeadersRecursively(mcp.servers);
|
|
542
|
-
}
|
|
543
|
-
const servers = readPlainObject(mcp.servers);
|
|
544
|
-
if (!servers) return false;
|
|
545
|
-
return Object.values(servers).some((server) =>
|
|
546
|
-
containsTransportHeadersRecursively(server),
|
|
547
|
-
);
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
function rejectMcpTransportHeaderWrite(patch: unknown): void {
|
|
551
|
-
if (!patchContainsMcpTransportHeaders(patch)) return;
|
|
552
|
-
throw new BadRequestError(
|
|
553
|
-
"MCP authentication headers must be managed through MCP server add/update APIs, not generic config writes.",
|
|
554
|
-
);
|
|
555
|
-
}
|
|
556
|
-
|
|
557
489
|
const WireProfileEntry = ProfileEntry.extend({
|
|
558
490
|
supportsVision: z.boolean().optional(),
|
|
559
491
|
})
|
|
@@ -756,7 +688,6 @@ const ConfigPatchRequestSchema = z
|
|
|
756
688
|
function handleGetConfig() {
|
|
757
689
|
try {
|
|
758
690
|
const config = applyContextDefaultsToRawConfig(loadRawConfig());
|
|
759
|
-
sanitizeMcpTransportHeadersForSettingsRead(config);
|
|
760
691
|
enrichProfilesWithVisionFlag(config);
|
|
761
692
|
return config;
|
|
762
693
|
} catch (err) {
|
|
@@ -909,7 +840,6 @@ async function handlePatchConfig({ body }: RouteHandlerArgs) {
|
|
|
909
840
|
throw new BadRequestError("Body must be a non-empty JSON object");
|
|
910
841
|
}
|
|
911
842
|
rejectManagedProfileDeletion(body as Record<string, unknown>);
|
|
912
|
-
rejectMcpTransportHeaderWrite(body);
|
|
913
843
|
|
|
914
844
|
const raw = loadRawConfig();
|
|
915
845
|
const patch = body as Record<string, unknown>;
|
|
@@ -918,7 +848,6 @@ async function handlePatchConfig({ body }: RouteHandlerArgs) {
|
|
|
918
848
|
await commitConfigWrite(raw, "patch");
|
|
919
849
|
|
|
920
850
|
const merged = applyContextDefaultsToRawConfig(loadRawConfig());
|
|
921
|
-
sanitizeMcpTransportHeadersForSettingsRead(merged);
|
|
922
851
|
enrichProfilesWithVisionFlag(merged);
|
|
923
852
|
return merged;
|
|
924
853
|
}
|
|
@@ -963,7 +892,6 @@ async function handleSetConfig({ body }: RouteHandlerArgs) {
|
|
|
963
892
|
const patchShape: Record<string, unknown> = {};
|
|
964
893
|
setNestedValue(patchShape, path, value);
|
|
965
894
|
rejectManagedProfileDeletion(patchShape);
|
|
966
|
-
rejectMcpTransportHeaderWrite(patchShape);
|
|
967
895
|
|
|
968
896
|
const raw = loadRawConfig();
|
|
969
897
|
setNestedValue(raw, path, value);
|
|
@@ -50,7 +50,6 @@ import {
|
|
|
50
50
|
getCannedFirstGreeting,
|
|
51
51
|
isWakeUpGreeting,
|
|
52
52
|
} from "../../daemon/first-greeting.js";
|
|
53
|
-
import { supersedePendingInteractionsOnEnqueue } from "../../daemon/handlers/conversations.js";
|
|
54
53
|
import {
|
|
55
54
|
collectAttachmentRefs,
|
|
56
55
|
type HistoryAttachmentRef,
|
|
@@ -68,7 +67,6 @@ import type {
|
|
|
68
67
|
HostProxyTransportMetadata,
|
|
69
68
|
NonHostProxyTransportMetadata,
|
|
70
69
|
} from "../../daemon/message-types/conversations.js";
|
|
71
|
-
import type { TrustContext } from "../../daemon/trust-context.js";
|
|
72
70
|
import { HeartbeatService } from "../../heartbeat/heartbeat-service.js";
|
|
73
71
|
import {
|
|
74
72
|
writeOnboardingSidecar,
|
|
@@ -122,30 +120,30 @@ import {
|
|
|
122
120
|
} from "../../util/platform.js";
|
|
123
121
|
import { silentlyWithLog } from "../../util/silently.js";
|
|
124
122
|
import { assistantEventHub, broadcastMessage } from "../assistant-event-hub.js";
|
|
123
|
+
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
|
|
125
124
|
import { getPersistedSeq } from "../assistant-stream-state.js";
|
|
126
125
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
127
126
|
import {
|
|
128
127
|
type GuardianPendingScope,
|
|
129
128
|
routeGuardianReply,
|
|
130
129
|
} from "../guardian-reply-router.js";
|
|
131
|
-
import {
|
|
130
|
+
import { healGuardianBindingDrift } from "../guardian-vellum-migration.js";
|
|
132
131
|
import type {
|
|
133
132
|
ApprovalConversationGenerator,
|
|
134
133
|
RuntimeAttachmentMetadata,
|
|
135
134
|
RuntimeMessagePayload,
|
|
136
135
|
SendMessageDeps,
|
|
137
136
|
} from "../http-types.js";
|
|
138
|
-
import {
|
|
139
|
-
findLocalGuardianPrincipalId,
|
|
140
|
-
resolveActorPrincipalIdForLocalGuardian,
|
|
141
|
-
} from "../local-actor-identity.js";
|
|
142
|
-
import { resolveLocalPrincipalTrustContext } from "../local-principal-trust.js";
|
|
137
|
+
import { resolveLocalTrustContext } from "../local-actor-identity.js";
|
|
143
138
|
import * as pendingInteractions from "../pending-interactions.js";
|
|
144
139
|
import {
|
|
145
140
|
publishConversationListAndMetadataChanged,
|
|
146
141
|
publishConversationMessagesChanged,
|
|
147
142
|
} from "../sync/resource-sync-events.js";
|
|
148
|
-
import {
|
|
143
|
+
import {
|
|
144
|
+
resolveTrustContext,
|
|
145
|
+
withSourceChannel,
|
|
146
|
+
} from "../trust-context-resolver.js";
|
|
149
147
|
import {
|
|
150
148
|
BadRequestError,
|
|
151
149
|
InternalError,
|
|
@@ -948,28 +946,25 @@ export function handleListMessages({
|
|
|
948
946
|
.filter((block) => block.type !== "text" || block.text.length > 0);
|
|
949
947
|
}
|
|
950
948
|
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
for (const att of msgAttachments) {
|
|
967
|
-
if (!existingAttachmentIds.has(att.id)) {
|
|
968
|
-
contentBlocks.push({ type: "attachment", attachment: att });
|
|
969
|
-
}
|
|
949
|
+
// Ensure every hydrated attachment has a corresponding content block.
|
|
950
|
+
// renderHistoryContent inlines attachment blocks only when it has
|
|
951
|
+
// file-block refs with matching DB rows; directives (assistant-authored
|
|
952
|
+
// <vellum-attachment/> tags) don't leave a file block after stripping,
|
|
953
|
+
// so their attachments end up in the flat `attachments` array but not in
|
|
954
|
+
// `contentBlocks`. Append any that are missing so the canonical
|
|
955
|
+
// projection is complete.
|
|
956
|
+
const existingAttachmentIds = new Set(
|
|
957
|
+
contentBlocks
|
|
958
|
+
.filter((b): b is Extract<ConversationContentBlock, { type: "attachment" }> => b.type === "attachment")
|
|
959
|
+
.map((b) => b.attachment.id),
|
|
960
|
+
);
|
|
961
|
+
for (const att of msgAttachments) {
|
|
962
|
+
if (!existingAttachmentIds.has(att.id)) {
|
|
963
|
+
contentBlocks.push({ type: "attachment", attachment: att });
|
|
970
964
|
}
|
|
965
|
+
}
|
|
971
966
|
|
|
972
|
-
|
|
967
|
+
const alignedContentOrder = aligned.rewriteContentOrder(contentOrder);
|
|
973
968
|
|
|
974
969
|
// Use sentAt (actual event time) for the display timestamp when available,
|
|
975
970
|
// falling back to createdAt (persistence time). Clients use this display
|
|
@@ -1445,65 +1440,56 @@ export async function handleSendMessage(
|
|
|
1445
1440
|
conversation.setOnboardingContext(body.onboarding!);
|
|
1446
1441
|
}
|
|
1447
1442
|
|
|
1448
|
-
// Resolve guardian context from the AuthContext's actorPrincipalId
|
|
1449
|
-
//
|
|
1443
|
+
// Resolve guardian context from the AuthContext's actorPrincipalId.
|
|
1444
|
+
// The JWT-verified principal is used as the sender identity through
|
|
1445
|
+
// the same trust resolution pipeline that channel ingress uses.
|
|
1450
1446
|
if (actorPrincipalId) {
|
|
1451
1447
|
// Dev bypass (HTTP auth disabled): the synthetic "dev-bypass" principal
|
|
1452
|
-
// won't match any guardian binding. Resolve the
|
|
1453
|
-
//
|
|
1448
|
+
// won't match any guardian binding. Resolve from the local guardian
|
|
1449
|
+
// binding instead, which produces the correct guardian trust context.
|
|
1454
1450
|
if (isHttpAuthDisabled() && actorPrincipalId === "dev-bypass") {
|
|
1455
|
-
|
|
1456
|
-
let trustCtx: TrustContext = guardianPrincipalId
|
|
1457
|
-
? withSourceChannel(
|
|
1458
|
-
sourceChannel,
|
|
1459
|
-
await resolveLocalPrincipalTrustContext({
|
|
1460
|
-
actorPrincipalId: guardianPrincipalId,
|
|
1461
|
-
sourceChannel: "vellum",
|
|
1462
|
-
conversationExternalId: "local",
|
|
1463
|
-
}),
|
|
1464
|
-
)
|
|
1465
|
-
: { trustClass: "unknown", sourceChannel };
|
|
1466
|
-
if (guardianPrincipalId && trustCtx.trustClass === "unknown") {
|
|
1467
|
-
const healed = await reResolveTrustOnResetDrift(
|
|
1468
|
-
guardianPrincipalId,
|
|
1469
|
-
sourceChannel,
|
|
1470
|
-
);
|
|
1471
|
-
if (healed) trustCtx = healed;
|
|
1472
|
-
}
|
|
1473
|
-
conversation.setTrustContext(trustCtx);
|
|
1451
|
+
conversation.setTrustContext(resolveLocalTrustContext(sourceChannel));
|
|
1474
1452
|
} else {
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
);
|
|
1453
|
+
const assistantId = DAEMON_INTERNAL_ASSISTANT_ID;
|
|
1454
|
+
let trustCtx = resolveTrustContext({
|
|
1455
|
+
assistantId,
|
|
1456
|
+
sourceChannel: "vellum",
|
|
1457
|
+
conversationExternalId: "local",
|
|
1458
|
+
actorExternalId: actorPrincipalId,
|
|
1459
|
+
});
|
|
1483
1460
|
if (trustCtx.trustClass === "unknown") {
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1461
|
+
// Attempt to heal guardian binding drift: after a DB reset the
|
|
1462
|
+
// guardian binding gets a new vellum-principal-* UUID while the
|
|
1463
|
+
// client still holds a valid JWT with the old one. The signing
|
|
1464
|
+
// key survives the reset, so the JWT is authentic — just stale.
|
|
1465
|
+
const healed = healGuardianBindingDrift(actorPrincipalId);
|
|
1466
|
+
if (healed) {
|
|
1467
|
+
trustCtx = resolveTrustContext({
|
|
1468
|
+
assistantId,
|
|
1469
|
+
sourceChannel: "vellum",
|
|
1470
|
+
conversationExternalId: "local",
|
|
1471
|
+
actorExternalId: actorPrincipalId,
|
|
1472
|
+
});
|
|
1490
1473
|
log.info(
|
|
1491
|
-
{
|
|
1492
|
-
|
|
1474
|
+
{
|
|
1475
|
+
actorPrincipalId: actorPrincipalId,
|
|
1476
|
+
trustClass: trustCtx.trustClass,
|
|
1477
|
+
},
|
|
1478
|
+
"Trust re-resolved after guardian binding drift heal",
|
|
1493
1479
|
);
|
|
1494
1480
|
} else {
|
|
1495
1481
|
log.warn(
|
|
1496
1482
|
{
|
|
1497
|
-
actorPrincipalId,
|
|
1483
|
+
actorPrincipalId: actorPrincipalId,
|
|
1498
1484
|
sourceChannel,
|
|
1499
|
-
trustClass:
|
|
1500
|
-
principalType,
|
|
1485
|
+
trustClass: trustCtx.trustClass,
|
|
1486
|
+
principalType: principalType,
|
|
1501
1487
|
},
|
|
1502
1488
|
"JWT-verified actor resolved to unknown trust class — possible guardian binding drift (e.g. DB reset without re-bootstrap)",
|
|
1503
1489
|
);
|
|
1504
1490
|
}
|
|
1505
1491
|
}
|
|
1506
|
-
conversation.setTrustContext(trustCtx);
|
|
1492
|
+
conversation.setTrustContext(withSourceChannel(sourceChannel, trustCtx));
|
|
1507
1493
|
}
|
|
1508
1494
|
} else {
|
|
1509
1495
|
// Service principals (svc_gateway) or tokens without an actor ID
|
|
@@ -1512,13 +1498,10 @@ export async function handleSendMessage(
|
|
|
1512
1498
|
}
|
|
1513
1499
|
|
|
1514
1500
|
const isInteractive = isInteractiveInterface(sourceInterface);
|
|
1515
|
-
//
|
|
1516
|
-
//
|
|
1517
|
-
//
|
|
1518
|
-
|
|
1519
|
-
const sourceActorPrincipalId = await resolveActorPrincipalIdForLocalGuardian(
|
|
1520
|
-
actorPrincipalId ?? undefined,
|
|
1521
|
-
);
|
|
1501
|
+
// Use the JWT-verified requester principal — not guardianPrincipalId,
|
|
1502
|
+
// which is the workspace owner and would let a trusted contact's web
|
|
1503
|
+
// turn match against the guardian's macOS client.
|
|
1504
|
+
const sourceActorPrincipalId = actorPrincipalId ?? undefined;
|
|
1522
1505
|
// Bash/File/Transfer singletons are globally available via isAvailable() —
|
|
1523
1506
|
// no per-conversation gating needed. CU is per-conversation (owns step
|
|
1524
1507
|
// count, AX tree history, loop detection).
|
|
@@ -1831,11 +1814,29 @@ export async function handleSendMessage(
|
|
|
1831
1814
|
// the client showing "Failed to send" for a message the daemon will
|
|
1832
1815
|
// process from the queue.
|
|
1833
1816
|
try {
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1817
|
+
if (conversation.hasAnyPendingConfirmation()) {
|
|
1818
|
+
// Emit authoritative denial state for each pending request.
|
|
1819
|
+
// sendToClient (wired to the SSE hub) delivers these to the client.
|
|
1820
|
+
for (const interaction of pendingInteractions.getByConversation(
|
|
1821
|
+
mapping.conversationId,
|
|
1822
|
+
)) {
|
|
1823
|
+
if (interaction.kind === "confirmation") {
|
|
1824
|
+
conversation.emitConfirmationStateChanged({
|
|
1825
|
+
conversationId: mapping.conversationId,
|
|
1826
|
+
requestId: interaction.requestId,
|
|
1827
|
+
state: "denied" as const,
|
|
1828
|
+
source: "auto_deny" as const,
|
|
1829
|
+
});
|
|
1830
|
+
// Sync canonical guardian request status so stale "pending" DB
|
|
1831
|
+
// records don't get matched by later guardian reply routing.
|
|
1832
|
+
resolveCanonicalGuardianRequest(interaction.requestId, "pending", {
|
|
1833
|
+
status: "denied",
|
|
1834
|
+
});
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
conversation.denyAllPendingConfirmations();
|
|
1838
|
+
pendingInteractions.removeByConversation(mapping.conversationId);
|
|
1839
|
+
}
|
|
1839
1840
|
|
|
1840
1841
|
// Expire any orphaned canonical requests that survived without a
|
|
1841
1842
|
// matching in-memory pending interaction (e.g. prompter timeouts).
|
|
@@ -43,7 +43,7 @@ import type { ReplaySubscriber } from "../assistant-stream-state.js";
|
|
|
43
43
|
import { getReplayWindow } from "../assistant-stream-state.js";
|
|
44
44
|
import { ACTOR_PRINCIPALS, GATEWAY_PRINCIPALS } from "../auth/route-policy.js";
|
|
45
45
|
import { DEFAULT_HEARTBEAT_INTERVAL_MS } from "../client-health.js";
|
|
46
|
-
import {
|
|
46
|
+
import { resolveActorPrincipalIdForLocalGuardian } from "../local-actor-identity.js";
|
|
47
47
|
import {
|
|
48
48
|
BadRequestError,
|
|
49
49
|
NotFoundError,
|
|
@@ -311,7 +311,7 @@ export function handleSubscribeAssistantEvents(
|
|
|
311
311
|
// bearer token's AuthContext. May be absent for legacy / service-token
|
|
312
312
|
// connections that have no principal. See `resolveActorPrincipalId` for the
|
|
313
313
|
// dev-bypass translation rationale.
|
|
314
|
-
const actorPrincipalId =
|
|
314
|
+
const actorPrincipalId = resolveActorPrincipalIdForLocalGuardian(
|
|
315
315
|
rawActorPrincipalId?.trim() || undefined,
|
|
316
316
|
);
|
|
317
317
|
|
|
@@ -263,9 +263,7 @@ async function handleGlobalSearch({
|
|
|
263
263
|
id: c.id,
|
|
264
264
|
displayName: c.displayName,
|
|
265
265
|
notes: c.notes,
|
|
266
|
-
|
|
267
|
-
// contacts.updatedAt, not the channel-derived lastInteraction column.
|
|
268
|
-
lastInteraction: c.updatedAt,
|
|
266
|
+
lastInteraction: c.lastInteraction,
|
|
269
267
|
}));
|
|
270
268
|
}
|
|
271
269
|
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import { z } from "zod";
|
|
15
15
|
|
|
16
16
|
import { isHttpAuthDisabled } from "../../config/env.js";
|
|
17
|
+
import { findGuardianForChannel } from "../../contacts/contact-store.js";
|
|
17
18
|
import {
|
|
18
19
|
type CanonicalGuardianRequest,
|
|
19
20
|
listPendingRequestsByConversationScope,
|
|
@@ -22,7 +23,6 @@ import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
|
22
23
|
import { processGuardianDecision } from "../guardian-action-service.js";
|
|
23
24
|
import type { GuardianDecisionPrompt } from "../guardian-decision-types.js";
|
|
24
25
|
import { buildOneTimeDecisionActions } from "../guardian-decision-types.js";
|
|
25
|
-
import { findLocalGuardianPrincipalId } from "../local-actor-identity.js";
|
|
26
26
|
import { BadRequestError, NotFoundError } from "./errors.js";
|
|
27
27
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
28
28
|
|
|
@@ -73,15 +73,16 @@ async function handleGuardianActionDecision({
|
|
|
73
73
|
// Resolve the actor's guardian principal ID. The HTTP adapter injects it
|
|
74
74
|
// from the AuthContext via the x-vellum-actor-principal-id header.
|
|
75
75
|
// For dev bypass (HTTP auth disabled) the synthetic "dev-bypass" principal
|
|
76
|
-
// won't match the real guardian binding, so
|
|
77
|
-
//
|
|
76
|
+
// won't match the real guardian binding, so fall back to the local guardian
|
|
77
|
+
// binding to avoid identity_mismatch.
|
|
78
78
|
let guardianPrincipalId: string | undefined =
|
|
79
79
|
headers["x-vellum-actor-principal-id"] ?? undefined;
|
|
80
80
|
if (
|
|
81
81
|
isHttpAuthDisabled() &&
|
|
82
82
|
headers["x-vellum-actor-principal-id"] === "dev-bypass"
|
|
83
83
|
) {
|
|
84
|
-
|
|
84
|
+
const binding = findGuardianForChannel("vellum");
|
|
85
|
+
guardianPrincipalId = binding?.contact.principalId ?? undefined;
|
|
85
86
|
}
|
|
86
87
|
|
|
87
88
|
const result = await processGuardianDecision({
|
|
@@ -39,7 +39,7 @@ const VALID_STATES: ReadonlySet<HostAppControlState> = new Set([
|
|
|
39
39
|
// POST /v1/host-app-control-result
|
|
40
40
|
// ---------------------------------------------------------------------------
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
function handleHostAppControlResult({ body, headers }: RouteHandlerArgs) {
|
|
43
43
|
if (!body || typeof body !== "object") {
|
|
44
44
|
throw new BadRequestError("Request body is required");
|
|
45
45
|
}
|
|
@@ -95,10 +95,9 @@ async function handleHostAppControlResult({ body, headers }: RouteHandlerArgs) {
|
|
|
95
95
|
`Client "${submittingClientId}" is not the target for this request (expected "${peeked.targetClientId}"). The targeted client must submit the result.`,
|
|
96
96
|
);
|
|
97
97
|
}
|
|
98
|
-
const submittingActorPrincipalId =
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
);
|
|
98
|
+
const submittingActorPrincipalId = resolveActorPrincipalIdForLocalGuardian(
|
|
99
|
+
headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
|
|
100
|
+
);
|
|
102
101
|
enforceSameActorOrThrow({
|
|
103
102
|
sourceActorPrincipalId: submittingActorPrincipalId,
|
|
104
103
|
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
@@ -26,7 +26,7 @@ import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
|
26
26
|
// POST /v1/host-bash-result
|
|
27
27
|
// ---------------------------------------------------------------------------
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
function handleHostBashResult({ body, headers }: RouteHandlerArgs) {
|
|
30
30
|
if (!body || typeof body !== "object") {
|
|
31
31
|
throw new BadRequestError("Request body is required");
|
|
32
32
|
}
|
|
@@ -45,10 +45,9 @@ async function handleHostBashResult({ body, headers }: RouteHandlerArgs) {
|
|
|
45
45
|
|
|
46
46
|
const submittingClientId =
|
|
47
47
|
headers?.["x-vellum-client-id"]?.trim() || undefined;
|
|
48
|
-
const submittingActorPrincipalId =
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
);
|
|
48
|
+
const submittingActorPrincipalId = resolveActorPrincipalIdForLocalGuardian(
|
|
49
|
+
headers?.["x-vellum-actor-principal-id"]?.trim() || undefined,
|
|
50
|
+
);
|
|
52
51
|
|
|
53
52
|
const peeked = pendingInteractions.get(requestId);
|
|
54
53
|
if (!peeked) {
|
|
@@ -61,14 +61,14 @@ export type HostBrowserResultResolution =
|
|
|
61
61
|
* already authenticated the caller (the HTTP route uses
|
|
62
62
|
* `requireBoundGuardian`).
|
|
63
63
|
*/
|
|
64
|
-
export
|
|
64
|
+
export function resolveHostBrowserResultByRequestId(
|
|
65
65
|
frame: {
|
|
66
66
|
requestId?: unknown;
|
|
67
67
|
content?: unknown;
|
|
68
68
|
isError?: unknown;
|
|
69
69
|
},
|
|
70
70
|
headers?: Record<string, string | undefined>,
|
|
71
|
-
):
|
|
71
|
+
): HostBrowserResultResolution {
|
|
72
72
|
const { requestId, content, isError } = frame;
|
|
73
73
|
|
|
74
74
|
if (!requestId || typeof requestId !== "string") {
|
|
@@ -127,10 +127,9 @@ export async function resolveHostBrowserResultByRequestId(
|
|
|
127
127
|
// stream. This prevents a different authenticated user with knowledge of
|
|
128
128
|
// both the requestId and target clientId from submitting a result on
|
|
129
129
|
// behalf of the targeted client.
|
|
130
|
-
const submittingActorPrincipalId =
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
);
|
|
130
|
+
const submittingActorPrincipalId = resolveActorPrincipalIdForLocalGuardian(
|
|
131
|
+
headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
|
|
132
|
+
);
|
|
134
133
|
try {
|
|
135
134
|
enforceSameActorOrThrow({
|
|
136
135
|
sourceActorPrincipalId: submittingActorPrincipalId,
|
|
@@ -261,12 +260,12 @@ export function resolveHostBrowserSessionInvalidated(frame: {
|
|
|
261
260
|
// POST /v1/host-browser-result
|
|
262
261
|
// ---------------------------------------------------------------------------
|
|
263
262
|
|
|
264
|
-
|
|
263
|
+
function handleHostBrowserResult({ body, headers }: RouteHandlerArgs) {
|
|
265
264
|
if (!body || typeof body !== "object") {
|
|
266
265
|
throw new BadRequestError("Request body is required");
|
|
267
266
|
}
|
|
268
267
|
|
|
269
|
-
const resolution =
|
|
268
|
+
const resolution = resolveHostBrowserResultByRequestId(
|
|
270
269
|
body,
|
|
271
270
|
headers as Record<string, string | undefined> | undefined,
|
|
272
271
|
);
|
|
@@ -400,7 +399,10 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
400
399
|
"Marks the target as invalidated in the runtime-side browser session registry.",
|
|
401
400
|
tags: ["host"],
|
|
402
401
|
requestBody: z.object({
|
|
403
|
-
targetId: z
|
|
402
|
+
targetId: z
|
|
403
|
+
.string()
|
|
404
|
+
.optional()
|
|
405
|
+
.describe("CDP target that was detached"),
|
|
404
406
|
reason: z.string().optional().describe("Detach reason"),
|
|
405
407
|
clientId: z
|
|
406
408
|
.string()
|
|
@@ -26,7 +26,7 @@ import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
|
26
26
|
// POST /v1/host-cu-result
|
|
27
27
|
// ---------------------------------------------------------------------------
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
function handleHostCuResult({ body, headers }: RouteHandlerArgs) {
|
|
30
30
|
if (!body || typeof body !== "object") {
|
|
31
31
|
throw new BadRequestError("Request body is required");
|
|
32
32
|
}
|
|
@@ -95,10 +95,9 @@ async function handleHostCuResult({ body, headers }: RouteHandlerArgs) {
|
|
|
95
95
|
// stream. This prevents a different authenticated user with knowledge of
|
|
96
96
|
// both the requestId and target clientId from submitting a result on
|
|
97
97
|
// behalf of the targeted client.
|
|
98
|
-
const submittingActorPrincipalId =
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
);
|
|
98
|
+
const submittingActorPrincipalId = resolveActorPrincipalIdForLocalGuardian(
|
|
99
|
+
headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
|
|
100
|
+
);
|
|
102
101
|
enforceSameActorOrThrow({
|
|
103
102
|
sourceActorPrincipalId: submittingActorPrincipalId,
|
|
104
103
|
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
@@ -26,7 +26,7 @@ import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
|
26
26
|
// POST /v1/host-file-result
|
|
27
27
|
// ---------------------------------------------------------------------------
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
function handleHostFileResult({ body, headers }: RouteHandlerArgs) {
|
|
30
30
|
if (!body || typeof body !== "object") {
|
|
31
31
|
throw new BadRequestError("Request body is required");
|
|
32
32
|
}
|
|
@@ -76,10 +76,9 @@ async function handleHostFileResult({ body, headers }: RouteHandlerArgs) {
|
|
|
76
76
|
// match the actor that opened the target client's SSE stream. This blocks
|
|
77
77
|
// cross-user submissions even if a different user somehow obtains the
|
|
78
78
|
// target client id.
|
|
79
|
-
const submittingActorPrincipalId =
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
);
|
|
79
|
+
const submittingActorPrincipalId = resolveActorPrincipalIdForLocalGuardian(
|
|
80
|
+
headerMap["x-vellum-actor-principal-id"]?.trim() || undefined,
|
|
81
|
+
);
|
|
83
82
|
enforceSameActorOrThrow({
|
|
84
83
|
sourceActorPrincipalId: submittingActorPrincipalId,
|
|
85
84
|
targetActorPrincipalId: peeked.targetActorPrincipalId,
|