@vellumai/assistant 0.10.2 → 0.10.3-dev.202606252046.9075fd5
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 +20 -0
- 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/gateway-ipc-contracts.ts +44 -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/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +28 -0
- package/node_modules/@vellumai/service-contracts/src/channels.ts +41 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/openapi.yaml +196 -56
- package/package.json +4 -1
- package/scripts/test.sh +36 -15
- package/src/__tests__/actor-token-service.test.ts +36 -14
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +83 -31
- 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__/assistant-attachments.test.ts +42 -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-approval-routes.test.ts +21 -26
- package/src/__tests__/channel-delivery-store.test.ts +28 -0
- package/src/__tests__/channel-guardian.test.ts +164 -78
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +11 -19
- package/src/__tests__/channel-reply-delivery.test.ts +2 -0
- package/src/__tests__/code-search-tool.test.ts +585 -0
- package/src/__tests__/compaction-events.test.ts +2 -0
- package/src/__tests__/compaction-ledger-store.test.ts +128 -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__/config-loader-backfill.test.ts +123 -10
- package/src/__tests__/config-schema.test.ts +1 -0
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +31 -29
- package/src/__tests__/consult-deadline.test.ts +60 -0
- package/src/__tests__/contact-store-interaction-info.test.ts +156 -0
- package/src/__tests__/contact-store-user-file.test.ts +7 -10
- package/src/__tests__/contacts-relay-reads.test.ts +19 -24
- package/src/__tests__/contacts-write.test.ts +0 -2
- 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 +134 -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-attention-telegram.test.ts +9 -11
- package/src/__tests__/conversation-confirmation-signals.test.ts +2 -0
- package/src/__tests__/conversation-fork-crud.test.ts +354 -24
- 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-task-progress.test.ts +29 -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 +1 -1
- package/src/__tests__/db-compaction-events-migration.test.ts +129 -0
- package/src/__tests__/db-migration-rollback.test.ts +205 -171
- package/src/__tests__/db-test-helpers.ts +5 -4
- package/src/__tests__/delete-propagation.test.ts +5 -3
- 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-backfill.test.ts +6 -4
- package/src/__tests__/dm-persistence.test.ts +2 -0
- package/src/__tests__/emit-signal-routing-intent.test.ts +7 -6
- package/src/__tests__/events-dev-bypass-actor.test.ts +7 -1
- package/src/__tests__/exploration-drift-hook.test.ts +3 -2
- package/src/__tests__/filing-service.test.ts +2 -0
- package/src/__tests__/guardian-binding-drift-heal.test.ts +104 -19
- package/src/__tests__/guardian-dispatch.test.ts +140 -1
- package/src/__tests__/guardian-expiry-notifier.test.ts +282 -0
- package/src/__tests__/guardian-outbound-http.test.ts +13 -0
- package/src/__tests__/guardian-routing-state.test.ts +6 -10
- 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 +46 -19
- package/src/__tests__/helpers/create-guardian-binding.ts +15 -23
- package/src/__tests__/helpers/mock-logger.ts +1 -0
- package/src/__tests__/helpers/seed-contact-channel.ts +96 -0
- 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-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 +290 -8
- package/src/__tests__/inbound-invite-redemption.test.ts +115 -10
- package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/invite-redemption-service.test.ts +471 -53
- package/src/__tests__/invite-routes-http.test.ts +34 -0
- package/src/__tests__/invite-service-ipc.test.ts +65 -2
- package/src/__tests__/llm-context-normalization.test.ts +105 -0
- package/src/__tests__/llm-request-log-error-payload.test.ts +71 -9
- package/src/__tests__/llm-usage-store.test.ts +25 -0
- package/src/__tests__/mcp-config-secret-boundary.test.ts +392 -0
- package/src/__tests__/mcp-health-check.test.ts +2 -1
- 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__/mtime-cache.test.ts +275 -5
- package/src/__tests__/native-web-search.test.ts +2 -0
- package/src/__tests__/non-member-access-request.test.ts +191 -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__/onboarding-persona-write.test.ts +52 -22
- package/src/__tests__/openai-provider.test.ts +22 -12
- package/src/__tests__/openai-responses-provider.test.ts +12 -2
- package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/pending-interactions-resolved-event.test.ts +7 -4
- package/src/__tests__/persist-onboarding-artifacts.test.ts +1 -0
- package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
- package/src/__tests__/persona-resolver.test.ts +75 -45
- package/src/__tests__/plugin-bootstrap.test.ts +21 -83
- package/src/__tests__/plugin-disabled-state.test.ts +190 -0
- package/src/__tests__/plugin-pipeline.test.ts +96 -0
- package/src/__tests__/plugin-route-contribution.test.ts +6 -19
- package/src/__tests__/plugin-tool-contribution.test.ts +5 -20
- package/src/__tests__/plugin-types.test.ts +2 -4
- 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-error-scenarios.test.ts +5 -4
- package/src/__tests__/provider-usage-tracking.test.ts +39 -0
- package/src/__tests__/reaction-intercept-cold-cache-warm.test.ts +135 -0
- package/src/__tests__/reaction-intercept-member-verdict-warm.test.ts +158 -0
- package/src/__tests__/reaction-persistence.test.ts +51 -4
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +2 -0
- package/src/__tests__/registry.test.ts +4 -1
- package/src/__tests__/relay-server.test.ts +758 -32
- package/src/__tests__/runtime-attachment-metadata.test.ts +9 -12
- package/src/__tests__/secret-ingress-http.test.ts +14 -0
- package/src/__tests__/send-endpoint-busy.test.ts +30 -8
- package/src/__tests__/settings-routes.test.ts +32 -0
- 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 +79 -0
- package/src/__tests__/steer-on-enqueue-question.test.ts +181 -0
- package/src/__tests__/stt-hints.test.ts +49 -15
- package/src/__tests__/subagent-detail.test.ts +27 -0
- package/src/__tests__/subagent-disposal.test.ts +65 -0
- package/src/__tests__/subagent-fork-prompt-role.test.ts +195 -0
- package/src/__tests__/subagent-fork-spawn.test.ts +6 -7
- package/src/__tests__/subagent-notify-parent.test.ts +2 -0
- package/src/__tests__/subagent-role-registry.test.ts +24 -6
- package/src/__tests__/subagent-spawn-and-await.test.ts +546 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +2 -0
- package/src/__tests__/subagent-tools.test.ts +398 -1
- package/src/__tests__/suggestion-routes.test.ts +2 -0
- package/src/__tests__/thread-backfill.test.ts +3 -3
- 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-approval-notifier.test.ts +37 -51
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +12 -12
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +9 -7
- package/src/__tests__/trusted-contact-multichannel.test.ts +16 -7
- package/src/__tests__/trusted-contact-verification.test.ts +79 -54
- package/src/__tests__/twilio-routes.test.ts +96 -0
- package/src/__tests__/ui-file-upload-surface.test.ts +86 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -0
- package/src/__tests__/voice-guardian-cold-cache-warm.test.ts +137 -0
- package/src/__tests__/voice-invite-redemption.test.ts +216 -20
- package/src/__tests__/web-search-backend-failure.test.ts +2 -0
- package/src/__tests__/workspace-migration-102-preserve-heartbeat-enabled-for-existing-workspaces.test.ts +3 -3
- package/src/__tests__/workspace-migration-111-prune-seeded-callsite-defaults.test.ts +208 -0
- package/src/__tests__/workspace-migration-112-remove-advisor-callsite-override.test.ts +170 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +196 -238
- package/src/__tests__/workspace-migration-remove-hooks.test.ts +14 -35
- package/src/__tests__/workspace-tool-loader.test.ts +195 -2
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +35 -47
- package/src/agent/loop-exclusive-tool.test.ts +154 -0
- package/src/agent/loop-native-web-search.test.ts +200 -0
- package/src/agent/loop.ts +164 -1
- package/src/api/constants/sse-replay.ts +41 -0
- package/src/api/events/conversation-notice.ts +26 -0
- package/src/api/index.ts +19 -1
- package/src/api/responses/llm-request-log-entry.ts +29 -0
- package/src/api/responses/subagent-detail.ts +17 -0
- package/src/api/surfaces.ts +39 -3
- package/src/approvals/guardian-channel-delivery.ts +30 -0
- package/src/approvals/guardian-expiry-notifier.ts +148 -0
- package/src/approvals/guardian-request-resolvers.ts +17 -15
- package/src/calls/__tests__/relay-setup-router.test.ts +267 -17
- package/src/calls/call-domain.ts +3 -3
- package/src/calls/guardian-dispatch.ts +14 -9
- package/src/calls/inbound-trust-reader.ts +24 -2
- package/src/calls/media-stream-server.ts +21 -0
- package/src/calls/relay-access-wait.ts +6 -6
- package/src/calls/relay-server.ts +188 -51
- package/src/calls/relay-setup-router.ts +47 -17
- 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/channels/types.ts +10 -20
- package/src/cli/commands/__tests__/cache.test.ts +8 -1
- package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -0
- package/src/cli/commands/cache.ts +194 -181
- package/src/cli/commands/contacts.ts +10 -7
- 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 +432 -0
- package/src/cli/commands/memory/index.ts +2 -0
- package/src/cli/commands/memory/worker.ts +242 -0
- package/src/cli/commands/plugins.ts +125 -13
- 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/__tests__/publish-plugin.test.ts +404 -0
- package/src/cli/lib/list-installed-plugins.ts +179 -1
- package/src/cli/lib/publish-plugin.ts +633 -0
- package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +143 -0
- package/src/config/__tests__/sync-gated-profiles.test.ts +16 -10
- 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/bundled-skills/subagent/SKILL.md +17 -2
- package/src/config/bundled-skills/subagent/TOOLS.json +5 -4
- package/src/config/call-site-defaults.ts +0 -6
- package/src/config/feature-flag-registry.json +5 -13
- package/src/config/llm-resolver.ts +0 -3
- package/src/config/loader.ts +38 -5
- package/src/config/prune-seeded-callsite-defaults.ts +110 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
- package/src/config/schemas/call-site-catalog.ts +0 -7
- package/src/config/schemas/heartbeat.ts +2 -5
- package/src/config/schemas/llm.ts +3 -12
- 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 +30 -34
- package/src/config/skills.ts +27 -5
- package/src/config/sync-gated-profiles.ts +12 -16
- package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +128 -0
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +312 -0
- package/src/contacts/__tests__/member-write-relay.test.ts +226 -0
- package/src/contacts/contact-store.ts +27 -237
- package/src/contacts/contacts-write.ts +18 -55
- package/src/contacts/gateway-channel-read.ts +51 -0
- package/src/contacts/guardian-delivery-reader.ts +223 -0
- package/src/contacts/member-write-relay.ts +183 -0
- package/src/contacts/types.ts +3 -15
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +35 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +0 -44
- package/src/daemon/assistant-attachments.ts +27 -4
- package/src/daemon/conversation-agent-loop.ts +28 -0
- package/src/daemon/conversation-notices.ts +60 -0
- package/src/daemon/conversation-process.ts +35 -16
- package/src/daemon/conversation-surfaces.ts +111 -38
- package/src/daemon/conversation-tool-setup.ts +71 -30
- package/src/daemon/conversation.ts +23 -1
- 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 +17 -41
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +0 -1
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +0 -2
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +25 -2
- package/src/daemon/handlers/__tests__/config-channels.test.ts +220 -0
- package/src/daemon/handlers/config-a2a.ts +6 -14
- package/src/daemon/handlers/config-channels.ts +67 -26
- package/src/daemon/handlers/conversations.ts +77 -0
- package/src/daemon/lifecycle.ts +16 -0
- package/src/daemon/mcp-reload-service.ts +10 -0
- package/src/daemon/memory-v2-startup.test.ts +72 -0
- package/src/daemon/memory-v2-startup.ts +87 -19
- package/src/daemon/message-types/conversations.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +12 -12
- 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/heartbeat/heartbeat-service.ts +5 -0
- package/src/home/relationship-state-writer.ts +5 -0
- package/src/hooks/hook-loader.ts +341 -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 +1 -0
- package/src/mcp/client.ts +15 -1
- package/src/mcp/mcp-auth-orchestrator.ts +6 -1
- package/src/mcp/mcp-header-store.ts +134 -0
- package/src/mcp/mcp-oauth-provider.ts +19 -8
- 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/compaction-ledger-store.ts +107 -0
- package/src/memory/conversation-crud.ts +129 -61
- package/src/memory/db-connection.ts +22 -3
- package/src/memory/db-init.ts +37 -503
- package/src/memory/db-singleton.ts +6 -4
- package/src/memory/jobs-worker.ts +104 -0
- package/src/memory/llm-request-log-store.ts +26 -1
- package/src/memory/llm-usage-store.ts +48 -20
- package/src/memory/memory-retrospective-job.ts +14 -8
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +152 -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/302-create-compaction-events.ts +107 -0
- package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +297 -0
- package/src/memory/migrations/__tests__/run-migrations.test.ts +2 -2
- package/src/memory/migrations/run-migrations.ts +106 -10
- package/src/memory/migrations/validate-migration-state.ts +105 -67
- package/src/memory/prompt-override.ts +129 -0
- package/src/memory/schema/contacts.ts +6 -2
- package/src/memory/schema/conversations.ts +37 -0
- package/src/memory/schema/infrastructure.ts +20 -0
- package/src/memory/steps.ts +1294 -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 +204 -0
- package/src/memory/worker-process.ts +89 -0
- package/src/messaging/channel-binding-metadata.ts +31 -0
- package/src/messaging/provider-types.ts +8 -0
- package/src/messaging/providers/slack/binding-metadata.ts +60 -0
- package/src/notifications/__tests__/broadcaster.test.ts +8 -8
- package/src/notifications/__tests__/connected-channels.test.ts +86 -0
- package/src/notifications/__tests__/decision-engine.test.ts +78 -9
- package/src/notifications/__tests__/destination-resolver.test.ts +151 -0
- package/src/notifications/broadcaster.ts +8 -1
- package/src/notifications/decision-engine.ts +15 -7
- package/src/notifications/destination-resolver.ts +53 -25
- package/src/notifications/emit-signal.ts +34 -15
- package/src/onboarding/checkin-event.test.ts +222 -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 +12 -12
- package/src/plugin-api/types.ts +12 -14
- package/src/plugin-api/vision-support.test.ts +28 -4
- package/src/plugin-api/vision-support.ts +66 -31
- package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +2 -2
- package/src/plugins/defaults/empty-response/hooks/stop.ts +2 -2
- package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +4 -3
- package/src/plugins/defaults/history-repair/hooks/post-model-call.ts +2 -2
- package/src/plugins/defaults/history-repair/hooks/stop.ts +2 -2
- package/src/plugins/defaults/history-repair/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +47 -7
- package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +12 -13
- package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +14 -22
- package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +42 -11
- package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +2 -2
- package/src/plugins/defaults/image-recovery/hooks/stop.ts +2 -2
- package/src/plugins/defaults/index.ts +0 -35
- package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +2 -2
- package/src/plugins/defaults/max-tokens-continue/hooks/stop.ts +2 -2
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +2 -2
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +33 -3
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +48 -4
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +4 -8
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +43 -15
- 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 +77 -13
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +12 -11
- package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +2 -2
- package/src/plugins/defaults/surface-completion-nudge/hooks/stop.ts +2 -2
- package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +2 -2
- package/src/plugins/defaults/title-generate/hooks/stop.ts +2 -2
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +2 -2
- package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +2 -2
- package/src/plugins/disabled-state.ts +31 -0
- package/src/plugins/external-plugin-loader.ts +2 -2
- package/src/plugins/mtime-cache.ts +186 -330
- package/src/plugins/pipeline.ts +111 -13
- package/src/plugins/registry.ts +59 -16
- package/src/plugins/surface-import.ts +121 -0
- package/src/plugins/types.ts +7 -9
- package/src/prompts/persona-resolver.ts +43 -11
- package/src/providers/anthropic/client.ts +5 -0
- package/src/providers/call-site-routing.ts +45 -0
- package/src/providers/model-catalog.ts +16 -0
- package/src/providers/openai/__tests__/api-error-normalization.test.ts +321 -0
- package/src/providers/openai/api-error-normalization.ts +270 -0
- package/src/providers/openai/chat-completions-provider.ts +37 -83
- package/src/providers/openai/responses-provider.ts +50 -46
- package/src/providers/openrouter/client.ts +5 -0
- package/src/providers/provider-send-message.ts +10 -0
- package/src/providers/ratelimit.ts +10 -0
- package/src/providers/registry.ts +1 -1
- package/src/providers/retry.ts +10 -0
- package/src/providers/types.ts +22 -0
- package/src/providers/usage-tracking.ts +10 -0
- package/src/runtime/__tests__/channel-verification-service.test.ts +133 -0
- package/src/runtime/__tests__/guardian-vellum-migration.test.ts +184 -0
- package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +66 -0
- package/src/runtime/__tests__/local-principal-trust.test.ts +162 -0
- package/src/runtime/__tests__/member-verdict-cache.test.ts +119 -0
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +402 -123
- package/src/runtime/access-request-helper.ts +18 -39
- package/src/runtime/actor-trust-resolver.ts +46 -19
- package/src/runtime/anchored-guardian.test.ts +109 -0
- package/src/runtime/anchored-guardian.ts +86 -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 +69 -8
- package/src/runtime/invite-redemption-service.ts +213 -187
- package/src/runtime/local-actor-identity.test.ts +108 -0
- package/src/runtime/local-actor-identity.ts +85 -13
- package/src/runtime/local-principal-trust.ts +52 -0
- package/src/runtime/member-verdict-cache.ts +0 -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 +305 -0
- package/src/runtime/routes/__tests__/global-search-routes.test.ts +92 -0
- package/src/runtime/routes/__tests__/http-adapter-actor-header.test.ts +129 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +188 -0
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +13 -5
- package/src/runtime/routes/channel-verification-routes.ts +3 -3
- package/src/runtime/routes/contact-routes.ts +48 -57
- 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-query-routes.ts +72 -0
- package/src/runtime/routes/conversation-routes.ts +84 -85
- 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 +16 -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 -59
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +13 -5
- 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/inbound-stages/reaction-intercept.ts +19 -0
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/llm-context-normalization.ts +83 -0
- package/src/runtime/routes/mcp-auth-routes.ts +171 -19
- 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/settings-routes.ts +8 -3
- package/src/runtime/routes/subagents-routes.ts +5 -0
- package/src/runtime/routes/surface-action-routes.ts +42 -56
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
- package/src/runtime/services/conversation-serializer.ts +13 -58
- package/src/runtime/tool-grant-request-helper.ts +3 -3
- package/src/runtime/trust-verdict-consumer.ts +111 -40
- package/src/runtime/verification-outbound-actions.ts +18 -18
- package/src/signals/user-message.ts +16 -0
- package/src/subagent/__tests__/consult-prompt.test.ts +35 -0
- package/src/{plugins/defaults/advisor/__tests__/transcript.test.ts → subagent/__tests__/consult-transcript.test.ts} +47 -10
- package/src/{plugins/defaults/advisor/steering.ts → subagent/consult-prompt.ts} +22 -32
- package/src/{plugins/defaults/advisor/transcript.ts → subagent/consult-transcript.ts} +18 -8
- package/src/subagent/index.ts +1 -1
- package/src/subagent/manager.ts +254 -33
- package/src/subagent/types.ts +11 -4
- 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/executor.ts +4 -4
- package/src/tools/filesystem/search.ts +543 -0
- package/src/tools/registry.ts +38 -0
- package/src/tools/shared/filesystem/path-policy.ts +12 -5
- package/src/tools/subagent/consult-deadline.ts +49 -0
- package/src/tools/subagent/spawn.ts +234 -5
- package/src/tools/tool-approval-handler.ts +1 -1
- package/src/tools/tool-defaults.ts +9 -2
- package/src/tools/tool-manifest.ts +3 -0
- package/src/tools/types.ts +131 -25
- package/src/tools/workspace-tools/loader.ts +348 -244
- package/src/util/errors.ts +26 -1
- package/src/util/logger.ts +9 -0
- package/src/util/platform.ts +19 -0
- package/src/util/telemetry-db-path.ts +24 -0
- package/src/workflows/library.test.ts +140 -0
- package/src/workflows/library.ts +82 -28
- 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/workspace/migrations/031-drop-user-md.ts +232 -148
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +14 -66
- package/src/workspace/migrations/111-prune-seeded-callsite-defaults.ts +134 -0
- package/src/workspace/migrations/112-remove-advisor-callsite-override.ts +64 -0
- package/src/workspace/migrations/registry.ts +4 -0
- 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
- package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +0 -56
- package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +0 -43
- package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +0 -137
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +0 -153
- package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +0 -138
- package/src/plugins/defaults/advisor/advisor-gate.ts +0 -29
- package/src/plugins/defaults/advisor/advisor-state-store.ts +0 -94
- package/src/plugins/defaults/advisor/config.ts +0 -21
- package/src/plugins/defaults/advisor/consult.ts +0 -93
- package/src/plugins/defaults/advisor/hooks/post-model-call.ts +0 -34
- package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +0 -30
- package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +0 -19
- package/src/plugins/defaults/advisor/package.json +0 -14
- package/src/plugins/defaults/advisor/tools/advisor.ts +0 -65
- package/src/providers/openai/__tests__/api-error-detail.test.ts +0 -120
|
@@ -8,8 +8,6 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { parseChannelId } from "../../channels/types.js";
|
|
11
|
-
import { getConfig } from "../../config/loader.js";
|
|
12
|
-
import { findConversation } from "../../daemon/conversation-registry.js";
|
|
13
11
|
import { normalizeConversationType } from "../../daemon/message-types/shared.js";
|
|
14
12
|
import {
|
|
15
13
|
type AttentionState,
|
|
@@ -21,13 +19,11 @@ import {
|
|
|
21
19
|
type ConversationRow,
|
|
22
20
|
getConversation,
|
|
23
21
|
getDisplayMetaForConversations,
|
|
22
|
+
isConversationProcessing,
|
|
24
23
|
} from "../../memory/conversation-crud.js";
|
|
25
24
|
import type { ExternalConversationBinding } from "../../memory/external-conversation-store.js";
|
|
26
25
|
import { getBindingsForConversations } from "../../memory/external-conversation-store.js";
|
|
27
|
-
import {
|
|
28
|
-
buildSlackMessageDeepLinks,
|
|
29
|
-
buildSlackWebChannelUrl,
|
|
30
|
-
} from "../../messaging/providers/slack/deep-link.js";
|
|
26
|
+
import { buildChannelBindingMetadata } from "../../messaging/channel-binding-metadata.js";
|
|
31
27
|
|
|
32
28
|
// ---------------------------------------------------------------------------
|
|
33
29
|
// Helpers
|
|
@@ -126,48 +122,7 @@ function resolveSerializedGroupId(
|
|
|
126
122
|
}
|
|
127
123
|
|
|
128
124
|
function buildChannelBinding(binding: ExternalConversationBinding) {
|
|
129
|
-
const externalChatName =
|
|
130
|
-
binding.externalChatName?.trim() ||
|
|
131
|
-
(binding.sourceChannel === "slack" ? binding.externalChatId : undefined);
|
|
132
|
-
const slackConfig =
|
|
133
|
-
binding.sourceChannel === "slack" ? getConfig().slack : undefined;
|
|
134
|
-
const slackThreadLink =
|
|
135
|
-
slackConfig && binding.externalThreadId
|
|
136
|
-
? buildSlackMessageDeepLinks({
|
|
137
|
-
teamId: slackConfig.teamId,
|
|
138
|
-
teamUrl: slackConfig.teamUrl,
|
|
139
|
-
channelId: binding.externalChatId,
|
|
140
|
-
messageTs: binding.externalThreadId,
|
|
141
|
-
})
|
|
142
|
-
: undefined;
|
|
143
|
-
const slackThread =
|
|
144
|
-
binding.sourceChannel === "slack" && binding.externalThreadId
|
|
145
|
-
? {
|
|
146
|
-
channelId: binding.externalChatId,
|
|
147
|
-
threadTs: binding.externalThreadId,
|
|
148
|
-
...(slackThreadLink ? { link: slackThreadLink } : {}),
|
|
149
|
-
}
|
|
150
|
-
: undefined;
|
|
151
|
-
const slackChannelWebUrl = slackConfig
|
|
152
|
-
? buildSlackWebChannelUrl({
|
|
153
|
-
teamUrl: slackConfig.teamUrl,
|
|
154
|
-
channelId: binding.externalChatId,
|
|
155
|
-
})
|
|
156
|
-
: undefined;
|
|
157
|
-
const slackChannel =
|
|
158
|
-
binding.sourceChannel === "slack"
|
|
159
|
-
? {
|
|
160
|
-
channelId: binding.externalChatId,
|
|
161
|
-
name: externalChatName,
|
|
162
|
-
...(slackChannelWebUrl
|
|
163
|
-
? {
|
|
164
|
-
link: {
|
|
165
|
-
webUrl: slackChannelWebUrl,
|
|
166
|
-
},
|
|
167
|
-
}
|
|
168
|
-
: {}),
|
|
169
|
-
}
|
|
170
|
-
: undefined;
|
|
125
|
+
const externalChatName = binding.externalChatName?.trim() || undefined;
|
|
171
126
|
|
|
172
127
|
return {
|
|
173
128
|
sourceChannel: binding.sourceChannel,
|
|
@@ -179,8 +134,10 @@ function buildChannelBinding(binding: ExternalConversationBinding) {
|
|
|
179
134
|
externalUserId: binding.externalUserId,
|
|
180
135
|
displayName: binding.displayName,
|
|
181
136
|
username: binding.username,
|
|
182
|
-
|
|
183
|
-
|
|
137
|
+
// Channel-specific enrichment (e.g. Slack deep links) is contributed by
|
|
138
|
+
// the source channel's binding-metadata builder, keeping this serializer
|
|
139
|
+
// channel-agnostic.
|
|
140
|
+
...buildChannelBindingMetadata(binding),
|
|
184
141
|
};
|
|
185
142
|
}
|
|
186
143
|
|
|
@@ -196,9 +153,9 @@ export function serializeConversationSummary(params: {
|
|
|
196
153
|
parentCache: Map<string, ConversationRow | null>;
|
|
197
154
|
/**
|
|
198
155
|
* Whether the agent loop is currently mid-turn for this conversation.
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
156
|
+
* Resolved by `isConversationProcessing(id)`, which checks the in-memory
|
|
157
|
+
* daemon flag first and falls back to the persisted
|
|
158
|
+
* `processing_started_at` column for cold conversations. Plumbed in
|
|
202
159
|
* rather than read here so the serializer stays a pure shape mapper
|
|
203
160
|
* with no daemon-store coupling.
|
|
204
161
|
*/
|
|
@@ -286,11 +243,9 @@ export function buildConversationDetailResponse(
|
|
|
286
243
|
attentionState: attentionStates.get(conversation.id),
|
|
287
244
|
displayMeta: displayMeta.get(conversation.id),
|
|
288
245
|
parentCache,
|
|
289
|
-
//
|
|
290
|
-
//
|
|
291
|
-
|
|
292
|
-
// mid-turn since the agent loop only runs on resident convs.
|
|
293
|
-
isProcessing: findConversation(conversation.id)?.isProcessing() ?? false,
|
|
246
|
+
// Checks in-memory flag first (hot path), falls back to the
|
|
247
|
+
// persisted `processing_started_at` column for cold conversations.
|
|
248
|
+
isProcessing: isConversationProcessing(conversation.id),
|
|
294
249
|
}),
|
|
295
250
|
};
|
|
296
251
|
}
|
|
@@ -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 },
|
|
@@ -4,10 +4,9 @@
|
|
|
4
4
|
*
|
|
5
5
|
* The gateway resolves a per-actor verdict from its ACL DB and stamps it onto
|
|
6
6
|
* inbound `sourceMetadata`. These pure mappers turn that verdict into the same
|
|
7
|
-
* {@link TrustContext}
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* locally by contactId.
|
|
7
|
+
* {@link TrustContext} the local resolver would have produced — ACL + identity
|
|
8
|
+
* only. INFO fields (notes, userFile, contactType, interactionCount) are never
|
|
9
|
+
* carried on the wire; the consumer re-joins them locally by contactId.
|
|
11
10
|
*/
|
|
12
11
|
|
|
13
12
|
import type { TrustVerdict } from "@vellumai/gateway-client";
|
|
@@ -18,12 +17,12 @@ import type {
|
|
|
18
17
|
ChannelPolicy,
|
|
19
18
|
ChannelStatus,
|
|
20
19
|
ContactChannel,
|
|
20
|
+
ContactRole,
|
|
21
21
|
ContactWithChannels,
|
|
22
22
|
} from "../contacts/types.js";
|
|
23
23
|
import type { TrustContext } from "../daemon/trust-context.js";
|
|
24
24
|
import type { ActorTrustContext } from "./actor-trust-resolver.js";
|
|
25
25
|
import { toTrustContext } from "./actor-trust-resolver.js";
|
|
26
|
-
import type { ResolvedMember } from "./routes/inbound-stages/acl-enforcement.js";
|
|
27
26
|
|
|
28
27
|
export interface TrustVerdictTransport {
|
|
29
28
|
sourceChannel: ChannelId;
|
|
@@ -33,16 +32,17 @@ export interface TrustVerdictTransport {
|
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
/**
|
|
36
|
-
*
|
|
35
|
+
* Reassemble an {@link ActorTrustContext} from a gateway verdict + transport
|
|
36
|
+
* identity (mirroring `resolveActorTrust`), without any local DB/IPC reads.
|
|
37
37
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
38
|
+
* Pure: the voice path consumes this directly for routing on
|
|
39
|
+
* `actorTrust.trustClass`; {@link trustContextFromVerdict} routes it through
|
|
40
|
+
* {@link toTrustContext}.
|
|
41
41
|
*/
|
|
42
|
-
export function
|
|
42
|
+
export function actorTrustContextFromVerdict(
|
|
43
43
|
verdict: TrustVerdict,
|
|
44
44
|
input: TrustVerdictTransport,
|
|
45
|
-
):
|
|
45
|
+
): ActorTrustContext {
|
|
46
46
|
const canonicalSenderId = verdict.canonicalSenderId;
|
|
47
47
|
const memberDisplayName = verdict.memberDisplayName;
|
|
48
48
|
const senderDisplayName = input.actorDisplayName;
|
|
@@ -51,7 +51,7 @@ export function trustContextFromVerdict(
|
|
|
51
51
|
? `@${username}`
|
|
52
52
|
: (canonicalSenderId ?? undefined);
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
return {
|
|
55
55
|
canonicalSenderId,
|
|
56
56
|
guardianBindingMatch: verdict.guardianExternalUserId
|
|
57
57
|
? {
|
|
@@ -60,7 +60,12 @@ export function trustContextFromVerdict(
|
|
|
60
60
|
}
|
|
61
61
|
: null,
|
|
62
62
|
guardianPrincipalId: verdict.guardianPrincipalId,
|
|
63
|
-
|
|
63
|
+
// Populate from the verdict so the voice path's ACL gates (which read
|
|
64
|
+
// actorTrust.memberRecord.channel status/policy) enforce blocked/revoked/
|
|
65
|
+
// deny/escalate. Null for memberless verdicts. Text path is unaffected:
|
|
66
|
+
// toTrustContext derives the same member fields trustContextFromVerdict
|
|
67
|
+
// already stamps.
|
|
68
|
+
memberRecord: memberRecordFromVerdict(verdict),
|
|
64
69
|
trustClass: verdict.trustClass,
|
|
65
70
|
actorMetadata: {
|
|
66
71
|
identifier,
|
|
@@ -72,25 +77,57 @@ export function trustContextFromVerdict(
|
|
|
72
77
|
trustStatus: verdict.trustClass,
|
|
73
78
|
},
|
|
74
79
|
};
|
|
80
|
+
}
|
|
75
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Build a {@link TrustContext} from a gateway verdict + transport identity.
|
|
84
|
+
*
|
|
85
|
+
* Reassembles an {@link ActorTrustContext} (mirroring `resolveActorTrust`) and
|
|
86
|
+
* routes it through {@link toTrustContext}, so the output is byte-identical to
|
|
87
|
+
* the local resolution path.
|
|
88
|
+
*/
|
|
89
|
+
export function trustContextFromVerdict(
|
|
90
|
+
verdict: TrustVerdict,
|
|
91
|
+
input: TrustVerdictTransport,
|
|
92
|
+
): TrustContext {
|
|
76
93
|
const context = toTrustContext(
|
|
77
|
-
|
|
94
|
+
actorTrustContextFromVerdict(verdict, input),
|
|
78
95
|
input.conversationExternalId,
|
|
79
96
|
);
|
|
80
97
|
|
|
81
98
|
// Stamp the verdict's ACL member fields onto the context so downstream turn
|
|
82
99
|
// assembly reads member status/policy from the verdict rather than a local
|
|
83
100
|
// re-resolution. The contact ID anchors the local info-only join.
|
|
84
|
-
const member =
|
|
101
|
+
const member = verdictMemberFromVerdict(verdict);
|
|
85
102
|
if (member) {
|
|
86
|
-
context.requesterContactId = member.
|
|
87
|
-
context.memberStatus = channelStatusToMemberStatus(member.
|
|
88
|
-
context.memberPolicy = member.
|
|
103
|
+
context.requesterContactId = member.contactId;
|
|
104
|
+
context.memberStatus = channelStatusToMemberStatus(member.status);
|
|
105
|
+
context.memberPolicy = member.policy;
|
|
89
106
|
}
|
|
90
107
|
|
|
91
108
|
return context;
|
|
92
109
|
}
|
|
93
110
|
|
|
111
|
+
/**
|
|
112
|
+
* True when the verdict carries a member identity (contactId or channelId),
|
|
113
|
+
* regardless of whether that member resolves to a usable {@link VerdictMember}.
|
|
114
|
+
*/
|
|
115
|
+
export function verdictHasMemberIdentity(verdict: TrustVerdict): boolean {
|
|
116
|
+
return !!(verdict.contactId || verdict.channelId);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* True when the verdict claims a member identity but that member can't be
|
|
121
|
+
* resolved (partial/mixed-version verdict). Such a verdict is unusable —
|
|
122
|
+
* callers fall back to local resolution.
|
|
123
|
+
*/
|
|
124
|
+
export function verdictMemberUnresolvable(verdict: TrustVerdict): boolean {
|
|
125
|
+
return (
|
|
126
|
+
verdictHasMemberIdentity(verdict) &&
|
|
127
|
+
verdictMemberFromVerdict(verdict) === null
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
94
131
|
// Allowed ACL enum values, kept in sync with the ContactChannel union types.
|
|
95
132
|
const CHANNEL_STATUS_VALUES: readonly ChannelStatus[] = [
|
|
96
133
|
"active",
|
|
@@ -114,38 +151,64 @@ function isChannelPolicy(value: string): value is ChannelPolicy {
|
|
|
114
151
|
}
|
|
115
152
|
|
|
116
153
|
/**
|
|
117
|
-
*
|
|
154
|
+
* The ACL fields a gateway verdict carries for a resolved member, decoupled
|
|
155
|
+
* from the schema-derived {@link ContactChannel}.
|
|
156
|
+
*/
|
|
157
|
+
export interface VerdictMember {
|
|
158
|
+
contactId: string;
|
|
159
|
+
channelId: string;
|
|
160
|
+
status: ChannelStatus;
|
|
161
|
+
policy: ChannelPolicy;
|
|
162
|
+
verifiedAt: number | null;
|
|
163
|
+
displayName: string | null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Extract the narrow {@link VerdictMember} ACL view from a gateway verdict.
|
|
118
168
|
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
169
|
+
* Guards on contactId/channelId presence + known status/policy enums, failing
|
|
170
|
+
* closed to null otherwise.
|
|
121
171
|
*/
|
|
122
|
-
export function
|
|
172
|
+
export function verdictMemberFromVerdict(
|
|
123
173
|
verdict: TrustVerdict,
|
|
124
|
-
):
|
|
174
|
+
): VerdictMember | null {
|
|
125
175
|
if (!verdict.contactId || !verdict.channelId) return null;
|
|
126
|
-
// Member verdict requires valid known status+policy enums, else null
|
|
127
|
-
// (fail-closed): a partial/mixed-version verdict (absent OR
|
|
128
|
-
// present-but-unknown ACL value) must not synthesize an active/allow channel
|
|
129
|
-
// that would skip ingress ACL gates.
|
|
130
176
|
if (!verdict.status || !verdict.policy) return null;
|
|
131
177
|
if (!isChannelStatus(verdict.status) || !isChannelPolicy(verdict.policy)) {
|
|
132
178
|
return null;
|
|
133
179
|
}
|
|
134
180
|
|
|
135
|
-
|
|
136
|
-
id: verdict.channelId,
|
|
181
|
+
return {
|
|
137
182
|
contactId: verdict.contactId,
|
|
183
|
+
channelId: verdict.channelId,
|
|
184
|
+
status: verdict.status,
|
|
185
|
+
policy: verdict.policy,
|
|
186
|
+
verifiedAt: verdict.verifiedAt ?? null,
|
|
187
|
+
displayName: verdict.memberDisplayName ?? null,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Build the voice-path {@link ActorTrustContext.memberRecord} from a gateway
|
|
193
|
+
* verdict's narrow ACL view.
|
|
194
|
+
*
|
|
195
|
+
* ACL + identity only; info fields are placeholders, re-joined locally by
|
|
196
|
+
* contactId. Returns null for memberless/unresolvable verdicts.
|
|
197
|
+
*/
|
|
198
|
+
function memberRecordFromVerdict(
|
|
199
|
+
verdict: TrustVerdict,
|
|
200
|
+
): ActorTrustContext["memberRecord"] {
|
|
201
|
+
const member = verdictMemberFromVerdict(verdict);
|
|
202
|
+
if (!member) return null;
|
|
203
|
+
|
|
204
|
+
const channel: ContactChannel = {
|
|
205
|
+
id: member.channelId,
|
|
206
|
+
contactId: member.contactId,
|
|
138
207
|
type: verdict.type ?? "",
|
|
139
208
|
address: verdict.address ?? "",
|
|
140
209
|
isPrimary: false,
|
|
141
210
|
externalChatId: verdict.externalChatId ?? null,
|
|
142
|
-
status: verdict.status,
|
|
143
|
-
policy: verdict.policy,
|
|
144
|
-
verifiedAt: verdict.verifiedAt ?? null,
|
|
145
|
-
verifiedVia: verdict.verifiedVia ?? null,
|
|
146
211
|
inviteId: null,
|
|
147
|
-
revokedReason: null,
|
|
148
|
-
blockedReason: null,
|
|
149
212
|
lastSeenAt: null,
|
|
150
213
|
interactionCount: 0,
|
|
151
214
|
lastInteraction: null,
|
|
@@ -153,20 +216,28 @@ export function resolvedMemberFromVerdict(
|
|
|
153
216
|
createdAt: 0,
|
|
154
217
|
};
|
|
155
218
|
|
|
219
|
+
const role: ContactRole =
|
|
220
|
+
verdict.trustClass === "guardian" ? "guardian" : "contact";
|
|
221
|
+
|
|
156
222
|
const contact: ContactWithChannels = {
|
|
157
|
-
id:
|
|
158
|
-
displayName:
|
|
223
|
+
id: member.contactId,
|
|
224
|
+
displayName: member.displayName ?? "",
|
|
159
225
|
notes: null,
|
|
226
|
+
role,
|
|
160
227
|
lastInteraction: null,
|
|
161
228
|
interactionCount: 0,
|
|
162
229
|
createdAt: 0,
|
|
163
230
|
updatedAt: 0,
|
|
164
|
-
role: verdict.trustClass === "guardian" ? "guardian" : "contact",
|
|
165
231
|
contactType: "human",
|
|
166
|
-
principalId: verdict.guardianPrincipalId ?? null,
|
|
167
232
|
userFile: null,
|
|
168
233
|
channels: [channel],
|
|
169
234
|
};
|
|
170
235
|
|
|
171
|
-
return {
|
|
236
|
+
return {
|
|
237
|
+
contact,
|
|
238
|
+
channel,
|
|
239
|
+
status: member.status,
|
|
240
|
+
policy: member.policy,
|
|
241
|
+
role,
|
|
242
|
+
};
|
|
172
243
|
}
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
countRecentSendsToDestination,
|
|
22
22
|
createOutboundSession,
|
|
23
23
|
findActiveSession,
|
|
24
|
-
|
|
24
|
+
isGuardianBoundForChannel,
|
|
25
25
|
updateSessionDelivery,
|
|
26
26
|
updateSessionStatus,
|
|
27
27
|
} from "./channel-verification-service.js";
|
|
@@ -224,7 +224,7 @@ export async function startOutbound(
|
|
|
224
224
|
originConversationId,
|
|
225
225
|
);
|
|
226
226
|
} else if (channel === "phone") {
|
|
227
|
-
return startOutboundVoice(
|
|
227
|
+
return await startOutboundVoice(
|
|
228
228
|
params.destination,
|
|
229
229
|
assistantId,
|
|
230
230
|
channel,
|
|
@@ -232,7 +232,7 @@ export async function startOutbound(
|
|
|
232
232
|
originConversationId,
|
|
233
233
|
);
|
|
234
234
|
} else if (channel === "slack") {
|
|
235
|
-
return startOutboundSlack(
|
|
235
|
+
return await startOutboundSlack(
|
|
236
236
|
params.destination,
|
|
237
237
|
assistantId,
|
|
238
238
|
channel,
|
|
@@ -240,7 +240,7 @@ export async function startOutbound(
|
|
|
240
240
|
originConversationId,
|
|
241
241
|
);
|
|
242
242
|
} else if (channel === "email") {
|
|
243
|
-
return startOutboundEmail(
|
|
243
|
+
return await startOutboundEmail(
|
|
244
244
|
params.destination,
|
|
245
245
|
assistantId,
|
|
246
246
|
channel,
|
|
@@ -274,8 +274,8 @@ async function startOutboundTelegram(
|
|
|
274
274
|
};
|
|
275
275
|
}
|
|
276
276
|
|
|
277
|
-
const
|
|
278
|
-
if (
|
|
277
|
+
const alreadyBound = await isGuardianBoundForChannel(channel);
|
|
278
|
+
if (alreadyBound && !rebind) {
|
|
279
279
|
return {
|
|
280
280
|
success: false,
|
|
281
281
|
error: "already_bound",
|
|
@@ -394,13 +394,13 @@ async function startOutboundTelegram(
|
|
|
394
394
|
};
|
|
395
395
|
}
|
|
396
396
|
|
|
397
|
-
function startOutboundVoice(
|
|
397
|
+
async function startOutboundVoice(
|
|
398
398
|
rawDestination: string | undefined,
|
|
399
399
|
assistantId: string,
|
|
400
400
|
channel: ChannelId,
|
|
401
401
|
rebind?: boolean,
|
|
402
402
|
originConversationId?: string,
|
|
403
|
-
): OutboundActionResult {
|
|
403
|
+
): Promise<OutboundActionResult> {
|
|
404
404
|
if (!rawDestination) {
|
|
405
405
|
return {
|
|
406
406
|
success: false,
|
|
@@ -422,8 +422,8 @@ function startOutboundVoice(
|
|
|
422
422
|
};
|
|
423
423
|
}
|
|
424
424
|
|
|
425
|
-
const
|
|
426
|
-
if (
|
|
425
|
+
const alreadyBound = await isGuardianBoundForChannel(channel);
|
|
426
|
+
if (alreadyBound && !rebind) {
|
|
427
427
|
return {
|
|
428
428
|
success: false,
|
|
429
429
|
error: "already_bound",
|
|
@@ -591,13 +591,13 @@ export function deliverVerificationEmail(
|
|
|
591
591
|
})();
|
|
592
592
|
}
|
|
593
593
|
|
|
594
|
-
function startOutboundSlack(
|
|
594
|
+
async function startOutboundSlack(
|
|
595
595
|
destination: string | undefined,
|
|
596
596
|
assistantId: string,
|
|
597
597
|
channel: ChannelId,
|
|
598
598
|
rebind?: boolean,
|
|
599
599
|
originConversationId?: string,
|
|
600
|
-
): OutboundActionResult {
|
|
600
|
+
): Promise<OutboundActionResult> {
|
|
601
601
|
if (!destination) {
|
|
602
602
|
return {
|
|
603
603
|
success: false,
|
|
@@ -607,8 +607,8 @@ function startOutboundSlack(
|
|
|
607
607
|
};
|
|
608
608
|
}
|
|
609
609
|
|
|
610
|
-
const
|
|
611
|
-
if (
|
|
610
|
+
const alreadyBound = await isGuardianBoundForChannel(channel);
|
|
611
|
+
if (alreadyBound && !rebind) {
|
|
612
612
|
return {
|
|
613
613
|
success: false,
|
|
614
614
|
error: "already_bound",
|
|
@@ -669,13 +669,13 @@ function startOutboundSlack(
|
|
|
669
669
|
};
|
|
670
670
|
}
|
|
671
671
|
|
|
672
|
-
function startOutboundEmail(
|
|
672
|
+
async function startOutboundEmail(
|
|
673
673
|
destination: string | undefined,
|
|
674
674
|
assistantId: string,
|
|
675
675
|
channel: ChannelId,
|
|
676
676
|
rebind?: boolean,
|
|
677
677
|
originConversationId?: string,
|
|
678
|
-
): OutboundActionResult {
|
|
678
|
+
): Promise<OutboundActionResult> {
|
|
679
679
|
if (!destination) {
|
|
680
680
|
return {
|
|
681
681
|
success: false,
|
|
@@ -688,8 +688,8 @@ function startOutboundEmail(
|
|
|
688
688
|
|
|
689
689
|
const normalizedEmail = destination.trim().toLowerCase();
|
|
690
690
|
|
|
691
|
-
const
|
|
692
|
-
if (
|
|
691
|
+
const alreadyBound = await isGuardianBoundForChannel(channel);
|
|
692
|
+
if (alreadyBound && !rebind) {
|
|
693
693
|
return {
|
|
694
694
|
success: false,
|
|
695
695
|
error: "already_bound",
|
|
@@ -15,6 +15,7 @@ import { readFileSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
|
15
15
|
import { join } from "node:path";
|
|
16
16
|
|
|
17
17
|
import { getOrCreateConversation } from "../daemon/conversation-store.js";
|
|
18
|
+
import { supersedePendingInteractionsOnEnqueue } from "../daemon/handlers/conversations.js";
|
|
18
19
|
import type { UserMessageAttachment } from "../daemon/message-types/shared.js";
|
|
19
20
|
import {
|
|
20
21
|
processMessageInBackground,
|
|
@@ -131,6 +132,21 @@ async function dispatchUserMessage(params: {
|
|
|
131
132
|
assistantMessageInterface: resolvedInterface,
|
|
132
133
|
},
|
|
133
134
|
});
|
|
135
|
+
if (!result.rejected) {
|
|
136
|
+
// Mirror the HTTP send path: a follow-up enqueued while the turn is busy
|
|
137
|
+
// auto-denies pending confirmations and supersedes a parked ask_question
|
|
138
|
+
// so it isn't stranded behind the prompt until the response backstop.
|
|
139
|
+
// Best-effort — the message is already queued, so a cleanup failure must
|
|
140
|
+
// not surface as an error that makes the CLI retry and enqueue a duplicate.
|
|
141
|
+
try {
|
|
142
|
+
supersedePendingInteractionsOnEnqueue(conversationId, requestId);
|
|
143
|
+
} catch (err) {
|
|
144
|
+
log.warn(
|
|
145
|
+
{ err, conversationId },
|
|
146
|
+
"Post-enqueue supersession failed — queued message unaffected",
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
134
150
|
return { accepted: !result.rejected };
|
|
135
151
|
}
|
|
136
152
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { advisorRequestText, buildAdvisorSystem } from "../consult-prompt.js";
|
|
4
|
+
|
|
5
|
+
describe("buildAdvisorSystem", () => {
|
|
6
|
+
test("includes the senior-advisor framing", () => {
|
|
7
|
+
const prompt = buildAdvisorSystem(null);
|
|
8
|
+
expect(prompt).toContain("senior advisor");
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test("embeds the parent prompt inside <agent_system_prompt> when provided", () => {
|
|
12
|
+
const prompt = buildAdvisorSystem("You are a coding agent.");
|
|
13
|
+
expect(prompt).toContain(
|
|
14
|
+
"<agent_system_prompt>\nYou are a coding agent.\n</agent_system_prompt>",
|
|
15
|
+
);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("omits the <agent_system_prompt> block when no parent prompt is given", () => {
|
|
19
|
+
const prompt = buildAdvisorSystem(null);
|
|
20
|
+
expect(prompt).not.toContain("<agent_system_prompt>");
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe("advisorRequestText", () => {
|
|
25
|
+
test("is non-empty and asks for focused strategic guidance", () => {
|
|
26
|
+
const text = advisorRequestText();
|
|
27
|
+
expect(text.length).toBeGreaterThan(0);
|
|
28
|
+
expect(text).toContain("focused strategic guidance");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("imposes no length cap", () => {
|
|
32
|
+
// The request must not constrain how much the advisor writes.
|
|
33
|
+
expect(advisorRequestText()).not.toContain("words");
|
|
34
|
+
});
|
|
35
|
+
});
|