@vellumai/assistant 0.10.4 → 0.10.5-dev.202607022329.d89bf2f
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 +94 -91
- package/Dockerfile +5 -16
- package/README.md +7 -10
- package/bun.lock +0 -4
- package/docs/architecture/security.md +20 -20
- package/docs/stt-provider-onboarding.md +4 -5
- package/docs/trusted-contact-access.md +7 -7
- package/eslint-rules/cli-no-daemon-internals.js +4 -0
- package/eslint.config.mjs +7 -1
- package/knip.json +0 -1
- package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +36 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/invite-contract.test.ts +233 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +40 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -8
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +10 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +33 -0
- package/node_modules/@vellumai/gateway-client/src/invite-contract.ts +216 -0
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +91 -0
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +39 -3
- package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +0 -8
- package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +1 -5
- package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +3 -14
- package/openapi.yaml +1073 -225
- package/package.json +1 -4
- package/scripts/test.sh +35 -13
- package/src/__tests__/access-request-seed-content-blocks.test.ts +60 -4
- package/src/__tests__/acp-session.test.ts +4 -1
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +0 -6
- package/src/__tests__/add-message-preassigned-id.test.ts +56 -0
- package/src/__tests__/agent-loop-set-system-prompt.test.ts +139 -0
- package/src/__tests__/app-conversation-ids-backfill.test.ts +3 -0
- package/src/__tests__/app-source-watcher.test.ts +11 -0
- package/src/__tests__/approval-interception-trust-gates.test.ts +148 -3
- package/src/__tests__/assistant-attachments.test.ts +62 -4
- package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -1
- package/src/__tests__/attachments-store-heic-normalize.test.ts +230 -0
- package/src/__tests__/attachments-store.test.ts +3 -0
- package/src/__tests__/background-shell-bash.test.ts +34 -0
- package/src/__tests__/background-shell-host-bash.test.ts +12 -0
- package/src/__tests__/background-tool-registry.test.ts +97 -0
- package/src/__tests__/background-tool-routes.test.ts +72 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
- package/src/__tests__/btw-routes.test.ts +57 -3
- package/src/__tests__/call-controller.test.ts +474 -84
- package/src/__tests__/call-domain.test.ts +48 -1
- package/src/__tests__/call-pointer-messages.test.ts +57 -19
- package/src/__tests__/call-pointer-no-hardcoded-copy.guard.test.ts +2 -6
- package/src/__tests__/call-routes-http.test.ts +15 -14
- package/src/__tests__/call-setup-flow-invite.test.ts +568 -0
- package/src/__tests__/call-setup-flow-midcall-trust.test.ts +231 -0
- package/src/__tests__/call-setup-flow-name-capture.test.ts +754 -0
- package/src/__tests__/call-setup-flow-verification.test.ts +925 -0
- package/src/__tests__/call-setup-flow.test.ts +311 -0
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +0 -1
- package/src/__tests__/channel-guardian.test.ts +4 -7
- package/src/__tests__/channel-readiness-service.test.ts +0 -6
- package/src/__tests__/channel-readiness-slack-remote.test.ts +0 -4
- package/src/__tests__/channel-retry-sweep.test.ts +76 -64
- package/src/__tests__/channel-setup-panel-ack.test.ts +184 -0
- package/src/__tests__/clear-all-lexical.test.ts +90 -0
- package/src/__tests__/compactor-media-strip.test.ts +177 -0
- package/src/__tests__/config-loader-backfill.test.ts +5 -5
- package/src/__tests__/config-schema.test.ts +17 -0
- package/src/__tests__/contact-store-interaction-info.test.ts +27 -70
- package/src/__tests__/contacts-relay-reads.test.ts +188 -23
- package/src/__tests__/contacts-tools.test.ts +42 -1
- package/src/__tests__/contacts-write.test.ts +181 -0
- package/src/__tests__/context-search-conversations-source.test.ts +220 -81
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop.test.ts +39 -0
- package/src/__tests__/conversation-analysis-routes.test.ts +1 -1
- package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -0
- package/src/__tests__/conversation-clear-safety.test.ts +0 -1
- package/src/__tests__/conversation-crud-enabled-plugins.test.ts +60 -0
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -1
- package/src/__tests__/conversation-disk-view.test.ts +1 -0
- package/src/__tests__/conversation-enabledplugins-route.test.ts +184 -0
- package/src/__tests__/conversation-error.test.ts +0 -18
- package/src/__tests__/conversation-fork-crud.test.ts +67 -0
- package/src/__tests__/conversation-history-web-search.test.ts +7 -137
- package/src/__tests__/conversation-initial-prompt.test.ts +110 -0
- package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +191 -0
- package/src/__tests__/conversation-process-callsite.test.ts +37 -0
- package/src/__tests__/conversation-queue.test.ts +149 -0
- package/src/__tests__/conversation-routes-enabled-plugins.test.ts +392 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +84 -0
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +407 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +36 -16
- package/src/__tests__/conversation-skill-tools.test.ts +73 -0
- package/src/__tests__/conversation-wipe.test.ts +20 -5
- package/src/__tests__/credential-prompt-route.test.ts +69 -0
- package/src/__tests__/credential-security-invariants.test.ts +1 -3
- package/src/__tests__/db-drop-messages-fts.test.ts +115 -0
- package/src/__tests__/deterministic-verification-control-plane.test.ts +1 -62
- package/src/__tests__/edit-propagation.test.ts +56 -2
- package/src/__tests__/empty-state-greeting-cache.test.ts +9 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +15 -110
- package/src/__tests__/guardian-expiry-notifier.test.ts +1 -0
- package/src/__tests__/guardian-question-mode.test.ts +57 -0
- package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -1
- package/src/__tests__/guardian-wait-controller.test.ts +619 -0
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +33 -2
- package/src/__tests__/heic-fixture.ts +55 -0
- package/src/__tests__/helpers/seed-contact-channel.ts +0 -2
- package/src/__tests__/http-conversation-lineage.test.ts +6 -1
- package/src/__tests__/image-conversion.test.ts +170 -0
- package/src/__tests__/inbound-invite-redemption.test.ts +72 -341
- package/src/__tests__/introduction-card-resolver.test.ts +354 -0
- package/src/__tests__/invite-redeemed-ipc.test.ts +97 -0
- package/src/__tests__/invite-routes-http.test.ts +246 -420
- package/src/__tests__/job-handler-registration-guard.test.ts +104 -0
- package/src/__tests__/lexical-index-dual-write.test.ts +426 -0
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +2 -2
- package/src/__tests__/list-messages-attachments.test.ts +159 -0
- package/src/__tests__/list-messages-background-tool-completion.test.ts +141 -0
- package/src/__tests__/list-messages-queued.test.ts +25 -0
- package/src/__tests__/managed-store.test.ts +129 -1
- package/src/__tests__/media-stream-audio-transcode.test.ts +113 -0
- package/src/__tests__/media-stream-output.test.ts +350 -19
- package/src/__tests__/media-stream-server-integration.test.ts +943 -169
- package/src/__tests__/media-stream-stt-session.test.ts +498 -1
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +2 -2
- package/src/__tests__/model-intents.test.ts +1 -1
- package/src/__tests__/mtime-cache.test.ts +19 -0
- package/src/__tests__/non-member-access-request.test.ts +349 -3
- package/src/__tests__/notification-decision-fallback.test.ts +104 -8
- package/src/__tests__/notification-decision-strategy.test.ts +57 -8
- package/src/__tests__/onboarding-template-contract.test.ts +27 -43
- package/src/__tests__/openai-provider.test.ts +33 -0
- package/src/__tests__/openai-responses-provider.test.ts +40 -0
- package/src/__tests__/persistence-layering-guard.test.ts +29 -20
- package/src/__tests__/persona-resolver.test.ts +56 -2
- package/src/__tests__/personal-memory-auth-bypass.test.ts +62 -0
- package/src/__tests__/phone.test.ts +1 -15
- package/src/__tests__/plugin-bootstrap.test.ts +25 -196
- package/src/__tests__/plugin-disabled-state.test.ts +33 -0
- package/src/__tests__/plugin-effective-enabled-set.test.ts +227 -0
- package/src/__tests__/plugin-event-hub-facade.test.ts +323 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +156 -42
- package/src/__tests__/plugin-injector-contribution.test.ts +4 -20
- package/src/__tests__/plugin-pipeline.test.ts +63 -1
- package/src/__tests__/plugin-route-contribution.test.ts +62 -115
- package/src/__tests__/plugin-tool-contribution.test.ts +0 -22
- package/src/__tests__/plugin-types.test.ts +0 -1
- package/src/__tests__/pointer-conversation-trust.test.ts +38 -6
- package/src/__tests__/pre-model-call-sanitize.test.ts +1 -1
- package/src/__tests__/prune-old-tool-invocations-job.test.ts +97 -0
- package/src/__tests__/public-ingress-urls.test.ts +0 -48
- package/src/__tests__/qdrant-collection-migration.test.ts +145 -2
- package/src/__tests__/reaction-intercept-member-verdict-warm.test.ts +0 -1
- package/src/__tests__/resolve-trust-class.test.ts +28 -10
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +137 -0
- package/src/__tests__/schedule-retry.test.ts +38 -14
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +3 -3
- package/src/__tests__/schedule-routes.test.ts +14 -6
- package/src/__tests__/schedule-store.test.ts +3 -1
- package/src/__tests__/scheduler-disk-pressure.test.ts +17 -6
- package/src/__tests__/scheduler-recurrence.test.ts +57 -107
- package/src/__tests__/scheduler-reuse-conversation.test.ts +51 -46
- package/src/__tests__/scheduler-wake.test.ts +13 -23
- package/src/__tests__/scheduler-worker-standdown.test.ts +220 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -1
- package/src/__tests__/shell-observability.test.ts +1 -0
- package/src/__tests__/skill-boundary-guard.test.ts +3 -4
- package/src/__tests__/skill-load-plugin-scope.test.ts +238 -0
- package/src/__tests__/skill-projection-feature-flag.test.ts +2 -0
- package/src/__tests__/skill-script-runner-host.test.ts +53 -0
- package/src/__tests__/skill-script-runner-sandbox.test.ts +5 -2
- package/src/__tests__/skill-tool-factory.test.ts +73 -1
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +37 -14
- package/src/__tests__/slack-inbound-verification.test.ts +36 -0
- package/src/__tests__/slack-notification-approval-card.test.ts +89 -2
- package/src/__tests__/slack-reaction-canonical-approval.test.ts +51 -1
- package/src/__tests__/stt-hints.test.ts +2 -256
- package/src/__tests__/subagent-allowlist-validation.test.ts +47 -0
- package/src/__tests__/subagent-call-site-routing.test.ts +72 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +14 -2
- package/src/__tests__/subagent-persistence.test.ts +122 -0
- package/src/__tests__/subagent-spawn-and-await.test.ts +1 -0
- package/src/__tests__/subagent-terminal-message.test.ts +99 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +78 -1
- package/src/__tests__/system-prompt.test.ts +17 -118
- package/src/__tests__/task-scheduler.test.ts +68 -89
- package/src/__tests__/telephony-credential-preflight.test.ts +312 -0
- package/src/__tests__/telephony-tts-guard.test.ts +538 -0
- package/src/__tests__/title-generate-hook.test.ts +16 -0
- package/src/__tests__/tool-approval-handler.test.ts +87 -1
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +45 -20
- package/src/__tests__/tool-grant-request-escalation.test.ts +39 -0
- package/src/__tests__/trust-context-guards.test.ts +21 -10
- package/src/__tests__/trusted-contact-multichannel.test.ts +4 -0
- package/src/__tests__/twilio-provider.test.ts +17 -17
- package/src/__tests__/twilio-routes-twiml.test.ts +6 -543
- package/src/__tests__/twilio-routes.test.ts +257 -387
- package/src/__tests__/twilio-validation.test.ts +1 -1
- package/src/__tests__/unified-turn-context-client-os.test.ts +45 -0
- package/src/__tests__/usage-cache-backfill-migration.test.ts +5 -0
- package/src/__tests__/voice-approval-resolver-relay.test.ts +150 -0
- package/src/__tests__/voice-ingress-preflight.test.ts +61 -0
- package/src/__tests__/voice-quality.test.ts +2 -2
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +1 -7
- package/src/__tests__/voice-session-bridge-processing-wait.test.ts +27 -0
- package/src/__tests__/voice-session-bridge.test.ts +1 -10
- package/src/__tests__/workspace-git-service.test.ts +1 -1
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +1 -0
- package/src/__tests__/workspace-migration-118-seed-now-md.test.ts +120 -0
- package/src/__tests__/workspace-migration-120-revise-onboarding-threads.test.ts +175 -0
- package/src/__tests__/workspace-migration-121-seed-default-user-guardrails.test.ts +118 -0
- package/src/__tests__/workspace-migration-122-relocate-default-user-boundary.test.ts +119 -0
- package/src/__tests__/workspace-migration-123-swap-quality-profile-to-fable.test.ts +191 -0
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +235 -241
- package/src/acp/__tests__/prepare-agent-env.test.ts +0 -97
- package/src/acp/__tests__/session-manager-persistence.test.ts +2 -0
- package/src/acp/__tests__/session-manager-resume.test.ts +8 -0
- package/src/acp/__tests__/session-manager-usage.test.ts +6 -0
- package/src/acp/__tests__/session-manager.test.ts +6 -0
- package/src/acp/agent-process.test.ts +116 -0
- package/src/acp/agent-process.ts +71 -0
- package/src/acp/auto-install.ts +12 -8
- package/src/acp/failure-error.test.ts +109 -0
- package/src/acp/failure-error.ts +111 -0
- package/src/acp/prepare-agent-env.ts +0 -12
- package/src/acp/resolve-agent.test.ts +6 -45
- package/src/acp/resolve-agent.ts +2 -4
- package/src/acp/session-manager.test.ts +312 -0
- package/src/acp/session-manager.ts +102 -46
- package/src/agent/ax-tree-compaction.test.ts +4 -1
- package/src/agent/image-optimize.ts +17 -127
- package/src/agent/loop.ts +45 -192
- package/src/api/events/background-tool-completed.test.ts +51 -0
- package/src/api/events/background-tool-completed.ts +29 -0
- package/src/api/events/background-tool-started.test.ts +36 -0
- package/src/api/events/background-tool-started.ts +28 -0
- package/src/api/events/conversation-error.ts +0 -1
- package/src/api/events/open-panel.ts +33 -0
- package/src/api/events/subagent-status-changed.ts +4 -1
- package/src/api/index.ts +19 -0
- package/src/api/responses/conversation-message.ts +34 -0
- package/src/approvals/guardian-decision-primitive.ts +74 -24
- package/src/approvals/guardian-request-resolvers.ts +450 -122
- package/src/apps/app-store.ts +1 -0
- package/src/apps/shared-app-links-store.ts +1 -0
- package/src/avatar/identity-avatar.ts +3 -7
- package/src/background-wake/wake-intent-hooks.test.ts +1 -1
- package/src/calls/__tests__/fish-audio-client.test.ts +73 -0
- package/src/calls/__tests__/gateway-invite-reader.test.ts +170 -0
- package/src/calls/__tests__/relay-setup-router.test.ts +126 -102
- package/src/calls/call-controller.ts +134 -48
- package/src/calls/call-domain.ts +18 -42
- package/src/calls/call-pointer-messages.ts +51 -67
- package/src/calls/call-setup-flow-types.ts +76 -0
- package/src/calls/call-setup-flow.ts +1743 -0
- package/src/calls/call-speech-output.ts +87 -23
- package/src/calls/call-store.ts +4 -0
- package/src/calls/call-transport.ts +22 -36
- package/src/calls/fish-audio-client.ts +3 -0
- package/src/calls/gateway-invite-reader.ts +98 -0
- package/src/calls/guardian-wait-controller.ts +451 -0
- package/src/calls/media-stream-audio-transcode.ts +82 -2
- package/src/calls/media-stream-output.ts +142 -36
- package/src/calls/media-stream-server.ts +297 -178
- package/src/calls/media-stream-stt-session.ts +393 -50
- package/src/calls/media-turn-detector.ts +4 -6
- package/src/calls/relay-access-wait.ts +3 -4
- package/src/calls/relay-setup-router.ts +22 -43
- package/src/calls/relay-verification.ts +17 -24
- package/src/calls/resolve-call-tts-provider.ts +96 -29
- package/src/calls/stt-hints.ts +24 -87
- package/src/calls/telephony-credential-preflight.ts +159 -0
- package/src/calls/telephony-tts-capability.ts +183 -0
- package/src/calls/tts-call-strategy.ts +18 -20
- package/src/calls/twilio-provider.ts +3 -2
- package/src/calls/twilio-routes.ts +47 -351
- package/src/calls/types.ts +5 -3
- package/src/calls/voice-ingress-preflight.ts +9 -0
- package/src/calls/voice-quality.ts +13 -18
- package/src/calls/voice-session-bridge.ts +25 -35
- package/src/channels/__tests__/types.test.ts +28 -0
- package/src/channels/channel-verification-sessions.ts +7 -2
- package/src/channels/config.ts +0 -42
- package/src/channels/slack-thread-store.ts +12 -0
- package/src/channels/types.ts +23 -0
- package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -1
- package/src/cli/commands/__tests__/schedules.test.ts +83 -34
- package/src/cli/commands/__tests__/status.test.ts +42 -2
- package/src/cli/commands/contacts.ts +2 -2
- package/src/cli/commands/credentials.ts +17 -0
- package/src/cli/commands/monitoring.ts +191 -0
- package/src/cli/commands/schedules-worker.ts +175 -0
- package/src/cli/commands/schedules.ts +169 -43
- package/src/cli/commands/status.ts +12 -1
- package/src/cli/commands/tools.ts +5 -1
- package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +1 -0
- package/src/cli/lib/__tests__/search-plugins.test.ts +29 -1
- package/src/cli/lib/__tests__/toggle-plugin.test.ts +7 -0
- package/src/cli/lib/search-plugins.ts +6 -0
- package/src/cli/lib/toggle-plugin.ts +21 -2
- package/src/cli/program.ts +3 -1
- package/src/config/__tests__/deployment-context-defaults.test.ts +23 -0
- package/src/config/acp-defaults.test.ts +0 -10
- package/src/config/acp-defaults.ts +0 -6
- package/src/config/bundled-skills/acp/SKILL.md +13 -45
- package/src/config/bundled-skills/acp/TOOLS.json +3 -3
- package/src/config/bundled-skills/app-builder/SKILL.md +3 -3
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +9 -9
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +1 -1
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +1 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -9
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +10 -7
- package/src/config/bundled-skills/skill-management/TOOLS.json +10 -0
- package/src/config/call-site-defaults.ts +0 -2
- package/src/config/feature-flag-registry.json +16 -8
- package/src/config/loader.ts +11 -0
- package/src/config/schema.ts +9 -1
- package/src/config/schemas/__tests__/memory-v2.test.ts +2 -2
- package/src/config/schemas/__tests__/memory-v3.test.ts +64 -0
- package/src/config/schemas/call-site-catalog.ts +0 -12
- package/src/config/schemas/calls.ts +8 -0
- package/src/config/schemas/elevenlabs.ts +1 -1
- package/src/config/schemas/llm.ts +0 -2
- package/src/config/schemas/memory-v2.ts +1 -1
- package/src/config/schemas/memory-v3.ts +82 -0
- package/src/config/schemas/monitoring.ts +61 -0
- package/src/config/schemas/schedules.ts +35 -0
- package/src/config/seed-inference-profiles.ts +2 -2
- package/src/config/skills-plugin-filter.test.ts +96 -0
- package/src/config/skills.ts +26 -0
- package/src/contacts/__tests__/member-write-relay.test.ts +156 -4
- package/src/contacts/canonical-guardian-store.ts +5 -0
- package/src/contacts/contact-store.ts +81 -35
- package/src/contacts/contacts-write.ts +50 -25
- package/src/contacts/member-write-relay.ts +115 -31
- package/src/contacts/types.ts +0 -8
- package/src/context/compactor.ts +29 -15
- package/src/context/outbound-sanitize.ts +202 -0
- package/src/daemon/__tests__/abort-null-controller.test.ts +167 -0
- package/src/daemon/__tests__/conversation-tool-setup-plugin-scope.test.ts +122 -0
- package/src/daemon/__tests__/embedding-reconcile.test.ts +99 -16
- package/src/daemon/__tests__/wake-conversation-ops-completion.test.ts +107 -0
- package/src/daemon/abort-watchdog.ts +7 -0
- package/src/daemon/app-source-watcher.ts +9 -0
- package/src/daemon/assistant-attachments.ts +42 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +256 -147
- package/src/daemon/conversation-agent-loop.ts +61 -68
- package/src/daemon/conversation-error.ts +1 -15
- package/src/daemon/conversation-history.ts +32 -236
- package/src/daemon/conversation-initial-prompt.ts +77 -0
- package/src/daemon/conversation-lifecycle.ts +25 -1
- package/src/daemon/conversation-messaging.ts +2 -2
- package/src/daemon/conversation-plugin-scope.ts +38 -0
- package/src/daemon/conversation-process.ts +50 -14
- package/src/daemon/conversation-runtime-assembly.ts +36 -6
- package/src/daemon/conversation-skill-tools.ts +19 -3
- package/src/daemon/conversation-store.ts +3 -3
- package/src/daemon/conversation-surfaces.ts +171 -0
- package/src/daemon/conversation-tool-setup.test.ts +95 -0
- package/src/daemon/conversation-tool-setup.ts +116 -1
- package/src/daemon/conversation-turn-finalize.ts +211 -0
- package/src/daemon/conversation.ts +92 -1
- package/src/daemon/disk-pressure-policy.ts +2 -1
- package/src/daemon/event-loop-watchdog.ts +22 -6
- package/src/daemon/external-plugins-bootstrap.ts +47 -134
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +26 -14
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +27 -14
- package/src/daemon/handlers/__tests__/config-channels.test.ts +0 -5
- package/src/daemon/handlers/config-a2a.ts +7 -14
- package/src/daemon/handlers/config-channels.ts +2 -10
- package/src/daemon/handlers/conversation-history.ts +3 -1
- package/src/daemon/handlers/conversations.ts +0 -52
- package/src/daemon/handlers/shared.ts +4 -24
- package/src/daemon/handlers/skills.ts +4 -1
- package/src/daemon/host-cu-proxy.ts +1 -1
- package/src/daemon/lifecycle.ts +59 -472
- package/src/daemon/message-protocol.ts +3 -3
- package/src/daemon/message-provenance.ts +12 -14
- package/src/daemon/message-types/background-tools.ts +28 -0
- package/src/daemon/message-types/contacts.ts +2 -10
- package/src/daemon/message-types/conversations.ts +10 -0
- package/src/daemon/message-types/integrations.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +1 -0
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/pointer-conversation-trust.ts +23 -9
- package/src/daemon/pointer-turn-runner.ts +174 -0
- package/src/daemon/providers-setup.ts +16 -0
- package/src/daemon/shutdown-handlers.ts +139 -47
- package/src/daemon/skill-memory-refresh.ts +2 -2
- package/src/daemon/sqlite-corruption-watchdog.test.ts +217 -0
- package/src/daemon/sqlite-corruption-watchdog.ts +155 -0
- package/src/daemon/tool-setup-types.ts +8 -0
- package/src/daemon/trust-context.ts +21 -6
- package/src/daemon/turn-latency-tracker.test.ts +93 -0
- package/src/daemon/turn-latency-tracker.ts +38 -0
- package/src/daemon/wake-conversation-ops.ts +10 -8
- package/src/documents/document-comments-store.test.ts +7 -1
- package/src/documents/document-comments-store.ts +8 -0
- package/src/documents/document-store.ts +15 -0
- package/src/export/__tests__/transcript-formatter.test.ts +11 -0
- package/src/export/transcript-formatter.ts +49 -67
- package/src/home/__tests__/feed-writer.test.ts +247 -1
- package/src/home/conversation-starter-checkpoints.ts +1 -0
- package/src/home/feed-writer.ts +61 -0
- package/src/home/job-handlers/conversation-starters.ts +1 -0
- package/src/hooks/hook-loader.ts +12 -0
- package/src/hooks/registry.ts +32 -4
- package/src/inbound/public-ingress-urls.ts +0 -17
- package/src/ipc/__tests__/contacts-info-ipc.test.ts +285 -0
- package/src/ipc/assistant-server.ts +28 -7
- package/src/ipc/routes/__tests__/contacts-mirror-apply-atomicity.test.ts +62 -0
- package/src/ipc/routes/__tests__/contacts-mirror-apply.test.ts +272 -0
- package/src/ipc/routes/__tests__/contacts-mirror-ipc-routes.test.ts +322 -0
- package/src/ipc/routes/__tests__/invite-ipc-routes.test.ts +60 -4
- package/src/ipc/routes/contacts-info-ipc-routes.ts +239 -0
- package/src/ipc/routes/contacts-mirror-ipc-routes.ts +202 -0
- package/src/ipc/routes/db-proxy.ts +5 -2
- package/src/ipc/routes/invite-ipc-routes.ts +53 -39
- package/src/jobs/worker.ts +9 -2
- package/src/live-voice/__tests__/live-voice-archive.test.ts +10 -1
- package/src/live-voice/live-voice-archive.ts +5 -0
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +22 -6
- package/src/messaging/providers/channel-transport.ts +6 -0
- package/src/messaging/providers/index.ts +3 -0
- package/src/messaging/providers/slack/api.test.ts +49 -1
- package/src/messaging/providers/slack/api.ts +110 -0
- package/src/messaging/providers/slack/send.test.ts +85 -0
- package/src/messaging/providers/slack/send.ts +100 -28
- package/src/messaging/providers/slack/transport.ts +7 -13
- package/src/messaging/providers/whatsapp/send.ts +29 -9
- package/src/monitoring/__tests__/control.test.ts +235 -0
- package/src/monitoring/__tests__/sample-ring-buffer.test.ts +96 -0
- package/src/monitoring/control.ts +105 -0
- package/src/monitoring/resource-sampler.ts +258 -0
- package/src/monitoring/sample-ring-buffer.ts +108 -0
- package/src/monitoring/worker.ts +94 -0
- package/src/notifications/README.md +1 -1
- package/src/notifications/access-request-copy.ts +94 -23
- package/src/notifications/adapters/slack.ts +89 -21
- package/src/notifications/approval-card-builder.ts +33 -18
- package/src/notifications/approval-card-data.ts +48 -15
- package/src/notifications/broadcaster.ts +25 -16
- package/src/notifications/decision-engine.ts +131 -32
- package/src/notifications/guardian-question-mode.ts +58 -10
- package/src/permissions/approval-policy.ts +8 -1
- package/src/permissions/checker.ts +2 -0
- package/src/permissions/gateway-threshold-reader.ts +7 -6
- package/src/permissions/ipc-risk-types.ts +1 -0
- package/src/permissions/secret-prompter.ts +11 -3
- package/src/permissions/types.ts +2 -2
- package/src/persistence/__tests__/conversation-queries-search.test.ts +397 -0
- package/src/persistence/__tests__/conversation-search-lexical.test.ts +103 -0
- package/src/persistence/__tests__/jobs-worker-memory-disabled.test.ts +95 -0
- package/src/persistence/__tests__/slow-query-log.test.ts +266 -0
- package/src/persistence/__tests__/slow-sync-log.test.ts +155 -0
- package/src/persistence/a2a-invite-store.ts +205 -0
- package/src/persistence/attachments-store.ts +94 -10
- package/src/persistence/checkpoints.ts +45 -0
- package/src/persistence/conversation-crud.ts +453 -260
- package/src/persistence/conversation-display-order-migration.ts +8 -2
- package/src/persistence/conversation-group-migration.test.ts +8 -0
- package/src/persistence/conversation-group-migration.ts +9 -0
- package/src/persistence/conversation-queries.ts +244 -125
- package/src/persistence/conversation-row-batch-delete.ts +9 -5
- package/src/persistence/conversation-search-lexical.ts +49 -0
- package/src/persistence/db-async-query.ts +42 -0
- package/src/persistence/db-connection.ts +13 -0
- package/src/persistence/delivery-channels.ts +0 -82
- package/src/persistence/delivery-crud.ts +27 -6
- package/src/persistence/embeddings/__tests__/embedding-identity.test.ts +18 -5
- package/src/persistence/embeddings/__tests__/messages-lexical-index.test.ts +334 -0
- package/src/persistence/embeddings/embedding-identity.ts +17 -5
- package/src/persistence/embeddings/embedding-runtime-manager.ts +31 -0
- package/src/persistence/embeddings/messages-lexical-index.ts +396 -0
- package/src/persistence/embeddings/qdrant-client.ts +81 -5
- package/src/persistence/group-crud.ts +13 -1
- package/src/persistence/job-handlers/__tests__/message-lexical-backfill.test.ts +506 -0
- package/src/persistence/job-handlers/__tests__/message-lexical-enqueue.test.ts +164 -0
- package/src/persistence/job-handlers/__tests__/message-lexical.test.ts +259 -0
- package/src/persistence/job-handlers/cleanup.ts +57 -9
- package/src/persistence/job-handlers/message-lexical-backfill.ts +187 -0
- package/src/persistence/job-handlers/message-lexical.ts +251 -0
- package/src/persistence/jobs-store.ts +102 -8
- package/src/persistence/jobs-worker.ts +68 -28
- package/src/persistence/llm-request-log-store.ts +35 -19
- package/src/persistence/llm-usage-store.ts +11 -0
- package/src/persistence/memory-lifecycle-hooks.test.ts +65 -0
- package/src/persistence/memory-lifecycle-hooks.ts +55 -1
- package/src/persistence/migrations/028-call-session-mode.ts +1 -1
- package/src/persistence/migrations/116-messages-fts.ts +8 -1
- package/src/persistence/migrations/311-create-subagents-table.ts +50 -0
- package/src/persistence/migrations/312-drop-inbox-conversation-state-table.ts +15 -0
- package/src/persistence/migrations/313-drop-messages-fts.ts +17 -0
- package/src/persistence/migrations/314-add-conversation-enabled-plugins.ts +25 -0
- package/src/persistence/migrations/315-create-a2a-invites.ts +58 -0
- package/src/persistence/migrations/316-drop-contact-channels-invite-id.ts +28 -0
- package/src/persistence/migrations/317-canonical-guardian-requester-signals.ts +24 -0
- package/src/persistence/migrations/318-drop-contact-channel-telemetry.ts +32 -0
- package/src/persistence/migrations/__tests__/315-create-a2a-invites.test.ts +161 -0
- package/src/persistence/migrations/__tests__/316-drop-contact-channels-invite-id.test.ts +156 -0
- package/src/persistence/migrations/__tests__/318-drop-contact-channel-telemetry.test.ts +134 -0
- package/src/persistence/migrations/__tests__/migration-prefix-guard.test.ts +99 -0
- package/src/persistence/raw-query.ts +50 -11
- package/src/persistence/schema/a2a.ts +14 -0
- package/src/persistence/schema/contacts.ts +0 -62
- package/src/persistence/schema/conversation-groups.ts +12 -0
- package/src/persistence/schema/conversations.ts +2 -0
- package/src/persistence/schema/documents.ts +65 -0
- package/src/persistence/schema/guardian.ts +4 -0
- package/src/persistence/schema/index.ts +4 -0
- package/src/persistence/schema/memory-injection.ts +62 -0
- package/src/persistence/schema/workflows.ts +55 -0
- package/src/persistence/slow-query-log.ts +437 -0
- package/src/persistence/slow-sync-log.ts +204 -0
- package/src/persistence/steps.ts +16 -0
- package/src/persistence/subagent-store.ts +125 -0
- package/src/persistence/worker-control.ts +45 -238
- package/src/plugin-api/event-hub-facade.ts +172 -0
- package/src/plugin-api/index.ts +9 -1
- package/src/plugin-api/types.ts +40 -9
- package/src/plugins/defaults/default-plugin-names.ts +60 -0
- package/src/plugins/defaults/index.ts +19 -29
- package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +46 -67
- package/src/plugins/defaults/memory/__tests__/db-async-query.test.ts +36 -1
- package/src/plugins/defaults/memory/__tests__/find-most-recent-retrospective-for.test.ts +2 -4
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +2 -2
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +9 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +7 -4
- package/src/plugins/defaults/memory/config.ts +11 -0
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +1 -1
- package/src/plugins/defaults/memory/context-search/sources/conversations.ts +124 -113
- package/src/plugins/defaults/memory/embeddings.ts +77 -0
- package/src/plugins/defaults/memory/find-most-recent-retrospective-for.ts +66 -0
- package/src/plugins/defaults/memory/frontmatter.ts +50 -0
- package/src/plugins/defaults/memory/graph/bootstrap.test.ts +36 -10
- package/src/plugins/defaults/memory/graph/bootstrap.ts +6 -5
- package/src/plugins/defaults/memory/graph/consolidation.ts +3 -5
- package/src/plugins/defaults/memory/graph/extraction.ts +3 -6
- package/src/plugins/defaults/memory/graph/graph-search.ts +12 -23
- package/src/plugins/defaults/memory/graph/narrative.ts +3 -5
- package/src/plugins/defaults/memory/graph/pattern-scan.ts +3 -5
- package/src/plugins/defaults/memory/graph/retriever.test.ts +1 -6
- package/src/plugins/defaults/memory/graph/retriever.ts +5 -10
- package/src/plugins/defaults/memory/graph/tools.ts +1 -1
- package/src/plugins/defaults/memory/hooks/init.ts +31 -5
- package/src/plugins/defaults/memory/indexer.ts +2 -3
- package/src/plugins/defaults/memory/injectors.ts +2 -2
- package/src/plugins/defaults/memory/job-handler-registration.ts +96 -0
- package/src/plugins/defaults/memory/job-handlers/backfill.ts +4 -26
- package/src/plugins/defaults/memory/job-handlers/embedding.test.ts +6 -19
- package/src/plugins/defaults/memory/job-handlers/embedding.ts +9 -22
- package/src/plugins/defaults/memory/job-handlers/index-maintenance.ts +2 -3
- package/src/plugins/defaults/memory/job-handlers.ts +13 -12
- package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +1 -1
- package/src/plugins/defaults/memory/llm-helpers.ts +76 -0
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +8 -5
- package/src/plugins/defaults/memory/memory-retrospective-startup-cleanup.ts +2 -2
- package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +2 -0
- package/src/plugins/defaults/memory/persistence-hooks.ts +46 -1
- package/src/plugins/defaults/memory/pkb/pkb-index.ts +1 -5
- package/src/plugins/defaults/memory/pkb/pkb-search.ts +2 -2
- package/src/plugins/defaults/memory/routes/__tests__/memory-v2-simulate-route.test.ts +4 -6
- package/src/plugins/defaults/memory/routes/memory-item-routes.ts +1 -1
- package/src/plugins/defaults/memory/search/semantic.ts +2 -2
- package/src/plugins/defaults/memory/startup.ts +244 -0
- package/src/plugins/defaults/memory/task-memory-cleanup.ts +8 -0
- package/src/{daemon → plugins/defaults/memory/v2}/__tests__/memory-v2-startup.test.ts +6 -6
- package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +2 -13
- package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +4 -5
- package/src/plugins/defaults/memory/v2/__tests__/sweep-job.test.ts +1 -8
- package/src/plugins/defaults/memory/v2/activation.ts +2 -4
- package/src/plugins/defaults/memory/v2/cli-command-store.ts +2 -4
- package/src/plugins/defaults/memory/v2/frontmatter-sweep.ts +1 -1
- package/src/{daemon → plugins/defaults/memory/v2}/memory-v2-startup.test.ts +8 -8
- package/src/{daemon → plugins/defaults/memory/v2}/memory-v2-startup.ts +20 -22
- package/src/plugins/defaults/memory/v2/migration.ts +2 -5
- package/src/plugins/defaults/memory/v2/page-store.ts +1 -1
- package/src/plugins/defaults/memory/v2/qdrant.ts +2 -3
- package/src/plugins/defaults/memory/v2/router.ts +5 -5
- package/src/plugins/defaults/memory/v2/sim.ts +2 -4
- package/src/plugins/defaults/memory/v2/skill-store.ts +2 -4
- package/src/plugins/defaults/memory/v2/sweep-job.ts +6 -6
- package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +11 -9
- package/src/plugins/defaults/memory/v3/__tests__/dense.test.ts +107 -2
- package/src/plugins/defaults/memory/v3/__tests__/gate-flag.test.ts +69 -0
- package/src/plugins/defaults/memory/v3/__tests__/gate.test.ts +181 -0
- package/src/plugins/defaults/memory/v3/__tests__/live-integration.test.ts +7 -3
- package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +345 -8
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +1 -4
- package/src/plugins/defaults/memory/v3/__tests__/section-needle.test.ts +64 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +18 -13
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +62 -1
- package/src/plugins/defaults/memory/v3/card.ts +1 -4
- package/src/plugins/defaults/memory/v3/dense.ts +60 -25
- package/src/plugins/defaults/memory/v3/edge.ts +1 -1
- package/src/plugins/defaults/memory/v3/gate-flag.ts +20 -0
- package/src/plugins/defaults/memory/v3/gate.ts +158 -0
- package/src/plugins/defaults/memory/v3/maintain-job.ts +2 -4
- package/src/plugins/defaults/memory/v3/orchestrate.ts +186 -25
- package/src/plugins/defaults/memory/v3/pool-select.test.ts +7 -9
- package/src/plugins/defaults/memory/v3/pool-select.ts +6 -6
- package/src/plugins/defaults/memory/v3/prune.ts +2 -2
- package/src/plugins/defaults/memory/v3/section-dense-store.ts +8 -11
- package/src/plugins/defaults/memory/v3/section-needle.ts +27 -7
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +10 -0
- package/src/plugins/defaults/memory/v3-eval/eval-packets.ts +1 -4
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +5 -0
- package/src/plugins/defaults/turn-context/injectors.ts +1 -0
- package/src/plugins/defaults/turn-context/unified-turn-context.ts +12 -0
- package/src/plugins/injector-registry.ts +13 -2
- package/src/plugins/mtime-cache.ts +36 -47
- package/src/plugins/pipeline.ts +15 -1
- package/src/plugins/types.ts +14 -23
- package/src/prompts/__tests__/system-prompt.test.ts +170 -32
- package/src/prompts/persona-resolver.ts +13 -9
- package/src/prompts/system-prompt.ts +30 -9
- package/src/prompts/templates/BOOTSTRAP.md +16 -119
- package/src/prompts/templates/SOUL.md +43 -13
- package/src/prompts/templates/system-sections.ts +32 -27
- package/src/prompts/templates/users/default.md +19 -0
- package/src/providers/__tests__/placeholder-sentinels.test.ts +56 -0
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +96 -1
- package/src/providers/model-intents.ts +2 -2
- package/src/providers/openai/chat-completions-provider.ts +14 -1
- package/src/providers/openai/responses-provider.ts +18 -0
- package/src/providers/placeholder-sentinels.ts +18 -8
- package/src/providers/retry.ts +1 -0
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +0 -64
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +92 -79
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +98 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +62 -3
- package/src/providers/speech-to-text/provider-catalog.ts +0 -89
- package/src/providers/speech-to-text/resolve.ts +55 -0
- package/src/providers/tool-progress-events.test.ts +50 -0
- package/src/providers/tool-progress-events.ts +99 -0
- package/src/providers/types.ts +1 -1
- package/src/providers/vellum-model-routing.test.ts +51 -0
- package/src/providers/vellum-model-routing.ts +84 -0
- package/src/runtime/AGENTS.md +5 -4
- package/src/runtime/__tests__/agent-wake.test.ts +158 -1
- package/src/runtime/__tests__/channel-verification-service.test.ts +2 -2
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +37 -8
- package/src/runtime/access-request-helper.ts +154 -3
- package/src/runtime/actor-trust-resolver.ts +7 -21
- package/src/runtime/agent-wake.ts +41 -1
- package/src/runtime/assistant-event.ts +86 -12
- package/src/runtime/auth/__tests__/route-policy.test.ts +31 -0
- package/src/runtime/channel-approval-types.ts +52 -2
- package/src/runtime/channel-approvals.ts +23 -8
- package/src/runtime/channel-invite-transport.ts +2 -2
- package/src/runtime/channel-invite-transports/voice.ts +1 -1
- package/src/runtime/channel-readiness-service.ts +3 -5
- package/src/runtime/channel-retry-sweep.ts +18 -24
- package/src/runtime/channel-verification-service.ts +9 -11
- package/src/runtime/finalize-event-delivery.ts +30 -16
- package/src/runtime/guardian-action-service.ts +10 -11
- package/src/runtime/guardian-reply-router.ts +122 -21
- package/src/runtime/http-server.ts +44 -101
- package/src/runtime/introduction-policy.test.ts +214 -0
- package/src/runtime/introduction-policy.ts +284 -0
- package/src/runtime/invite-service.ts +104 -361
- package/src/runtime/local-actor-identity.test.ts +38 -0
- package/src/runtime/local-actor-identity.ts +14 -0
- package/src/runtime/middleware/__tests__/rate-limiter.test.ts +22 -0
- package/src/runtime/middleware/rate-limiter.ts +30 -0
- package/src/runtime/middleware/twilio-validation.ts +5 -7
- package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +28 -0
- package/src/runtime/migrations/origin-mode.ts +6 -6
- package/src/runtime/pre-first-message-gate.ts +1 -0
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +6 -35
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +24 -3
- package/src/runtime/routes/__tests__/contact-routes.test.ts +80 -15
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +7 -1
- package/src/runtime/routes/__tests__/global-search-routes.test.ts +0 -3
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +142 -1
- package/src/runtime/routes/__tests__/invite-relay-routes.test.ts +119 -30
- package/src/runtime/routes/__tests__/migration-import-allowed-hosts-env.test.ts +70 -0
- package/src/runtime/routes/__tests__/monitoring-routes.test.ts +194 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +755 -29
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +4 -0
- package/src/runtime/routes/__tests__/schedule-routes-create.test.ts +70 -0
- package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +161 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +1 -1
- package/src/runtime/routes/acp-routes.ts +15 -3
- package/src/runtime/routes/app-management-routes.ts +4 -7
- package/src/runtime/routes/approval-routes.ts +4 -0
- package/src/runtime/routes/attachment-routes.ts +54 -3
- package/src/runtime/routes/avatar-routes.ts +0 -4
- package/src/runtime/routes/background-tool-routes.ts +34 -5
- package/src/runtime/routes/btw-routes.ts +32 -4
- package/src/runtime/routes/channel-route-shared.ts +18 -14
- package/src/runtime/routes/channel-verification-routes.ts +0 -3
- package/src/runtime/routes/contact-routes.ts +298 -117
- package/src/runtime/routes/conversation-list-routes.ts +6 -0
- package/src/runtime/routes/conversation-management-routes.ts +74 -37
- package/src/runtime/routes/conversation-query-routes.ts +5 -2
- package/src/runtime/routes/conversation-routes.ts +222 -82
- package/src/runtime/routes/conversations-import-routes.ts +8 -1
- package/src/runtime/routes/credential-prompt-routes.ts +20 -5
- package/src/runtime/routes/debug-routes.ts +1 -0
- package/src/runtime/routes/documents-routes.ts +5 -2
- package/src/runtime/routes/empty-state-greeting-cache.ts +37 -10
- package/src/runtime/routes/global-search-routes.ts +2 -1
- package/src/runtime/routes/guardian-approval-interception.ts +51 -0
- package/src/runtime/routes/home-feed-routes.ts +60 -1
- package/src/runtime/routes/identity-routes.ts +4 -87
- package/src/runtime/routes/inbound-message-handler.ts +82 -41
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +430 -57
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +302 -572
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +76 -270
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +21 -116
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +9 -1
- package/src/runtime/routes/inbound-stages/escalation-intercept.test.ts +158 -0
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +22 -1
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +22 -16
- package/src/runtime/routes/internal-twilio-routes.ts +0 -15
- package/src/runtime/routes/messages-lexical-routes.ts +75 -0
- package/src/runtime/routes/migration-routes.ts +69 -6
- package/src/runtime/routes/monitoring-routes.ts +237 -0
- package/src/runtime/routes/plugins-routes.ts +329 -8
- package/src/runtime/routes/schedule-routes.ts +49 -8
- package/src/runtime/routes/schedule-worker-routes.ts +210 -0
- package/src/runtime/routes/secret-routes.ts +1 -1
- package/src/runtime/routes/surface-conversation-resolver.ts +1 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +54 -9
- package/src/runtime/services/__tests__/auto-analysis-enqueue.test.ts +30 -6
- package/src/runtime/services/__tests__/conversation-analyze-job.test.ts +43 -8
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +20 -0
- package/src/runtime/services/analyze-conversation.ts +14 -4
- package/src/runtime/services/conversation-serializer.ts +5 -0
- package/src/runtime/slack-no-response.ts +47 -0
- package/src/runtime/slack-reply-session.test.ts +633 -0
- package/src/runtime/slack-reply-session.ts +382 -0
- package/src/runtime/slack-task-progress.ts +95 -0
- package/src/runtime/sync/resource-sync-events.ts +25 -0
- package/src/runtime/tool-grant-request-helper.ts +17 -1
- package/src/runtime/trust-class.test.ts +141 -0
- package/src/runtime/trust-class.ts +121 -0
- package/src/runtime/trust-verdict-consumer.ts +7 -6
- package/src/schedule/__tests__/run-script.test.ts +21 -0
- package/src/schedule/__tests__/worker-control.test.ts +241 -0
- package/src/schedule/run-script.ts +13 -6
- package/src/schedule/schedule-usage-store.ts +1 -0
- package/src/schedule/scheduler.ts +178 -127
- package/src/schedule/worker-control.ts +118 -0
- package/src/schedule/worker.ts +131 -0
- package/src/skills/__tests__/categories-cache.test.ts +38 -0
- package/src/skills/categories-cache.ts +40 -5
- package/src/skills/managed-store.ts +41 -6
- package/src/skills/validate-input.ts +47 -0
- package/src/stt/types.ts +5 -9
- package/src/subagent/manager.ts +267 -39
- package/src/subagent/types.ts +6 -2
- package/src/subagent/validate-allowlists.ts +65 -0
- package/src/telemetry/watchdog-direct-emit.test.ts +109 -0
- package/src/telemetry/watchdog-direct-emit.ts +89 -0
- package/src/tools/acp/list-agents.test.ts +0 -6
- package/src/tools/background-tool-registry.ts +61 -0
- package/src/tools/document/document-comment-tool.test.ts +4 -0
- package/src/tools/host-terminal/host-shell.test.ts +397 -0
- package/src/tools/host-terminal/host-shell.ts +203 -14
- package/src/tools/skills/find-similar-skills.test.ts +152 -1
- package/src/tools/skills/find-similar-skills.ts +30 -4
- package/src/tools/skills/load.ts +36 -0
- package/src/tools/skills/scaffold-managed.ts +66 -34
- package/src/tools/skills/skill-script-runner.ts +17 -0
- package/src/tools/skills/skill-tool-factory.ts +5 -1
- package/src/tools/terminal/safe-env.ts +3 -0
- package/src/tools/terminal/shell.test.ts +177 -0
- package/src/tools/terminal/shell.ts +98 -4
- package/src/tools/tool-approval-handler.ts +106 -29
- package/{node_modules/@vellumai/skill-host-contracts/src → src/tools}/tool-types.ts +16 -17
- package/src/tools/types.ts +29 -17
- package/src/tools/ui-surface/definitions.ts +3 -1
- package/src/tts/__tests__/provider-adapters.test.ts +37 -0
- package/src/tts/__tests__/provider-catalog.test.ts +21 -0
- package/src/tts/provider-catalog.ts +40 -9
- package/src/tts/providers/fish-audio-provider.ts +19 -10
- package/src/tts/types.ts +3 -4
- package/src/util/__tests__/process-tree.test.ts +10 -2
- package/src/util/__tests__/text-spacing.test.ts +53 -0
- package/src/util/cgroup-memory.ts +142 -0
- package/src/util/image-conversion.ts +281 -0
- package/src/util/phone.ts +1 -8
- package/src/util/platform.ts +33 -0
- package/src/util/process-tree.ts +10 -2
- package/src/util/text-spacing.ts +53 -0
- package/src/util/worker-process.ts +271 -0
- package/src/workflows/journal-store.ts +16 -1
- package/src/workflows/library.test.ts +35 -20
- package/src/workflows/library.ts +105 -66
- package/src/workspace/git-service.ts +1 -0
- package/src/workspace/migrations/011-backfill-installation-id.ts +83 -31
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +41 -22
- package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +1 -1
- package/src/workspace/migrations/118-seed-now-md.ts +64 -0
- package/src/workspace/migrations/119-strip-persisted-memory-v3-tuning-defaults.ts +169 -0
- package/src/workspace/migrations/120-revise-onboarding-threads.ts +47 -0
- package/src/workspace/migrations/121-seed-default-user-guardrails.ts +82 -0
- package/src/workspace/migrations/122-relocate-default-user-boundary.ts +111 -0
- package/src/workspace/migrations/123-swap-quality-profile-to-fable.ts +85 -0
- package/src/workspace/migrations/__tests__/119-strip-persisted-memory-v3-tuning-defaults.test.ts +181 -0
- package/src/workspace/migrations/registry.ts +12 -0
- package/drizzle/0000_dizzy_maggott.sql +0 -301
- package/drizzle/meta/0000_snapshot.json +0 -1933
- package/drizzle/meta/_journal.json +0 -13
- package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +0 -887
- package/node_modules/@vellumai/skill-host-contracts/bun.lock +0 -24
- package/node_modules/@vellumai/skill-host-contracts/package.json +0 -18
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -97
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +0 -1349
- package/node_modules/@vellumai/skill-host-contracts/src/index.ts +0 -6
- package/node_modules/@vellumai/skill-host-contracts/src/runtime-mode.ts +0 -11
- package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +0 -32
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +0 -333
- package/node_modules/@vellumai/skill-host-contracts/tsconfig.json +0 -20
- package/node_modules/@vellumai/skill-host-contracts/tsconfig.test.json +0 -12
- package/src/__tests__/invite-redemption-service.test.ts +0 -1180
- package/src/__tests__/invite-service-ipc.test.ts +0 -350
- package/src/__tests__/job-handler-registry-guard.test.ts +0 -125
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +0 -203
- package/src/__tests__/relay-server.test.ts +0 -6153
- package/src/__tests__/telephony-stt-routing.test.ts +0 -329
- package/src/__tests__/voice-invite-redemption.test.ts +0 -702
- package/src/calls/relay-server.ts +0 -2463
- package/src/calls/telephony-stt-routing.ts +0 -145
- package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +0 -128
- package/src/daemon/__tests__/daemon-skill-host.test.ts +0 -273
- package/src/daemon/daemon-skill-host.ts +0 -262
- package/src/daemon/message-types/meet.ts +0 -143
- package/src/daemon/shutdown-registry.ts +0 -40
- package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -253
- package/src/ipc/__tests__/skill-server.test.ts +0 -182
- package/src/ipc/skill-ipc-types.ts +0 -54
- package/src/ipc/skill-routes/__tests__/config.test.ts +0 -146
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +0 -448
- package/src/ipc/skill-routes/__tests__/identity.test.ts +0 -62
- package/src/ipc/skill-routes/__tests__/log.test.ts +0 -133
- package/src/ipc/skill-routes/__tests__/memory.test.ts +0 -203
- package/src/ipc/skill-routes/__tests__/platform.test.ts +0 -111
- package/src/ipc/skill-routes/__tests__/providers.test.ts +0 -265
- package/src/ipc/skill-routes/__tests__/registries.test.ts +0 -400
- package/src/ipc/skill-routes/config.ts +0 -47
- package/src/ipc/skill-routes/events.ts +0 -147
- package/src/ipc/skill-routes/identity.ts +0 -21
- package/src/ipc/skill-routes/index.ts +0 -37
- package/src/ipc/skill-routes/log.ts +0 -40
- package/src/ipc/skill-routes/memory.ts +0 -92
- package/src/ipc/skill-routes/platform.ts +0 -39
- package/src/ipc/skill-routes/providers.ts +0 -162
- package/src/ipc/skill-routes/registries.ts +0 -338
- package/src/ipc/skill-server.ts +0 -831
- package/src/ipc/skill-socket-path.ts +0 -20
- package/src/jobs/register-job-handlers.ts +0 -74
- package/src/persistence/invite-store.ts +0 -481
- package/src/plugins/job-handler-registry.ts +0 -94
- package/src/providers/cache-control.ts +0 -26
- package/src/runtime/__tests__/runtime-mode.test.ts +0 -62
- package/src/runtime/invite-redemption-service.ts +0 -828
- package/src/runtime/invite-redemption-templates.ts +0 -46
- package/src/runtime/runtime-mode.ts +0 -40
- package/src/runtime/slack-dm-text-delivery.ts +0 -177
- package/src/util/voice-code.ts +0 -31
package/src/subagent/manager.ts
CHANGED
|
@@ -20,6 +20,11 @@ import {
|
|
|
20
20
|
} from "../daemon/conversation-registry.js";
|
|
21
21
|
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
22
22
|
import { bootstrapConversation } from "../persistence/conversation-bootstrap.js";
|
|
23
|
+
import {
|
|
24
|
+
deleteSubagentRecord,
|
|
25
|
+
loadAllSubagentRecords,
|
|
26
|
+
upsertSubagentRecord,
|
|
27
|
+
} from "../persistence/subagent-store.js";
|
|
23
28
|
import { wrapWithCallSiteRouting } from "../providers/call-site-routing.js";
|
|
24
29
|
import { resolveDefaultProvider } from "../providers/connection-resolution.js";
|
|
25
30
|
import { RateLimitProvider } from "../providers/ratelimit.js";
|
|
@@ -117,6 +122,73 @@ function buildSubagentSystemPrompt(
|
|
|
117
122
|
return sections.join("\n");
|
|
118
123
|
}
|
|
119
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Build the message injected into the parent conversation when a subagent
|
|
127
|
+
* reaches a terminal state.
|
|
128
|
+
*
|
|
129
|
+
* For a completed subagent the final synthesis is inlined directly, so the
|
|
130
|
+
* parent acts on the result without a `subagent_read` round-trip and has
|
|
131
|
+
* nothing left to re-spawn. The `subagent_read` pointer survives only as a
|
|
132
|
+
* fallback for the rare run that ends with no trailing assistant text.
|
|
133
|
+
*
|
|
134
|
+
* Exported for unit testing.
|
|
135
|
+
*/
|
|
136
|
+
export function buildSubagentTerminalMessage(opts: {
|
|
137
|
+
label: string;
|
|
138
|
+
subagentId: string;
|
|
139
|
+
isFork: boolean;
|
|
140
|
+
outcome: "completed" | "failed";
|
|
141
|
+
silent: boolean;
|
|
142
|
+
finalText?: string;
|
|
143
|
+
error?: string;
|
|
144
|
+
/** A follow-up turn is still queued, so the current synthesis is a snapshot. */
|
|
145
|
+
deferred?: boolean;
|
|
146
|
+
}): string {
|
|
147
|
+
const {
|
|
148
|
+
label,
|
|
149
|
+
subagentId,
|
|
150
|
+
isFork,
|
|
151
|
+
outcome,
|
|
152
|
+
silent,
|
|
153
|
+
finalText,
|
|
154
|
+
error,
|
|
155
|
+
deferred,
|
|
156
|
+
} = opts;
|
|
157
|
+
const prefix = isFork ? "Fork" : "Subagent";
|
|
158
|
+
|
|
159
|
+
if (outcome === "failed") {
|
|
160
|
+
return (
|
|
161
|
+
`[${prefix} "${label}" failed]\n\n` +
|
|
162
|
+
`Error: ${error ?? "Unknown error"}\n` +
|
|
163
|
+
`Do NOT re-spawn or retry this ${prefix.toLowerCase()} unless the user explicitly asks.`
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const trimmed = finalText?.trim() ?? "";
|
|
168
|
+
if (trimmed && !deferred) {
|
|
169
|
+
return (
|
|
170
|
+
`[${prefix} "${label}" completed — result below]\n\n` +
|
|
171
|
+
`${trimmed}\n\n` +
|
|
172
|
+
(silent
|
|
173
|
+
? `(Use these findings internally; do not relay the raw ${prefix.toLowerCase()} output to the user.)`
|
|
174
|
+
: `(Incorporate this into your reply to the user as appropriate.)`)
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Read-pointer path: either the run left no trailing assistant text to inline,
|
|
179
|
+
// or a queued follow-up turn is still draining — so the current synthesis is a
|
|
180
|
+
// stale snapshot and the parent should read the latest output instead.
|
|
181
|
+
const lastN = isFork ? " and last_n: 1" : "";
|
|
182
|
+
const reason = deferred
|
|
183
|
+
? `Queued follow-up guidance is still being processed`
|
|
184
|
+
: `The ${prefix.toLowerCase()} produced no final text`;
|
|
185
|
+
return (
|
|
186
|
+
`[${prefix} "${label}" completed]\n\n` +
|
|
187
|
+
`${reason}. Use subagent_read with subagent_id "${subagentId}"${lastN} for the latest output.` +
|
|
188
|
+
(silent ? ` Keep the result internal.` : ``)
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
120
192
|
// ── Manager ─────────────────────────────────────────────────────────────
|
|
121
193
|
|
|
122
194
|
interface ManagedSubagent {
|
|
@@ -190,6 +262,13 @@ export class SubagentManager {
|
|
|
190
262
|
/** `${parentConversationId}:${normalizedLabel}` → subagentId */
|
|
191
263
|
private labelIndex = new Map<string, string>();
|
|
192
264
|
|
|
265
|
+
/**
|
|
266
|
+
* Set during `disposeAll()` (shutdown) so `dispose()` keeps the durable rows
|
|
267
|
+
* instead of deleting them — an in-flight subagent must survive as a row to
|
|
268
|
+
* be rehydrated as `interrupted` on the next boot.
|
|
269
|
+
*/
|
|
270
|
+
private shuttingDown = false;
|
|
271
|
+
|
|
193
272
|
/**
|
|
194
273
|
* Cross-conversation rate-limit window. The conversation store reads this
|
|
195
274
|
* same array when building its per-conversation RateLimitProvider, so
|
|
@@ -433,6 +512,17 @@ export class SubagentManager {
|
|
|
433
512
|
if (parentConversation?.assistantId) {
|
|
434
513
|
conversation.setAssistantId(parentConversation.assistantId);
|
|
435
514
|
}
|
|
515
|
+
// Inherit the parent chat's per-conversation plugin scope so a subagent
|
|
516
|
+
// spawned from a scoped chat can't see or execute plugins the user
|
|
517
|
+
// deselected. `null` (no per-chat restriction) is the default and
|
|
518
|
+
// propagates unchanged; a materialized scope is copied by value.
|
|
519
|
+
if (parentConversation) {
|
|
520
|
+
conversation.setEnabledPlugins(
|
|
521
|
+
parentConversation.enabledPlugins
|
|
522
|
+
? [...parentConversation.enabledPlugins]
|
|
523
|
+
: null,
|
|
524
|
+
);
|
|
525
|
+
}
|
|
436
526
|
|
|
437
527
|
if (isFork && !config.systemPromptOverride) {
|
|
438
528
|
// A verbatim-prompt fork pins the parent's system prompt as-is, skipping
|
|
@@ -485,6 +575,9 @@ export class SubagentManager {
|
|
|
485
575
|
}
|
|
486
576
|
this.parentToChildren.get(config.parentConversationId)!.add(subagentId);
|
|
487
577
|
|
|
578
|
+
// Persist the initial record so the subagent survives a daemon restart.
|
|
579
|
+
this.persistState(managed.state);
|
|
580
|
+
|
|
488
581
|
// Notify client that a subagent was spawned.
|
|
489
582
|
parentSendToClient({
|
|
490
583
|
type: "subagent_spawned",
|
|
@@ -599,8 +692,11 @@ export class SubagentManager {
|
|
|
599
692
|
// Read the current parent sender so reconnects are picked up.
|
|
600
693
|
const getSender = () => managed.parentSendToClient;
|
|
601
694
|
|
|
602
|
-
|
|
695
|
+
// Stamp startedAt before the status transition so the persistence hook
|
|
696
|
+
// inside setStatus captures it on the running row (otherwise a crash mid-run
|
|
697
|
+
// rehydrates as interrupted with no start time).
|
|
603
698
|
managed.state.startedAt = Date.now();
|
|
699
|
+
this.setStatus(subagentId, "running", getSender());
|
|
604
700
|
|
|
605
701
|
try {
|
|
606
702
|
// For forks, inject the parent's message history before the first message.
|
|
@@ -669,12 +765,12 @@ export class SubagentManager {
|
|
|
669
765
|
|
|
670
766
|
log.info({ subagentId }, "Subagent completed");
|
|
671
767
|
|
|
672
|
-
// Notify the parent conversation
|
|
673
|
-
//
|
|
674
|
-
//
|
|
675
|
-
//
|
|
768
|
+
// Notify the parent conversation, inlining the subagent's final
|
|
769
|
+
// synthesis so the LLM acts on the result without a subagent_read
|
|
770
|
+
// round-trip. Skipped on the synchronous path — the awaiting caller
|
|
771
|
+
// receives the final text directly.
|
|
676
772
|
if (!managed.synchronous) {
|
|
677
|
-
this.notifyParentTerminal(managed, "completed");
|
|
773
|
+
this.notifyParentTerminal(managed, "completed", finalText);
|
|
678
774
|
}
|
|
679
775
|
}
|
|
680
776
|
} catch (err) {
|
|
@@ -805,6 +901,7 @@ export class SubagentManager {
|
|
|
805
901
|
}
|
|
806
902
|
} else {
|
|
807
903
|
managed.state.status = "aborted";
|
|
904
|
+
this.persistState(managed.state);
|
|
808
905
|
}
|
|
809
906
|
|
|
810
907
|
log.info({ subagentId }, "Subagent aborted");
|
|
@@ -915,8 +1012,12 @@ export class SubagentManager {
|
|
|
915
1012
|
}
|
|
916
1013
|
|
|
917
1014
|
/**
|
|
918
|
-
* Update the parent sender for all active children of a conversation
|
|
919
|
-
* Called when the parent client
|
|
1015
|
+
* Update the parent sender for all active children of a conversation and
|
|
1016
|
+
* re-emit each child's current status to it. Called when the parent client
|
|
1017
|
+
* reconnects to a new socket, so a reconnecting client resyncs any status it
|
|
1018
|
+
* missed while disconnected (e.g. a subagent marked `interrupted` during
|
|
1019
|
+
* rehydration after a daemon restart, whose card would otherwise stay stuck
|
|
1020
|
+
* on a stale `running`).
|
|
920
1021
|
*/
|
|
921
1022
|
updateParentSender(
|
|
922
1023
|
parentConversationId: string,
|
|
@@ -927,9 +1028,19 @@ export class SubagentManager {
|
|
|
927
1028
|
|
|
928
1029
|
for (const childId of children) {
|
|
929
1030
|
const managed = this.subagents.get(childId);
|
|
930
|
-
if (
|
|
1031
|
+
if (!managed) continue;
|
|
1032
|
+
if (!TERMINAL_STATUSES.has(managed.state.status)) {
|
|
931
1033
|
managed.parentSendToClient = newSendToClient;
|
|
932
1034
|
}
|
|
1035
|
+
// Re-emit the current status so the reconnecting client corrects any card
|
|
1036
|
+
// it left in a stale state while disconnected.
|
|
1037
|
+
newSendToClient({
|
|
1038
|
+
type: "subagent_status_changed",
|
|
1039
|
+
subagentId: childId,
|
|
1040
|
+
status: managed.state.status,
|
|
1041
|
+
error: managed.state.error,
|
|
1042
|
+
usage: managed.state.usage,
|
|
1043
|
+
} as ServerMessage);
|
|
933
1044
|
}
|
|
934
1045
|
}
|
|
935
1046
|
|
|
@@ -981,6 +1092,17 @@ export class SubagentManager {
|
|
|
981
1092
|
}
|
|
982
1093
|
this.subagents.delete(subagentId);
|
|
983
1094
|
|
|
1095
|
+
// Drop the durable record too — but only during normal operation. On
|
|
1096
|
+
// shutdown we keep rows so a subagent that was in flight can rehydrate as
|
|
1097
|
+
// `interrupted` on the next boot.
|
|
1098
|
+
if (!this.shuttingDown) {
|
|
1099
|
+
try {
|
|
1100
|
+
deleteSubagentRecord(subagentId);
|
|
1101
|
+
} catch (err) {
|
|
1102
|
+
log.warn({ subagentId, err }, "Failed to delete subagent record");
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
|
|
984
1106
|
// Remove from label index only if it still maps to this subagent
|
|
985
1107
|
// (guards against stale delete when a newer subagent reused the label).
|
|
986
1108
|
const label = managed.state.config.label;
|
|
@@ -1003,12 +1125,122 @@ export class SubagentManager {
|
|
|
1003
1125
|
|
|
1004
1126
|
/** Dispose all subagents. Called on daemon shutdown. */
|
|
1005
1127
|
disposeAll(): void {
|
|
1128
|
+
// Mark shutdown so dispose() keeps the durable rows: an in-flight subagent
|
|
1129
|
+
// must survive as a row to be rehydrated as `interrupted` on the next boot.
|
|
1130
|
+
this.shuttingDown = true;
|
|
1006
1131
|
this.stopSweep();
|
|
1007
1132
|
for (const id of [...this.subagents.keys()]) {
|
|
1008
1133
|
this.dispose(id);
|
|
1009
1134
|
}
|
|
1010
1135
|
}
|
|
1011
1136
|
|
|
1137
|
+
// ── Persistence / rehydration ─────────────────────────────────────────
|
|
1138
|
+
|
|
1139
|
+
/**
|
|
1140
|
+
* Write the subagent's current state to the durable `subagents` table.
|
|
1141
|
+
* Best-effort: persistence failures are logged, never thrown — a background
|
|
1142
|
+
* subagent must not fail because its bookkeeping row could not be written.
|
|
1143
|
+
*/
|
|
1144
|
+
private persistState(state: SubagentState): void {
|
|
1145
|
+
try {
|
|
1146
|
+
upsertSubagentRecord({
|
|
1147
|
+
id: state.config.id,
|
|
1148
|
+
parentConversationId: state.config.parentConversationId,
|
|
1149
|
+
conversationId: state.conversationId,
|
|
1150
|
+
label: state.config.label,
|
|
1151
|
+
objective: state.config.objective,
|
|
1152
|
+
role: state.config.role ?? "general",
|
|
1153
|
+
isFork: state.isFork,
|
|
1154
|
+
sendResultToUser: state.config.sendResultToUser ?? null,
|
|
1155
|
+
status: state.status,
|
|
1156
|
+
error: state.error ?? null,
|
|
1157
|
+
createdAt: state.createdAt,
|
|
1158
|
+
startedAt: state.startedAt ?? null,
|
|
1159
|
+
completedAt: state.completedAt ?? null,
|
|
1160
|
+
inputTokens: state.usage.inputTokens,
|
|
1161
|
+
outputTokens: state.usage.outputTokens,
|
|
1162
|
+
estimatedCost: state.usage.estimatedCost,
|
|
1163
|
+
});
|
|
1164
|
+
} catch (err) {
|
|
1165
|
+
log.warn(
|
|
1166
|
+
{ subagentId: state.config.id, err },
|
|
1167
|
+
"Failed to persist subagent record",
|
|
1168
|
+
);
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
/**
|
|
1173
|
+
* Rebuild in-memory subagent metadata from the durable table after a restart.
|
|
1174
|
+
* Terminal records load as-is so `subagent_read`/`getState` keep working
|
|
1175
|
+
* (output is read from the child conversation's persisted messages). Records
|
|
1176
|
+
* still in flight when the process died are marked `interrupted` — the run is
|
|
1177
|
+
* not resumed; the parent decides whether to re-spawn. Rehydrated entries
|
|
1178
|
+
* carry a no-op sender and no live conversation, and are swept on the normal
|
|
1179
|
+
* TTL like any other terminal subagent.
|
|
1180
|
+
*
|
|
1181
|
+
* Best-effort and idempotent: a second restart re-reads `interrupted` rows
|
|
1182
|
+
* and leaves them unchanged.
|
|
1183
|
+
*/
|
|
1184
|
+
rehydrateFromDb(): { rehydrated: number; interrupted: number } {
|
|
1185
|
+
const records = loadAllSubagentRecords();
|
|
1186
|
+
let interrupted = 0;
|
|
1187
|
+
const now = Date.now();
|
|
1188
|
+
for (const rec of records) {
|
|
1189
|
+
const wasInFlight = !TERMINAL_STATUSES.has(rec.status as SubagentStatus);
|
|
1190
|
+
const status: SubagentStatus = wasInFlight
|
|
1191
|
+
? "interrupted"
|
|
1192
|
+
: (rec.status as SubagentStatus);
|
|
1193
|
+
if (wasInFlight) interrupted++;
|
|
1194
|
+
|
|
1195
|
+
const state: SubagentState = {
|
|
1196
|
+
config: {
|
|
1197
|
+
id: rec.id,
|
|
1198
|
+
parentConversationId: rec.parentConversationId,
|
|
1199
|
+
label: rec.label,
|
|
1200
|
+
objective: rec.objective,
|
|
1201
|
+
role: rec.role as SubagentRole,
|
|
1202
|
+
fork: rec.isFork,
|
|
1203
|
+
...(rec.sendResultToUser != null
|
|
1204
|
+
? { sendResultToUser: rec.sendResultToUser }
|
|
1205
|
+
: {}),
|
|
1206
|
+
},
|
|
1207
|
+
status,
|
|
1208
|
+
conversationId: rec.conversationId,
|
|
1209
|
+
isFork: rec.isFork,
|
|
1210
|
+
...(rec.error != null ? { error: rec.error } : {}),
|
|
1211
|
+
createdAt: rec.createdAt,
|
|
1212
|
+
...(rec.startedAt != null ? { startedAt: rec.startedAt } : {}),
|
|
1213
|
+
...(rec.completedAt != null ? { completedAt: rec.completedAt } : {}),
|
|
1214
|
+
usage: {
|
|
1215
|
+
inputTokens: rec.inputTokens,
|
|
1216
|
+
outputTokens: rec.outputTokens,
|
|
1217
|
+
estimatedCost: rec.estimatedCost,
|
|
1218
|
+
},
|
|
1219
|
+
};
|
|
1220
|
+
|
|
1221
|
+
const managed: ManagedSubagent = {
|
|
1222
|
+
conversation: null,
|
|
1223
|
+
state,
|
|
1224
|
+
parentSendToClient: () => {},
|
|
1225
|
+
retainedUntil: now + TERMINAL_RETENTION_MS,
|
|
1226
|
+
};
|
|
1227
|
+
this.subagents.set(rec.id, managed);
|
|
1228
|
+
|
|
1229
|
+
const labelKey = `${rec.parentConversationId}:${rec.label.toLowerCase().trim()}`;
|
|
1230
|
+
this.labelIndex.set(labelKey, rec.id);
|
|
1231
|
+
|
|
1232
|
+
if (!this.parentToChildren.has(rec.parentConversationId)) {
|
|
1233
|
+
this.parentToChildren.set(rec.parentConversationId, new Set());
|
|
1234
|
+
}
|
|
1235
|
+
this.parentToChildren.get(rec.parentConversationId)!.add(rec.id);
|
|
1236
|
+
|
|
1237
|
+
// Persist the interrupted transition so a second restart is a no-op.
|
|
1238
|
+
if (wasInFlight) this.persistState(state);
|
|
1239
|
+
}
|
|
1240
|
+
if (records.length > 0) this.ensureSweepRunning();
|
|
1241
|
+
return { rehydrated: records.length, interrupted };
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1012
1244
|
// ── TTL sweep for terminal metadata ──────────────────────────────────
|
|
1013
1245
|
|
|
1014
1246
|
private sweepTimer?: ReturnType<typeof setInterval>;
|
|
@@ -1097,6 +1329,9 @@ export class SubagentManager {
|
|
|
1097
1329
|
error,
|
|
1098
1330
|
usage: managed.state.usage,
|
|
1099
1331
|
} as ServerMessage);
|
|
1332
|
+
|
|
1333
|
+
// Mirror the transition to the durable record.
|
|
1334
|
+
this.persistState(managed.state);
|
|
1100
1335
|
}
|
|
1101
1336
|
|
|
1102
1337
|
// ── Child → Parent notification ────────────────────────────────────
|
|
@@ -1165,43 +1400,36 @@ export class SubagentManager {
|
|
|
1165
1400
|
}
|
|
1166
1401
|
|
|
1167
1402
|
/**
|
|
1168
|
-
* Inject a completion/failure notification into the parent conversation
|
|
1169
|
-
*
|
|
1403
|
+
* Inject a completion/failure notification into the parent conversation so
|
|
1404
|
+
* the LLM automatically informs the user. On completion the subagent's final
|
|
1405
|
+
* synthesis is inlined (via `buildSubagentTerminalMessage`) so the parent acts
|
|
1406
|
+
* on the result directly rather than issuing a `subagent_read` call.
|
|
1170
1407
|
*/
|
|
1171
1408
|
private notifyParentTerminal(
|
|
1172
1409
|
managed: ManagedSubagent,
|
|
1173
1410
|
outcome: "completed" | "failed",
|
|
1411
|
+
finalText?: string,
|
|
1174
1412
|
): void {
|
|
1175
1413
|
const { config } = managed.state;
|
|
1176
1414
|
const isFork = managed.state.isFork;
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
: `Do NOT re-spawn this subagent — just read and share the results.`);
|
|
1196
|
-
}
|
|
1197
|
-
} else {
|
|
1198
|
-
const error = managed.state.error ?? "Unknown error";
|
|
1199
|
-
const prefix = isFork ? "Fork" : "Subagent";
|
|
1200
|
-
message =
|
|
1201
|
-
`[${prefix} "${config.label}" failed]\n\n` +
|
|
1202
|
-
`Error: ${error}\n` +
|
|
1203
|
-
`Do NOT re-spawn or retry this ${prefix.toLowerCase()} unless the user explicitly asks.`;
|
|
1204
|
-
}
|
|
1415
|
+
// Forks default to internal/silent unless explicitly shared; regular
|
|
1416
|
+
// subagents share with the user unless explicitly silenced.
|
|
1417
|
+
const silent = isFork
|
|
1418
|
+
? config.sendResultToUser !== true
|
|
1419
|
+
: config.sendResultToUser === false;
|
|
1420
|
+
|
|
1421
|
+
const message = buildSubagentTerminalMessage({
|
|
1422
|
+
label: config.label,
|
|
1423
|
+
subagentId: config.id,
|
|
1424
|
+
isFork,
|
|
1425
|
+
outcome,
|
|
1426
|
+
silent,
|
|
1427
|
+
finalText,
|
|
1428
|
+
error: managed.state.error,
|
|
1429
|
+
// A queued follow-up turn means the snapshot we hold is stale; defer to a
|
|
1430
|
+
// read pointer so the parent picks up the queued turn's output instead.
|
|
1431
|
+
deferred: managed.hadEnqueuedMessages === true,
|
|
1432
|
+
});
|
|
1205
1433
|
|
|
1206
1434
|
const notification: SubagentNotificationInfo = {
|
|
1207
1435
|
subagentId: config.id,
|
package/src/subagent/types.ts
CHANGED
|
@@ -17,11 +17,15 @@ export type SubagentStatus =
|
|
|
17
17
|
| "awaiting_input"
|
|
18
18
|
| "completed"
|
|
19
19
|
| "failed"
|
|
20
|
-
| "aborted"
|
|
20
|
+
| "aborted"
|
|
21
|
+
// Assigned on daemon restart to a subagent that was still in flight when the
|
|
22
|
+
// process died. Terminal — the run is not auto-resumed; the parent is left to
|
|
23
|
+
// decide whether to re-spawn.
|
|
24
|
+
| "interrupted";
|
|
21
25
|
|
|
22
26
|
/** Terminal states — once entered, a subagent cannot transition out. */
|
|
23
27
|
export const TERMINAL_STATUSES: ReadonlySet<SubagentStatus> =
|
|
24
|
-
new Set<SubagentStatus>(["completed", "failed", "aborted"]);
|
|
28
|
+
new Set<SubagentStatus>(["completed", "failed", "aborted", "interrupted"]);
|
|
25
29
|
|
|
26
30
|
// ── Config (spawn-time) ─────────────────────────────────────────────────
|
|
27
31
|
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boot-time validation that every tool named in a subagent role's allowlist
|
|
3
|
+
* resolves to a real registered tool.
|
|
4
|
+
*
|
|
5
|
+
* A role allowlist (`SUBAGENT_ROLE_REGISTRY[role].allowedTools` in ./types.ts)
|
|
6
|
+
* is a list of plain tool-name strings. The names are matched against the live
|
|
7
|
+
* tool set purely by string equality (`subagentAllowedTools.has(name)`), so if
|
|
8
|
+
* a tool is renamed in the registry without updating the allowlist, the role
|
|
9
|
+
* silently loses access to it — the stale name simply never matches anything.
|
|
10
|
+
* This check surfaces that drift as a startup warning instead of a silent
|
|
11
|
+
* capability gap.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { getAllTools } from "../tools/registry.js";
|
|
15
|
+
import { getLogger } from "../util/logger.js";
|
|
16
|
+
import { SUBAGENT_ROLE_REGISTRY } from "./types.js";
|
|
17
|
+
|
|
18
|
+
const log = getLogger("subagent-allowlist");
|
|
19
|
+
|
|
20
|
+
/** A role allowlist entry that has no matching registered tool. */
|
|
21
|
+
export interface UnknownAllowlistTool {
|
|
22
|
+
role: string;
|
|
23
|
+
tool: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Pure core: given the set of registered tool names, return every allowlist
|
|
28
|
+
* entry that has no matching registered tool. Roles with no allowlist
|
|
29
|
+
* (`allowedTools: undefined`, e.g. `general`) impose no filter and contribute
|
|
30
|
+
* nothing. Exported for direct unit testing without standing up the real tool
|
|
31
|
+
* registry.
|
|
32
|
+
*/
|
|
33
|
+
export function findUnknownAllowlistTools(
|
|
34
|
+
registeredToolNames: ReadonlySet<string>,
|
|
35
|
+
): UnknownAllowlistTool[] {
|
|
36
|
+
const unknown: UnknownAllowlistTool[] = [];
|
|
37
|
+
for (const [role, config] of Object.entries(SUBAGENT_ROLE_REGISTRY)) {
|
|
38
|
+
if (!config.allowedTools) continue;
|
|
39
|
+
for (const tool of config.allowedTools) {
|
|
40
|
+
if (!registeredToolNames.has(tool)) unknown.push({ role, tool });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return unknown;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Validate every subagent role allowlist against the live tool registry,
|
|
48
|
+
* logging a warning for each unknown tool name. Uses `getAllTools()` — the raw
|
|
49
|
+
* registry, including tools owned by disabled plugins — rather than
|
|
50
|
+
* `getEnabledTools()`, so a legitimately-disabled plugin does not produce a
|
|
51
|
+
* false-positive warning: we are checking that the *name* exists, not that the
|
|
52
|
+
* tool is currently enabled. Never throws; returns the list of unknown
|
|
53
|
+
* `${role}:${tool}` entries (empty when every allowlist entry resolves).
|
|
54
|
+
*/
|
|
55
|
+
export function validateSubagentRoleAllowlists(): string[] {
|
|
56
|
+
const registered = new Set(getAllTools().map((tool) => tool.name));
|
|
57
|
+
const unknown = findUnknownAllowlistTools(registered);
|
|
58
|
+
for (const { role, tool } of unknown) {
|
|
59
|
+
log.warn(
|
|
60
|
+
{ role, tool },
|
|
61
|
+
"Subagent role allowlist references unknown tool — role will silently lack access to it",
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
return unknown.map(({ role, tool }) => `${role}:${tool}`);
|
|
65
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the direct (unbuffered) watchdog telemetry emit.
|
|
3
|
+
*
|
|
4
|
+
* Unlike the batched reporter, this POSTs a single event straight to the
|
|
5
|
+
* platform ingest. It must honor the `share_analytics` opt-out and the
|
|
6
|
+
* platform-features gate, skip cleanly when credentials aren't resolved yet,
|
|
7
|
+
* and otherwise send a well-formed single-event payload.
|
|
8
|
+
*/
|
|
9
|
+
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
10
|
+
|
|
11
|
+
mock.module("../util/logger.js", () => ({
|
|
12
|
+
getLogger: () =>
|
|
13
|
+
new Proxy({} as Record<string, unknown>, { get: () => () => {} }),
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
let shareAnalytics = true;
|
|
17
|
+
mock.module("../platform/consent-cache.js", () => ({
|
|
18
|
+
getCachedShareAnalytics: () => shareAnalytics,
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
let platformEnabled = true;
|
|
22
|
+
mock.module("../platform/feature-gate.js", () => ({
|
|
23
|
+
arePlatformFeaturesEnabled: () => platformEnabled,
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
const fetchCalls: Array<{ path: string; body: string }> = [];
|
|
27
|
+
let clientAvailable = true;
|
|
28
|
+
mock.module("../platform/client.js", () => ({
|
|
29
|
+
VellumPlatformClient: {
|
|
30
|
+
create: async () =>
|
|
31
|
+
clientAvailable
|
|
32
|
+
? {
|
|
33
|
+
fetch: async (path: string, init: { body: string }) => {
|
|
34
|
+
fetchCalls.push({ path, body: init.body });
|
|
35
|
+
return new Response("", { status: 200 });
|
|
36
|
+
},
|
|
37
|
+
}
|
|
38
|
+
: null,
|
|
39
|
+
},
|
|
40
|
+
}));
|
|
41
|
+
|
|
42
|
+
mock.module("../config/env.js", () => ({
|
|
43
|
+
getPlatformOrganizationId: () => "org-1",
|
|
44
|
+
getPlatformUserId: () => "user-1",
|
|
45
|
+
}));
|
|
46
|
+
mock.module("../util/device-id.js", () => ({
|
|
47
|
+
getDeviceId: () => "device-xyz",
|
|
48
|
+
}));
|
|
49
|
+
mock.module("../version.js", () => ({ APP_VERSION: "9.9.9" }));
|
|
50
|
+
|
|
51
|
+
import { emitWatchdogEventDirect } from "./watchdog-direct-emit.js";
|
|
52
|
+
|
|
53
|
+
describe("emitWatchdogEventDirect", () => {
|
|
54
|
+
beforeEach(() => {
|
|
55
|
+
fetchCalls.length = 0;
|
|
56
|
+
shareAnalytics = true;
|
|
57
|
+
platformEnabled = true;
|
|
58
|
+
clientAvailable = true;
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("POSTs a single well-formed watchdog event when opted in", async () => {
|
|
62
|
+
await emitWatchdogEventDirect("sqlite_corrupted", {
|
|
63
|
+
database: "main",
|
|
64
|
+
error: "database disk image is malformed",
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
expect(fetchCalls).toHaveLength(1);
|
|
68
|
+
expect(fetchCalls[0].path).toBe("/v1/telemetry/ingest/");
|
|
69
|
+
const payload = JSON.parse(fetchCalls[0].body) as {
|
|
70
|
+
device_id: string;
|
|
71
|
+
assistant_version: string;
|
|
72
|
+
organization_id?: string;
|
|
73
|
+
user_id?: string;
|
|
74
|
+
events: Array<Record<string, unknown>>;
|
|
75
|
+
};
|
|
76
|
+
expect(payload.device_id).toBe("device-xyz");
|
|
77
|
+
expect(payload.assistant_version).toBe("9.9.9");
|
|
78
|
+
expect(payload.organization_id).toBe("org-1");
|
|
79
|
+
expect(payload.user_id).toBe("user-1");
|
|
80
|
+
expect(payload.events).toHaveLength(1);
|
|
81
|
+
const event = payload.events[0];
|
|
82
|
+
expect(event.type).toBe("watchdog");
|
|
83
|
+
expect(event.check_name).toBe("sqlite_corrupted");
|
|
84
|
+
expect(event.value).toBeNull();
|
|
85
|
+
expect(event.daemon_event_id).toBeString();
|
|
86
|
+
expect(event.detail).toMatchObject({
|
|
87
|
+
database: "main",
|
|
88
|
+
error: "database disk image is malformed",
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("sends nothing when share_analytics is opted out", async () => {
|
|
93
|
+
shareAnalytics = false;
|
|
94
|
+
await emitWatchdogEventDirect("sqlite_corrupted", { database: "main" });
|
|
95
|
+
expect(fetchCalls).toHaveLength(0);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test("sends nothing when platform features are disabled", async () => {
|
|
99
|
+
platformEnabled = false;
|
|
100
|
+
await emitWatchdogEventDirect("sqlite_corrupted", { database: "main" });
|
|
101
|
+
expect(fetchCalls).toHaveLength(0);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("sends nothing (no throw) when credentials aren't resolved yet", async () => {
|
|
105
|
+
clientAvailable = false;
|
|
106
|
+
await emitWatchdogEventDirect("sqlite_corrupted", { database: "main" });
|
|
107
|
+
expect(fetchCalls).toHaveLength(0);
|
|
108
|
+
});
|
|
109
|
+
});
|