@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
|
@@ -12,29 +12,22 @@
|
|
|
12
12
|
* {@link registerDefaultPlugins}. Registration is idempotent so repeat
|
|
13
13
|
* calls (e.g. during integration tests) do not throw.
|
|
14
14
|
* 2. Walks {@link getRegisteredPlugins} in registration order.
|
|
15
|
-
* 3.
|
|
16
|
-
* {@link isAssistantFeatureFlagEnabled}. If any listed flag is disabled,
|
|
17
|
-
* the plugin is skipped wholesale — no `init()`, no tool/route
|
|
18
|
-
* contributions, no entry in the shutdown hook, and the plugin is also
|
|
19
|
-
* dropped from the hook registry via {@link unregisterPlugin} so none of its
|
|
20
|
-
* hooks participate in the turn lifecycle. This is the primary mechanism for
|
|
21
|
-
* shipping experimental plugins behind a feature flag.
|
|
22
|
-
* 4. Validates the config block under `plugins.<name>` against
|
|
15
|
+
* 3. Validates the config block under `plugins.<name>` against
|
|
23
16
|
* `manifest.config` if the manifest supplies a parser-like validator
|
|
24
17
|
* (Zod schemas with `.parse()` are supported; anything else is passed
|
|
25
18
|
* through untouched).
|
|
26
|
-
*
|
|
19
|
+
* 4. Creates a per-plugin writable data directory on demand and exposes it via
|
|
27
20
|
* {@link InitContext.pluginStorageDir}. For user plugins this is
|
|
28
21
|
* `<pluginDir>/data/`; for default plugins it is
|
|
29
22
|
* `<workspaceDir>/plugins-data/<plugin>/`.
|
|
30
|
-
*
|
|
23
|
+
* 5. For each surviving plugin, registers its contributed tools and routes
|
|
31
24
|
* into their global registries via {@link registerPluginTools} and
|
|
32
25
|
* {@link registerSkillRoute}. Contributions land BEFORE `init()` so
|
|
33
26
|
* the plugin's hook can observe a registry where its own model-visible
|
|
34
27
|
* surface is already wired — useful for plugins that want to attach
|
|
35
28
|
* metadata, warm caches, or otherwise interact with their own
|
|
36
29
|
* contributions during initialization.
|
|
37
|
-
*
|
|
30
|
+
* 6. Awaits `plugin.init(ctx)` sequentially. An init failure is contained to
|
|
38
31
|
* the offending plugin: its already-registered tools and routes are rolled
|
|
39
32
|
* back, it is dropped from the registry, the failure is logged, and
|
|
40
33
|
* bootstrap continues with the remaining plugins. A single plugin's failure
|
|
@@ -43,28 +36,24 @@
|
|
|
43
36
|
* history repair, title generation) — so the daemon comes up with the
|
|
44
37
|
* failing plugin absent rather than blacking out the whole plugin layer.
|
|
45
38
|
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* the hook registry already swallows hook-level throws, but we log at the
|
|
54
|
-
* plugin level so the plugin name is attributed.
|
|
39
|
+
* Plugin `shutdown` hooks fire through the unified `runHook(HOOKS.SHUTDOWN, …)`
|
|
40
|
+
* pipeline that the daemon shutdown handler runs — the same path every other
|
|
41
|
+
* lifecycle hook uses; this module does not register a shutdown hook of its own.
|
|
42
|
+
* Surfaces (tools/routes/injectors) are not unregistered at daemon shutdown:
|
|
43
|
+
* the process is exiting, so that in-memory registry state is discarded anyway.
|
|
44
|
+
* Surfaces are only torn down when a single plugin is rolled back after a failed
|
|
45
|
+
* bring-up, via {@link teardownPlugin}.
|
|
55
46
|
*/
|
|
56
47
|
|
|
57
48
|
import { existsSync, mkdirSync } from "node:fs";
|
|
58
49
|
import { join } from "node:path";
|
|
59
50
|
|
|
60
|
-
import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
|
|
61
51
|
import { getConfig } from "../config/loader.js";
|
|
62
52
|
import type { AssistantConfig } from "../config/schema.js";
|
|
63
53
|
import { HOOKS } from "../plugin-api/constants.js";
|
|
64
54
|
import {
|
|
65
55
|
getAllDefaultPlugins,
|
|
66
56
|
registerDefaultPluginInjectors,
|
|
67
|
-
registerDefaultPluginJobHandlers,
|
|
68
57
|
registerDefaultPluginPersistenceHooks,
|
|
69
58
|
registerDefaultPlugins,
|
|
70
59
|
} from "../plugins/defaults/index.js";
|
|
@@ -72,10 +61,6 @@ import {
|
|
|
72
61
|
registerPluginInjectors,
|
|
73
62
|
unregisterPluginInjectors,
|
|
74
63
|
} from "../plugins/injector-registry.js";
|
|
75
|
-
import {
|
|
76
|
-
registerPluginJobHandlers,
|
|
77
|
-
unregisterPluginJobHandlers,
|
|
78
|
-
} from "../plugins/job-handler-registry.js";
|
|
79
64
|
import { getRegisteredPlugins, unregisterPlugin } from "../plugins/registry.js";
|
|
80
65
|
import {
|
|
81
66
|
type Plugin,
|
|
@@ -95,7 +80,6 @@ import {
|
|
|
95
80
|
import { getLogger } from "../util/logger.js";
|
|
96
81
|
import { getWorkspaceDir, getWorkspacePluginsDir } from "../util/platform.js";
|
|
97
82
|
import { APP_VERSION } from "../version.js";
|
|
98
|
-
import { registerShutdownHook } from "./shutdown-registry.js";
|
|
99
83
|
|
|
100
84
|
const log = getLogger("plugins-bootstrap");
|
|
101
85
|
|
|
@@ -152,16 +136,6 @@ function ensurePluginStorageDir(pluginName: string): string {
|
|
|
152
136
|
return dir;
|
|
153
137
|
}
|
|
154
138
|
|
|
155
|
-
function getDisabledPluginFlag(
|
|
156
|
-
plugin: Plugin,
|
|
157
|
-
config: AssistantConfig,
|
|
158
|
-
): string | undefined {
|
|
159
|
-
for (const flagKey of plugin.manifest.requiresFlag ?? []) {
|
|
160
|
-
if (!isAssistantFeatureFlagEnabled(flagKey, config)) return flagKey;
|
|
161
|
-
}
|
|
162
|
-
return undefined;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
139
|
/**
|
|
166
140
|
* Bring the plugin layer up during daemon startup. Runs the full sequence in
|
|
167
141
|
* the one order the rest of the system depends on:
|
|
@@ -190,8 +164,8 @@ export async function initializePlugins(): Promise<void> {
|
|
|
190
164
|
}
|
|
191
165
|
|
|
192
166
|
/**
|
|
193
|
-
* Run every registered plugin's `init()` hook sequentially
|
|
194
|
-
*
|
|
167
|
+
* Run every registered plugin's `init()` hook sequentially. See the module
|
|
168
|
+
* docstring for full lifecycle semantics (including how `shutdown` hooks fire).
|
|
195
169
|
*
|
|
196
170
|
* Returns once every plugin has been processed. A plugin whose `init()` throws
|
|
197
171
|
* is rolled back, dropped from the registry, and logged; bootstrap continues
|
|
@@ -222,17 +196,13 @@ export async function bootstrapPlugins(): Promise<void> {
|
|
|
222
196
|
// register while disabled.
|
|
223
197
|
registerDefaultPluginInjectors();
|
|
224
198
|
|
|
225
|
-
// Register the default plugins' background-job handlers up front, the
|
|
226
|
-
// job-handler analog of the injector registration above. The general job
|
|
227
|
-
// worker's `registerMemoryJobHandlers` forwards the registry union into the
|
|
228
|
-
// worker dispatch table; pre-registering here keeps the daemon path symmetric
|
|
229
|
-
// with tools/routes/injectors (the standalone worker self-registers instead).
|
|
230
|
-
registerDefaultPluginJobHandlers();
|
|
231
|
-
|
|
232
199
|
// Install the memory feature's persistence-lifecycle handlers into the
|
|
233
200
|
// persistence seam up front, so the layer below memory can drive memory
|
|
234
201
|
// side effects (message indexing) without importing memory internals.
|
|
235
|
-
// Symmetric with the injector
|
|
202
|
+
// Symmetric with the injector registration above. (Background-job handlers
|
|
203
|
+
// are not registered here: the memory plugin registers its own directly in
|
|
204
|
+
// its `init` hook, and the daemon registers the host's non-plugin handlers in
|
|
205
|
+
// `lifecycle.ts`.)
|
|
236
206
|
registerDefaultPluginPersistenceHooks();
|
|
237
207
|
|
|
238
208
|
// Combine the canonical default plugins with any plugins registered via
|
|
@@ -253,36 +223,8 @@ export async function bootstrapPlugins(): Promise<void> {
|
|
|
253
223
|
|
|
254
224
|
const assistantConfig = getConfig();
|
|
255
225
|
|
|
256
|
-
// Plugins that passed `requiresFlag` gating and therefore need the full
|
|
257
|
-
// init → contribute → shutdown lifecycle. Plugins skipped by the flag gate
|
|
258
|
-
// are omitted from this list so the shutdown hook below never tears down
|
|
259
|
-
// capabilities that were never wired up in the first place. Each entry
|
|
260
|
-
// carries the opaque route handles returned by `registerSkillRoute` so
|
|
261
|
-
// teardown can key on identity rather than regex-pattern text — two plugins
|
|
262
|
-
// registering the same pattern would otherwise step on each other's routes
|
|
263
|
-
// during shutdown, violating the "no traffic hits a plugin handler during
|
|
264
|
-
// onShutdown" invariant.
|
|
265
|
-
const activePlugins: ActivePlugin[] = [];
|
|
266
|
-
|
|
267
|
-
// Shutdown context is identical for every plugin in this boot — construct
|
|
268
|
-
// once and reuse across the per-plugin teardown and the normal shutdown
|
|
269
|
-
// hook below. Only `assistantVersion` is exposed today; future additions
|
|
270
|
-
// live on {@link ShutdownContext}.
|
|
271
|
-
const shutdownContext: ShutdownContext = {
|
|
272
|
-
assistantVersion: APP_VERSION,
|
|
273
|
-
};
|
|
274
|
-
|
|
275
226
|
for (const plugin of plugins) {
|
|
276
227
|
const name = plugin.manifest.name;
|
|
277
|
-
const disabledFlag = getDisabledPluginFlag(plugin, assistantConfig);
|
|
278
|
-
if (disabledFlag !== undefined) {
|
|
279
|
-
log.info(
|
|
280
|
-
{ plugin: name, flag: disabledFlag },
|
|
281
|
-
`skipping plugin ${name}: feature flag ${disabledFlag} is disabled`,
|
|
282
|
-
);
|
|
283
|
-
unregisterPlugin(name);
|
|
284
|
-
continue;
|
|
285
|
-
}
|
|
286
228
|
|
|
287
229
|
// Check for the .disabled sentinel. Both default and user plugins
|
|
288
230
|
// can be disabled by creating a `.disabled` file at
|
|
@@ -294,12 +236,12 @@ export async function bootstrapPlugins(): Promise<void> {
|
|
|
294
236
|
// and drops a `.disabled` file inside it. Runs before init so no
|
|
295
237
|
// tools or routes from the disabled plugin are ever wired.
|
|
296
238
|
//
|
|
297
|
-
//
|
|
298
|
-
//
|
|
299
|
-
//
|
|
300
|
-
//
|
|
301
|
-
//
|
|
302
|
-
//
|
|
239
|
+
// We do NOT call `unregisterPlugin(name)` here. The plugin's hooks
|
|
240
|
+
// stay in the hook registry and are filtered at read time by
|
|
241
|
+
// `isPluginDisabled` in `getHooksFor`. This means `assistant plugins
|
|
242
|
+
// enable <name>` takes effect on the next turn without a restart —
|
|
243
|
+
// the hooks are already registered, they just need the sentinel
|
|
244
|
+
// removed to be included.
|
|
303
245
|
const disabledSentinelPath = join(
|
|
304
246
|
getWorkspacePluginsDir(),
|
|
305
247
|
name,
|
|
@@ -314,7 +256,7 @@ export async function bootstrapPlugins(): Promise<void> {
|
|
|
314
256
|
}
|
|
315
257
|
|
|
316
258
|
try {
|
|
317
|
-
|
|
259
|
+
await initializePlugin(plugin, assistantConfig);
|
|
318
260
|
} catch (err) {
|
|
319
261
|
// Contain the failure to this plugin. `initializePlugin` already rolled
|
|
320
262
|
// back its own partial tool/route contributions, so we just drop
|
|
@@ -330,27 +272,6 @@ export async function bootstrapPlugins(): Promise<void> {
|
|
|
330
272
|
);
|
|
331
273
|
}
|
|
332
274
|
}
|
|
333
|
-
|
|
334
|
-
// Shutdown hook — walks plugins in REVERSE registration order. We snapshot
|
|
335
|
-
// only the plugins that actually initialized so later registrations (if
|
|
336
|
-
// any) don't end up being torn down by this hook, and plugins skipped by
|
|
337
|
-
// `requiresFlag` gating do not appear in the tear-down list. Subsequent
|
|
338
|
-
// bootstraps (hot-reload) would register their own hook.
|
|
339
|
-
//
|
|
340
|
-
// For each plugin we:
|
|
341
|
-
// 1. Unregister contributed HTTP routes so incoming requests stop hitting
|
|
342
|
-
// the plugin's handlers before its state is torn down.
|
|
343
|
-
// 2. Unregister contributed tools so the model-visible tool surface is
|
|
344
|
-
// cleared before `onShutdown()` runs.
|
|
345
|
-
// 3. Call `onShutdown()` (if defined) so the plugin can release resources
|
|
346
|
-
// (background tasks, timers, connections) with its tools and routes
|
|
347
|
-
// already removed.
|
|
348
|
-
const shutdownSnapshot: ActivePlugin[] = [...activePlugins];
|
|
349
|
-
registerShutdownHook("plugins", async (reason) => {
|
|
350
|
-
for (let i = shutdownSnapshot.length - 1; i >= 0; i--) {
|
|
351
|
-
await teardownPlugin(shutdownSnapshot[i]!, reason, shutdownContext);
|
|
352
|
-
}
|
|
353
|
-
});
|
|
354
275
|
}
|
|
355
276
|
|
|
356
277
|
/**
|
|
@@ -422,14 +343,6 @@ async function initializePlugin(
|
|
|
422
343
|
);
|
|
423
344
|
}
|
|
424
345
|
|
|
425
|
-
if (plugin.jobHandlers && plugin.jobHandlers.length > 0) {
|
|
426
|
-
registerPluginJobHandlers(name, plugin.jobHandlers);
|
|
427
|
-
log.info(
|
|
428
|
-
{ plugin: name, count: plugin.jobHandlers.length },
|
|
429
|
-
"plugin job handlers registered",
|
|
430
|
-
);
|
|
431
|
-
}
|
|
432
|
-
|
|
433
346
|
if (plugin.hooks?.[HOOKS.INIT]) {
|
|
434
347
|
try {
|
|
435
348
|
await plugin.hooks[HOOKS.INIT](initContext);
|
|
@@ -449,45 +362,50 @@ async function initializePlugin(
|
|
|
449
362
|
return { plugin, routeHandles };
|
|
450
363
|
} catch (err) {
|
|
451
364
|
if (initCompleted) {
|
|
452
|
-
await teardownPlugin(
|
|
453
|
-
|
|
454
|
-
|
|
365
|
+
await teardownPlugin(
|
|
366
|
+
{ plugin, routeHandles },
|
|
367
|
+
{ assistantVersion: APP_VERSION, reason: "disable" },
|
|
368
|
+
);
|
|
455
369
|
} else {
|
|
456
370
|
for (const handle of routeHandles) {
|
|
457
371
|
unregisterSkillRoute(handle);
|
|
458
372
|
}
|
|
459
373
|
unregisterPluginTools(name);
|
|
460
374
|
unregisterPluginInjectors(name);
|
|
461
|
-
unregisterPluginJobHandlers(name);
|
|
462
375
|
}
|
|
463
376
|
throw err;
|
|
464
377
|
}
|
|
465
378
|
}
|
|
466
379
|
|
|
467
380
|
/**
|
|
468
|
-
*
|
|
469
|
-
*
|
|
470
|
-
*
|
|
471
|
-
*
|
|
381
|
+
* Unregister every initialized plugin's contributed routes and tools in reverse
|
|
382
|
+
* registration order, clearing the model-visible surface before the shutdown
|
|
383
|
+
* handler dispatches `shutdown` hooks via `runHook(HOOKS.SHUTDOWN, …)`. Reads
|
|
384
|
+
* the snapshot captured by the most recent {@link bootstrapPlugins} run; a
|
|
385
|
+
* no-op when no plugins initialized. Called by the daemon shutdown handler.
|
|
386
|
+
*/
|
|
387
|
+
/**
|
|
388
|
+
* Tear down a single fully-initialized plugin: unregister its model-visible
|
|
389
|
+
* surfaces (contributed HTTP routes — keyed by the opaque handles retained at
|
|
390
|
+
* registration time, since pattern text is not a stable key when two owners
|
|
391
|
+
* register the same regex — plus its tools and runtime injectors), then invoke
|
|
392
|
+
* its optional `shutdown` hook with the tools/routes already gone. Every step
|
|
393
|
+
* swallows errors and logs with plugin attribution so one bad plugin can't
|
|
394
|
+
* block teardown.
|
|
472
395
|
*
|
|
473
|
-
*
|
|
474
|
-
*
|
|
396
|
+
* Used by the bootstrap-failure rollback path. The normal daemon shutdown path
|
|
397
|
+
* does not unregister surfaces (the process is exiting, so that in-memory state
|
|
398
|
+
* is discarded anyway); it only fires `shutdown` hooks through the unified
|
|
399
|
+
* `runHook(HOOKS.SHUTDOWN, …)` pipeline.
|
|
475
400
|
*/
|
|
476
401
|
async function teardownPlugin(
|
|
477
402
|
active: ActivePlugin,
|
|
478
|
-
reason: string,
|
|
479
403
|
shutdownContext: ShutdownContext,
|
|
480
404
|
): Promise<void> {
|
|
481
405
|
const { plugin, routeHandles } = active;
|
|
482
406
|
const name = plugin.manifest.name;
|
|
407
|
+
const { reason } = shutdownContext;
|
|
483
408
|
|
|
484
|
-
// Unregister model-visible surfaces before invoking `onShutdown()` so the
|
|
485
|
-
// plugin's onShutdown hook observes a registry state where its tools and
|
|
486
|
-
// routes are already gone. `unregisterPluginTools` is a no-op when the
|
|
487
|
-
// plugin never contributed tools, so we don't need to guard on
|
|
488
|
-
// `plugin.tools` here. Route unregistration keys on the opaque handles
|
|
489
|
-
// retained at registration time — pattern text is not a stable key because
|
|
490
|
-
// two owners can legitimately register the same regex.
|
|
491
409
|
for (const handle of routeHandles) {
|
|
492
410
|
try {
|
|
493
411
|
unregisterSkillRoute(handle);
|
|
@@ -509,16 +427,11 @@ async function teardownPlugin(
|
|
|
509
427
|
}
|
|
510
428
|
|
|
511
429
|
unregisterPluginInjectors(name);
|
|
512
|
-
unregisterPluginJobHandlers(name);
|
|
513
430
|
|
|
514
431
|
if (plugin.hooks?.[HOOKS.SHUTDOWN]) {
|
|
515
432
|
try {
|
|
516
433
|
await plugin.hooks[HOOKS.SHUTDOWN](shutdownContext);
|
|
517
434
|
} catch (err) {
|
|
518
|
-
// Swallow — we want every plugin's shutdown to get a chance to run
|
|
519
|
-
// even when an earlier one throws. The outer runShutdownHooks already
|
|
520
|
-
// logs at hook level, but the plugin-name attribution here is what
|
|
521
|
-
// operators read first.
|
|
522
435
|
log.warn(
|
|
523
436
|
{ err, plugin: name, reason },
|
|
524
437
|
"plugin shutdown hook failed (continuing with remaining plugins)",
|
|
@@ -38,7 +38,7 @@ await initializeDb();
|
|
|
38
38
|
|
|
39
39
|
function resetTables(): void {
|
|
40
40
|
const sqlite = getSqlite();
|
|
41
|
-
sqlite.run("DELETE FROM
|
|
41
|
+
sqlite.run("DELETE FROM a2a_invites");
|
|
42
42
|
sqlite.run("DELETE FROM assistant_contact_metadata");
|
|
43
43
|
sqlite.run("DELETE FROM contact_channels");
|
|
44
44
|
sqlite.run("DELETE FROM contacts");
|
|
@@ -26,19 +26,31 @@ import {
|
|
|
26
26
|
} from "../../../contacts/contact-store.js";
|
|
27
27
|
import { getSqlite } from "../../../persistence/db-connection.js";
|
|
28
28
|
import { initializeDb } from "../../../persistence/db-init.js";
|
|
29
|
-
import { findById } from "../../../persistence/invite-store.js";
|
|
30
29
|
import { completeA2AInvite, createA2AInvite } from "../config-a2a.js";
|
|
31
30
|
|
|
32
31
|
await initializeDb();
|
|
33
32
|
|
|
34
33
|
function resetTables(): void {
|
|
35
34
|
const sqlite = getSqlite();
|
|
36
|
-
sqlite.run("DELETE FROM
|
|
35
|
+
sqlite.run("DELETE FROM a2a_invites");
|
|
37
36
|
sqlite.run("DELETE FROM assistant_contact_metadata");
|
|
38
37
|
sqlite.run("DELETE FROM contact_channels");
|
|
39
38
|
sqlite.run("DELETE FROM contacts");
|
|
40
39
|
}
|
|
41
40
|
|
|
41
|
+
interface A2aInviteRow {
|
|
42
|
+
id: string;
|
|
43
|
+
contact_id: string;
|
|
44
|
+
status: string;
|
|
45
|
+
use_count: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function getInviteRow(id: string): A2aInviteRow | null {
|
|
49
|
+
return getSqlite()
|
|
50
|
+
.prepare("SELECT * FROM a2a_invites WHERE id = ?")
|
|
51
|
+
.get(id) as A2aInviteRow | null;
|
|
52
|
+
}
|
|
53
|
+
|
|
42
54
|
function setConfig(opts: {
|
|
43
55
|
a2aEnabled?: boolean;
|
|
44
56
|
publicBaseUrl?: string;
|
|
@@ -92,10 +104,10 @@ describe("completeA2AInvite", () => {
|
|
|
92
104
|
expect(result.error).toBeUndefined();
|
|
93
105
|
|
|
94
106
|
// Verify the placeholder contact was promoted
|
|
95
|
-
const invite =
|
|
107
|
+
const invite = getInviteRow(created.inviteId!);
|
|
96
108
|
expect(invite).not.toBeNull();
|
|
97
109
|
|
|
98
|
-
const contact = getContact(invite!.
|
|
110
|
+
const contact = getContact(invite!.contact_id);
|
|
99
111
|
expect(contact).not.toBeNull();
|
|
100
112
|
expect(contact!.displayName).toBe("Acceptor Bot");
|
|
101
113
|
expect(contact!.channels).toHaveLength(1);
|
|
@@ -116,8 +128,8 @@ describe("completeA2AInvite", () => {
|
|
|
116
128
|
});
|
|
117
129
|
expect(result.success).toBe(true);
|
|
118
130
|
|
|
119
|
-
const invite =
|
|
120
|
-
const contact = getContact(invite!.
|
|
131
|
+
const invite = getInviteRow(created.inviteId!);
|
|
132
|
+
const contact = getContact(invite!.contact_id);
|
|
121
133
|
expect(contact!.channels[0]!.address).toBe("upper-case-id-123");
|
|
122
134
|
});
|
|
123
135
|
|
|
@@ -130,8 +142,8 @@ describe("completeA2AInvite", () => {
|
|
|
130
142
|
});
|
|
131
143
|
expect(result.success).toBe(true);
|
|
132
144
|
|
|
133
|
-
const invite =
|
|
134
|
-
const metadata = getAssistantContactMetadata(invite!.
|
|
145
|
+
const invite = getInviteRow(created.inviteId!);
|
|
146
|
+
const metadata = getAssistantContactMetadata(invite!.contact_id);
|
|
135
147
|
expect(metadata).not.toBeNull();
|
|
136
148
|
expect(metadata!.species).toBe("vellum");
|
|
137
149
|
expect(metadata!.metadata).toEqual({
|
|
@@ -159,10 +171,10 @@ describe("completeA2AInvite", () => {
|
|
|
159
171
|
// The invite was just created with 0 hours expiry, so expiresAt ~= now
|
|
160
172
|
// Manually expire it by updating the DB
|
|
161
173
|
const sqlite = getSqlite();
|
|
162
|
-
sqlite.run(
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
);
|
|
174
|
+
sqlite.run("UPDATE a2a_invites SET expires_at = ? WHERE id = ?", [
|
|
175
|
+
Date.now() - 1000,
|
|
176
|
+
created.inviteId!,
|
|
177
|
+
]);
|
|
166
178
|
|
|
167
179
|
const result = completeA2AInvite({
|
|
168
180
|
token: created.token!,
|
|
@@ -238,8 +250,8 @@ describe("completeA2AInvite", () => {
|
|
|
238
250
|
expect(result.error).toContain("public base URL");
|
|
239
251
|
|
|
240
252
|
// Verify the invite was NOT consumed
|
|
241
|
-
const invite =
|
|
253
|
+
const invite = getInviteRow(created.inviteId!);
|
|
242
254
|
expect(invite!.status).toBe("active");
|
|
243
|
-
expect(invite!.
|
|
255
|
+
expect(invite!.use_count).toBe(0);
|
|
244
256
|
});
|
|
245
257
|
});
|
|
@@ -23,19 +23,33 @@ import {
|
|
|
23
23
|
import { getContact } from "../../../contacts/contact-store.js";
|
|
24
24
|
import { getSqlite } from "../../../persistence/db-connection.js";
|
|
25
25
|
import { initializeDb } from "../../../persistence/db-init.js";
|
|
26
|
-
import { findById } from "../../../persistence/invite-store.js";
|
|
27
26
|
import { createA2AInvite, getA2AConfig } from "../config-a2a.js";
|
|
28
27
|
|
|
29
28
|
await initializeDb();
|
|
30
29
|
|
|
31
30
|
function resetTables(): void {
|
|
32
31
|
const sqlite = getSqlite();
|
|
33
|
-
sqlite.run("DELETE FROM
|
|
32
|
+
sqlite.run("DELETE FROM a2a_invites");
|
|
34
33
|
sqlite.run("DELETE FROM assistant_contact_metadata");
|
|
35
34
|
sqlite.run("DELETE FROM contact_channels");
|
|
36
35
|
sqlite.run("DELETE FROM contacts");
|
|
37
36
|
}
|
|
38
37
|
|
|
38
|
+
interface A2aInviteRow {
|
|
39
|
+
id: string;
|
|
40
|
+
contact_id: string;
|
|
41
|
+
status: string;
|
|
42
|
+
max_uses: number;
|
|
43
|
+
use_count: number;
|
|
44
|
+
expires_at: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function getInviteRow(id: string): A2aInviteRow | null {
|
|
48
|
+
return getSqlite()
|
|
49
|
+
.prepare("SELECT * FROM a2a_invites WHERE id = ?")
|
|
50
|
+
.get(id) as A2aInviteRow | null;
|
|
51
|
+
}
|
|
52
|
+
|
|
39
53
|
function setConfig(opts: {
|
|
40
54
|
a2aEnabled?: boolean;
|
|
41
55
|
publicBaseUrl?: string;
|
|
@@ -75,15 +89,14 @@ describe("createA2AInvite", () => {
|
|
|
75
89
|
expect(result.error).toBeUndefined();
|
|
76
90
|
});
|
|
77
91
|
|
|
78
|
-
test("creates invite in
|
|
92
|
+
test("creates invite in a2a_invites with status=active, max_uses=1", () => {
|
|
79
93
|
const result = createA2AInvite({});
|
|
80
94
|
expect(result.inviteId).toBeDefined();
|
|
81
95
|
|
|
82
|
-
const invite =
|
|
96
|
+
const invite = getInviteRow(result.inviteId!);
|
|
83
97
|
expect(invite).not.toBeNull();
|
|
84
|
-
expect(invite!.sourceChannel).toBe("a2a");
|
|
85
98
|
expect(invite!.status).toBe("active");
|
|
86
|
-
expect(invite!.
|
|
99
|
+
expect(invite!.max_uses).toBe(1);
|
|
87
100
|
});
|
|
88
101
|
|
|
89
102
|
test("auto-enables A2A if not already on", () => {
|
|
@@ -101,10 +114,10 @@ describe("createA2AInvite", () => {
|
|
|
101
114
|
const result = createA2AInvite({});
|
|
102
115
|
expect(result.inviteId).toBeDefined();
|
|
103
116
|
|
|
104
|
-
const invite =
|
|
117
|
+
const invite = getInviteRow(result.inviteId!);
|
|
105
118
|
expect(invite).not.toBeNull();
|
|
106
119
|
|
|
107
|
-
const contact = getContact(invite!.
|
|
120
|
+
const contact = getContact(invite!.contact_id);
|
|
108
121
|
expect(contact).not.toBeNull();
|
|
109
122
|
expect(contact!.displayName).toBe("Pending A2A invite");
|
|
110
123
|
expect(contact!.channels).toHaveLength(0);
|
|
@@ -128,13 +141,13 @@ describe("createA2AInvite", () => {
|
|
|
128
141
|
const after = Date.now();
|
|
129
142
|
expect(result.success).toBe(true);
|
|
130
143
|
|
|
131
|
-
const invite =
|
|
144
|
+
const invite = getInviteRow(result.inviteId!);
|
|
132
145
|
expect(invite).not.toBeNull();
|
|
133
146
|
|
|
134
147
|
const expectedMinMs = before + 24 * 60 * 60 * 1000;
|
|
135
148
|
const expectedMaxMs = after + 24 * 60 * 60 * 1000;
|
|
136
|
-
expect(invite!.
|
|
137
|
-
expect(invite!.
|
|
149
|
+
expect(invite!.expires_at).toBeGreaterThanOrEqual(expectedMinMs);
|
|
150
|
+
expect(invite!.expires_at).toBeLessThanOrEqual(expectedMaxMs);
|
|
138
151
|
});
|
|
139
152
|
|
|
140
153
|
test("default expiry is 72 hours", () => {
|
|
@@ -143,12 +156,12 @@ describe("createA2AInvite", () => {
|
|
|
143
156
|
const after = Date.now();
|
|
144
157
|
expect(result.success).toBe(true);
|
|
145
158
|
|
|
146
|
-
const invite =
|
|
159
|
+
const invite = getInviteRow(result.inviteId!);
|
|
147
160
|
expect(invite).not.toBeNull();
|
|
148
161
|
|
|
149
162
|
const expectedMinMs = before + 72 * 60 * 60 * 1000;
|
|
150
163
|
const expectedMaxMs = after + 72 * 60 * 60 * 1000;
|
|
151
|
-
expect(invite!.
|
|
152
|
-
expect(invite!.
|
|
164
|
+
expect(invite!.expires_at).toBeGreaterThanOrEqual(expectedMinMs);
|
|
165
|
+
expect(invite!.expires_at).toBeLessThanOrEqual(expectedMaxMs);
|
|
153
166
|
});
|
|
154
167
|
});
|
|
@@ -92,7 +92,6 @@ mock.module("../../../ipc/gateway-client.js", () => ({
|
|
|
92
92
|
|
|
93
93
|
mock.module("../../../runtime/channel-verification-service.js", () => ({
|
|
94
94
|
getGuardianBinding: () => mockBinding,
|
|
95
|
-
revokeBinding: () => true,
|
|
96
95
|
revokePendingSessions: () => {},
|
|
97
96
|
createOutboundSession: () => ({
|
|
98
97
|
sessionId: "sess",
|
|
@@ -129,10 +128,6 @@ function channel(overrides: Partial<ContactChannel> = {}): ContactChannel {
|
|
|
129
128
|
address: "user-123",
|
|
130
129
|
isPrimary: true,
|
|
131
130
|
externalChatId: "chat-123",
|
|
132
|
-
inviteId: null,
|
|
133
|
-
lastSeenAt: null,
|
|
134
|
-
interactionCount: 0,
|
|
135
|
-
lastInteraction: null,
|
|
136
131
|
updatedAt: null,
|
|
137
132
|
createdAt: 0,
|
|
138
133
|
...overrides,
|
|
@@ -26,12 +26,11 @@ import {
|
|
|
26
26
|
} from "../../contacts/contact-store.js";
|
|
27
27
|
import type { VellumAssistantMetadata } from "../../contacts/types.js";
|
|
28
28
|
import { getPublicBaseUrl } from "../../inbound/public-ingress-urls.js";
|
|
29
|
-
import { getDb } from "../../persistence/db-connection.js";
|
|
30
29
|
import {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
} from "../../persistence/
|
|
30
|
+
claimA2aInvite,
|
|
31
|
+
createA2aInvite,
|
|
32
|
+
} from "../../persistence/a2a-invite-store.js";
|
|
33
|
+
import { getDb } from "../../persistence/db-connection.js";
|
|
35
34
|
import { assistantContactMetadata } from "../../persistence/schema/index.js";
|
|
36
35
|
import type { HttpErrorResponse } from "../../runtime/http-errors.js";
|
|
37
36
|
import { getLogger } from "../../util/logger.js";
|
|
@@ -157,8 +156,7 @@ export function createA2AInvite(params: {
|
|
|
157
156
|
|
|
158
157
|
// 4. Create the invite
|
|
159
158
|
const expiresInMs = (params.expiresInHours ?? 72) * 60 * 60 * 1000;
|
|
160
|
-
const { invite, rawToken } =
|
|
161
|
-
sourceChannel: "a2a",
|
|
159
|
+
const { invite, rawToken } = createA2aInvite({
|
|
162
160
|
contactId: contact.id,
|
|
163
161
|
maxUses: 1,
|
|
164
162
|
expiresInMs,
|
|
@@ -197,9 +195,8 @@ export function completeA2AInvite(params: {
|
|
|
197
195
|
};
|
|
198
196
|
}
|
|
199
197
|
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
tokenHash,
|
|
198
|
+
const claimResult = claimA2aInvite({
|
|
199
|
+
token: params.token,
|
|
203
200
|
redeemedByExternalUserId: params.acceptor.assistantId,
|
|
204
201
|
});
|
|
205
202
|
|
|
@@ -219,8 +216,6 @@ export function completeA2AInvite(params: {
|
|
|
219
216
|
{
|
|
220
217
|
type: "a2a",
|
|
221
218
|
address: params.acceptor.assistantId.toLowerCase(),
|
|
222
|
-
status: "active",
|
|
223
|
-
policy: "allow",
|
|
224
219
|
},
|
|
225
220
|
],
|
|
226
221
|
});
|
|
@@ -283,8 +278,6 @@ export function redeemA2AInvite(params: {
|
|
|
283
278
|
{
|
|
284
279
|
type: "a2a",
|
|
285
280
|
address: params.sender.assistantId.toLowerCase(),
|
|
286
|
-
status: "active",
|
|
287
|
-
policy: "allow",
|
|
288
281
|
},
|
|
289
282
|
],
|
|
290
283
|
});
|
|
@@ -34,7 +34,6 @@ import {
|
|
|
34
34
|
getGuardianBinding,
|
|
35
35
|
getPendingSession,
|
|
36
36
|
isGuardianBoundForChannel,
|
|
37
|
-
revokeBinding,
|
|
38
37
|
revokePendingSessions,
|
|
39
38
|
updateSessionDelivery,
|
|
40
39
|
} from "../../runtime/channel-verification-service.js";
|
|
@@ -263,19 +262,12 @@ export async function revokeVerificationForChannel(
|
|
|
263
262
|
if (!parsed.ok) {
|
|
264
263
|
throw new Error("mark_channel_revoked relay returned ok: false");
|
|
265
264
|
}
|
|
266
|
-
//
|
|
267
|
-
//
|
|
268
|
-
// and won't fire the invalidation. Emit it here so open client views
|
|
269
|
-
// stop showing the channel as active.
|
|
265
|
+
// Emit the invalidation so open client views stop showing the channel
|
|
266
|
+
// as active after the gateway dual-writes it to "revoked".
|
|
270
267
|
notifyContactsChanged();
|
|
271
268
|
}
|
|
272
269
|
}
|
|
273
270
|
|
|
274
|
-
// The guardian binding is assistant-owned state the gateway relay does not
|
|
275
|
-
// manage; tear it down here. The contact-change invalidation is emitted
|
|
276
|
-
// explicitly above on relay success.
|
|
277
|
-
revokeBinding(assistantId, resolvedChannel);
|
|
278
|
-
|
|
279
271
|
return {
|
|
280
272
|
success: true,
|
|
281
273
|
bound: false,
|
|
@@ -16,7 +16,9 @@ export interface ConversationSearchParams {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
/** Search conversations and return results (no transport dependency). */
|
|
19
|
-
export function performConversationSearch(
|
|
19
|
+
export async function performConversationSearch(
|
|
20
|
+
params: ConversationSearchParams,
|
|
21
|
+
) {
|
|
20
22
|
// Treat "*" as a list-all wildcard — FTS treats it as a literal character.
|
|
21
23
|
if (params.query.trim() === "*") {
|
|
22
24
|
const rows = listConversations(params.limit);
|