@vellumai/assistant 0.10.1 → 0.10.2-dev.202606241651.2d2b40d
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/docs/workspace-tools.md +42 -33
- package/eslint-rules/cli-no-daemon-internals.js +6 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +91 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +31 -0
- package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +48 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +14 -0
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +17 -0
- package/openapi.yaml +74 -1
- package/package.json +1 -1
- package/scripts/test.sh +36 -15
- package/src/__tests__/actor-token-service.test.ts +36 -14
- package/src/__tests__/agent-loop-override-profile.test.ts +1 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +2 -0
- package/src/__tests__/annotate-activity-metadata.test.ts +2 -0
- package/src/__tests__/annotate-risk-options.test.ts +2 -0
- package/src/__tests__/approval-cascade.test.ts +2 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +2 -0
- package/src/__tests__/btw-routes.test.ts +2 -0
- package/src/__tests__/build-persisted-content.test.ts +2 -0
- package/src/__tests__/call-controller.test.ts +19 -0
- package/src/__tests__/channel-guardian.test.ts +94 -58
- package/src/__tests__/channel-reply-delivery.test.ts +2 -0
- package/src/__tests__/compaction-events.test.ts +2 -0
- package/src/__tests__/compaction.benchmark.test.ts +2 -0
- package/src/__tests__/compactor-call-site-logging.test.ts +2 -0
- package/src/__tests__/compactor-low-watermark-cut.test.ts +2 -0
- package/src/__tests__/compactor-preserved-tail-count.test.ts +2 -0
- package/src/__tests__/compactor-summary-call-truncation.test.ts +2 -0
- package/src/__tests__/compactor-web-search-strip.test.ts +2 -0
- package/src/__tests__/computer-use-tools.test.ts +13 -0
- package/src/__tests__/config-loader-backfill.test.ts +5 -1
- package/src/__tests__/config-schema.test.ts +1 -0
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +31 -29
- package/src/__tests__/contacts-relay-reads.test.ts +13 -15
- package/src/__tests__/conversation-abort-tool-results.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop.test.ts +7 -0
- package/src/__tests__/conversation-analysis-routes.test.ts +2 -0
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +2 -0
- package/src/__tests__/conversation-confirmation-signals.test.ts +2 -0
- package/src/__tests__/conversation-history-web-search.test.ts +2 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +2 -0
- package/src/__tests__/conversation-load-history-stripped.test.ts +2 -0
- package/src/__tests__/conversation-pairing.test.ts +2 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +2 -0
- package/src/__tests__/conversation-process-callsite.test.ts +2 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -0
- package/src/__tests__/conversation-queue.test.ts +91 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +14 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +14 -0
- package/src/__tests__/conversation-slash-queue.test.ts +2 -0
- package/src/__tests__/conversation-slash-unknown.test.ts +2 -0
- package/src/__tests__/conversation-speed-override.test.ts +2 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +65 -0
- package/src/__tests__/conversation-title-service.test.ts +2 -0
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +47 -0
- package/src/__tests__/conversation-usage.test.ts +2 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +2 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +2 -0
- package/src/__tests__/credential-security-invariants.test.ts +0 -1
- package/src/__tests__/db-migration-rollback.test.ts +205 -171
- package/src/__tests__/db-test-helpers.ts +5 -4
- package/src/__tests__/deterministic-verification-control-plane.test.ts +4 -2
- package/src/__tests__/disk-pressure-guard.test.ts +41 -0
- package/src/__tests__/dm-persistence.test.ts +2 -0
- package/src/__tests__/emit-signal-routing-intent.test.ts +10 -5
- package/src/__tests__/events-dev-bypass-actor.test.ts +7 -1
- package/src/__tests__/filing-service.test.ts +2 -0
- package/src/__tests__/guardian-binding-drift-heal.test.ts +75 -10
- package/src/__tests__/guardian-dispatch.test.ts +95 -1
- package/src/__tests__/guardian-outbound-http.test.ts +13 -0
- package/src/__tests__/heartbeat-disk-pressure.test.ts +2 -0
- package/src/__tests__/heartbeat-service.test.ts +2 -0
- package/src/__tests__/helpers/channel-test-adapter.ts +1 -7
- package/src/__tests__/host-app-control-routes.test.ts +24 -30
- package/src/__tests__/host-bash-routes.test.ts +31 -41
- package/src/__tests__/host-browser-routes.test.ts +26 -32
- package/src/__tests__/host-cu-proxy.test.ts +299 -0
- package/src/__tests__/host-cu-routes-targeted.test.ts +25 -33
- package/src/__tests__/host-file-routes-targeted.test.ts +40 -52
- package/src/__tests__/host-transfer-routes-targeted.test.ts +31 -43
- package/src/__tests__/http-user-message-parity.test.ts +167 -8
- package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/invite-redemption-service.test.ts +43 -0
- package/src/__tests__/llm-context-normalization.test.ts +105 -0
- package/src/__tests__/llm-usage-store.test.ts +25 -0
- package/src/__tests__/media-stream-server-integration.test.ts +127 -0
- package/src/__tests__/memory-retrieval-hook.test.ts +2 -0
- package/src/__tests__/messaging-send-tool.test.ts +2 -0
- package/src/__tests__/migration-import-from-url.test.ts +2 -2
- package/src/__tests__/native-web-search.test.ts +2 -0
- package/src/__tests__/non-member-access-request.test.ts +189 -17
- package/src/__tests__/notification-broadcaster.test.ts +4 -0
- package/src/__tests__/notification-decision-recipient-context.test.ts +33 -32
- package/src/__tests__/notification-deep-link.test.ts +6 -0
- package/src/__tests__/notification-guardian-path.test.ts +19 -0
- package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/pending-interactions-resolved-event.test.ts +7 -4
- package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
- package/src/__tests__/plugin-bootstrap.test.ts +3 -73
- package/src/__tests__/plugin-route-contribution.test.ts +4 -17
- package/src/__tests__/plugin-tool-contribution.test.ts +3 -18
- package/src/__tests__/plugin-types.test.ts +0 -2
- package/src/__tests__/process-message-background-slack.test.ts +2 -0
- package/src/__tests__/process-message-display-content.test.ts +2 -0
- package/src/__tests__/provider-usage-tracking.test.ts +39 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +2 -0
- package/src/__tests__/registry.test.ts +3 -0
- package/src/__tests__/relay-server.test.ts +694 -25
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
- package/src/__tests__/secret-ingress-http.test.ts +14 -0
- package/src/__tests__/send-endpoint-busy.test.ts +30 -8
- package/src/__tests__/skills.test.ts +44 -0
- package/src/__tests__/slack-inbound-verification.test.ts +47 -2
- package/src/__tests__/sse-actor-principal-guardian-source.test.ts +102 -0
- package/src/__tests__/steer-on-enqueue-question.test.ts +181 -0
- package/src/__tests__/stt-hints.test.ts +44 -13
- package/src/__tests__/subagent-detail.test.ts +27 -0
- package/src/__tests__/subagent-disposal.test.ts +65 -0
- package/src/__tests__/subagent-notify-parent.test.ts +2 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +2 -0
- package/src/__tests__/subagent-tools.test.ts +2 -0
- package/src/__tests__/suggestion-routes.test.ts +2 -0
- package/src/__tests__/title-generate-hook.test.ts +2 -0
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -0
- package/src/__tests__/tool-executor.test.ts +16 -11
- package/src/__tests__/tool-preview-lifecycle.test.ts +2 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +2 -0
- package/src/__tests__/tool-start-timestamp.test.ts +2 -0
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +10 -10
- package/src/__tests__/twilio-routes.test.ts +96 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -0
- package/src/__tests__/web-search-backend-failure.test.ts +2 -0
- package/src/__tests__/workspace-tool-loader.test.ts +195 -2
- package/src/agent/loop-exclusive-tool.test.ts +150 -0
- package/src/agent/loop.ts +56 -0
- package/src/api/constants/sse-replay.ts +41 -0
- package/src/api/index.ts +6 -0
- package/src/api/responses/llm-request-log-entry.ts +25 -0
- package/src/api/responses/subagent-detail.ts +17 -0
- package/src/calls/__tests__/relay-setup-router.test.ts +262 -4
- package/src/calls/call-domain.ts +3 -3
- package/src/calls/guardian-dispatch.ts +10 -8
- package/src/calls/inbound-trust-reader.ts +17 -1
- package/src/calls/media-stream-server.ts +21 -0
- package/src/calls/relay-server.ts +167 -50
- package/src/calls/relay-setup-router.ts +37 -7
- package/src/calls/relay-verification.ts +4 -4
- package/src/calls/stt-hints.ts +9 -12
- package/src/calls/twilio-routes.ts +14 -4
- package/src/cli/commands/__tests__/cache.test.ts +8 -1
- package/src/cli/commands/cache.ts +194 -181
- package/src/cli/commands/db/__tests__/repair.test.ts +6 -5
- package/src/cli/commands/db/status.ts +37 -1
- package/src/cli/commands/mcp.ts +252 -218
- package/src/cli/commands/memory/__tests__/worker.test.ts +302 -0
- package/src/cli/commands/memory/index.ts +2 -0
- package/src/cli/commands/memory/worker.ts +175 -0
- package/src/cli/commands/plugins.ts +75 -3
- package/src/cli/lib/__tests__/install-from-github.test.ts +102 -0
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +160 -1
- package/src/cli/lib/list-installed-plugins.ts +179 -1
- package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +143 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +6 -1
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +27 -17
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +13 -3
- package/src/config/feature-flag-registry.json +0 -8
- package/src/config/loader.ts +36 -5
- package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
- package/src/config/schemas/memory-lifecycle.ts +12 -0
- package/src/config/schemas/memory-v3.ts +7 -0
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/timeouts.ts +8 -0
- package/src/config/seed-inference-profiles.ts +14 -5
- package/src/config/skills.ts +27 -5
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +312 -0
- package/src/contacts/contacts-write.ts +3 -0
- package/src/contacts/guardian-delivery-reader.ts +223 -0
- package/src/daemon/conversation-agent-loop.ts +9 -0
- package/src/daemon/conversation-process.ts +39 -17
- package/src/daemon/conversation-surfaces.ts +8 -0
- package/src/daemon/conversation-tool-setup.ts +49 -16
- package/src/daemon/conversation.ts +21 -2
- package/src/daemon/disk-pressure-guard.ts +12 -2
- package/src/daemon/event-loop-watchdog.ts +28 -1
- package/src/daemon/external-plugins-bootstrap.ts +4 -34
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +25 -0
- package/src/daemon/handlers/__tests__/config-channels.test.ts +225 -0
- package/src/daemon/handlers/config-a2a.ts +6 -14
- package/src/daemon/handlers/config-channels.ts +78 -22
- package/src/daemon/handlers/conversations.ts +77 -0
- package/src/daemon/host-cu-proxy.ts +102 -11
- package/src/daemon/lifecycle.ts +4 -0
- package/src/daemon/memory-v2-startup.test.ts +72 -0
- package/src/daemon/memory-v2-startup.ts +87 -19
- package/src/daemon/server.ts +0 -4
- package/src/daemon/shutdown-handlers.ts +20 -0
- package/src/daemon/tool-setup-types.ts +9 -0
- package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
- package/src/ipc/assistant-server.ts +2 -2
- package/src/memory/__tests__/301-create-watchdog-events.test.ts +110 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +8 -0
- package/src/memory/__tests__/prompt-override.test.ts +192 -0
- package/src/memory/__tests__/watchdog-events-store.test.ts +161 -0
- package/src/memory/conversation-crud.ts +38 -0
- package/src/memory/db-connection.ts +22 -3
- package/src/memory/db-init.ts +36 -502
- package/src/memory/db-singleton.ts +6 -4
- package/src/memory/jobs-worker.ts +58 -0
- package/src/memory/llm-usage-store.ts +48 -20
- package/src/memory/memory-retrospective-job.ts +9 -8
- package/src/memory/migrations/014-backfill-inbox-thread-state.ts +13 -3
- package/src/memory/migrations/136-drop-assistant-id-columns.ts +52 -27
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +130 -56
- package/src/memory/migrations/300-add-processing-started-at.ts +30 -0
- package/src/memory/migrations/301-create-watchdog-events.ts +45 -0
- package/src/memory/migrations/__tests__/014-backfill-inbox-thread-state.test.ts +108 -0
- package/src/memory/migrations/__tests__/136-drop-assistant-id-columns.test.ts +82 -0
- package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +224 -0
- package/src/memory/migrations/__tests__/run-migrations.test.ts +2 -2
- package/src/memory/migrations/run-migrations.ts +90 -6
- package/src/memory/migrations/schema-introspection.ts +14 -0
- package/src/memory/migrations/validate-migration-state.ts +101 -66
- package/src/memory/prompt-override.ts +129 -0
- package/src/memory/schema/conversations.ts +9 -0
- package/src/memory/schema/infrastructure.ts +20 -0
- package/src/memory/steps.ts +573 -0
- package/src/memory/v2/__tests__/cli-command-store.test.ts +25 -0
- package/src/memory/v2/__tests__/skill-store.test.ts +80 -0
- package/src/memory/v2/cli-command-store.ts +75 -38
- package/src/memory/v2/prompts/consolidation.ts +13 -82
- package/src/memory/v2/prompts/router.ts +21 -93
- package/src/memory/v2/skill-store.ts +68 -31
- package/src/memory/watchdog-events-store.ts +87 -0
- package/src/memory/worker-control.ts +118 -0
- package/src/memory/worker-process.ts +72 -0
- package/src/notifications/__tests__/broadcaster.test.ts +16 -8
- package/src/notifications/__tests__/connected-channels.test.ts +114 -0
- package/src/notifications/__tests__/decision-engine.test.ts +78 -9
- package/src/notifications/__tests__/destination-resolver.test.ts +256 -0
- package/src/notifications/broadcaster.ts +8 -1
- package/src/notifications/decision-engine.ts +15 -7
- package/src/notifications/destination-resolver.ts +68 -24
- package/src/notifications/emit-signal.ts +39 -14
- package/src/onboarding/checkin-event.test.ts +220 -0
- package/src/onboarding/checkin-event.ts +321 -0
- package/src/onboarding/schedule-checkin.ts +190 -0
- package/src/permissions/question-prompter.test.ts +1 -1
- package/src/permissions/question-prompter.ts +7 -4
- package/src/plugin-api/index.ts +6 -6
- package/src/plugin-api/types.ts +3 -5
- package/src/plugin-api/vision-support.test.ts +28 -4
- package/src/plugin-api/vision-support.ts +66 -31
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +161 -0
- package/src/plugins/defaults/advisor/__tests__/context-pack-gating.test.ts +106 -0
- package/src/plugins/defaults/advisor/__tests__/context-pack.test.ts +60 -0
- package/src/plugins/defaults/advisor/consult.ts +110 -6
- package/src/plugins/defaults/advisor/context-pack.ts +288 -0
- package/src/plugins/defaults/advisor/steering.ts +14 -2
- package/src/plugins/defaults/advisor/tools/advisor.ts +32 -5
- package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +47 -7
- package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +10 -11
- package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +12 -20
- package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +42 -11
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +11 -2
- package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +146 -0
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +29 -1
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +8 -1
- package/src/plugins/mtime-cache.ts +7 -2
- package/src/plugins/types.ts +0 -2
- package/src/providers/anthropic/client.ts +5 -0
- package/src/providers/call-site-routing.ts +4 -0
- package/src/providers/model-catalog.ts +16 -0
- package/src/providers/openai/responses-provider.ts +5 -0
- package/src/providers/openrouter/client.ts +5 -0
- package/src/providers/provider-send-message.ts +4 -0
- package/src/providers/ratelimit.ts +4 -0
- package/src/providers/retry.ts +4 -0
- package/src/providers/types.ts +9 -0
- package/src/providers/usage-tracking.ts +4 -0
- package/src/runtime/__tests__/channel-verification-service.test.ts +133 -0
- package/src/runtime/__tests__/guardian-vellum-migration.test.ts +181 -0
- package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +66 -0
- package/src/runtime/__tests__/local-principal-trust.test.ts +164 -0
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +335 -3
- package/src/runtime/access-request-helper.ts +19 -39
- package/src/runtime/actor-trust-resolver.ts +2 -2
- package/src/runtime/anchored-guardian.test.ts +156 -0
- package/src/runtime/anchored-guardian.ts +135 -0
- package/src/runtime/assistant-event-hub.ts +1 -1
- package/src/runtime/assistant-stream-state.ts +9 -2
- package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +99 -0
- package/src/runtime/auth/require-bound-guardian.ts +21 -11
- package/src/runtime/channel-verification-service.ts +56 -31
- package/src/runtime/confirmation-request-guardian-bridge.ts +3 -3
- package/src/runtime/guardian-vellum-migration.ts +66 -7
- package/src/runtime/invite-redemption-service.ts +50 -18
- package/src/runtime/local-actor-identity.ts +76 -11
- package/src/runtime/local-principal-trust.ts +52 -0
- package/src/runtime/pending-interactions.ts +11 -1
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +56 -5
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/contact-routes.test.ts +212 -0
- package/src/runtime/routes/__tests__/global-search-routes.test.ts +93 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +215 -1
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/channel-verification-routes.ts +3 -3
- package/src/runtime/routes/contact-routes.ts +8 -32
- package/src/runtime/routes/conversation-cli-routes.ts +4 -5
- package/src/runtime/routes/conversation-list-routes.ts +4 -7
- package/src/runtime/routes/conversation-routes.ts +74 -81
- package/src/runtime/routes/events-routes.ts +2 -2
- package/src/runtime/routes/global-search-routes.ts +3 -1
- package/src/runtime/routes/guardian-action-routes.ts +4 -5
- package/src/runtime/routes/host-app-control-routes.ts +5 -4
- package/src/runtime/routes/host-bash-routes.ts +5 -4
- package/src/runtime/routes/host-browser-routes.ts +9 -11
- package/src/runtime/routes/host-cu-routes.ts +5 -4
- package/src/runtime/routes/host-file-routes.ts +5 -4
- 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 +3 -2
- package/src/runtime/routes/inbound-message-handler.ts +5 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +97 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +61 -49
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +16 -4
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +7 -7
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +21 -8
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -3
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/llm-context-normalization.ts +71 -0
- package/src/runtime/routes/mcp-auth-routes.ts +38 -15
- package/src/runtime/routes/migration-rollback-routes.ts +4 -3
- package/src/runtime/routes/migration-routes.ts +4 -1
- package/src/runtime/routes/onboarding-checkin-routes.ts +86 -0
- package/src/runtime/routes/subagents-routes.ts +5 -0
- package/src/runtime/routes/surface-action-routes.ts +51 -55
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
- package/src/runtime/services/conversation-serializer.ts +7 -9
- package/src/runtime/tool-grant-request-helper.ts +3 -3
- package/src/runtime/trust-verdict-consumer.ts +85 -9
- package/src/runtime/verification-outbound-actions.ts +18 -18
- package/src/signals/user-message.ts +16 -0
- package/src/subagent/manager.ts +9 -0
- package/src/telemetry/types.ts +34 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +3 -2
- package/src/telemetry/usage-telemetry-reporter.ts +87 -3
- package/src/tools/ask-question/ask-question-tool.test.ts +29 -0
- package/src/tools/ask-question/ask-question-tool.ts +13 -0
- package/src/tools/computer-use/definitions.ts +8 -2
- package/src/tools/executor.ts +4 -4
- package/src/tools/registry.ts +18 -0
- package/src/tools/tool-approval-handler.ts +1 -1
- package/src/tools/tool-defaults.ts +9 -2
- package/src/tools/types.ts +17 -2
- package/src/tools/workspace-tools/loader.ts +348 -244
- package/src/util/platform.ts +5 -0
- package/src/util/telemetry-db-path.ts +24 -0
- package/src/workspace/migrations/017-seed-persona-dirs.ts +3 -34
- package/src/workspace/migrations/019-scope-journal-to-guardian.ts +3 -24
- package/src/__tests__/workspace-tools-watcher-flag.test.ts +0 -70
- package/src/daemon/workspace-tools-watcher.ts +0 -328
- package/src/memory/migrations/registry.ts +0 -573
|
@@ -40,10 +40,27 @@ export interface LlmContextSection {
|
|
|
40
40
|
language?: string;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Structured error extracted from a rejected call's response payload.
|
|
45
|
+
* Mirrors the on-disk `responsePayload.error` shape produced by
|
|
46
|
+
* `buildProviderErrorResponsePayload`. Present only when the call failed
|
|
47
|
+
* before returning a response — consumers branch on its presence to
|
|
48
|
+
* render the call as failed.
|
|
49
|
+
*/
|
|
50
|
+
export interface LlmContextError {
|
|
51
|
+
name?: string;
|
|
52
|
+
message?: string;
|
|
53
|
+
code?: string;
|
|
54
|
+
provider?: string;
|
|
55
|
+
statusCode?: number;
|
|
56
|
+
retryAfterMs?: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
43
59
|
export interface LlmContextNormalizationResult {
|
|
44
60
|
summary?: LlmContextSummary;
|
|
45
61
|
requestSections?: LlmContextSection[];
|
|
46
62
|
responseSections?: LlmContextSection[];
|
|
63
|
+
error?: LlmContextError;
|
|
47
64
|
}
|
|
48
65
|
|
|
49
66
|
interface NormalizedPayloadCandidate {
|
|
@@ -55,6 +72,60 @@ interface NormalizedPayloadCandidate {
|
|
|
55
72
|
|
|
56
73
|
export function normalizeLlmContextPayloads(
|
|
57
74
|
input: LlmContextNormalizationInput,
|
|
75
|
+
): LlmContextNormalizationResult {
|
|
76
|
+
const base = normalizeSuccessPayloads(input);
|
|
77
|
+
const error = normalizeProviderErrorPayload(input.responsePayload);
|
|
78
|
+
if (!error) {
|
|
79
|
+
return base;
|
|
80
|
+
}
|
|
81
|
+
// A rejected call has no response sections to render — only the request
|
|
82
|
+
// side normalized. Attach the structured error so the inspector can show
|
|
83
|
+
// a failure banner and treat the cost as $0.00 instead of silently
|
|
84
|
+
// falling back to "section rendering unavailable".
|
|
85
|
+
return { ...base, error };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Detect a provider/transport error stored in the response payload.
|
|
90
|
+
*
|
|
91
|
+
* Error rows are written as `{ error: { name, message, code?, provider?,
|
|
92
|
+
* statusCode?, retryAfterMs? } }` by `buildProviderErrorResponsePayload`.
|
|
93
|
+
* Successful provider responses never carry a top-level `error` object, so
|
|
94
|
+
* the presence of one (with at least one identifying field) is a reliable
|
|
95
|
+
* signal that the call failed.
|
|
96
|
+
*/
|
|
97
|
+
function normalizeProviderErrorPayload(
|
|
98
|
+
responsePayload: unknown,
|
|
99
|
+
): LlmContextError | null {
|
|
100
|
+
const error = asRecord(asRecord(responsePayload)?.error);
|
|
101
|
+
if (!error) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const name = asString(error.name);
|
|
106
|
+
const message = asString(error.message);
|
|
107
|
+
const code = asString(error.code);
|
|
108
|
+
// Require at least one identifying field so an unrelated `error` key on a
|
|
109
|
+
// success payload isn't misread as a provider failure.
|
|
110
|
+
if (name === undefined && message === undefined && code === undefined) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const normalized: LlmContextError = {};
|
|
115
|
+
if (name !== undefined) normalized.name = name;
|
|
116
|
+
if (message !== undefined) normalized.message = message;
|
|
117
|
+
if (code !== undefined) normalized.code = code;
|
|
118
|
+
const provider = asString(error.provider);
|
|
119
|
+
if (provider !== undefined) normalized.provider = provider;
|
|
120
|
+
const statusCode = asNumber(error.statusCode);
|
|
121
|
+
if (statusCode !== undefined) normalized.statusCode = statusCode;
|
|
122
|
+
const retryAfterMs = asNumber(error.retryAfterMs);
|
|
123
|
+
if (retryAfterMs !== undefined) normalized.retryAfterMs = retryAfterMs;
|
|
124
|
+
return normalized;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function normalizeSuccessPayloads(
|
|
128
|
+
input: LlmContextNormalizationInput,
|
|
58
129
|
): LlmContextNormalizationResult {
|
|
59
130
|
const requestCandidates = [
|
|
60
131
|
normalizeOpenAiRequestPayload(input.requestPayload),
|
|
@@ -24,7 +24,7 @@ import { getMcpAuthState } from "../../mcp/mcp-auth-state.js";
|
|
|
24
24
|
import { deleteMcpOAuthCredentials } from "../../mcp/mcp-oauth-provider.js";
|
|
25
25
|
import { getMcpToolsByServer } from "../../tools/registry.js";
|
|
26
26
|
import { getLogger } from "../../util/logger.js";
|
|
27
|
-
import { ACTOR_PRINCIPALS
|
|
27
|
+
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
28
28
|
import { BadRequestError, InternalError, NotFoundError } from "./errors.js";
|
|
29
29
|
import type { RouteDefinition } from "./types.js";
|
|
30
30
|
|
|
@@ -281,6 +281,7 @@ async function handleMcpUpdate({
|
|
|
281
281
|
maxTools,
|
|
282
282
|
allowedTools,
|
|
283
283
|
blockedTools,
|
|
284
|
+
headers,
|
|
284
285
|
} = body as {
|
|
285
286
|
name: string;
|
|
286
287
|
enabled?: boolean;
|
|
@@ -288,6 +289,7 @@ async function handleMcpUpdate({
|
|
|
288
289
|
maxTools?: number;
|
|
289
290
|
allowedTools?: string[] | null;
|
|
290
291
|
blockedTools?: string[] | null;
|
|
292
|
+
headers?: Record<string, string> | null;
|
|
291
293
|
};
|
|
292
294
|
|
|
293
295
|
const raw = loadRawConfig();
|
|
@@ -326,6 +328,19 @@ async function handleMcpUpdate({
|
|
|
326
328
|
server.blockedTools = blockedTools;
|
|
327
329
|
}
|
|
328
330
|
}
|
|
331
|
+
if (headers !== undefined) {
|
|
332
|
+
const transport = server.transport as Record<string, unknown> | undefined;
|
|
333
|
+
if (
|
|
334
|
+
transport &&
|
|
335
|
+
(transport.type === "sse" || transport.type === "streamable-http")
|
|
336
|
+
) {
|
|
337
|
+
if (headers === null || Object.keys(headers).length === 0) {
|
|
338
|
+
delete transport.headers;
|
|
339
|
+
} else {
|
|
340
|
+
transport.headers = headers;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
329
344
|
|
|
330
345
|
saveRawConfig(raw);
|
|
331
346
|
triggerReload("internal_mcp_update");
|
|
@@ -342,15 +357,17 @@ async function handleMcpAdd({
|
|
|
342
357
|
}: {
|
|
343
358
|
body?: Record<string, unknown>;
|
|
344
359
|
}): Promise<{ added: true }> {
|
|
345
|
-
const { name, transportType, url, command, args, risk, disabled } =
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
360
|
+
const { name, transportType, url, command, args, risk, disabled, headers } =
|
|
361
|
+
body as {
|
|
362
|
+
name: string;
|
|
363
|
+
transportType: string;
|
|
364
|
+
url?: string;
|
|
365
|
+
command?: string;
|
|
366
|
+
args?: string[];
|
|
367
|
+
risk?: string;
|
|
368
|
+
disabled?: boolean;
|
|
369
|
+
headers?: Record<string, string>;
|
|
370
|
+
};
|
|
354
371
|
|
|
355
372
|
const riskLevel = risk ?? "high";
|
|
356
373
|
if (!["low", "medium", "high"].includes(riskLevel)) {
|
|
@@ -374,7 +391,11 @@ async function handleMcpAdd({
|
|
|
374
391
|
`--url is required for ${transportType} transport`,
|
|
375
392
|
);
|
|
376
393
|
}
|
|
377
|
-
transport = {
|
|
394
|
+
transport = {
|
|
395
|
+
type: transportType,
|
|
396
|
+
url,
|
|
397
|
+
...(headers && Object.keys(headers).length > 0 ? { headers } : {}),
|
|
398
|
+
};
|
|
378
399
|
break;
|
|
379
400
|
default:
|
|
380
401
|
throw new BadRequestError(
|
|
@@ -455,8 +476,8 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
455
476
|
endpoint: "internal/mcp/auth/start",
|
|
456
477
|
method: "POST",
|
|
457
478
|
policy: {
|
|
458
|
-
requiredScopes: ["
|
|
459
|
-
allowedPrincipalTypes:
|
|
479
|
+
requiredScopes: ["settings.write"],
|
|
480
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
460
481
|
},
|
|
461
482
|
summary: "Start MCP OAuth flow",
|
|
462
483
|
description:
|
|
@@ -470,8 +491,8 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
470
491
|
endpoint: "internal/mcp/auth/status/:serverId",
|
|
471
492
|
method: "GET",
|
|
472
493
|
policy: {
|
|
473
|
-
requiredScopes: ["
|
|
474
|
-
allowedPrincipalTypes:
|
|
494
|
+
requiredScopes: ["settings.read"],
|
|
495
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
475
496
|
},
|
|
476
497
|
summary: "Poll MCP OAuth flow status",
|
|
477
498
|
description:
|
|
@@ -579,6 +600,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
579
600
|
maxTools: z.number().optional(),
|
|
580
601
|
allowedTools: z.array(z.string()).nullable().optional(),
|
|
581
602
|
blockedTools: z.array(z.string()).nullable().optional(),
|
|
603
|
+
headers: z.record(z.string(), z.string()).nullable().optional(),
|
|
582
604
|
}),
|
|
583
605
|
handler: handleMcpUpdate,
|
|
584
606
|
},
|
|
@@ -602,6 +624,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
602
624
|
args: z.array(z.string()).optional(),
|
|
603
625
|
risk: z.string().optional(),
|
|
604
626
|
disabled: z.boolean().optional(),
|
|
627
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
605
628
|
}),
|
|
606
629
|
handler: handleMcpAdd,
|
|
607
630
|
},
|
|
@@ -10,8 +10,9 @@
|
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
|
|
12
12
|
import { getDb } from "../../memory/db-connection.js";
|
|
13
|
-
import {
|
|
13
|
+
import { getMaxRollbackVersion } from "../../memory/migrations/run-migrations.js";
|
|
14
14
|
import { rollbackMemoryMigration } from "../../memory/migrations/validate-migration-state.js";
|
|
15
|
+
import { migrationSteps } from "../../memory/steps.js";
|
|
15
16
|
import { getWorkspaceDir } from "../../util/platform.js";
|
|
16
17
|
import { WORKSPACE_MIGRATIONS } from "../../workspace/migrations/registry.js";
|
|
17
18
|
import {
|
|
@@ -43,7 +44,7 @@ async function handleRollbackMigrations({ body = {} }: RouteHandlerArgs) {
|
|
|
43
44
|
|
|
44
45
|
if (rollbackToRegistryCeiling === true) {
|
|
45
46
|
if (effectiveDbVersion === undefined)
|
|
46
|
-
effectiveDbVersion =
|
|
47
|
+
effectiveDbVersion = getMaxRollbackVersion(migrationSteps);
|
|
47
48
|
if (effectiveWorkspaceMigrationId === undefined)
|
|
48
49
|
effectiveWorkspaceMigrationId =
|
|
49
50
|
getLastWorkspaceMigrationId(WORKSPACE_MIGRATIONS) ?? undefined;
|
|
@@ -104,7 +105,7 @@ async function handleRollbackMigrations({ body = {} }: RouteHandlerArgs) {
|
|
|
104
105
|
// Roll back DB migrations if requested.
|
|
105
106
|
if (effectiveDbVersion !== undefined) {
|
|
106
107
|
try {
|
|
107
|
-
rolledBack.db = rollbackMemoryMigration(getDb(), effectiveDbVersion);
|
|
108
|
+
rolledBack.db = rollbackMemoryMigration(getDb(), effectiveDbVersion, migrationSteps);
|
|
108
109
|
} catch (err) {
|
|
109
110
|
const detail = err instanceof Error ? err.message : "Unknown error";
|
|
110
111
|
throw new InternalError(`DB migration rollback failed: ${detail}`);
|
|
@@ -28,9 +28,11 @@ import {
|
|
|
28
28
|
getDb,
|
|
29
29
|
getLogsSqlite,
|
|
30
30
|
getMemorySqlite,
|
|
31
|
+
getTelemetrySqlite,
|
|
31
32
|
resetDb,
|
|
32
33
|
} from "../../memory/db-connection.js";
|
|
33
34
|
import { validateMigrationState } from "../../memory/migrations/validate-migration-state.js";
|
|
35
|
+
import { migrationSteps } from "../../memory/steps.js";
|
|
34
36
|
import { credentialKey } from "../../security/credential-key.js";
|
|
35
37
|
import {
|
|
36
38
|
bulkSetSecureKeysAsync,
|
|
@@ -180,6 +182,7 @@ async function checkpointDbsForExport(): Promise<void> {
|
|
|
180
182
|
for (const [label, sqlite] of [
|
|
181
183
|
["logs", getLogsSqlite()],
|
|
182
184
|
["memory", getMemorySqlite()],
|
|
185
|
+
["telemetry", getTelemetrySqlite()],
|
|
183
186
|
] as const) {
|
|
184
187
|
if (!sqlite) {
|
|
185
188
|
log.warn(
|
|
@@ -1712,7 +1715,7 @@ function appendNewerMigrationWarningsIfAny(report: ImportCommitReport): void {
|
|
|
1712
1715
|
return;
|
|
1713
1716
|
}
|
|
1714
1717
|
try {
|
|
1715
|
-
const migrationValidation = validateMigrationState(getDb());
|
|
1718
|
+
const migrationValidation = validateMigrationState(getDb(), migrationSteps);
|
|
1716
1719
|
if (migrationValidation.unknownCheckpoints.length > 0) {
|
|
1717
1720
|
report.warnings.push(
|
|
1718
1721
|
`Imported data contains ${migrationValidation.unknownCheckpoints.length} migration(s) from a newer version. Some data may not be fully compatible.`,
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route for programmatically scheduling the onboarding "Day 2 Check-in".
|
|
3
|
+
*
|
|
4
|
+
* POST /v1/onboarding/checkin — resolve the user's Google Calendar, find the
|
|
5
|
+
* first open 15-minute slot tomorrow afternoon, and book the check-in event.
|
|
6
|
+
*
|
|
7
|
+
* Called by the web `/onboarding/research` flow the moment Google Calendar
|
|
8
|
+
* OAuth lands. Best-effort by contract: a missing/insufficient calendar
|
|
9
|
+
* connection returns `{ scheduled: false }` rather than an error.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
|
|
14
|
+
import { scheduleOnboardingCheckin } from "../../onboarding/schedule-checkin.js";
|
|
15
|
+
import { getLogger } from "../../util/logger.js";
|
|
16
|
+
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
17
|
+
import { BadRequestError } from "./errors.js";
|
|
18
|
+
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
19
|
+
|
|
20
|
+
const log = getLogger("onboarding-checkin-routes");
|
|
21
|
+
|
|
22
|
+
function asOptionalString(value: unknown, field: string): string | undefined {
|
|
23
|
+
if (value === undefined || value === null) return undefined;
|
|
24
|
+
if (typeof value !== "string") {
|
|
25
|
+
throw new BadRequestError(`${field} must be a string`);
|
|
26
|
+
}
|
|
27
|
+
const trimmed = value.trim();
|
|
28
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function handleScheduleOnboardingCheckin({
|
|
32
|
+
body = {},
|
|
33
|
+
}: RouteHandlerArgs) {
|
|
34
|
+
// The shared route adapter does not runtime-validate the body against the
|
|
35
|
+
// Zod requestBody (codegen-only), so guard types before use.
|
|
36
|
+
const userName = asOptionalString(body.userName, "userName");
|
|
37
|
+
const assistantName = asOptionalString(body.assistantName, "assistantName");
|
|
38
|
+
const timeZone = asOptionalString(body.timezone, "timezone");
|
|
39
|
+
|
|
40
|
+
const result = await scheduleOnboardingCheckin({
|
|
41
|
+
userName,
|
|
42
|
+
assistantName,
|
|
43
|
+
timeZone,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
if (!result.scheduled) {
|
|
47
|
+
log.info({ reason: result.reason }, "Onboarding check-in not scheduled");
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const RESPONSE_SCHEMA = z.object({
|
|
53
|
+
scheduled: z.boolean(),
|
|
54
|
+
reason: z.string().optional(),
|
|
55
|
+
eventId: z.string().optional(),
|
|
56
|
+
htmlLink: z.string().nullable().optional(),
|
|
57
|
+
start: z.string().optional(),
|
|
58
|
+
end: z.string().optional(),
|
|
59
|
+
timeZone: z.string().optional(),
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
export const ROUTES: RouteDefinition[] = [
|
|
63
|
+
{
|
|
64
|
+
operationId: "scheduleOnboardingCheckin",
|
|
65
|
+
endpoint: "onboarding/checkin",
|
|
66
|
+
method: "POST",
|
|
67
|
+
policy: {
|
|
68
|
+
requiredScopes: ["chat.write"],
|
|
69
|
+
allowedPrincipalTypes: ACTOR_PRINCIPALS,
|
|
70
|
+
},
|
|
71
|
+
summary: "Schedule the onboarding Day 2 check-in",
|
|
72
|
+
description:
|
|
73
|
+
"Find the first open 15-minute slot between 12pm and 5pm tomorrow " +
|
|
74
|
+
"(widening to 8am–8pm if booked) on the user's Google Calendar and " +
|
|
75
|
+
"create the Day 2 Check-in event. Best-effort: returns scheduled=false " +
|
|
76
|
+
"when no calendar is connected or the calendar scope wasn't granted.",
|
|
77
|
+
tags: ["onboarding"],
|
|
78
|
+
requestBody: z.object({
|
|
79
|
+
userName: z.string().optional(),
|
|
80
|
+
assistantName: z.string().optional(),
|
|
81
|
+
timezone: z.string().optional(),
|
|
82
|
+
}),
|
|
83
|
+
responseBody: RESPONSE_SCHEMA,
|
|
84
|
+
handler: handleScheduleOnboardingCheckin,
|
|
85
|
+
},
|
|
86
|
+
];
|
|
@@ -39,6 +39,8 @@ export interface SubagentDetailResult {
|
|
|
39
39
|
toolName?: string;
|
|
40
40
|
isError?: boolean;
|
|
41
41
|
messageId?: string;
|
|
42
|
+
toolUseId?: string;
|
|
43
|
+
input?: Record<string, unknown>;
|
|
42
44
|
}>;
|
|
43
45
|
}
|
|
44
46
|
|
|
@@ -112,6 +114,8 @@ export function parseSubagentMessages(
|
|
|
112
114
|
type: "tool_use",
|
|
113
115
|
content: JSON.stringify(input),
|
|
114
116
|
toolName: name,
|
|
117
|
+
toolUseId: id || undefined,
|
|
118
|
+
input,
|
|
115
119
|
});
|
|
116
120
|
if (id) pendingTools.set(id, name);
|
|
117
121
|
} else if (
|
|
@@ -147,6 +151,7 @@ export function parseSubagentMessages(
|
|
|
147
151
|
content: resultContent,
|
|
148
152
|
toolName: toolName ?? "unknown",
|
|
149
153
|
isError,
|
|
154
|
+
toolUseId: toolUseId || undefined,
|
|
150
155
|
});
|
|
151
156
|
}
|
|
152
157
|
}
|
|
@@ -9,20 +9,17 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
|
|
12
|
-
import type { ChannelId } from "../../channels/types.js";
|
|
13
12
|
import { isHttpAuthDisabled } from "../../config/env.js";
|
|
14
|
-
import {
|
|
13
|
+
import type { TrustContext } from "../../daemon/trust-context.js";
|
|
15
14
|
import { getLogger } from "../../util/logger.js";
|
|
16
|
-
import type { TrustClass } from "../actor-trust-resolver.js";
|
|
17
|
-
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
|
|
18
15
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
19
16
|
import { processGuardianDecision } from "../guardian-action-service.js";
|
|
20
|
-
import {
|
|
21
|
-
import { resolveLocalTrustContext } from "../local-actor-identity.js";
|
|
17
|
+
import { reResolveTrustOnResetDrift } from "../guardian-vellum-migration.js";
|
|
22
18
|
import {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
} from "../
|
|
19
|
+
findLocalGuardianPrincipalId,
|
|
20
|
+
resolveActorPrincipalIdForLocalGuardian,
|
|
21
|
+
} from "../local-actor-identity.js";
|
|
22
|
+
import { resolveLocalPrincipalTrustContext } from "../local-principal-trust.js";
|
|
26
23
|
import { parseCallbackData } from "./channel-route-shared.js";
|
|
27
24
|
import {
|
|
28
25
|
BadRequestError,
|
|
@@ -40,58 +37,51 @@ const log = getLogger("surface-action-routes");
|
|
|
40
37
|
// ---------------------------------------------------------------------------
|
|
41
38
|
|
|
42
39
|
/**
|
|
43
|
-
* Resolve trust context
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* rather than defaulting to unknown.
|
|
40
|
+
* Resolve trust context for the actor principal from the gateway guardian
|
|
41
|
+
* binding and set it on the conversation. A vellum principal is the guardian or
|
|
42
|
+
* nobody, so the mapper yields guardian or unknown.
|
|
47
43
|
*/
|
|
48
|
-
function applyTrustContext(
|
|
44
|
+
async function applyTrustContext(
|
|
49
45
|
conversation: {
|
|
50
|
-
setTrustContext?(ctx:
|
|
51
|
-
trustClass: TrustClass;
|
|
52
|
-
sourceChannel: ChannelId;
|
|
53
|
-
}): void;
|
|
46
|
+
setTrustContext?(ctx: TrustContext): void;
|
|
54
47
|
},
|
|
55
48
|
actorPrincipalId: string | undefined,
|
|
56
|
-
): void {
|
|
49
|
+
): Promise<void> {
|
|
57
50
|
if (!conversation.setTrustContext) return;
|
|
58
51
|
|
|
59
52
|
const sourceChannel = "vellum";
|
|
60
53
|
|
|
61
|
-
if (actorPrincipalId) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
54
|
+
if (!actorPrincipalId) {
|
|
55
|
+
conversation.setTrustContext({ trustClass: "guardian", sourceChannel });
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Dev-bypass injects a synthetic principal that won't match the real
|
|
60
|
+
// guardian binding, so resolve the actual guardian principalId (gateway
|
|
61
|
+
// first, local store fallback) before mapping trust.
|
|
62
|
+
let principalId = actorPrincipalId;
|
|
63
|
+
if (isHttpAuthDisabled() && actorPrincipalId === "dev-bypass") {
|
|
64
|
+
principalId = (await findLocalGuardianPrincipalId()) ?? actorPrincipalId;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let trustCtx = await resolveLocalPrincipalTrustContext({
|
|
68
|
+
actorPrincipalId: principalId,
|
|
69
|
+
sourceChannel,
|
|
70
|
+
conversationExternalId: "local",
|
|
71
|
+
});
|
|
72
|
+
if (trustCtx.trustClass === "unknown") {
|
|
73
|
+
const healed = await reResolveTrustOnResetDrift(principalId, sourceChannel);
|
|
74
|
+
if (healed) {
|
|
75
|
+
trustCtx = healed;
|
|
76
|
+
if (healed.trustClass !== "unknown") {
|
|
77
|
+
log.info(
|
|
78
|
+
{ actorPrincipalId: principalId, trustClass: trustCtx.trustClass },
|
|
79
|
+
"Trust re-resolved from local mirror after gateway reset drift (surface action)",
|
|
80
|
+
);
|
|
89
81
|
}
|
|
90
|
-
conversation.setTrustContext(withSourceChannel(sourceChannel, trustCtx));
|
|
91
82
|
}
|
|
92
|
-
} else {
|
|
93
|
-
conversation.setTrustContext({ trustClass: "guardian", sourceChannel });
|
|
94
83
|
}
|
|
84
|
+
conversation.setTrustContext(trustCtx);
|
|
95
85
|
}
|
|
96
86
|
|
|
97
87
|
// ---------------------------------------------------------------------------
|
|
@@ -129,16 +119,15 @@ async function handleSurfaceAction({
|
|
|
129
119
|
const aprDecision = parseCallbackData(actionId, "vellum");
|
|
130
120
|
if (aprDecision) {
|
|
131
121
|
// Resolve the actor's guardian principal ID. In dev mode the synthetic
|
|
132
|
-
// "dev-bypass" principal won't match the real guardian binding, so
|
|
133
|
-
//
|
|
122
|
+
// "dev-bypass" principal won't match the real guardian binding, so resolve
|
|
123
|
+
// the local guardian principal — mirrors guardian-action-routes.ts.
|
|
134
124
|
let guardianPrincipalId: string | undefined =
|
|
135
125
|
headers?.["x-vellum-actor-principal-id"] ?? undefined;
|
|
136
126
|
if (
|
|
137
127
|
isHttpAuthDisabled() &&
|
|
138
128
|
headers?.["x-vellum-actor-principal-id"] === "dev-bypass"
|
|
139
129
|
) {
|
|
140
|
-
|
|
141
|
-
guardianPrincipalId = binding?.contact.principalId ?? undefined;
|
|
130
|
+
guardianPrincipalId = (await findLocalGuardianPrincipalId()) ?? undefined;
|
|
142
131
|
}
|
|
143
132
|
|
|
144
133
|
const result = await processGuardianDecision({
|
|
@@ -186,13 +175,20 @@ async function handleSurfaceAction({
|
|
|
186
175
|
}
|
|
187
176
|
|
|
188
177
|
const actorPrincipalId = headers?.["x-vellum-actor-principal-id"];
|
|
189
|
-
applyTrustContext(conversation, actorPrincipalId);
|
|
178
|
+
await applyTrustContext(conversation, actorPrincipalId);
|
|
179
|
+
|
|
180
|
+
// Translate dev-bypass → real guardian so the surface turn's principal matches
|
|
181
|
+
// the SSE host-proxy client's registered principal; otherwise CU/app-control
|
|
182
|
+
// same-actor checks reject the turn. Real principals pass through unchanged.
|
|
183
|
+
const resolvedActorPrincipalId =
|
|
184
|
+
await resolveActorPrincipalIdForLocalGuardian(actorPrincipalId ?? undefined);
|
|
190
185
|
|
|
191
186
|
try {
|
|
192
187
|
const raw = await conversation.handleSurfaceAction(
|
|
193
188
|
surfaceId,
|
|
194
189
|
actionId,
|
|
195
190
|
data,
|
|
191
|
+
resolvedActorPrincipalId,
|
|
196
192
|
);
|
|
197
193
|
const result =
|
|
198
194
|
raw && typeof raw === "object" && "accepted" in raw
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
|
|
10
10
|
import { parseChannelId } from "../../channels/types.js";
|
|
11
11
|
import { getConfig } from "../../config/loader.js";
|
|
12
|
-
import { findConversation } from "../../daemon/conversation-registry.js";
|
|
13
12
|
import { normalizeConversationType } from "../../daemon/message-types/shared.js";
|
|
14
13
|
import {
|
|
15
14
|
type AttentionState,
|
|
@@ -21,6 +20,7 @@ import {
|
|
|
21
20
|
type ConversationRow,
|
|
22
21
|
getConversation,
|
|
23
22
|
getDisplayMetaForConversations,
|
|
23
|
+
isConversationProcessing,
|
|
24
24
|
} from "../../memory/conversation-crud.js";
|
|
25
25
|
import type { ExternalConversationBinding } from "../../memory/external-conversation-store.js";
|
|
26
26
|
import { getBindingsForConversations } from "../../memory/external-conversation-store.js";
|
|
@@ -196,9 +196,9 @@ export function serializeConversationSummary(params: {
|
|
|
196
196
|
parentCache: Map<string, ConversationRow | null>;
|
|
197
197
|
/**
|
|
198
198
|
* Whether the agent loop is currently mid-turn for this conversation.
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
199
|
+
* Resolved by `isConversationProcessing(id)`, which checks the in-memory
|
|
200
|
+
* daemon flag first and falls back to the persisted
|
|
201
|
+
* `processing_started_at` column for cold conversations. Plumbed in
|
|
202
202
|
* rather than read here so the serializer stays a pure shape mapper
|
|
203
203
|
* with no daemon-store coupling.
|
|
204
204
|
*/
|
|
@@ -286,11 +286,9 @@ export function buildConversationDetailResponse(
|
|
|
286
286
|
attentionState: attentionStates.get(conversation.id),
|
|
287
287
|
displayMeta: displayMeta.get(conversation.id),
|
|
288
288
|
parentCache,
|
|
289
|
-
//
|
|
290
|
-
//
|
|
291
|
-
|
|
292
|
-
// mid-turn since the agent loop only runs on resident convs.
|
|
293
|
-
isProcessing: findConversation(conversation.id)?.isProcessing() ?? false,
|
|
289
|
+
// Checks in-memory flag first (hot path), falls back to the
|
|
290
|
+
// persisted `processing_started_at` column for cold conversations.
|
|
291
|
+
isProcessing: isConversationProcessing(conversation.id),
|
|
294
292
|
}),
|
|
295
293
|
};
|
|
296
294
|
}
|
|
@@ -59,9 +59,9 @@ export type ToolGrantRequestResult =
|
|
|
59
59
|
* Returns a result indicating whether a new request was created, an existing
|
|
60
60
|
* one was deduped, or the escalation failed (no binding, missing identity).
|
|
61
61
|
*/
|
|
62
|
-
export function createOrReuseToolGrantRequest(
|
|
62
|
+
export async function createOrReuseToolGrantRequest(
|
|
63
63
|
params: ToolGrantRequestParams,
|
|
64
|
-
): ToolGrantRequestResult {
|
|
64
|
+
): Promise<ToolGrantRequestResult> {
|
|
65
65
|
const {
|
|
66
66
|
assistantId,
|
|
67
67
|
sourceChannel,
|
|
@@ -78,7 +78,7 @@ export function createOrReuseToolGrantRequest(
|
|
|
78
78
|
return { failed: true, reason: "missing_identity" };
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
const binding = getGuardianBinding(assistantId, sourceChannel);
|
|
81
|
+
const binding = await getGuardianBinding(assistantId, sourceChannel);
|
|
82
82
|
if (!binding) {
|
|
83
83
|
log.debug(
|
|
84
84
|
{ sourceChannel, assistantId },
|