@vellumai/assistant 0.9.0 → 0.10.0-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +18 -34
- package/bun.lock +7 -8
- package/docs/activation-funnel-telemetry.md +28 -22
- package/docs/architecture/security.md +29 -28
- package/docs/stt-provider-onboarding.md +3 -5
- package/docs/workflows-testing.md +13 -44
- package/docs/workflows.md +3 -5
- package/node_modules/@vellumai/ces-client/src/__tests__/ces-client.test.ts +47 -0
- package/node_modules/@vellumai/ces-client/src/rpc-client.ts +28 -5
- package/node_modules/@vellumai/environments/src/seeds.ts +2 -5
- package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +97 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +10 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +32 -6
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +119 -0
- package/node_modules/@vellumai/gateway-client/src/types.ts +15 -84
- package/openapi.yaml +976 -63
- package/package.json +2 -1
- package/scripts/sync-llm-catalog.ts +6 -15
- package/scripts/sync-web-search-catalog.ts +3 -11
- package/src/__tests__/access-request-card-view.test.ts +98 -0
- package/src/__tests__/access-request-seed-content-blocks.test.ts +2 -4
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +72 -32
- package/src/__tests__/agent-loop-compaction-strip.test.ts +241 -0
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +16 -13
- package/src/__tests__/agent-loop-output-hooks.test.ts +69 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +25 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -3
- package/src/__tests__/app-compiler.test.ts +15 -1
- package/src/__tests__/app-dir-path-guard.test.ts +0 -1
- package/src/__tests__/assistant-feature-flag-guard.test.ts +1 -4
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +0 -2
- package/src/__tests__/auth-fallback-events-store.test.ts +6 -14
- package/src/__tests__/avatar-identity-sync.test.ts +2 -27
- package/src/__tests__/btw-routes.test.ts +6 -8
- package/src/__tests__/call-pointer-messages.test.ts +28 -0
- package/src/__tests__/cancel-clears-processing.test.ts +89 -0
- package/src/__tests__/channel-approval-routes.test.ts +0 -4
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +5 -15
- package/src/__tests__/checker.test.ts +0 -3
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +3 -4
- package/src/__tests__/compactor-image-manifest-trust.test.ts +21 -1
- package/src/__tests__/compactor-summary-call-truncation.test.ts +223 -0
- package/src/__tests__/config-loader-backfill.test.ts +268 -27
- package/src/__tests__/config-schema.test.ts +35 -0
- package/src/__tests__/config-watcher.test.ts +0 -18
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -2
- package/src/__tests__/contact-store-user-file.test.ts +0 -6
- package/src/__tests__/contacts-tools.test.ts +29 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +22 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop.test.ts +58 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
- package/src/__tests__/conversation-lifecycle.test.ts +7 -9
- package/src/__tests__/conversation-load-history-repair.test.ts +101 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +15 -12
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -3
- package/src/__tests__/conversation-title-service.test.ts +62 -0
- package/src/__tests__/credential-broker.test.ts +449 -1
- package/src/__tests__/credential-execution-shell-lockdown.test.ts +18 -11
- package/src/__tests__/credential-execution-tools.test.ts +0 -1
- package/src/__tests__/credential-prompt-route.test.ts +4 -4
- package/src/__tests__/credential-routes.test.ts +360 -0
- package/src/__tests__/credential-security-invariants.test.ts +4 -13
- package/src/__tests__/disk-pressure-policy.test.ts +12 -0
- package/src/__tests__/disk-usage.test.ts +65 -0
- package/src/__tests__/dynamic-page-surface.test.ts +152 -1
- package/src/__tests__/fixtures/credential-security-fixtures.ts +2 -33
- package/src/__tests__/gateway-flag-listener.test.ts +110 -1
- package/src/__tests__/gateway-only-guard.test.ts +3 -7
- package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
- package/src/__tests__/guardian-card-withdrawal.test.ts +403 -0
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +5 -3
- package/src/__tests__/guardian-grant-minting.test.ts +3 -35
- package/src/__tests__/guardian-routing-invariants.test.ts +64 -26
- package/src/__tests__/guardian-routing-state.test.ts +0 -1
- package/src/__tests__/headless-browser-mode.test.ts +10 -0
- package/src/__tests__/headless-browser-navigate.test.ts +8 -3
- package/src/__tests__/helpers/create-guardian-binding.ts +0 -1
- package/src/__tests__/host-browser-proxy.test.ts +87 -0
- package/src/__tests__/identity-routes.test.ts +0 -189
- package/src/__tests__/inbound-invite-redemption.test.ts +4 -4
- package/src/__tests__/injector-v3-suppression.test.ts +27 -20
- package/src/__tests__/internal-telemetry-routes.test.ts +6 -14
- package/src/__tests__/invite-redemption-service.test.ts +4 -7
- package/src/__tests__/llm-callsite-catalog.test.ts +5 -6
- package/src/__tests__/llm-catalog-parity.test.ts +30 -23
- package/src/__tests__/llm-resolver.test.ts +70 -24
- package/src/__tests__/llm-schema.test.ts +1 -0
- package/src/__tests__/managed-profile-guard.test.ts +163 -4
- package/src/__tests__/mcp-health-check.test.ts +6 -7
- package/src/__tests__/media-stream-server-integration.test.ts +317 -13
- package/src/__tests__/oauth-provider-seed-logos.test.ts +4 -6
- package/src/__tests__/onboarding-persona-write.test.ts +1 -1
- package/src/__tests__/path-policy.test.ts +34 -0
- package/src/__tests__/persona-resolver.test.ts +49 -14
- package/src/__tests__/plugin-api-model-profiles.test.ts +178 -0
- package/src/__tests__/plugin-api-provider.test.ts +24 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +6 -3
- package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +214 -0
- package/src/__tests__/provider-send-message-override-profile.test.ts +76 -0
- package/src/__tests__/reaction-persistence.test.ts +150 -29
- package/src/__tests__/registry.test.ts +2 -7
- package/src/__tests__/relay-server.test.ts +285 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +1 -10
- package/src/__tests__/schedule-routes.test.ts +0 -30
- package/src/__tests__/schedule-tools.test.ts +2 -18
- package/src/__tests__/scheduler-reuse-conversation.test.ts +8 -5
- package/src/__tests__/skill-execute-input.test.ts +51 -1
- package/src/__tests__/skill-runtime-path.test.ts +2 -3
- package/src/__tests__/skills.test.ts +51 -0
- package/src/__tests__/slack-notification-approval-card.test.ts +176 -0
- package/src/__tests__/slack-reaction-canonical-approval.test.ts +285 -0
- package/src/__tests__/subagent-tools.test.ts +266 -0
- package/src/__tests__/surface-completion-nudge-hook.test.ts +367 -0
- package/src/__tests__/task-progress-nudge-hook.test.ts +1 -1
- package/src/__tests__/title-generate-hook.test.ts +100 -3
- package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +1 -29
- package/src/__tests__/token-manager.test.ts +519 -0
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +1 -1
- package/src/__tests__/tool-audit-listener.test.ts +7 -7
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +6 -3
- package/src/__tests__/tool-executor.test.ts +0 -79
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +4 -2
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +220 -3
- package/src/__tests__/trusted-contact-multichannel.test.ts +3 -3
- package/src/__tests__/trusted-contact-verification.test.ts +8 -10
- package/src/__tests__/twilio-routes.test.ts +81 -1
- package/src/__tests__/voice-invite-redemption.test.ts +2 -3
- package/src/__tests__/weak-open-model.test.ts +30 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +6 -25
- package/src/__tests__/workspace-greetings.test.ts +152 -0
- package/src/__tests__/workspace-migration-105-enable-memory-v3-live-for-new-workspaces.test.ts +149 -0
- package/src/__tests__/workspace-migration-108-drop-balanced-economy-profile.test.ts +285 -0
- package/src/__tests__/workspace-migration-add-send-diagnostics.test.ts +1 -1
- package/src/__tests__/workspace-migration-drop-collect-usage-data.test.ts +118 -0
- package/src/__tests__/workspace-migration-drop-send-diagnostics.test.ts +118 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +0 -4
- package/src/agent/loop.ts +49 -29
- package/src/api/README.md +6 -6
- package/src/api/events/tool-result.ts +6 -0
- package/src/api/events/workflow-completed.ts +53 -0
- package/src/api/events/workflow-leaf-finished.ts +38 -0
- package/src/api/events/workflow-leaf-started.ts +35 -0
- package/src/api/events/workflow-progress.ts +32 -0
- package/src/api/events/workflow-started.ts +31 -0
- package/src/api/index.ts +40 -0
- package/src/api/responses/conversation-message.ts +28 -4
- package/src/api/responses/home.ts +26 -4
- package/src/api/responses/workflow-journal.ts +53 -0
- package/src/approvals/guardian-card-withdrawal.ts +145 -0
- package/src/approvals/guardian-decision-primitive.ts +26 -3
- package/src/approvals/guardian-request-resolvers.ts +183 -80
- package/src/calls/__tests__/channel-admission-reader.test.ts +132 -0
- package/src/calls/__tests__/relay-setup-router.test.ts +350 -0
- package/src/calls/call-pointer-messages.ts +10 -4
- package/src/calls/channel-admission-reader.ts +104 -0
- package/src/calls/guardian-dispatch.ts +17 -45
- package/src/calls/media-stream-server.ts +84 -2
- package/src/calls/relay-access-wait.ts +1 -1
- package/src/calls/relay-server.ts +66 -0
- package/src/calls/relay-setup-router.ts +82 -1
- package/src/calls/twilio-routes.ts +17 -8
- package/src/calls/voice-session-bridge.ts +2 -2
- package/src/cli/commands/clients.ts +3 -0
- package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2-compare-render.test.ts +1 -1
- package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2.test.ts +8 -7
- package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v3.test.ts +5 -4
- package/src/cli/commands/memory/index.ts +30 -0
- package/src/cli/commands/{memory-v2-compare-render.ts → memory/memory-v2-compare-render.ts} +1 -1
- package/src/cli/commands/{memory-v2.ts → memory/memory-v2.ts} +6 -15
- package/src/cli/commands/{memory-v3.ts → memory/memory-v3.ts} +97 -11
- package/src/cli/commands/oauth/status.test.ts +36 -0
- package/src/cli/commands/oauth/status.ts +23 -3
- package/src/cli/commands/plugins.ts +197 -4
- package/src/cli/lib/__tests__/diff-plugin.test.ts +443 -0
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
- package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +443 -0
- package/src/cli/lib/__tests__/plugin-surfaces.test.ts +111 -0
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +295 -2
- package/src/cli/lib/diff-plugin.ts +346 -0
- package/src/cli/lib/inspect-plugin.ts +12 -1
- package/src/cli/lib/install-from-github.ts +105 -17
- package/src/cli/lib/merge-plugin-tree.ts +328 -0
- package/src/cli/lib/plugin-fingerprint.ts +14 -0
- package/src/cli/lib/plugin-surfaces.ts +104 -0
- package/src/cli/lib/upgrade-plugin.ts +298 -10
- package/src/cli/program.ts +2 -6
- package/src/config/__tests__/sync-gated-profiles.test.ts +368 -0
- package/src/config/assistant-feature-flags.ts +22 -7
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +0 -1
- package/src/config/bundled-skills/messaging/SKILL.md +6 -4
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +9 -8
- package/src/config/bundled-skills/subagent/SKILL.md +4 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +4 -0
- package/src/config/bundled-skills/workflows/SKILL.md +14 -8
- package/src/config/bundled-tool-registry.ts +2 -7
- package/src/config/call-site-defaults.ts +15 -2
- package/src/config/feature-flag-registry.json +46 -31
- package/src/config/inference-profile-validation.ts +26 -0
- package/src/config/llm-resolver.ts +3 -0
- package/src/config/loader.ts +4 -0
- package/src/config/memory-v3-gate.ts +11 -0
- package/src/config/profile-order.ts +28 -0
- package/src/config/schema.ts +8 -6
- package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
- package/src/config/schemas/call-site-catalog.ts +7 -0
- package/src/config/schemas/channels.ts +11 -0
- package/src/config/schemas/elevenlabs.ts +0 -1
- package/src/config/schemas/llm.ts +31 -0
- package/src/config/schemas/memory-lifecycle.ts +3 -7
- package/src/config/schemas/memory-v3.ts +6 -0
- package/src/config/schemas/platform.ts +0 -8
- package/src/config/schemas/services.ts +18 -0
- package/src/config/seed-inference-profiles.ts +109 -44
- package/src/config/skills.ts +21 -0
- package/src/config/sync-gated-profiles.ts +220 -0
- package/src/contacts/contact-store.ts +89 -106
- package/src/contacts/contacts-write.ts +5 -22
- package/src/contacts/types.ts +0 -1
- package/src/context/compactor.ts +88 -54
- package/src/context/strip-injections.ts +58 -10
- package/src/context/token-estimator.ts +1 -1
- package/src/credential-execution/process-manager.ts +55 -14
- package/src/credential-execution/prompted-credential.ts +2 -3
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -2
- package/src/daemon/config-watcher.ts +0 -4
- package/src/daemon/conversation-agent-loop-handlers.ts +2 -0
- package/src/daemon/conversation-agent-loop.ts +114 -22
- package/src/daemon/conversation-history.ts +1 -1
- package/src/daemon/conversation-lifecycle.ts +3 -5
- package/src/daemon/conversation-process.ts +13 -5
- package/src/daemon/conversation-runtime-assembly.ts +13 -15
- package/src/daemon/conversation-slash.ts +2 -23
- package/src/daemon/conversation-surfaces.ts +26 -0
- package/src/daemon/conversation-tool-setup.ts +27 -14
- package/src/daemon/conversation.ts +66 -14
- package/src/daemon/disk-pressure-policy.ts +5 -3
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +0 -1
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -1
- package/src/daemon/handlers/config-a2a.ts +0 -2
- package/src/daemon/handlers/config-channels.ts +15 -16
- package/src/daemon/handlers/config-slack-channel.ts +22 -3
- package/src/daemon/handlers/conversations.ts +107 -0
- package/src/daemon/host-browser-proxy.ts +41 -0
- package/src/daemon/lifecycle.ts +55 -27
- package/src/daemon/message-provenance.ts +2 -0
- package/src/daemon/message-types/contacts.ts +0 -1
- package/src/daemon/message-types/conversations.ts +3 -3
- package/src/daemon/message-types/sync.ts +0 -1
- package/src/daemon/message-types/web-activity.ts +7 -1
- package/src/daemon/message-types/workflows.ts +83 -1
- package/src/daemon/orphan-reaper.test.ts +0 -19
- package/src/daemon/orphan-reaper.ts +2 -24
- package/src/daemon/server.ts +0 -10
- package/src/daemon/tool-setup-types.ts +4 -0
- package/src/daemon/trust-context.ts +1 -1
- package/src/events/tool-audit-listener.ts +2 -2
- package/src/home/feed-source-enrichment.test.ts +151 -0
- package/src/home/feed-source-enrichment.ts +176 -0
- package/src/home/relationship-state.ts +2 -4
- package/src/instrument.ts +18 -6
- package/src/ipc/__tests__/binary-result-ipc.test.ts +81 -0
- package/src/ipc/__tests__/clients-list-ipc.test.ts +20 -0
- package/src/ipc/assistant-server.ts +37 -4
- package/src/ipc/gateway-flag-listener.ts +18 -2
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +5 -16
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +7 -11
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +37 -7
- package/src/memory/__tests__/memory-retrospective-job.test.ts +229 -401
- package/src/memory/__tests__/onboarding-events-store.test.ts +7 -7
- package/src/memory/auth-fallback-events-store.ts +2 -2
- package/src/memory/auto-analysis-enqueue.ts +3 -5
- package/src/memory/bookmark-crud.ts +1 -2
- package/src/memory/canonical-guardian-store.ts +39 -1
- package/src/memory/conversation-crud.ts +9 -4
- package/src/memory/conversation-key-store.ts +17 -2
- package/src/memory/conversation-title-service.ts +64 -7
- package/src/memory/db-init.ts +17 -17
- package/src/memory/embedding-backend.ts +38 -1
- package/src/memory/embedding-billing-breaker.ts +96 -0
- package/src/memory/jobs-store.ts +25 -13
- package/src/memory/jobs-worker.ts +54 -1
- package/src/memory/lifecycle-events-store.ts +2 -2
- package/src/memory/memory-retrospective-constants.ts +4 -4
- package/src/memory/memory-retrospective-enqueue.ts +31 -6
- package/src/memory/memory-retrospective-job.ts +28 -227
- package/src/memory/migrations/129-contact-channels-access-fields.ts +18 -9
- package/src/memory/migrations/131-drop-legacy-member-guardian-tables.ts +14 -2
- package/src/memory/migrations/289-contact-channels-unique-ext-user.ts +10 -0
- package/src/memory/migrations/291-contact-channels-renormalize-addresses.ts +72 -0
- package/src/memory/migrations/292-schedule-default-no-reuse-conversation.test.ts +67 -0
- package/src/memory/migrations/292-schedule-default-no-reuse-conversation.ts +25 -0
- package/src/memory/migrations/293-workflow-journal-leaf-tokens.ts +32 -0
- package/src/memory/migrations/294-drop-external-user-id.ts +31 -0
- package/src/memory/migrations/295-drop-approval-prompt-ts-tracker.ts +20 -0
- package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.test.ts +110 -0
- package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.ts +68 -0
- package/src/memory/migrations/__tests__/131-drop-legacy-member-guardian-tables.test.ts +154 -0
- package/src/memory/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +31 -0
- package/src/memory/migrations/__tests__/291-contact-channels-renormalize-addresses.test.ts +341 -0
- package/src/memory/migrations/__tests__/run-migrations.test.ts +52 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/run-migrations.ts +41 -0
- package/src/memory/migrations/validate-migration-state.ts +1 -1
- package/src/memory/onboarding-events-store.ts +3 -3
- package/src/memory/schema/contacts.ts +0 -5
- package/src/memory/skill-loaded-events-store.test.ts +7 -15
- package/src/memory/skill-loaded-events-store.ts +2 -2
- package/src/memory/tool-executed-events-store.test.ts +7 -7
- package/src/memory/turn-trace-store.test.ts +736 -0
- package/src/memory/turn-trace-store.ts +364 -0
- package/src/memory/v2/__tests__/consolidation-job.test.ts +8 -0
- package/src/memory/v2/__tests__/skill-content.test.ts +30 -0
- package/src/memory/v2/consolidation-job.ts +2 -2
- package/src/memory/v2/skill-content.ts +25 -7
- package/src/memory/v2/skill-store.ts +7 -1
- package/src/memory/v3-eval/__tests__/eval-packets.test.ts +248 -0
- package/src/memory/v3-eval/eval-packets.ts +546 -0
- package/src/messaging/providers/slack/adapter.ts +1 -1
- package/src/messaging/providers/slack/api.ts +31 -0
- package/src/messaging/providers/slack/send.test.ts +114 -2
- package/src/messaging/providers/slack/send.ts +30 -7
- package/src/messaging/providers/slack/withdraw.test.ts +200 -0
- package/src/messaging/providers/slack/withdraw.ts +161 -0
- package/src/notifications/AGENTS.md +2 -0
- package/src/notifications/access-request-copy.ts +72 -59
- package/src/notifications/adapters/shared.ts +29 -0
- package/src/notifications/adapters/slack.ts +58 -103
- package/src/notifications/adapters/telegram.ts +2 -20
- package/src/notifications/approval-card-data.ts +333 -0
- package/src/notifications/broadcaster.ts +16 -3
- package/src/notifications/canonical-delivery-recorder.ts +139 -0
- package/src/notifications/copy-composer.ts +3 -3
- package/src/notifications/decision-engine.ts +4 -2
- package/src/notifications/destination-resolver.ts +4 -6
- package/src/notifications/guardian-question-mode.ts +10 -0
- package/src/notifications/home-feed-side-effect.ts +7 -16
- package/src/notifications/notification-utils.ts +19 -20
- package/src/notifications/signal.ts +79 -43
- package/src/notifications/types.ts +98 -121
- package/src/oauth/AGENTS.md +5 -24
- package/src/permissions/checker.test.ts +51 -0
- package/src/permissions/checker.ts +185 -26
- package/src/permissions/ipc-risk-types.ts +24 -0
- package/src/permissions/question-prompter.test.ts +27 -0
- package/src/permissions/question-prompter.ts +4 -0
- package/src/platform/client.test.ts +119 -0
- package/src/platform/client.ts +66 -0
- package/src/platform/consent-cache.test.ts +267 -0
- package/src/platform/consent-cache.ts +174 -0
- package/src/plugin-api/constants.ts +1 -1
- package/src/plugin-api/index.ts +33 -1
- package/src/plugin-api/model-profiles.ts +33 -0
- package/src/plugin-api/types.ts +50 -2
- package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +56 -0
- package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +43 -0
- package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +137 -0
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +153 -0
- package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +138 -0
- package/src/plugins/defaults/advisor/__tests__/transcript.test.ts +147 -0
- package/src/plugins/defaults/advisor/advisor-gate.ts +29 -0
- package/src/plugins/defaults/advisor/advisor-state-store.ts +94 -0
- package/src/plugins/defaults/advisor/config.ts +21 -0
- package/src/plugins/defaults/advisor/consult.ts +93 -0
- package/src/plugins/defaults/advisor/hooks/post-model-call.ts +34 -0
- package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +30 -0
- package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +19 -0
- package/src/plugins/defaults/advisor/package.json +14 -0
- package/src/plugins/defaults/advisor/steering.ts +67 -0
- package/src/plugins/defaults/advisor/tools/advisor.ts +65 -0
- package/src/plugins/defaults/advisor/transcript.ts +76 -0
- package/src/plugins/defaults/index.ts +60 -0
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +22 -9
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/memory-retrieval/tail-reinjection-strip.ts +64 -0
- package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +29 -21
- package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +129 -9
- package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +31 -4
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +77 -2
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +7 -10
- package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +144 -11
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +32 -20
- package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +56 -3
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +23 -2
- package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +276 -0
- package/src/plugins/defaults/surface-completion-nudge/hooks/stop.ts +22 -0
- package/src/plugins/defaults/surface-completion-nudge/nudge-state-store.ts +46 -0
- package/src/plugins/defaults/surface-completion-nudge/package.json +14 -0
- package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +3 -13
- package/src/plugins/defaults/title-generate/hooks/stop.ts +56 -21
- package/src/prompts/persona-resolver.ts +14 -4
- package/src/prompts/templates/system-sections.ts +7 -2
- package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +1 -0
- package/src/providers/__tests__/retry-callsite.test.ts +176 -0
- package/src/providers/atlascloud/client.ts +85 -0
- package/src/providers/fetch-provider-catalog.ts +85 -0
- package/src/providers/inference/adapter-factory.ts +3 -0
- package/src/providers/model-catalog.ts +58 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +33 -0
- package/src/providers/openai/chat-completions-provider.ts +7 -0
- package/src/providers/openai/responses-provider.ts +10 -0
- package/src/providers/provider-send-message.ts +11 -3
- package/src/providers/retry.ts +53 -12
- package/src/providers/search-provider-catalog.ts +10 -0
- package/src/providers/weak-open-model.ts +22 -0
- package/src/runtime/AGENTS.md +0 -1
- package/src/runtime/__tests__/agent-wake.test.ts +181 -0
- package/src/runtime/__tests__/client-health.test.ts +44 -0
- package/src/runtime/access-request-helper.ts +21 -53
- package/src/runtime/actor-trust-resolver.ts +59 -63
- package/src/runtime/agent-wake.ts +52 -0
- package/src/runtime/assistant-event-hub.ts +18 -4
- package/src/runtime/auth/__tests__/route-policy.test.ts +12 -0
- package/src/runtime/auth/require-bound-guardian.ts +1 -4
- package/src/runtime/btw-sidechain.ts +3 -6
- package/src/runtime/capabilities.test.ts +120 -0
- package/src/runtime/capabilities.ts +197 -0
- package/src/runtime/channel-approval-types.ts +22 -45
- package/src/runtime/channel-invite-transports/telegram.ts +4 -4
- package/src/runtime/channel-retry-sweep.ts +1 -0
- package/src/runtime/channel-verification-service.ts +3 -3
- package/src/runtime/client-health.ts +26 -0
- package/src/runtime/confirmation-request-guardian-bridge.ts +38 -29
- package/src/runtime/effective-capabilities.test.ts +128 -0
- package/src/runtime/effective-capabilities.ts +84 -0
- package/src/runtime/guardian-reply-router.ts +106 -21
- package/src/runtime/invite-redemption-service.ts +9 -25
- package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +123 -0
- package/src/runtime/migrations/vbundle-builder.ts +49 -20
- package/src/runtime/pending-interactions.ts +15 -0
- package/src/runtime/routes/__tests__/client-routes.test.ts +13 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +67 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +240 -1
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +2 -2
- package/src/runtime/routes/assets/vellum-design-system.css +1959 -0
- package/src/runtime/routes/browser-tabs-routes.ts +9 -0
- package/src/runtime/routes/btw-routes.ts +1 -27
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +17 -8
- package/src/runtime/routes/client-routes.ts +10 -0
- package/src/runtime/routes/contact-routes.ts +31 -8
- package/src/runtime/routes/conversation-compaction-routes.ts +1 -1
- package/src/runtime/routes/conversation-management-routes.ts +80 -1
- package/src/runtime/routes/conversation-query-routes.ts +68 -22
- package/src/runtime/routes/conversation-routes.ts +39 -14
- package/src/runtime/routes/credential-routes.ts +40 -16
- package/src/runtime/routes/empty-state-greeting-cache.ts +1 -2
- package/src/runtime/routes/events-routes.ts +1 -3
- package/src/runtime/routes/guardian-approval-interception.ts +14 -73
- package/src/runtime/routes/guardian-approval-prompt.ts +22 -4
- package/src/runtime/routes/home-feed-routes.ts +8 -3
- package/src/runtime/routes/identity-routes.ts +1 -296
- package/src/runtime/routes/inbound-message-handler.ts +214 -228
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +89 -7
- package/src/runtime/routes/inbound-stages/admission-policy.test.ts +154 -0
- package/src/runtime/routes/inbound-stages/admission-policy.ts +140 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +3 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +11 -6
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -2
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +1 -2
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +7 -7
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +47 -28
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +358 -0
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +8 -0
- package/src/runtime/routes/integrations/slack/channel.ts +36 -0
- package/src/runtime/routes/internal-telemetry-routes.ts +1 -1
- package/src/runtime/routes/mcp-auth-routes.ts +233 -41
- package/src/runtime/routes/memory-eval-routes.ts +87 -0
- package/src/runtime/routes/notification-routes.ts +122 -133
- package/src/runtime/routes/platform-routes.ts +2 -2
- package/src/runtime/routes/plugins-routes.ts +202 -3
- package/src/runtime/routes/schedule-routes.ts +0 -22
- package/src/runtime/routes/secret-routes.ts +10 -0
- package/src/runtime/routes/surface-action-routes.ts +2 -1
- package/src/runtime/routes/tool-call-question-enrichment.test.ts +146 -0
- package/src/runtime/routes/tool-call-question-enrichment.ts +66 -0
- package/src/runtime/routes/workflow-routes.test.ts +229 -44
- package/src/runtime/routes/workflow-routes.ts +131 -29
- package/src/runtime/routes/workspace-greetings.ts +55 -0
- package/src/runtime/sync/resource-sync-events.ts +1 -11
- package/src/runtime/tool-grant-request-helper.ts +18 -16
- package/src/runtime/trust-context-resolver.ts +8 -5
- package/src/schedule/inference-profile.ts +2 -14
- package/src/schedule/schedule-store.ts +1 -1
- package/src/schedule/scheduler-types.ts +5 -1
- package/src/security/__tests__/provider-key-env-fallback.test.ts +6 -0
- package/src/security/secret-patterns.ts +3 -0
- package/src/subagent/manager.ts +17 -4
- package/src/subagent/types.ts +6 -0
- package/src/telemetry/trace-collection-policy.test.ts +28 -0
- package/src/telemetry/trace-collection-policy.ts +30 -0
- package/src/telemetry/types.ts +89 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +586 -36
- package/src/telemetry/usage-telemetry-reporter.ts +148 -41
- package/src/tools/AGENTS.md +3 -3
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +31 -0
- package/src/tools/browser/browser-execution.ts +30 -19
- package/src/tools/document/document-tool.ts +2 -3
- package/src/tools/executor.ts +5 -3
- package/src/tools/host-terminal/host-shell.ts +5 -4
- package/src/tools/memory/register.ts +2 -2
- package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +360 -0
- package/src/tools/network/__tests__/web-search.test.ts +143 -0
- package/src/tools/network/web-fetch.ts +372 -1
- package/src/tools/network/web-search-error.ts +1 -1
- package/src/tools/network/web-search.ts +213 -10
- package/src/tools/permission-checker.ts +4 -3
- package/src/tools/registry.ts +20 -0
- package/src/tools/schedule/create.ts +7 -12
- package/src/tools/schedule/update.ts +4 -11
- package/src/tools/shared/filesystem/path-policy.ts +39 -13
- package/src/tools/side-effects.ts +2 -17
- package/src/tools/skills/execute.ts +33 -0
- package/src/tools/subagent/spawn.ts +61 -12
- package/src/tools/terminal/shell.ts +10 -4
- package/src/tools/tool-approval-handler.ts +18 -13
- package/src/tools/tool-manifest.ts +0 -2
- package/src/tools/types.ts +9 -0
- package/src/tools/ui-surface/definitions.ts +64 -3
- package/src/tools/verification-control-plane-policy.ts +3 -1
- package/src/tools/workflows/run-workflow.test.ts +8 -18
- package/src/tools/workflows/run-workflow.ts +1 -0
- package/src/util/disk-usage.ts +78 -23
- package/src/util/platform.ts +10 -3
- package/src/watcher/telemetry.ts +2 -2
- package/src/workflows/capabilities.ts +2 -3
- package/src/workflows/engine.test.ts +175 -1
- package/src/workflows/engine.ts +82 -0
- package/src/workflows/journal-store.test.ts +70 -0
- package/src/workflows/journal-store.ts +18 -3
- package/src/workflows/run-manager.test.ts +171 -28
- package/src/workflows/run-manager.ts +66 -24
- package/src/workspace/migrations/105-enable-memory-v3-live-for-new-workspaces.ts +63 -0
- package/src/workspace/migrations/106-drop-collect-usage-data.ts +47 -0
- package/src/workspace/migrations/107-drop-send-diagnostics.ts +47 -0
- package/src/workspace/migrations/108-drop-balanced-economy-profile.ts +129 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/__tests__/app-control-no-global-cgevent.test.ts +0 -98
- package/src/__tests__/credential-security-e2e.test.ts +0 -362
- package/src/__tests__/credential-vault-unit.test.ts +0 -1528
- package/src/__tests__/credential-vault.test.ts +0 -1706
- package/src/__tests__/identity-intro-cache.test.ts +0 -315
- package/src/__tests__/secret-onetime-send.test.ts +0 -182
- package/src/cli/commands/__tests__/task.test.ts +0 -914
- package/src/cli/commands/task.ts +0 -771
- package/src/config/bundled-skills/personal-page/SKILL.md +0 -57
- package/src/config/bundled-skills/personal-page/TOOLS.json +0 -27
- package/src/config/bundled-skills/personal-page/tools/app-refresh.ts +0 -17
- package/src/config/preloaded-apps/personal-page/src/components/About.tsx +0 -22
- package/src/config/preloaded-apps/personal-page/src/components/App.tsx +0 -16
- package/src/config/preloaded-apps/personal-page/src/components/Features.tsx +0 -77
- package/src/config/preloaded-apps/personal-page/src/components/Hero.tsx +0 -57
- package/src/config/preloaded-apps/personal-page/src/components/Pending.tsx +0 -28
- package/src/config/preloaded-apps/personal-page/src/components/animations.tsx +0 -234
- package/src/config/preloaded-apps/personal-page/src/components/icons.tsx +0 -48
- package/src/config/preloaded-apps/personal-page/src/components/media.ts +0 -16
- package/src/config/preloaded-apps/personal-page/src/index.html +0 -20
- package/src/config/preloaded-apps/personal-page/src/main.tsx +0 -7
- package/src/config/preloaded-apps/personal-page/src/profile-data.ts +0 -82
- package/src/config/preloaded-apps/personal-page/src/styles.css +0 -759
- package/src/memory/__tests__/preloaded-apps.test.ts +0 -85
- package/src/memory/preloaded-apps.ts +0 -116
- package/src/notifications/tool-approval-copy.ts +0 -142
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +0 -78
- package/src/runtime/routes/identity-intro-cache.ts +0 -172
- package/src/tools/credentials/vault.ts +0 -712
|
@@ -28,6 +28,33 @@ import type { Message } from "../providers/types.js";
|
|
|
28
28
|
*/
|
|
29
29
|
export type InjectionMatcher = string | { prefix: string; suffix: string };
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Whether an injected text block matches any of the given matchers. A plain
|
|
33
|
+
* string matches by prefix; a `{ prefix, suffix }` wrapper requires both ends
|
|
34
|
+
* so user-authored text merely opening with an injection-like tag is kept.
|
|
35
|
+
*/
|
|
36
|
+
function textBlockMatchesInjection(
|
|
37
|
+
text: string,
|
|
38
|
+
matchers: InjectionMatcher[],
|
|
39
|
+
): boolean {
|
|
40
|
+
return matchers.some((m) =>
|
|
41
|
+
typeof m === "string"
|
|
42
|
+
? text.startsWith(m)
|
|
43
|
+
: text.startsWith(m.prefix) && text.endsWith(m.suffix),
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Drop the matching injection text blocks from a single content array. */
|
|
48
|
+
function filterInjectionBlocks(
|
|
49
|
+
content: Message["content"],
|
|
50
|
+
matchers: InjectionMatcher[],
|
|
51
|
+
): Message["content"] {
|
|
52
|
+
return content.filter(
|
|
53
|
+
(block) =>
|
|
54
|
+
block.type !== "text" || !textBlockMatchesInjection(block.text, matchers),
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
31
58
|
/**
|
|
32
59
|
* Remove text blocks from user messages that match any of the given matchers.
|
|
33
60
|
* If stripping removes all content blocks from a message, the message itself
|
|
@@ -43,14 +70,7 @@ export function stripUserTextBlocksByPrefix(
|
|
|
43
70
|
return messages
|
|
44
71
|
.map((message) => {
|
|
45
72
|
if (message.role !== "user") return message;
|
|
46
|
-
const nextContent = message.content
|
|
47
|
-
if (block.type !== "text") return true;
|
|
48
|
-
return !matchers.some((m) =>
|
|
49
|
-
typeof m === "string"
|
|
50
|
-
? block.text.startsWith(m)
|
|
51
|
-
: block.text.startsWith(m.prefix) && block.text.endsWith(m.suffix),
|
|
52
|
-
);
|
|
53
|
-
});
|
|
73
|
+
const nextContent = filterInjectionBlocks(message.content, matchers);
|
|
54
74
|
if (nextContent.length === message.content.length) return message;
|
|
55
75
|
if (nextContent.length === 0) return null;
|
|
56
76
|
return { ...message, content: nextContent };
|
|
@@ -60,6 +80,30 @@ export function stripUserTextBlocksByPrefix(
|
|
|
60
80
|
);
|
|
61
81
|
}
|
|
62
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Tail-scoped variant of {@link stripUserTextBlocksByPrefix}: remove matching
|
|
85
|
+
* text blocks from ONLY the last message, and only when that message is a user
|
|
86
|
+
* message. This mirrors the runtime injection step, which applies every
|
|
87
|
+
* per-turn block to the tail user message, so clearing the tail's stale copies
|
|
88
|
+
* before re-injection makes re-injection idempotent.
|
|
89
|
+
*
|
|
90
|
+
* The tail message is retained even if all of its blocks are removed, so the
|
|
91
|
+
* role-`"user"` tail invariant the re-injection step relies on is preserved.
|
|
92
|
+
* Earlier messages are untouched, so per-message historical grounding (e.g.
|
|
93
|
+
* each turn's `<turn_context>`) survives and the stable cached prefix — which
|
|
94
|
+
* lives entirely before the tail — is never disturbed.
|
|
95
|
+
*/
|
|
96
|
+
export function stripTailUserTextBlocksByPrefix(
|
|
97
|
+
messages: Message[],
|
|
98
|
+
matchers: InjectionMatcher[],
|
|
99
|
+
): Message[] {
|
|
100
|
+
const last = messages[messages.length - 1];
|
|
101
|
+
if (!last || last.role !== "user") return messages;
|
|
102
|
+
const nextContent = filterInjectionBlocks(last.content, matchers);
|
|
103
|
+
if (nextContent.length === last.content.length) return messages;
|
|
104
|
+
return [...messages.slice(0, -1), { ...last, content: nextContent }];
|
|
105
|
+
}
|
|
106
|
+
|
|
63
107
|
/**
|
|
64
108
|
* Full-wrapper matcher for the memory-v3 ephemeral `<memory_spotlight>` block.
|
|
65
109
|
* Shared by the per-turn scoped strip ({@link stripSpotlightInjections}) and
|
|
@@ -88,8 +132,12 @@ export const NOW_SCRATCHPAD_STRIP_PREFIXES: InjectionMatcher[] = [
|
|
|
88
132
|
"<now_scratchpad>",
|
|
89
133
|
];
|
|
90
134
|
|
|
91
|
-
/**
|
|
92
|
-
|
|
135
|
+
/**
|
|
136
|
+
* Matchers stripped by the compaction pipeline (order doesn't matter — single
|
|
137
|
+
* pass). Exported so the post-compaction re-injection path can reuse this set
|
|
138
|
+
* as the base of its idempotency strip without duplicating it.
|
|
139
|
+
*/
|
|
140
|
+
export const RUNTIME_INJECTION_PREFIXES: InjectionMatcher[] = [
|
|
93
141
|
"<channel_capabilities>",
|
|
94
142
|
"<channel_command_context>",
|
|
95
143
|
"<disk_pressure_warning>",
|
|
@@ -305,7 +305,7 @@ export function estimateMessagesTokens(
|
|
|
305
305
|
}
|
|
306
306
|
|
|
307
307
|
/** Estimate token cost for a single tool definition. */
|
|
308
|
-
function estimateToolDefinitionTokens(tool: ToolDefinition): number {
|
|
308
|
+
export function estimateToolDefinitionTokens(tool: ToolDefinition): number {
|
|
309
309
|
return (
|
|
310
310
|
TOOL_DEFINITION_OVERHEAD_TOKENS +
|
|
311
311
|
estimateTextTokens(tool.name) +
|
|
@@ -312,6 +312,43 @@ function buildLocalCesEnv(): Record<string, string | undefined> {
|
|
|
312
312
|
};
|
|
313
313
|
}
|
|
314
314
|
|
|
315
|
+
// ---------------------------------------------------------------------------
|
|
316
|
+
// Close notification (shared by both transports)
|
|
317
|
+
// ---------------------------------------------------------------------------
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Tracks the transport `alive` state and notifies registered handlers exactly
|
|
321
|
+
* once when the transport dies, so the RPC client can fail-fast any in-flight
|
|
322
|
+
* calls instead of waiting out their timeouts.
|
|
323
|
+
*/
|
|
324
|
+
function createCloseNotifier(): {
|
|
325
|
+
isAlive: () => boolean;
|
|
326
|
+
markDead: () => void;
|
|
327
|
+
onClose: (handler: () => void) => void;
|
|
328
|
+
} {
|
|
329
|
+
let alive = true;
|
|
330
|
+
let notified = false;
|
|
331
|
+
const handlers: Array<() => void> = [];
|
|
332
|
+
return {
|
|
333
|
+
isAlive: () => alive,
|
|
334
|
+
markDead() {
|
|
335
|
+
alive = false;
|
|
336
|
+
if (notified) return;
|
|
337
|
+
notified = true;
|
|
338
|
+
for (const handler of handlers) {
|
|
339
|
+
try {
|
|
340
|
+
handler();
|
|
341
|
+
} catch {
|
|
342
|
+
// a close handler must never throw back into the transport
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
onClose(handler) {
|
|
347
|
+
handlers.push(handler);
|
|
348
|
+
},
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
315
352
|
// ---------------------------------------------------------------------------
|
|
316
353
|
// Stdio transport (local mode)
|
|
317
354
|
// ---------------------------------------------------------------------------
|
|
@@ -319,7 +356,7 @@ function buildLocalCesEnv(): Record<string, string | undefined> {
|
|
|
319
356
|
function createStdioTransport(proc: Subprocess): CesTransport {
|
|
320
357
|
const messageHandlers: Array<(message: string) => void> = [];
|
|
321
358
|
let buffer = "";
|
|
322
|
-
|
|
359
|
+
const death = createCloseNotifier();
|
|
323
360
|
|
|
324
361
|
// Read stdout line by line — narrow past `number` union arm from Subprocess type
|
|
325
362
|
if (proc.stdout && typeof proc.stdout !== "number") {
|
|
@@ -350,9 +387,9 @@ function createStdioTransport(proc: Subprocess): CesTransport {
|
|
|
350
387
|
endReason = "error";
|
|
351
388
|
readError = err;
|
|
352
389
|
} finally {
|
|
353
|
-
//
|
|
354
|
-
// the
|
|
355
|
-
|
|
390
|
+
// Report dead the moment the stdout stream ends (regardless of why),
|
|
391
|
+
// and notify the client so it can fail-fast any in-flight calls.
|
|
392
|
+
death.markDead();
|
|
356
393
|
|
|
357
394
|
// DIAGNOSTIC (observation only). The reconnection path (secure-keys.ts)
|
|
358
395
|
// bounces CES whenever isAlive() goes false. This classifies WHY the
|
|
@@ -384,7 +421,7 @@ function createStdioTransport(proc: Subprocess): CesTransport {
|
|
|
384
421
|
|
|
385
422
|
// Track process exit
|
|
386
423
|
void proc.exited.then((exitCode) => {
|
|
387
|
-
|
|
424
|
+
death.markDead();
|
|
388
425
|
log.info(
|
|
389
426
|
{ pid: proc.pid, exitCode },
|
|
390
427
|
"CES stdio transport: process exited",
|
|
@@ -393,7 +430,7 @@ function createStdioTransport(proc: Subprocess): CesTransport {
|
|
|
393
430
|
|
|
394
431
|
return {
|
|
395
432
|
write(line: string): void {
|
|
396
|
-
if (!
|
|
433
|
+
if (!death.isAlive() || !proc.stdin || typeof proc.stdin === "number") {
|
|
397
434
|
throw new Error("CES stdio transport is not alive");
|
|
398
435
|
}
|
|
399
436
|
proc.stdin.write(line + "\n");
|
|
@@ -404,11 +441,13 @@ function createStdioTransport(proc: Subprocess): CesTransport {
|
|
|
404
441
|
},
|
|
405
442
|
|
|
406
443
|
isAlive(): boolean {
|
|
407
|
-
return
|
|
444
|
+
return death.isAlive();
|
|
408
445
|
},
|
|
409
446
|
|
|
447
|
+
onClose: death.onClose,
|
|
448
|
+
|
|
410
449
|
close(): void {
|
|
411
|
-
|
|
450
|
+
death.markDead();
|
|
412
451
|
if (proc.stdin && typeof proc.stdin !== "number") {
|
|
413
452
|
proc.stdin.end();
|
|
414
453
|
}
|
|
@@ -423,7 +462,7 @@ function createStdioTransport(proc: Subprocess): CesTransport {
|
|
|
423
462
|
function createSocketTransport(socket: Socket): CesTransport {
|
|
424
463
|
const messageHandlers: Array<(message: string) => void> = [];
|
|
425
464
|
let buffer = "";
|
|
426
|
-
|
|
465
|
+
const death = createCloseNotifier();
|
|
427
466
|
|
|
428
467
|
const decoder = new StringDecoder("utf8");
|
|
429
468
|
|
|
@@ -442,17 +481,17 @@ function createSocketTransport(socket: Socket): CesTransport {
|
|
|
442
481
|
});
|
|
443
482
|
|
|
444
483
|
socket.on("close", () => {
|
|
445
|
-
|
|
484
|
+
death.markDead();
|
|
446
485
|
});
|
|
447
486
|
|
|
448
487
|
socket.on("error", (err) => {
|
|
449
488
|
log.warn({ err }, "CES socket transport error");
|
|
450
|
-
|
|
489
|
+
death.markDead();
|
|
451
490
|
});
|
|
452
491
|
|
|
453
492
|
return {
|
|
454
493
|
write(line: string): void {
|
|
455
|
-
if (!
|
|
494
|
+
if (!death.isAlive() || socket.destroyed) {
|
|
456
495
|
throw new Error("CES socket transport is not alive");
|
|
457
496
|
}
|
|
458
497
|
socket.write(line + "\n");
|
|
@@ -463,11 +502,13 @@ function createSocketTransport(socket: Socket): CesTransport {
|
|
|
463
502
|
},
|
|
464
503
|
|
|
465
504
|
isAlive(): boolean {
|
|
466
|
-
return
|
|
505
|
+
return death.isAlive() && !socket.destroyed;
|
|
467
506
|
},
|
|
468
507
|
|
|
508
|
+
onClose: death.onClose,
|
|
509
|
+
|
|
469
510
|
close(): void {
|
|
470
|
-
|
|
511
|
+
death.markDead();
|
|
471
512
|
socket.destroy();
|
|
472
513
|
},
|
|
473
514
|
};
|
|
@@ -8,9 +8,8 @@
|
|
|
8
8
|
* channel actually connects, not just stored;
|
|
9
9
|
* - any other credential: written to secure storage.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* identically.
|
|
11
|
+
* The CLI `credentials prompt` route uses this logic to persist a credential
|
|
12
|
+
* collected through a secure prompt.
|
|
14
13
|
*/
|
|
15
14
|
|
|
16
15
|
import { getConfig } from "../config/loader.js";
|
|
@@ -236,8 +236,9 @@ describe("disposeConversation — auto-analysis enqueue", () => {
|
|
|
236
236
|
|
|
237
237
|
test("untrusted conversation — enqueues neither graph_extract nor conversation_analyze", () => {
|
|
238
238
|
// `unknown` is the trust class used for untrusted actors. The disposal
|
|
239
|
-
// code short-circuits
|
|
240
|
-
// path should fire. This preserves the
|
|
239
|
+
// code short-circuits when `resolveCapabilities(trustClass).canAccessMemory`
|
|
240
|
+
// is false, so neither enqueue path should fire. This preserves the
|
|
241
|
+
// memory trust boundary.
|
|
241
242
|
const ctx = makeDisposeContext({
|
|
242
243
|
conversationId: "conv-untrusted",
|
|
243
244
|
trustClass: "unknown",
|
|
@@ -178,8 +178,6 @@ export class ConfigWatcher {
|
|
|
178
178
|
* Start all file watchers. `onConversationEvict` is called when watched
|
|
179
179
|
* files change and conversations need to be evicted for reload.
|
|
180
180
|
* `onIdentityChanged` is called when IDENTITY.md changes on disk.
|
|
181
|
-
* `onIdentityIntroChanged` is called when SOUL.md changes and identity
|
|
182
|
-
* intro subscribers should refetch.
|
|
183
181
|
* `onSkillsChanged` is called after skill directory changes evict
|
|
184
182
|
* conversations.
|
|
185
183
|
*/
|
|
@@ -190,7 +188,6 @@ export class ConfigWatcher {
|
|
|
190
188
|
onAvatarChanged?: () => void,
|
|
191
189
|
onConfigChanged?: () => void,
|
|
192
190
|
onSkillsChanged?: () => void,
|
|
193
|
-
onIdentityIntroChanged?: () => void,
|
|
194
191
|
): void {
|
|
195
192
|
// Reset the stopped flag so a stop()→start() cycle on the same
|
|
196
193
|
// instance resumes hot-reload instead of silently bailing in every
|
|
@@ -226,7 +223,6 @@ export class ConfigWatcher {
|
|
|
226
223
|
},
|
|
227
224
|
"SOUL.md": () => {
|
|
228
225
|
onConversationEvict();
|
|
229
|
-
onIdentityIntroChanged?.();
|
|
230
226
|
},
|
|
231
227
|
"IDENTITY.md": () => {
|
|
232
228
|
onConversationEvict();
|
|
@@ -1184,6 +1184,7 @@ export async function finalizePendingToolResultRow(
|
|
|
1184
1184
|
let provenanceTrustClass:
|
|
1185
1185
|
| "guardian"
|
|
1186
1186
|
| "trusted_contact"
|
|
1187
|
+
| "unverified_contact"
|
|
1187
1188
|
| "unknown"
|
|
1188
1189
|
| undefined;
|
|
1189
1190
|
let automated: boolean | undefined;
|
|
@@ -1845,6 +1846,7 @@ export async function handleMessageComplete(
|
|
|
1845
1846
|
let provenanceTrustClass:
|
|
1846
1847
|
| "guardian"
|
|
1847
1848
|
| "trusted_contact"
|
|
1849
|
+
| "unverified_contact"
|
|
1848
1850
|
| "unknown"
|
|
1849
1851
|
| undefined;
|
|
1850
1852
|
let automated: boolean | undefined;
|
|
@@ -70,9 +70,9 @@ import type { UserPromptSubmitContext } from "../plugin-api/types.js";
|
|
|
70
70
|
import { runHook } from "../plugins/pipeline.js";
|
|
71
71
|
import type { ContentBlock, Message } from "../providers/types.js";
|
|
72
72
|
import type { Provider } from "../providers/types.js";
|
|
73
|
-
import { isUntrustedTrustClass } from "../runtime/actor-trust-resolver.js";
|
|
74
73
|
import { broadcastMessage } from "../runtime/assistant-event-hub.js";
|
|
75
74
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
|
|
75
|
+
import { resolveCapabilities } from "../runtime/capabilities.js";
|
|
76
76
|
import { publishConversationMessagesChanged } from "../runtime/sync/resource-sync-events.js";
|
|
77
77
|
import type { ActivationMomentParam } from "../telemetry/activation-funnel.js";
|
|
78
78
|
import type { UsageActor } from "../usage/actors.js";
|
|
@@ -187,6 +187,67 @@ export interface AssistantSurface {
|
|
|
187
187
|
activationMoment?: ActivationMomentParam;
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
+
// ── abort watchdog ───────────────────────────────────────────────────
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Generous backstop that drives an aborted turn to its `finally` even if some
|
|
194
|
+
* awaited operation fails to observe the abort signal.
|
|
195
|
+
*
|
|
196
|
+
* Abort is otherwise cooperative and already wired into the slow paths: the
|
|
197
|
+
* provider call forwards the signal to its HTTP/streaming fetch, and tool
|
|
198
|
+
* execution races the signal so a stuck tool can't block cancellation. This
|
|
199
|
+
* watchdog only fires when a future code path silently ignores abort — without
|
|
200
|
+
* it, such a path would hang the loop forever and latch the conversation's
|
|
201
|
+
* `processing` flag true (the wedged "Thinking…" indicator). It is
|
|
202
|
+
* defense-in-depth, not the primary mechanism, so the timeout is deliberately
|
|
203
|
+
* generous; in the common case abort settles in-flight work well before it.
|
|
204
|
+
*/
|
|
205
|
+
const ABORT_WATCHDOG_MS = 45_000;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Race `work` against an abort watchdog. The watchdog stays disarmed until the
|
|
209
|
+
* signal fires; once it does, the turn has `timeoutMs` to settle before the
|
|
210
|
+
* watchdog rejects with the signal's own abort reason so the caller unwinds to
|
|
211
|
+
* its `finally` and the reason classifies as a user cancellation downstream.
|
|
212
|
+
* The abandoned `work` promise keeps running detached — its eventual rejection
|
|
213
|
+
* is swallowed so it can't surface as an unhandled rejection.
|
|
214
|
+
*/
|
|
215
|
+
async function withAbortWatchdog<T>(
|
|
216
|
+
work: Promise<T>,
|
|
217
|
+
signal: AbortSignal,
|
|
218
|
+
timeoutMs: number,
|
|
219
|
+
onFire: () => void,
|
|
220
|
+
): Promise<T> {
|
|
221
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
222
|
+
let onAbort: (() => void) | undefined;
|
|
223
|
+
const watchdog = new Promise<never>((_, reject) => {
|
|
224
|
+
const arm = () => {
|
|
225
|
+
timer = setTimeout(() => {
|
|
226
|
+
onFire();
|
|
227
|
+
// Propagate the signal's own reason (an `AbortReason` for daemon-owned
|
|
228
|
+
// cancels) so the loop's catch classifies this as a user cancellation;
|
|
229
|
+
// fall back to a tagged AbortError when the signal carries no reason.
|
|
230
|
+
reject(
|
|
231
|
+
signal.reason ??
|
|
232
|
+
new DOMException("The operation was aborted", "AbortError"),
|
|
233
|
+
);
|
|
234
|
+
}, timeoutMs);
|
|
235
|
+
};
|
|
236
|
+
if (signal.aborted) arm();
|
|
237
|
+
else {
|
|
238
|
+
onAbort = arm;
|
|
239
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
try {
|
|
243
|
+
return await Promise.race([work, watchdog]);
|
|
244
|
+
} finally {
|
|
245
|
+
if (timer) clearTimeout(timer);
|
|
246
|
+
if (onAbort) signal.removeEventListener("abort", onAbort);
|
|
247
|
+
void work.catch(() => {});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
190
251
|
// ── runAgentLoop ─────────────────────────────────────────────────────
|
|
191
252
|
|
|
192
253
|
export async function runAgentLoopImpl(
|
|
@@ -215,6 +276,11 @@ export async function runAgentLoopImpl(
|
|
|
215
276
|
* spawns).
|
|
216
277
|
*/
|
|
217
278
|
overrideProfile?: string;
|
|
279
|
+
/**
|
|
280
|
+
* Float `overrideProfile` above call-site layers for non-main-agent call
|
|
281
|
+
* sites. Used when a caller explicitly pins a background run to a profile.
|
|
282
|
+
*/
|
|
283
|
+
forceOverrideProfile?: boolean;
|
|
218
284
|
},
|
|
219
285
|
): Promise<void> {
|
|
220
286
|
if (!ctx.abortController) {
|
|
@@ -290,6 +356,7 @@ export async function runAgentLoopImpl(
|
|
|
290
356
|
ctx.toolRoutedProfile = undefined;
|
|
291
357
|
|
|
292
358
|
const turnOverrideProfile = userExplicitOverride;
|
|
359
|
+
const forceOverrideProfile = options?.forceOverrideProfile === true;
|
|
293
360
|
|
|
294
361
|
const readCurrentOverrideProfile = (): string | undefined =>
|
|
295
362
|
options?.overrideProfile ??
|
|
@@ -300,6 +367,7 @@ export async function runAgentLoopImpl(
|
|
|
300
367
|
llm: config.llm,
|
|
301
368
|
callSite: turnCallSite,
|
|
302
369
|
overrideProfile: turnOverrideProfile ?? undefined,
|
|
370
|
+
forceOverrideProfile,
|
|
303
371
|
selectionSeed: ctx.conversationId,
|
|
304
372
|
});
|
|
305
373
|
let currentEffectiveContextWindow: EffectiveContextWindow =
|
|
@@ -307,6 +375,7 @@ export async function runAgentLoopImpl(
|
|
|
307
375
|
let currentContextWindowConfig = contextWindowConfigFromEffective(
|
|
308
376
|
resolveCallSiteConfig(turnCallSite, config.llm, {
|
|
309
377
|
overrideProfile: turnOverrideProfile ?? undefined,
|
|
378
|
+
forceOverrideProfile,
|
|
310
379
|
selectionSeed: ctx.conversationId,
|
|
311
380
|
}).contextWindow,
|
|
312
381
|
currentEffectiveContextWindow,
|
|
@@ -322,11 +391,13 @@ export async function runAgentLoopImpl(
|
|
|
322
391
|
llm: config.llm,
|
|
323
392
|
callSite: turnCallSite,
|
|
324
393
|
overrideProfile: currentOverrideProfile,
|
|
394
|
+
forceOverrideProfile,
|
|
325
395
|
selectionSeed: ctx.conversationId,
|
|
326
396
|
});
|
|
327
397
|
currentContextWindowConfig = contextWindowConfigFromEffective(
|
|
328
398
|
resolveCallSiteConfig(turnCallSite, config.llm, {
|
|
329
399
|
overrideProfile: currentOverrideProfile,
|
|
400
|
+
forceOverrideProfile,
|
|
330
401
|
selectionSeed: ctx.conversationId,
|
|
331
402
|
}).contextWindow,
|
|
332
403
|
currentEffectiveContextWindow,
|
|
@@ -892,21 +963,36 @@ export async function runAgentLoopImpl(
|
|
|
892
963
|
msgs: Message[],
|
|
893
964
|
compactInPlace = false,
|
|
894
965
|
): Promise<Message[]> => {
|
|
895
|
-
const
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
966
|
+
const watchdogMs = ctx.abortWatchdogMs ?? ABORT_WATCHDOG_MS;
|
|
967
|
+
const { history, exitReason, newMessages } = await withAbortWatchdog(
|
|
968
|
+
ctx.agentLoop.run({
|
|
969
|
+
messages: msgs,
|
|
970
|
+
onEvent: eventHandler,
|
|
971
|
+
signal: abortController.signal,
|
|
972
|
+
requestId: reqId,
|
|
973
|
+
onCheckpoint,
|
|
974
|
+
callSite: turnCallSite,
|
|
975
|
+
trust: loopTrust,
|
|
976
|
+
overrideProfile: turnOverrideProfile,
|
|
977
|
+
...(forceOverrideProfile ? { forceOverrideProfile: true } : {}),
|
|
978
|
+
resolveOverrideProfile: resolveCurrentOverrideProfile,
|
|
979
|
+
resolveContextWindow,
|
|
980
|
+
compactInPlace,
|
|
981
|
+
isNonInteractive,
|
|
982
|
+
modelProfileKey,
|
|
983
|
+
}),
|
|
984
|
+
abortController.signal,
|
|
985
|
+
watchdogMs,
|
|
986
|
+
() =>
|
|
987
|
+
rlog.error(
|
|
988
|
+
{
|
|
989
|
+
conversationId: ctx.conversationId,
|
|
990
|
+
requestId: reqId,
|
|
991
|
+
timeoutMs: watchdogMs,
|
|
992
|
+
},
|
|
993
|
+
"Abort watchdog fired — agent loop did not settle after cancel; forcing turn to finally",
|
|
994
|
+
),
|
|
995
|
+
);
|
|
910
996
|
lastRunNewMessages = newMessages;
|
|
911
997
|
if (exitReason === "handoff") {
|
|
912
998
|
yieldedForHandoff = true;
|
|
@@ -1439,6 +1525,12 @@ export async function runAgentLoopImpl(
|
|
|
1439
1525
|
|
|
1440
1526
|
ctx.profiler.emitSummary(ctx.traceEmitter, reqId);
|
|
1441
1527
|
|
|
1528
|
+
// Tear down this turn's per-turn state. Abort reliably drives the loop to
|
|
1529
|
+
// this `finally` within a bounded time — cooperative signal propagation
|
|
1530
|
+
// (provider fetch + tool race) backed by the abort watchdog — so a
|
|
1531
|
+
// cancelled turn always unwinds before any resend can start a new one.
|
|
1532
|
+
// There is therefore only ever one turn alive, and clearing the shared
|
|
1533
|
+
// state below cannot clobber a concurrent turn.
|
|
1442
1534
|
ctx.abortController = null;
|
|
1443
1535
|
ctx.setProcessing(false);
|
|
1444
1536
|
ctx.onConfirmationOutcome = undefined;
|
|
@@ -1578,9 +1670,9 @@ export async function applyCompactionResult(
|
|
|
1578
1670
|
// in-context boundary rather than the raw mirror so the persisted count
|
|
1579
1671
|
// stays consistent with what the new summary represents and never
|
|
1580
1672
|
// double-counts an unsliced untrusted view.
|
|
1581
|
-
const inContextCompactedCount =
|
|
1673
|
+
const inContextCompactedCount = !resolveCapabilities(
|
|
1582
1674
|
ctx.trustContext?.trustClass,
|
|
1583
|
-
)
|
|
1675
|
+
).canAccessMemory
|
|
1584
1676
|
? 0
|
|
1585
1677
|
: ctx.contextCompactedMessageCount;
|
|
1586
1678
|
ctx.contextCompactedMessageCount =
|
|
@@ -1657,10 +1749,10 @@ function collapseRawResponses(rawResponses?: unknown[]): unknown | undefined {
|
|
|
1657
1749
|
|
|
1658
1750
|
/**
|
|
1659
1751
|
* Matches any runtime-injection tag that should never appear inside a
|
|
1660
|
-
* generated summary.
|
|
1661
|
-
*
|
|
1662
|
-
*
|
|
1663
|
-
*
|
|
1752
|
+
* generated summary. A hit means the summary echoed an injection tag —
|
|
1753
|
+
* either parroted from history the summarizer read or invented outright.
|
|
1754
|
+
* The durable summary should be clean prose, so the match is surfaced via
|
|
1755
|
+
* telemetry.
|
|
1664
1756
|
*/
|
|
1665
1757
|
const SUMMARY_MEMORY_ECHO_PATTERN =
|
|
1666
1758
|
/<(?:memory|memory_context|memory_image|turn_context|workspace|workspace_top_level|knowledge_base|pkb|system_reminder|now_scratchpad|NOW\.md|active_thread|active_subagents|active_workspace|active_dynamic_page|channel_capabilities|transport_hints|system_notice|non_interactive_context|temporal_context|guardian_context|inbound_actor_context|channel_turn_context|interface_turn_context|channel_command_context|voice_call_control)\b/i;
|
|
@@ -23,7 +23,7 @@ const log = getLogger("conversation-history");
|
|
|
23
23
|
|
|
24
24
|
// ── Helpers ──────────────────────────────────────────────────────────
|
|
25
25
|
|
|
26
|
-
function isToolResultBlock(
|
|
26
|
+
export function isToolResultBlock(
|
|
27
27
|
block: ContentBlock | Record<string, unknown>,
|
|
28
28
|
): boolean {
|
|
29
29
|
return (
|
|
@@ -16,10 +16,8 @@ import type { PermissionPrompter } from "../permissions/prompter.js";
|
|
|
16
16
|
import type { SecretPrompter } from "../permissions/secret-prompter.js";
|
|
17
17
|
import { disposeContextWindowManager } from "../plugins/defaults/compaction/manager-store.js";
|
|
18
18
|
import type { ContentBlock, Message } from "../providers/types.js";
|
|
19
|
-
import {
|
|
20
|
-
|
|
21
|
-
type TrustClass,
|
|
22
|
-
} from "../runtime/actor-trust-resolver.js";
|
|
19
|
+
import { type TrustClass } from "../runtime/actor-trust-resolver.js";
|
|
20
|
+
import { resolveCapabilities } from "../runtime/capabilities.js";
|
|
23
21
|
import { unregisterConversationSender } from "../tools/browser/browser-screencast.js";
|
|
24
22
|
import { type AbortReason, createAbortReason } from "../util/abort-reasons.js";
|
|
25
23
|
import { getLogger } from "../util/logger.js";
|
|
@@ -147,7 +145,7 @@ export function disposeConversation(ctx: DisposeContext): void {
|
|
|
147
145
|
// Trigger graph extraction for end-of-conversation sweep.
|
|
148
146
|
// Only extract from guardian conversations to preserve the memory trust
|
|
149
147
|
// boundary — untrusted content must not influence future memory retrieval.
|
|
150
|
-
if (
|
|
148
|
+
if (resolveCapabilities(ctx.trustContext?.trustClass).canAccessMemory) {
|
|
151
149
|
// Recursion guard: skip graph_extract for auto-analysis conversations.
|
|
152
150
|
// The analysis agent writes memory directly via tools, so extracting
|
|
153
151
|
// from its reflective musings would double-write into the memory graph.
|
|
@@ -28,7 +28,10 @@ import {
|
|
|
28
28
|
import { extractPreferences } from "../notifications/preference-extractor.js";
|
|
29
29
|
import { createPreference } from "../notifications/preferences-store.js";
|
|
30
30
|
import type { ContextWindowResult } from "../plugins/defaults/compaction/window-manager.js";
|
|
31
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
type GuardianPendingScope,
|
|
33
|
+
routeGuardianReply,
|
|
34
|
+
} from "../runtime/guardian-reply-router.js";
|
|
32
35
|
import { publishConversationMessagesChanged } from "../runtime/sync/resource-sync-events.js";
|
|
33
36
|
import { getLogger } from "../util/logger.js";
|
|
34
37
|
import type { CleanResult, Conversation } from "./conversation.js";
|
|
@@ -153,7 +156,7 @@ function resolveQueuedTurnInterfaceContext(
|
|
|
153
156
|
}
|
|
154
157
|
|
|
155
158
|
/** Build a SlashContext from the current conversation state and config. */
|
|
156
|
-
function buildSlashContext(
|
|
159
|
+
export function buildSlashContext(
|
|
157
160
|
content: string,
|
|
158
161
|
conversation: Conversation,
|
|
159
162
|
): SlashContext | undefined {
|
|
@@ -1407,9 +1410,14 @@ export async function processMessage(
|
|
|
1407
1410
|
"vellum",
|
|
1408
1411
|
).map((request) => request.id)
|
|
1409
1412
|
: [];
|
|
1410
|
-
|
|
1413
|
+
// Empty hints → leave the scope unset (identity-fallback): the desktop
|
|
1414
|
+
// guardian can still resolve their pending work by identity/principal.
|
|
1415
|
+
const pendingScope: GuardianPendingScope | undefined =
|
|
1411
1416
|
canonicalPendingRequestHintIdsForConversation.length > 0
|
|
1412
|
-
?
|
|
1417
|
+
? {
|
|
1418
|
+
mode: "scoped",
|
|
1419
|
+
requestIds: canonicalPendingRequestHintIdsForConversation,
|
|
1420
|
+
}
|
|
1413
1421
|
: undefined;
|
|
1414
1422
|
|
|
1415
1423
|
// ── Canonical guardian reply router (desktop/conversation path) ──
|
|
@@ -1428,7 +1436,7 @@ export async function processMessage(
|
|
|
1428
1436
|
conversation.trustContext?.guardianPrincipalId ?? undefined,
|
|
1429
1437
|
},
|
|
1430
1438
|
conversationId: conversation.conversationId,
|
|
1431
|
-
|
|
1439
|
+
pendingScope,
|
|
1432
1440
|
// Desktop path: disable NL classification to avoid consuming non-decision
|
|
1433
1441
|
// messages while a tool confirmation is pending. Deterministic code-prefix
|
|
1434
1442
|
// and callback parsing remain active.
|