@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
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A bounded, append-only JSONL ring buffer persisted to disk.
|
|
3
|
+
*
|
|
4
|
+
* The resource monitor writes one sample per tick here so that when the
|
|
5
|
+
* container is OOM-SIGKILL'd — which resets every in-process buffer and cgroup
|
|
6
|
+
* peak — the last samples leading up to the freeze are still on the workspace
|
|
7
|
+
* volume for post-mortem inspection.
|
|
8
|
+
*
|
|
9
|
+
* Bounding is done by rotation rather than rewrite: the active file is appended
|
|
10
|
+
* to until it reaches `capacity` lines, then renamed to `<name>.1` and a fresh
|
|
11
|
+
* active file is started. At most two files exist (`<name>` + `<name>.1`), so
|
|
12
|
+
* disk stays bounded at ~2× capacity while the most recent writes always land
|
|
13
|
+
* in the active file (append is atomic per line and needs no read-modify-write,
|
|
14
|
+
* so a SIGKILL mid-run can lose at most the in-flight line).
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
appendFileSync,
|
|
19
|
+
existsSync,
|
|
20
|
+
mkdirSync,
|
|
21
|
+
readFileSync,
|
|
22
|
+
renameSync,
|
|
23
|
+
} from "node:fs";
|
|
24
|
+
import { dirname } from "node:path";
|
|
25
|
+
|
|
26
|
+
export class SampleRingBuffer<T> {
|
|
27
|
+
private readonly activePath: string;
|
|
28
|
+
private readonly rotatedPath: string;
|
|
29
|
+
private readonly capacity: number;
|
|
30
|
+
private lineCount: number;
|
|
31
|
+
|
|
32
|
+
constructor(path: string, capacity: number) {
|
|
33
|
+
this.activePath = path;
|
|
34
|
+
this.rotatedPath = `${path}.1`;
|
|
35
|
+
this.capacity = Math.max(1, capacity);
|
|
36
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
37
|
+
// Resume line accounting from a prior run so an existing active file
|
|
38
|
+
// rotates at the right point instead of growing unbounded.
|
|
39
|
+
this.lineCount = countLines(this.activePath);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
append(record: T): void {
|
|
43
|
+
appendFileSync(this.activePath, `${JSON.stringify(record)}\n`);
|
|
44
|
+
this.lineCount += 1;
|
|
45
|
+
if (this.lineCount >= this.capacity) {
|
|
46
|
+
renameSync(this.activePath, this.rotatedPath);
|
|
47
|
+
this.lineCount = 0;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Return the most recent `limit` records (default: all retained), oldest
|
|
53
|
+
* first. Reads the rotated file then the active file so ordering is
|
|
54
|
+
* chronological across the rotation boundary. Malformed trailing lines (e.g.
|
|
55
|
+
* a half-written line from a SIGKILL) are skipped.
|
|
56
|
+
*/
|
|
57
|
+
readRecent(limit?: number): T[] {
|
|
58
|
+
const records = [
|
|
59
|
+
...parseJsonl<T>(this.rotatedPath),
|
|
60
|
+
...parseJsonl<T>(this.activePath),
|
|
61
|
+
];
|
|
62
|
+
if (limit != null && records.length > limit) {
|
|
63
|
+
return records.slice(records.length - limit);
|
|
64
|
+
}
|
|
65
|
+
return records;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** The most recent record, or null when the buffer is empty. */
|
|
69
|
+
readLast(): T | null {
|
|
70
|
+
const recent = this.readRecent(1);
|
|
71
|
+
return recent.length > 0 ? recent[recent.length - 1] : null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function countLines(path: string): number {
|
|
76
|
+
if (!existsSync(path)) return 0;
|
|
77
|
+
try {
|
|
78
|
+
const raw = readFileSync(path, "utf-8");
|
|
79
|
+
if (raw.length === 0) return 0;
|
|
80
|
+
let count = 0;
|
|
81
|
+
for (let i = 0; i < raw.length; i++) {
|
|
82
|
+
if (raw[i] === "\n") count += 1;
|
|
83
|
+
}
|
|
84
|
+
return count;
|
|
85
|
+
} catch {
|
|
86
|
+
return 0;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function parseJsonl<T>(path: string): T[] {
|
|
91
|
+
if (!existsSync(path)) return [];
|
|
92
|
+
let raw: string;
|
|
93
|
+
try {
|
|
94
|
+
raw = readFileSync(path, "utf-8");
|
|
95
|
+
} catch {
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
const out: T[] = [];
|
|
99
|
+
for (const line of raw.split("\n")) {
|
|
100
|
+
if (!line.trim()) continue;
|
|
101
|
+
try {
|
|
102
|
+
out.push(JSON.parse(line) as T);
|
|
103
|
+
} catch {
|
|
104
|
+
// Skip a malformed (e.g. partially-written) line.
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standalone entry point for the resource monitor as its own OS process.
|
|
3
|
+
*
|
|
4
|
+
* Spawned by `assistant monitoring start` (and at daemon startup when
|
|
5
|
+
* `monitoring.enabled` is set). Loads config, starts the sampling loop,
|
|
6
|
+
* writes a PID file, and stays alive until SIGTERM/SIGINT.
|
|
7
|
+
*
|
|
8
|
+
* Running as a separate process — off the assistant's main event loop — is the
|
|
9
|
+
* whole point: the sampler keeps recording during a main-thread freeze, and its
|
|
10
|
+
* on-disk ring buffer survives the OOM SIGKILL that resets all in-VM state.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { existsSync, mkdirSync, unlinkSync, writeFileSync } from "node:fs";
|
|
14
|
+
|
|
15
|
+
import { getConfig } from "../config/loader.js";
|
|
16
|
+
import { getLogger } from "../util/logger.js";
|
|
17
|
+
import {
|
|
18
|
+
getMonitoringDataDir,
|
|
19
|
+
getMonitoringPidPath,
|
|
20
|
+
} from "../util/platform.js";
|
|
21
|
+
import {
|
|
22
|
+
type ResourceSamplerHandle,
|
|
23
|
+
startResourceSampler,
|
|
24
|
+
} from "./resource-sampler.js";
|
|
25
|
+
|
|
26
|
+
const log = getLogger("monitoring-worker");
|
|
27
|
+
|
|
28
|
+
function cleanupPidFile(): void {
|
|
29
|
+
const pidPath = getMonitoringPidPath();
|
|
30
|
+
try {
|
|
31
|
+
if (existsSync(pidPath)) unlinkSync(pidPath);
|
|
32
|
+
} catch {
|
|
33
|
+
// best-effort
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function main(): Promise<void> {
|
|
38
|
+
const config = getConfig();
|
|
39
|
+
const pidPath = getMonitoringPidPath();
|
|
40
|
+
|
|
41
|
+
// Ensure the data dir exists before the PID write — the sampler's ring buffer
|
|
42
|
+
// would otherwise be the first to create it, but the PID file lands here too.
|
|
43
|
+
mkdirSync(getMonitoringDataDir(), { recursive: true });
|
|
44
|
+
|
|
45
|
+
// Write PID file so `status` and `stop` can find us.
|
|
46
|
+
writeFileSync(pidPath, String(process.pid), { flag: "w" });
|
|
47
|
+
log.info(
|
|
48
|
+
{
|
|
49
|
+
pid: process.pid,
|
|
50
|
+
pidPath,
|
|
51
|
+
sampleIntervalMs: config.monitoring.sampleIntervalMs,
|
|
52
|
+
},
|
|
53
|
+
"Resource monitor process started",
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const sampler: ResourceSamplerHandle = startResourceSampler(
|
|
57
|
+
config.monitoring,
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const shutdown = (signal: string) => {
|
|
61
|
+
log.info({ signal }, "Resource monitor process shutting down");
|
|
62
|
+
sampler.stop();
|
|
63
|
+
cleanupPidFile();
|
|
64
|
+
process.exit(0);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
68
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
69
|
+
|
|
70
|
+
process.on("uncaughtException", (err) => {
|
|
71
|
+
log.error({ err }, "Uncaught exception in resource monitor process");
|
|
72
|
+
sampler.stop();
|
|
73
|
+
cleanupPidFile();
|
|
74
|
+
process.exit(1);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
process.on("unhandledRejection", (reason) => {
|
|
78
|
+
log.error({ reason }, "Unhandled rejection in resource monitor process");
|
|
79
|
+
sampler.stop();
|
|
80
|
+
cleanupPidFile();
|
|
81
|
+
process.exit(1);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
process.on("exit", () => {
|
|
85
|
+
sampler.stop();
|
|
86
|
+
cleanupPidFile();
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
void main().catch((err) => {
|
|
91
|
+
log.error({ err }, "Resource monitor process failed to start");
|
|
92
|
+
cleanupPidFile();
|
|
93
|
+
process.exit(1);
|
|
94
|
+
});
|
|
@@ -57,7 +57,7 @@ Hard invariants that the LLM cannot override:
|
|
|
57
57
|
|
|
58
58
|
**Post-generation enforcement** (`decision-engine.ts`):
|
|
59
59
|
|
|
60
|
-
- **Guardian question request-code enforcement** — `enforceGuardianRequestCode()` ensures request-code instructions (approve/reject or free-text answer) appear in all `guardian.question` notification copy, even when the LLM omits them.
|
|
60
|
+
- **Guardian question request-code enforcement** — `enforceGuardianRequestCode()` ensures request-code instructions (approve/reject or free-text answer) appear in all `guardian.question` notification copy, even when the LLM omits them. Exception: for approval-mode questions the Slack adapter renders an interactive card with Approve/Reject buttons, so Slack copy is instead **stripped** of request-code instructions and bare code mentions (`stripGuardianRequestCodeInstructions()`).
|
|
61
61
|
- **Access-request instruction enforcement** — `enforceAccessRequestInstructions()` validates that `ingress.access_request` copy contains: (1) the request-code approve/reject directive, (2) the exact "open invite flow" phrase. If any required element is missing, the full deterministic contract text is appended. This prevents model-generated copy from dropping security-critical action directives.
|
|
62
62
|
|
|
63
63
|
**Pre-send gate checks** (`deterministic-checks.ts`) — these all depend on the decision, so they run here, after it:
|
|
@@ -7,6 +7,12 @@
|
|
|
7
7
|
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
|
|
10
|
+
import {
|
|
11
|
+
buildIntroductionActions,
|
|
12
|
+
coerceSignalBoolean,
|
|
13
|
+
type IntroductionActionOption,
|
|
14
|
+
isHandshakeOffered,
|
|
15
|
+
} from "../runtime/introduction-policy.js";
|
|
10
16
|
import {
|
|
11
17
|
nonEmpty,
|
|
12
18
|
sanitizeIdentityField,
|
|
@@ -20,8 +26,12 @@ const optStr = z
|
|
|
20
26
|
.unknown()
|
|
21
27
|
.transform((v) => (typeof v === "string" ? v : undefined));
|
|
22
28
|
|
|
23
|
-
/**
|
|
24
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Tri-state identity-signal boolean (see `coerceSignalBoolean`): explicit
|
|
31
|
+
* `false` is preserved as a positive platform resolution, everything
|
|
32
|
+
* non-boolean is unknown.
|
|
33
|
+
*/
|
|
34
|
+
const optBool = z.unknown().transform(coerceSignalBoolean);
|
|
25
35
|
|
|
26
36
|
export const AccessRequestPayloadSchema = z.object({
|
|
27
37
|
requestId: optStr,
|
|
@@ -36,6 +46,7 @@ export const AccessRequestPayloadSchema = z.object({
|
|
|
36
46
|
guardianResolutionSource: optStr,
|
|
37
47
|
previousMemberStatus: optStr,
|
|
38
48
|
messagePreview: optStr,
|
|
49
|
+
isBot: optBool,
|
|
39
50
|
isStranger: optBool,
|
|
40
51
|
isRestricted: optBool,
|
|
41
52
|
messageTs: optStr,
|
|
@@ -64,6 +75,11 @@ export function buildAccessRequestWarnings(
|
|
|
64
75
|
if (p.previousMemberStatus === "revoked") {
|
|
65
76
|
warnings.push("This user was previously revoked.");
|
|
66
77
|
}
|
|
78
|
+
if (p.isBot) {
|
|
79
|
+
warnings.push(
|
|
80
|
+
"Bot / integration account — code verification isn't possible.",
|
|
81
|
+
);
|
|
82
|
+
}
|
|
67
83
|
if (p.isStranger) {
|
|
68
84
|
warnings.push("External Slack user (not in this workspace).");
|
|
69
85
|
}
|
|
@@ -73,6 +89,35 @@ export function buildAccessRequestWarnings(
|
|
|
73
89
|
return warnings;
|
|
74
90
|
}
|
|
75
91
|
|
|
92
|
+
// ── Introduction actions ─────────────────────────────────────────────────────
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Signal-driven introduction-card action list for a parsed access-request
|
|
96
|
+
* payload. Shared by every card renderer (Slack Card block, Telegram inline
|
|
97
|
+
* keyboard, Vellum Surface card) so the offered actions never drift between
|
|
98
|
+
* surfaces.
|
|
99
|
+
*/
|
|
100
|
+
export function buildIntroductionActionsForPayload(
|
|
101
|
+
p: ParsedAccessRequestPayload,
|
|
102
|
+
): IntroductionActionOption[] {
|
|
103
|
+
return buildIntroductionActions(p.sourceChannel, {
|
|
104
|
+
isBot: p.isBot,
|
|
105
|
+
isStranger: p.isStranger,
|
|
106
|
+
isRestricted: p.isRestricted,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Whether the verification handshake is offered for this requester. */
|
|
111
|
+
export function isHandshakeOfferedForPayload(
|
|
112
|
+
p: ParsedAccessRequestPayload,
|
|
113
|
+
): boolean {
|
|
114
|
+
return isHandshakeOffered(p.sourceChannel, {
|
|
115
|
+
isBot: p.isBot,
|
|
116
|
+
isStranger: p.isStranger,
|
|
117
|
+
isRestricted: p.isRestricted,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
76
121
|
// ── Slack conversation helpers ───────────────────────────────────────────────
|
|
77
122
|
|
|
78
123
|
/** Slack DM conversation IDs start with `D` followed by alphanumeric chars. */
|
|
@@ -159,10 +204,14 @@ function buildMessagePreviewFromParsed(
|
|
|
159
204
|
p: ParsedAccessRequestPayload,
|
|
160
205
|
): string | undefined {
|
|
161
206
|
const raw = p.messagePreview;
|
|
162
|
-
if (!raw)
|
|
207
|
+
if (!raw) {
|
|
208
|
+
return undefined;
|
|
209
|
+
}
|
|
163
210
|
|
|
164
211
|
const sanitized = sanitizeMessagePreview(raw);
|
|
165
|
-
if (sanitized.length === 0)
|
|
212
|
+
if (sanitized.length === 0) {
|
|
213
|
+
return undefined;
|
|
214
|
+
}
|
|
166
215
|
|
|
167
216
|
return `> Their message: "${sanitized}"`;
|
|
168
217
|
}
|
|
@@ -189,16 +238,28 @@ export function normalizeForDirectiveMatching(text: string): string {
|
|
|
189
238
|
.trim();
|
|
190
239
|
}
|
|
191
240
|
|
|
241
|
+
/** Build a negated-lookbehind directive regex for `reply ... "CODE <verb>"`. */
|
|
242
|
+
function buildCodeDirectiveRegex(escapedCode: string, verb: string): RegExp {
|
|
243
|
+
return new RegExp(
|
|
244
|
+
`(?<!not\\s)(?<!n't\\s)(?<!never\\s)reply\\b[^.!?\\n]*?"${escapedCode}\\s+${verb}"`,
|
|
245
|
+
"i",
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
192
249
|
/**
|
|
193
|
-
* Check whether a text contains the required access-request instruction
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
250
|
+
* Check whether a text contains the required access-request instruction
|
|
251
|
+
* elements for the introduction card:
|
|
252
|
+
* 1. Trust directive: Reply "CODE trust"
|
|
253
|
+
* 2. Verify directive: Reply "CODE verify" — only when the handshake is
|
|
254
|
+
* offered for this requester (never for bots / workspace-vouched members)
|
|
255
|
+
* 3. Leave-unverified directive: Reply "CODE reject"
|
|
256
|
+
* 4. Block directive: Reply "CODE block"
|
|
257
|
+
* 5. Invite directive: Reply "open invite flow"
|
|
197
258
|
*
|
|
198
259
|
* Each directive is matched independently using negative lookbehind to reject
|
|
199
260
|
* matches preceded by negation words ("not", "n't", "never"). This prevents
|
|
200
261
|
* contradictory copy like `Do not reply "CODE reject"` from satisfying the
|
|
201
|
-
* check even when a positive
|
|
262
|
+
* check even when a positive directive exists nearby.
|
|
202
263
|
*
|
|
203
264
|
* The text is normalized before matching to handle smart apostrophes and
|
|
204
265
|
* multiple whitespace characters that would otherwise bypass negation detection.
|
|
@@ -206,26 +267,28 @@ export function normalizeForDirectiveMatching(text: string): string {
|
|
|
206
267
|
export function hasAccessRequestInstructions(
|
|
207
268
|
text: string | undefined,
|
|
208
269
|
requestCode: string,
|
|
270
|
+
options?: { handshakeOffered?: boolean },
|
|
209
271
|
): boolean {
|
|
210
|
-
if (typeof text !== "string")
|
|
272
|
+
if (typeof text !== "string") {
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
const handshakeOffered = options?.handshakeOffered ?? true;
|
|
211
276
|
const normalized = normalizeForDirectiveMatching(text);
|
|
212
277
|
const escapedCode = requestCode.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
213
278
|
// Each directive must follow "reply" without a preceding negation word.
|
|
214
279
|
// Negative lookbehinds reject "do not reply", "don't reply", "never reply".
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
);
|
|
219
|
-
const rejectRe = new RegExp(
|
|
220
|
-
`(?<!not\\s)(?<!n't\\s)(?<!never\\s)reply\\b[^.!?\\n]*?"${escapedCode}\\s+reject"`,
|
|
221
|
-
"i",
|
|
222
|
-
);
|
|
280
|
+
const trustRe = buildCodeDirectiveRegex(escapedCode, "trust");
|
|
281
|
+
const verifyRe = buildCodeDirectiveRegex(escapedCode, "verify");
|
|
282
|
+
const rejectRe = buildCodeDirectiveRegex(escapedCode, "reject");
|
|
283
|
+
const blockRe = buildCodeDirectiveRegex(escapedCode, "block");
|
|
223
284
|
const inviteRe =
|
|
224
285
|
/(?<!not\s)(?<!n't\s)(?<!never\s)reply\b[^.!?\n]*?"open invite flow"/i;
|
|
225
286
|
|
|
226
287
|
return (
|
|
227
|
-
|
|
288
|
+
trustRe.test(normalized) &&
|
|
289
|
+
(!handshakeOffered || verifyRe.test(normalized)) &&
|
|
228
290
|
rejectRe.test(normalized) &&
|
|
291
|
+
blockRe.test(normalized) &&
|
|
229
292
|
inviteRe.test(normalized)
|
|
230
293
|
);
|
|
231
294
|
}
|
|
@@ -237,7 +300,9 @@ export function hasAccessRequestInstructions(
|
|
|
237
300
|
* directive should still be present.
|
|
238
301
|
*/
|
|
239
302
|
export function hasInviteFlowDirective(text: string | undefined): boolean {
|
|
240
|
-
if (typeof text !== "string")
|
|
303
|
+
if (typeof text !== "string") {
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
241
306
|
const normalized = normalizeForDirectiveMatching(text);
|
|
242
307
|
const inviteRe =
|
|
243
308
|
/(?<!not\s)(?<!n't\s)(?<!never\s)reply\b[^.!?\n]*?"open invite flow"/i;
|
|
@@ -293,9 +358,15 @@ export function buildAccessRequestContractText(
|
|
|
293
358
|
|
|
294
359
|
if (requestCode) {
|
|
295
360
|
const code = requestCode.toUpperCase();
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
361
|
+
if (isHandshakeOfferedForPayload(p)) {
|
|
362
|
+
lines.push(
|
|
363
|
+
`Reply "${code} verify" to send them a verification code, "${code} trust" to trust them without one, "${code} reject" to leave them unverified, or "${code} block" to block them.`,
|
|
364
|
+
);
|
|
365
|
+
} else {
|
|
366
|
+
lines.push(
|
|
367
|
+
`Reply "${code} trust" to trust them, "${code} reject" to leave them unverified, or "${code} block" to block them.`,
|
|
368
|
+
);
|
|
369
|
+
}
|
|
299
370
|
}
|
|
300
371
|
lines.push(buildAccessRequestInviteDirective());
|
|
301
372
|
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* using native Card blocks for approval notifications.
|
|
4
4
|
*
|
|
5
5
|
* Approval notifications (access requests, tool approvals) render as a
|
|
6
|
-
* single Slack Card block with Approve/Reject action buttons
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* text sections.
|
|
6
|
+
* single Slack Card block with Approve/Reject action buttons. Text that
|
|
7
|
+
* exceeds the card body's 200-character cap continues in a companion
|
|
8
|
+
* section block below the card. Non-approval notifications use standard
|
|
9
|
+
* Block Kit text sections.
|
|
10
10
|
*
|
|
11
11
|
* Card block reference:
|
|
12
12
|
* https://docs.slack.dev/reference/block-kit/blocks/card-block
|
|
@@ -40,14 +40,41 @@ const log = getLogger("notif-adapter-slack");
|
|
|
40
40
|
// Slack Card block builders for approval notifications
|
|
41
41
|
// ---------------------------------------------------------------------------
|
|
42
42
|
|
|
43
|
-
/**
|
|
43
|
+
/** Translate a surface-agnostic emphasis into Slack's button style token. */
|
|
44
|
+
function slackStyleForEmphasis(
|
|
45
|
+
emphasis: "primary" | "secondary" | "destructive",
|
|
46
|
+
): { style: "primary" | "danger" } | Record<string, never> {
|
|
47
|
+
switch (emphasis) {
|
|
48
|
+
case "primary":
|
|
49
|
+
return { style: "primary" };
|
|
50
|
+
case "destructive":
|
|
51
|
+
return { style: "danger" };
|
|
52
|
+
case "secondary":
|
|
53
|
+
return {};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Build action buttons for a Slack Card block from approval metadata.
|
|
59
|
+
*
|
|
60
|
+
* Actions carrying an `emphasis` (introduction cards) render it directly, so
|
|
61
|
+
* emphasis policy stays in introduction-policy.ts. Actions without one (tool
|
|
62
|
+
* approvals) fall back to positional styling: first action `primary`,
|
|
63
|
+
* `reject` `danger`.
|
|
64
|
+
*/
|
|
44
65
|
function buildCardActions(approval: ApprovalUIMetadata): Button[] {
|
|
45
|
-
return approval.actions.map((action) => ({
|
|
66
|
+
return approval.actions.map((action, index) => ({
|
|
46
67
|
type: "button",
|
|
47
68
|
text: { type: "plain_text", text: action.label, emoji: true },
|
|
48
69
|
action_id: `apr:${approval.requestId}:${action.id}`,
|
|
49
70
|
value: `apr:${approval.requestId}:${action.id}`,
|
|
50
|
-
...(action.
|
|
71
|
+
...(action.emphasis
|
|
72
|
+
? slackStyleForEmphasis(action.emphasis)
|
|
73
|
+
: action.id === "reject"
|
|
74
|
+
? { style: "danger" }
|
|
75
|
+
: index === 0
|
|
76
|
+
? { style: "primary" }
|
|
77
|
+
: {}),
|
|
51
78
|
}));
|
|
52
79
|
}
|
|
53
80
|
|
|
@@ -63,7 +90,9 @@ function buildAccessRequestSubtitle(view: AccessRequestCardView): string {
|
|
|
63
90
|
parts.push(`(@${view.username})`);
|
|
64
91
|
}
|
|
65
92
|
|
|
66
|
-
if (view.sourceChannel)
|
|
93
|
+
if (view.sourceChannel) {
|
|
94
|
+
parts.push(`via ${view.sourceChannel}`);
|
|
95
|
+
}
|
|
67
96
|
|
|
68
97
|
return truncate(parts.join(" "), 150);
|
|
69
98
|
}
|
|
@@ -111,7 +140,9 @@ function buildRequesterIdBlock(
|
|
|
111
140
|
view: AccessRequestCardView,
|
|
112
141
|
): ContextBlock | undefined {
|
|
113
142
|
const safeExternalId = view.externalId;
|
|
114
|
-
if (!safeExternalId)
|
|
143
|
+
if (!safeExternalId) {
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
115
146
|
|
|
116
147
|
if (safeExternalId === view.displayName || safeExternalId === view.username) {
|
|
117
148
|
return undefined;
|
|
@@ -171,10 +202,14 @@ function buildAccessRequestCardBlocks(
|
|
|
171
202
|
}
|
|
172
203
|
|
|
173
204
|
const sourceContext = buildSourceContextBlock(view);
|
|
174
|
-
if (sourceContext)
|
|
205
|
+
if (sourceContext) {
|
|
206
|
+
blocks.push(sourceContext);
|
|
207
|
+
}
|
|
175
208
|
|
|
176
209
|
const idBlock = buildRequesterIdBlock(view);
|
|
177
|
-
if (idBlock)
|
|
210
|
+
if (idBlock) {
|
|
211
|
+
blocks.push(idBlock);
|
|
212
|
+
}
|
|
178
213
|
|
|
179
214
|
blocks.push({
|
|
180
215
|
type: "context",
|
|
@@ -204,11 +239,40 @@ function buildAccessRequestCardBlocks(
|
|
|
204
239
|
// Tool approval card
|
|
205
240
|
// ---------------------------------------------------------------------------
|
|
206
241
|
|
|
242
|
+
/** Slack caps a card block's `body` text at 200 characters. */
|
|
243
|
+
const CARD_BODY_MAX_LENGTH = 200;
|
|
244
|
+
|
|
245
|
+
/** Marker signalling the card body continues in the section below. */
|
|
246
|
+
const CARD_BODY_CONTINUATION_MARKER = " ↓";
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Split message text so the head fits Slack's card body cap (marker
|
|
250
|
+
* included) and the tail continues in a companion section below the card.
|
|
251
|
+
* Splits on the last whitespace inside the budget when there is one, so
|
|
252
|
+
* neither piece cuts mid-word. Text within the cap needs no split.
|
|
253
|
+
*/
|
|
254
|
+
function splitAtCardBodyLimit(text: string): { head: string; tail?: string } {
|
|
255
|
+
if (text.length <= CARD_BODY_MAX_LENGTH) {
|
|
256
|
+
return { head: text };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const budget = CARD_BODY_MAX_LENGTH - CARD_BODY_CONTINUATION_MARKER.length;
|
|
260
|
+
const window = text.slice(0, budget + 1);
|
|
261
|
+
const lastWhitespace = window.search(/\s\S*$/);
|
|
262
|
+
const cut = lastWhitespace > 0 ? lastWhitespace : budget;
|
|
263
|
+
|
|
264
|
+
return {
|
|
265
|
+
head: text.slice(0, cut).trimEnd() + CARD_BODY_CONTINUATION_MARKER,
|
|
266
|
+
tail: text.slice(cut).trimStart(),
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
207
270
|
/**
|
|
208
271
|
* Build Slack blocks for a tool approval notification using a native Card block.
|
|
209
272
|
*
|
|
210
273
|
* Layout:
|
|
211
274
|
* Card — title + subtitle (tool + requester) + body (notification text) + actions
|
|
275
|
+
* Section — continuation of body text exceeding the card's 200-char cap
|
|
212
276
|
*/
|
|
213
277
|
function buildToolApprovalCardBlocks(
|
|
214
278
|
payload: ChannelDeliveryPayload,
|
|
@@ -227,28 +291,27 @@ function buildToolApprovalCardBlocks(
|
|
|
227
291
|
subtitle = truncate(toolName, 150);
|
|
228
292
|
}
|
|
229
293
|
|
|
230
|
-
const
|
|
294
|
+
const { head, tail } = splitAtCardBodyLimit(messageText);
|
|
231
295
|
const card: CardBlock = {
|
|
232
296
|
type: "card",
|
|
233
297
|
title: {
|
|
234
298
|
type: "mrkdwn",
|
|
235
299
|
text: details ? "Tool Approval" : "Approval Request",
|
|
236
300
|
},
|
|
237
|
-
body: {
|
|
238
|
-
type: "mrkdwn",
|
|
239
|
-
text: needsOverflow ? truncate(messageText, 197) + " ↓" : messageText,
|
|
240
|
-
},
|
|
301
|
+
body: { type: "mrkdwn", text: head },
|
|
241
302
|
actions: buildCardActions(approval),
|
|
242
303
|
};
|
|
243
|
-
if (subtitle)
|
|
304
|
+
if (subtitle) {
|
|
305
|
+
card.subtitle = { type: "mrkdwn", text: subtitle };
|
|
306
|
+
}
|
|
244
307
|
blocks.push(card);
|
|
245
308
|
|
|
246
|
-
//
|
|
247
|
-
//
|
|
248
|
-
if (
|
|
309
|
+
// The companion section carries only the remainder — repeating the full
|
|
310
|
+
// text would render the same message twice (once in the card, once below).
|
|
311
|
+
if (tail) {
|
|
249
312
|
blocks.push({
|
|
250
313
|
type: "section",
|
|
251
|
-
text: { type: "mrkdwn", text: truncate(
|
|
314
|
+
text: { type: "mrkdwn", text: truncate(`… ${tail}`, 3000) },
|
|
252
315
|
});
|
|
253
316
|
}
|
|
254
317
|
|
|
@@ -305,9 +368,14 @@ export class SlackAdapter implements ChannelAdapter {
|
|
|
305
368
|
const messageText = resolveMessageText(payload);
|
|
306
369
|
|
|
307
370
|
try {
|
|
371
|
+
// `approval` rides along with the prebuilt card blocks so the send
|
|
372
|
+
// layer treats a rejected Block Kit payload as an approval prompt:
|
|
373
|
+
// its block-free retry re-attaches `plainTextFallback` reply
|
|
374
|
+
// instructions instead of posting text with no way to respond.
|
|
308
375
|
const result = payload.approvalContext
|
|
309
376
|
? await sendSlackReply(chatId, messageText, {
|
|
310
377
|
blocks: buildApprovalNotificationBlocks(payload, messageText),
|
|
378
|
+
approval: payload.approvalContext,
|
|
311
379
|
})
|
|
312
380
|
: await sendSlackReply(chatId, messageText, { useBlocks: true });
|
|
313
381
|
|