@vellumai/assistant 0.10.0 → 0.10.1-dev.202606240317.ea25efe
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 +36 -37
- package/bun.lock +3 -0
- package/docs/workflows.md +12 -7
- package/eslint-rules/cli-no-daemon-internals.js +12 -0
- package/node_modules/@slack/types/LICENSE +23 -0
- package/node_modules/@slack/types/README.md +32 -0
- package/node_modules/@slack/types/dist/block-kit/block-elements.d.ts +953 -0
- package/node_modules/@slack/types/dist/block-kit/block-elements.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/block-elements.js +4 -0
- package/node_modules/@slack/types/dist/block-kit/block-elements.js.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/blocks.d.ts +474 -0
- package/node_modules/@slack/types/dist/block-kit/blocks.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/blocks.js +3 -0
- package/node_modules/@slack/types/dist/block-kit/blocks.js.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/composition-objects.d.ts +237 -0
- package/node_modules/@slack/types/dist/block-kit/composition-objects.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/composition-objects.js +4 -0
- package/node_modules/@slack/types/dist/block-kit/composition-objects.js.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/extensions.d.ts +88 -0
- package/node_modules/@slack/types/dist/block-kit/extensions.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/extensions.js +3 -0
- package/node_modules/@slack/types/dist/block-kit/extensions.js.map +1 -0
- package/node_modules/@slack/types/dist/calls.d.ts +26 -0
- package/node_modules/@slack/types/dist/calls.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/calls.js +6 -0
- package/node_modules/@slack/types/dist/calls.js.map +1 -0
- package/node_modules/@slack/types/dist/chunk.d.ts +52 -0
- package/node_modules/@slack/types/dist/chunk.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/chunk.js +3 -0
- package/node_modules/@slack/types/dist/chunk.js.map +1 -0
- package/node_modules/@slack/types/dist/common/bot-profile.d.ts +12 -0
- package/node_modules/@slack/types/dist/common/bot-profile.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/common/bot-profile.js +3 -0
- package/node_modules/@slack/types/dist/common/bot-profile.js.map +1 -0
- package/node_modules/@slack/types/dist/common/status-emoji-display-info.d.ts +6 -0
- package/node_modules/@slack/types/dist/common/status-emoji-display-info.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/common/status-emoji-display-info.js +3 -0
- package/node_modules/@slack/types/dist/common/status-emoji-display-info.js.map +1 -0
- package/node_modules/@slack/types/dist/dialog.d.ts +36 -0
- package/node_modules/@slack/types/dist/dialog.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/dialog.js +3 -0
- package/node_modules/@slack/types/dist/dialog.js.map +1 -0
- package/node_modules/@slack/types/dist/events/app.d.ts +204 -0
- package/node_modules/@slack/types/dist/events/app.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/app.js +3 -0
- package/node_modules/@slack/types/dist/events/app.js.map +1 -0
- package/node_modules/@slack/types/dist/events/assistant.d.ts +29 -0
- package/node_modules/@slack/types/dist/events/assistant.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/assistant.js +3 -0
- package/node_modules/@slack/types/dist/events/assistant.js.map +1 -0
- package/node_modules/@slack/types/dist/events/call.d.ts +8 -0
- package/node_modules/@slack/types/dist/events/call.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/call.js +3 -0
- package/node_modules/@slack/types/dist/events/call.js.map +1 -0
- package/node_modules/@slack/types/dist/events/channel.d.ts +85 -0
- package/node_modules/@slack/types/dist/events/channel.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/channel.js +3 -0
- package/node_modules/@slack/types/dist/events/channel.js.map +1 -0
- package/node_modules/@slack/types/dist/events/dnd.d.ts +24 -0
- package/node_modules/@slack/types/dist/events/dnd.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/dnd.js +3 -0
- package/node_modules/@slack/types/dist/events/dnd.js.map +1 -0
- package/node_modules/@slack/types/dist/events/email.d.ts +6 -0
- package/node_modules/@slack/types/dist/events/email.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/email.js +3 -0
- package/node_modules/@slack/types/dist/events/email.js.map +1 -0
- package/node_modules/@slack/types/dist/events/emoji.d.ts +11 -0
- package/node_modules/@slack/types/dist/events/emoji.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/emoji.js +3 -0
- package/node_modules/@slack/types/dist/events/emoji.js.map +1 -0
- package/node_modules/@slack/types/dist/events/entity-details-requested.d.ts +21 -0
- package/node_modules/@slack/types/dist/events/entity-details-requested.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/entity-details-requested.js +3 -0
- package/node_modules/@slack/types/dist/events/entity-details-requested.js.map +1 -0
- package/node_modules/@slack/types/dist/events/file.d.ts +60 -0
- package/node_modules/@slack/types/dist/events/file.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/file.js +4 -0
- package/node_modules/@slack/types/dist/events/file.js.map +1 -0
- package/node_modules/@slack/types/dist/events/function.d.ts +33 -0
- package/node_modules/@slack/types/dist/events/function.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/function.js +3 -0
- package/node_modules/@slack/types/dist/events/function.js.map +1 -0
- package/node_modules/@slack/types/dist/events/grid-migration.d.ts +9 -0
- package/node_modules/@slack/types/dist/events/grid-migration.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/grid-migration.js +3 -0
- package/node_modules/@slack/types/dist/events/grid-migration.js.map +1 -0
- package/node_modules/@slack/types/dist/events/group.d.ts +55 -0
- package/node_modules/@slack/types/dist/events/group.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/group.js +3 -0
- package/node_modules/@slack/types/dist/events/group.js.map +1 -0
- package/node_modules/@slack/types/dist/events/im.d.ts +26 -0
- package/node_modules/@slack/types/dist/events/im.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/im.js +3 -0
- package/node_modules/@slack/types/dist/events/im.js.map +1 -0
- package/node_modules/@slack/types/dist/events/index.d.ts +60 -0
- package/node_modules/@slack/types/dist/events/index.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/index.js +43 -0
- package/node_modules/@slack/types/dist/events/index.js.map +1 -0
- package/node_modules/@slack/types/dist/events/invite.d.ts +20 -0
- package/node_modules/@slack/types/dist/events/invite.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/invite.js +3 -0
- package/node_modules/@slack/types/dist/events/invite.js.map +1 -0
- package/node_modules/@slack/types/dist/events/link-shared.d.ts +16 -0
- package/node_modules/@slack/types/dist/events/link-shared.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/link-shared.js +3 -0
- package/node_modules/@slack/types/dist/events/link-shared.js.map +1 -0
- package/node_modules/@slack/types/dist/events/member.d.ts +19 -0
- package/node_modules/@slack/types/dist/events/member.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/member.js +3 -0
- package/node_modules/@slack/types/dist/events/member.js.map +1 -0
- package/node_modules/@slack/types/dist/events/message-metadata.d.ts +38 -0
- package/node_modules/@slack/types/dist/events/message-metadata.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/message-metadata.js +3 -0
- package/node_modules/@slack/types/dist/events/message-metadata.js.map +1 -0
- package/node_modules/@slack/types/dist/events/message.d.ts +306 -0
- package/node_modules/@slack/types/dist/events/message.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/message.js +3 -0
- package/node_modules/@slack/types/dist/events/message.js.map +1 -0
- package/node_modules/@slack/types/dist/events/pin.d.ts +60 -0
- package/node_modules/@slack/types/dist/events/pin.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/pin.js +3 -0
- package/node_modules/@slack/types/dist/events/pin.js.map +1 -0
- package/node_modules/@slack/types/dist/events/reaction.d.ts +23 -0
- package/node_modules/@slack/types/dist/events/reaction.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/reaction.js +3 -0
- package/node_modules/@slack/types/dist/events/reaction.js.map +1 -0
- package/node_modules/@slack/types/dist/events/shared-channel.d.ts +134 -0
- package/node_modules/@slack/types/dist/events/shared-channel.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/shared-channel.js +3 -0
- package/node_modules/@slack/types/dist/events/shared-channel.js.map +1 -0
- package/node_modules/@slack/types/dist/events/star.d.ts +13 -0
- package/node_modules/@slack/types/dist/events/star.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/star.js +3 -0
- package/node_modules/@slack/types/dist/events/star.js.map +1 -0
- package/node_modules/@slack/types/dist/events/steps-from-apps.d.ts +82 -0
- package/node_modules/@slack/types/dist/events/steps-from-apps.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/steps-from-apps.js +3 -0
- package/node_modules/@slack/types/dist/events/steps-from-apps.js.map +1 -0
- package/node_modules/@slack/types/dist/events/subteam.d.ts +66 -0
- package/node_modules/@slack/types/dist/events/subteam.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/subteam.js +3 -0
- package/node_modules/@slack/types/dist/events/subteam.js.map +1 -0
- package/node_modules/@slack/types/dist/events/team.d.ts +99 -0
- package/node_modules/@slack/types/dist/events/team.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/team.js +3 -0
- package/node_modules/@slack/types/dist/events/team.js.map +1 -0
- package/node_modules/@slack/types/dist/events/token.d.ts +8 -0
- package/node_modules/@slack/types/dist/events/token.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/token.js +3 -0
- package/node_modules/@slack/types/dist/events/token.js.map +1 -0
- package/node_modules/@slack/types/dist/events/user.d.ts +313 -0
- package/node_modules/@slack/types/dist/events/user.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/user.js +3 -0
- package/node_modules/@slack/types/dist/events/user.js.map +1 -0
- package/node_modules/@slack/types/dist/index.d.ts +12 -0
- package/node_modules/@slack/types/dist/index.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/index.js +28 -0
- package/node_modules/@slack/types/dist/index.js.map +1 -0
- package/node_modules/@slack/types/dist/message-attachments.d.ts +171 -0
- package/node_modules/@slack/types/dist/message-attachments.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/message-attachments.js +3 -0
- package/node_modules/@slack/types/dist/message-attachments.js.map +1 -0
- package/node_modules/@slack/types/dist/message-metadata.d.ts +281 -0
- package/node_modules/@slack/types/dist/message-metadata.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/message-metadata.js +27 -0
- package/node_modules/@slack/types/dist/message-metadata.js.map +1 -0
- package/node_modules/@slack/types/dist/views.d.ts +71 -0
- package/node_modules/@slack/types/dist/views.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/views.js +3 -0
- package/node_modules/@slack/types/dist/views.js.map +1 -0
- package/node_modules/@slack/types/package.json +47 -0
- package/node_modules/@vellumai/gateway-client/bun.lock +3 -0
- package/node_modules/@vellumai/gateway-client/package.json +1 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +69 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +91 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +96 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +162 -0
- package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +48 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +8 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +28 -0
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +4 -2
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +3 -2
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +95 -0
- package/openapi.yaml +458 -18
- package/package.json +2 -1
- package/scripts/memory-inspect.ts +24 -14
- package/scripts/test.sh +36 -15
- package/src/__tests__/access-request-seed-content-blocks.test.ts +83 -103
- package/src/__tests__/activation-early-marking.test.ts +1 -1
- package/src/__tests__/actor-token-service.test.ts +39 -17
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +1 -40
- package/src/__tests__/agent-loop-compaction-events.test.ts +0 -1
- package/src/__tests__/agent-loop-compaction-strip.test.ts +0 -1
- package/src/__tests__/agent-loop-exit-reason.test.ts +0 -1
- package/src/__tests__/agent-loop-pushes-post-hook-prompt.test.ts +306 -0
- package/src/__tests__/agent-loop-regrowth-guard.test.ts +0 -1
- package/src/__tests__/agent-loop.test.ts +3 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +2 -0
- package/src/__tests__/anthropic-provider.test.ts +210 -9
- package/src/__tests__/app-builder-skill-instructions.test.ts +47 -5
- package/src/__tests__/app-conversation-ids-backfill.test.ts +1 -1
- package/src/__tests__/app-source-watcher.test.ts +30 -10
- package/src/__tests__/approval-cascade.test.ts +6 -0
- package/src/__tests__/approval-interception-trust-gates.test.ts +151 -0
- package/src/__tests__/approval-primitive.test.ts +1 -1
- package/src/__tests__/approval-routes-http.test.ts +1 -1
- package/src/__tests__/assistant-attachments.test.ts +155 -0
- package/src/__tests__/assistant-event-hub-machine-name.test.ts +2 -4
- package/src/__tests__/assistant-events-sse-hardening.test.ts +1 -1
- package/src/__tests__/assistant-events-sse-shed.test.ts +1 -1
- package/src/__tests__/attachment-upload-trusted-source.test.ts +13 -8
- package/src/__tests__/attachments-store.test.ts +1 -1
- package/src/__tests__/audit-log-rotation.test.ts +50 -54
- package/src/__tests__/auth-fallback-events-store.test.ts +1 -1
- package/src/__tests__/auto-analysis-end-to-end.test.ts +9 -14
- package/src/__tests__/background-shell-bash.test.ts +4 -1
- package/src/__tests__/background-shell-host-bash.test.ts +17 -3
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -0
- package/src/__tests__/call-controller.test.ts +20 -1
- package/src/__tests__/call-conversation-messages.test.ts +1 -1
- package/src/__tests__/call-domain.test.ts +1 -1
- package/src/__tests__/call-pointer-messages.test.ts +3 -4
- package/src/__tests__/call-recovery.test.ts +1 -1
- package/src/__tests__/call-routes-http.test.ts +1 -1
- package/src/__tests__/call-store.test.ts +1 -1
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
- package/src/__tests__/canonical-guardian-store.test.ts +24 -1
- package/src/__tests__/card-surface-data.test.ts +60 -0
- package/src/__tests__/channel-approval-routes.test.ts +73 -1119
- package/src/__tests__/channel-delivery-store.test.ts +1 -1
- package/src/__tests__/channel-guardian.test.ts +291 -641
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +1 -2
- package/src/__tests__/channel-retry-sweep.test.ts +1 -1
- package/src/__tests__/compaction-events.test.ts +6 -0
- package/src/__tests__/compaction-trail-store.test.ts +6 -5
- package/src/__tests__/compaction.benchmark.test.ts +0 -1
- package/src/__tests__/compactor-image-manifest-trust.test.ts +1 -1
- package/src/__tests__/config-loader-backfill.test.ts +188 -52
- package/src/__tests__/config-schema.test.ts +35 -0
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +1 -2
- package/src/__tests__/contact-store-user-file.test.ts +2 -2
- package/src/__tests__/contacts-relay-reads.test.ts +409 -0
- package/src/__tests__/contacts-tools.test.ts +4 -4
- package/src/__tests__/contacts-write.test.ts +1 -2
- package/src/__tests__/context-search-conversations-source.test.ts +1 -1
- package/src/__tests__/context-window-manager-compact-retry.test.ts +6 -2
- package/src/__tests__/context-window-manager-overflow-rung.test.ts +6 -2
- package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +3 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +3 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +3 -0
- package/src/__tests__/conversation-agent-loop.test.ts +7 -0
- package/src/__tests__/conversation-attachments.test.ts +2 -5
- package/src/__tests__/conversation-attention-store.test.ts +1 -1
- package/src/__tests__/conversation-attention-telegram.test.ts +1 -2
- package/src/__tests__/conversation-clear-safety.test.ts +1 -1
- package/src/__tests__/conversation-confirmation-signals.test.ts +6 -0
- package/src/__tests__/conversation-crud-inference-profile.test.ts +1 -1
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +12 -19
- package/src/__tests__/conversation-disk-view-integration.test.ts +1 -1
- package/src/__tests__/conversation-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-fork-crud.test.ts +10 -8
- package/src/__tests__/conversation-fork-retrospective.test.ts +250 -0
- package/src/__tests__/conversation-fork-route.test.ts +1 -1
- package/src/__tests__/conversation-inference-profile-list.test.ts +1 -1
- package/src/__tests__/conversation-inference-profile-route.test.ts +1 -1
- package/src/__tests__/conversation-init.benchmark.test.ts +1 -1
- package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-lifecycle.test.ts +117 -0
- package/src/__tests__/conversation-list-source.test.ts +3 -3
- package/src/__tests__/conversation-process-callsite.test.ts +6 -14
- package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
- package/src/__tests__/conversation-queue.test.ts +95 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +12 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +12 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +115 -12
- package/src/__tests__/conversation-slash-queue.test.ts +6 -0
- package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
- package/src/__tests__/conversation-speed-override.test.ts +6 -0
- package/src/__tests__/conversation-starter-routes.test.ts +5 -5
- package/src/__tests__/conversation-store.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +4 -4
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +352 -0
- package/src/__tests__/conversation-sync-tags.test.ts +1 -1
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +47 -0
- package/src/__tests__/conversation-usage.test.ts +1 -1
- package/src/__tests__/conversation-wipe.test.ts +9 -8
- package/src/__tests__/conversation-workspace-cache-state.test.ts +6 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
- package/src/__tests__/conversations-import-system-filter.test.ts +1 -1
- package/src/__tests__/copy-composer-tc-templates.test.ts +17 -0
- package/src/__tests__/credential-security-invariants.test.ts +0 -1
- package/src/__tests__/db-acp-history.test.ts +2 -2
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +5 -7
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +6 -7
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +5 -10
- package/src/__tests__/db-migration-rollback.test.ts +129 -39
- package/src/__tests__/db-proxy-transaction.test.ts +1 -1
- package/src/__tests__/db-schedule-syntax-migration.test.ts +0 -11
- package/src/__tests__/db-test-helpers.ts +36 -19
- package/src/__tests__/delete-propagation.test.ts +1 -1
- package/src/__tests__/deterministic-verification-control-plane.test.ts +28 -8
- package/src/__tests__/disk-pressure-guard.test.ts +41 -0
- package/src/__tests__/disk-pressure-tools.test.ts +41 -1
- package/src/__tests__/dm-backfill.test.ts +1 -1
- package/src/__tests__/drop-capability-card-state-migration.test.ts +0 -8
- package/src/__tests__/dynamic-page-surface.test.ts +0 -94
- package/src/__tests__/edit-propagation.test.ts +1 -1
- package/src/__tests__/emit-signal-routing-intent.test.ts +93 -5
- package/src/__tests__/empty-response-hook.test.ts +42 -0
- package/src/__tests__/events-client-registration.test.ts +1 -1
- package/src/__tests__/events-dev-bypass-actor.test.ts +7 -1
- package/src/__tests__/followup-tools.test.ts +1 -1
- package/src/__tests__/gemini-count-tokens.test.ts +70 -0
- package/src/__tests__/guardian-action-sweep.test.ts +9 -2
- package/src/__tests__/guardian-binding-drift-heal.test.ts +76 -11
- package/src/__tests__/guardian-card-withdrawal.test.ts +1 -1
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +1 -1
- package/src/__tests__/guardian-dispatch.test.ts +96 -2
- package/src/__tests__/guardian-outbound-http.test.ts +20 -12
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
- package/src/__tests__/guardian-routing-state.test.ts +1 -2
- package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -1
- package/src/__tests__/headless-browser-mode.test.ts +2 -2
- package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
- package/src/__tests__/heartbeat-service.test.ts +6 -0
- package/src/__tests__/helpers/channel-test-adapter.ts +92 -0
- package/src/__tests__/host-app-control-routes.test.ts +24 -30
- package/src/__tests__/host-bash-routes.test.ts +31 -41
- package/src/__tests__/host-browser-routes.test.ts +26 -32
- package/src/__tests__/host-cu-routes-targeted.test.ts +25 -33
- package/src/__tests__/host-file-routes-targeted.test.ts +40 -52
- package/src/__tests__/host-transfer-routes-targeted.test.ts +31 -43
- package/src/__tests__/http-conversation-lineage.test.ts +1 -1
- package/src/__tests__/http-user-message-parity.test.ts +165 -8
- package/src/__tests__/image-recovery-hook.test.ts +1 -1
- package/src/__tests__/inbound-invite-redemption.test.ts +1 -2
- package/src/__tests__/inbound-trust-verdict.test.ts +254 -0
- package/src/__tests__/inference-profile-reaper.test.ts +1 -1
- package/src/__tests__/inference-profile-session-handler.test.ts +1 -1
- package/src/__tests__/inference-profile-session-ipc.test.ts +1 -1
- package/src/__tests__/injector-chain.test.ts +1 -1
- package/src/__tests__/injector-disk-pressure.test.ts +11 -6
- package/src/__tests__/internal-telemetry-routes.test.ts +1 -1
- package/src/__tests__/invite-redemption-service.test.ts +244 -43
- package/src/__tests__/invite-routes-http.test.ts +35 -186
- package/src/__tests__/invite-service-ipc.test.ts +287 -0
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +5 -5
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +9 -12
- package/src/__tests__/list-messages-attachments.test.ts +42 -1
- package/src/__tests__/list-messages-client-message-id.test.ts +1 -1
- package/src/__tests__/list-messages-hidden-metadata.test.ts +1 -1
- package/src/__tests__/list-messages-page-latest.test.ts +1 -1
- package/src/__tests__/list-messages-tool-merge.test.ts +1 -1
- package/src/__tests__/llm-context-normalization.test.ts +105 -0
- package/src/__tests__/llm-context-route-provider.test.ts +69 -4
- package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +9 -5
- package/src/__tests__/llm-request-log-call-site.test.ts +6 -6
- package/src/__tests__/llm-request-log-turn-query.test.ts +27 -13
- package/src/__tests__/llm-resolver.test.ts +205 -5
- package/src/__tests__/llm-usage-store.test.ts +65 -1
- package/src/__tests__/log-export-routes.test.ts +1 -1
- package/src/__tests__/log-export-workspace.test.ts +3 -3
- package/src/__tests__/media-stream-server-integration.test.ts +127 -0
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +5 -5
- package/src/__tests__/memory-recall-log-store.test.ts +1 -1
- package/src/__tests__/memory-upsert-concurrency.test.ts +3 -4
- package/src/__tests__/messages-after-tiebreaker.test.ts +1 -1
- package/src/__tests__/migration-import-from-url.test.ts +2 -2
- package/src/__tests__/mtime-cache.test.ts +375 -0
- package/src/__tests__/non-member-access-request.test.ts +190 -19
- package/src/__tests__/notification-broadcaster.test.ts +4 -0
- package/src/__tests__/notification-candidate-guardian-context.test.ts +203 -0
- package/src/__tests__/notification-decision-recipient-context.test.ts +33 -32
- package/src/__tests__/notification-deep-link.test.ts +4 -0
- package/src/__tests__/notification-guardian-path.test.ts +20 -1
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +1 -1
- package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
- package/src/__tests__/oauth-provider-visibility.test.ts +1 -1
- package/src/__tests__/oauth-store.test.ts +1 -1
- package/src/__tests__/pending-interactions-resolved-event.test.ts +7 -4
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +1 -1
- package/src/__tests__/persist-unsendable-image.test.ts +1 -1
- package/src/__tests__/persona-resolver.test.ts +39 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +1 -1
- package/src/__tests__/playbook-execution.test.ts +1 -1
- package/src/__tests__/playbook-tools.test.ts +1 -1
- package/src/__tests__/plugin-api-model-profiles.test.ts +74 -21
- package/src/__tests__/plugin-bootstrap.test.ts +78 -0
- package/src/__tests__/provider-platform-proxy-integration.test.ts +25 -5
- package/src/__tests__/provider-usage-tracking.test.ts +40 -1
- package/src/__tests__/prune-old-conversations-job.test.ts +1 -1
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/registry.test.ts +3 -0
- package/src/__tests__/relay-server.test.ts +1026 -73
- package/src/__tests__/runtime-attachment-metadata.test.ts +9 -1
- package/src/__tests__/runtime-events-sse-bilingual.test.ts +7 -9
- package/src/__tests__/runtime-events-sse-parity.test.ts +1 -1
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +1 -1
- package/src/__tests__/runtime-events-sse.test.ts +1 -1
- package/src/__tests__/schedule-retry.test.ts +1 -1
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +1 -1
- package/src/__tests__/schedule-routes.test.ts +1 -1
- package/src/__tests__/schedule-store.test.ts +1 -1
- package/src/__tests__/schedule-tools.test.ts +1 -1
- package/src/__tests__/scheduler-disk-pressure.test.ts +1 -1
- package/src/__tests__/scheduler-recurrence.test.ts +1 -1
- package/src/__tests__/scheduler-reuse-conversation.test.ts +1 -1
- package/src/__tests__/scheduler-wake.test.ts +2 -1
- package/src/__tests__/scoped-approval-grants.test.ts +1 -1
- package/src/__tests__/scoped-grant-security-matrix.test.ts +5 -5
- package/src/__tests__/scrub-corrupted-image-attachments.test.ts +0 -8
- package/src/__tests__/secret-ingress-http.test.ts +12 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -0
- package/src/__tests__/send-endpoint-busy.test.ts +31 -9
- package/src/__tests__/sequence-store.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +40 -1
- package/src/__tests__/settings-routes.test.ts +11 -10
- package/src/__tests__/skill-load-tool.test.ts +72 -0
- package/src/__tests__/skills.test.ts +44 -0
- package/src/__tests__/slack-inbound-verification.test.ts +48 -5
- package/src/__tests__/slack-messaging-token-resolution.test.ts +13 -2
- package/src/__tests__/slack-reaction-canonical-approval.test.ts +1 -1
- package/src/__tests__/sse-actor-principal-guardian-source.test.ts +102 -0
- package/src/__tests__/steer-on-enqueue-question.test.ts +181 -0
- package/src/__tests__/stt-hints.test.ts +44 -13
- package/src/__tests__/subagent-detail.test.ts +27 -0
- package/src/__tests__/subagent-disposal.test.ts +65 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +2 -73
- package/src/__tests__/subagent-tools.test.ts +1 -31
- package/src/__tests__/system-prompt.test.ts +1 -1
- package/src/__tests__/system-storage-cleanup-skill.test.ts +56 -0
- package/src/__tests__/task-compiler.test.ts +1 -1
- package/src/__tests__/task-management-tools.test.ts +1 -1
- package/src/__tests__/task-memory-cleanup.test.ts +9 -6
- package/src/__tests__/task-scheduler.test.ts +1 -1
- package/src/__tests__/thread-backfill.test.ts +1 -1
- package/src/__tests__/tool-approval-handler.test.ts +1 -1
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +2 -0
- package/src/__tests__/tool-executor.test.ts +37 -1
- package/src/__tests__/tool-grant-request-escalation.test.ts +1 -2
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +73 -1
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +34 -34
- package/src/__tests__/trusted-contact-multichannel.test.ts +1 -2
- package/src/__tests__/trusted-contact-verification.test.ts +1 -1
- package/src/__tests__/turn-boundary-resolution.test.ts +3 -3
- package/src/__tests__/turn-events-store.test.ts +1 -1
- package/src/__tests__/twilio-routes.test.ts +98 -3
- package/src/__tests__/usage-cache-backfill-migration.test.ts +20 -10
- package/src/__tests__/usage-routes.test.ts +1 -1
- package/src/__tests__/user-plugin-loader.test.ts +34 -29
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
- package/src/__tests__/voice-invite-redemption.test.ts +134 -36
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +1 -1
- package/src/__tests__/voice-session-bridge.test.ts +1 -1
- package/src/__tests__/workspace-git-service.test.ts +114 -1
- package/src/__tests__/workspace-heartbeat-service.test.ts +45 -0
- package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +1 -1
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +1 -1
- package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +88 -18
- package/src/__tests__/workspace-migration-108-drop-balanced-economy-profile.test.ts +6 -6
- package/src/__tests__/workspace-migration-109-swap-quality-profile-to-glm-5p2.test.ts +281 -0
- package/src/__tests__/workspace-migration-110-flip-balanced-profile-to-together.test.ts +167 -0
- package/src/__tests__/workspace-migrations-runner.test.ts +55 -0
- package/src/__tests__/workspace-tool-loader.test.ts +3 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +1 -1
- package/src/a2a/__tests__/task-store.test.ts +1 -1
- package/src/acp/__tests__/session-manager-persistence.test.ts +1 -1
- package/src/acp/__tests__/session-manager-resume.test.ts +22 -11
- package/src/acp/__tests__/session-manager-startup.test.ts +1 -1
- package/src/acp/__tests__/session-manager.test.ts +72 -1
- package/src/acp/index.ts +10 -0
- package/src/acp/session-manager.ts +35 -0
- package/src/agent/loop-exclusive-tool.test.ts +150 -0
- package/src/agent/loop.ts +101 -27
- package/src/api/constants/sse-replay.ts +41 -0
- package/src/api/events/ui-surface-show.ts +8 -3
- package/src/api/index.ts +7 -6
- package/src/api/responses/conversation-message.ts +4 -0
- package/src/api/responses/llm-request-log-entry.ts +25 -0
- package/src/api/responses/subagent-detail.ts +17 -0
- package/src/api/surfaces.ts +33 -0
- package/src/approvals/AGENTS.md +1 -2
- package/src/approvals/guardian-decision-primitive.ts +13 -210
- package/src/approvals/guardian-request-resolvers.ts +104 -58
- package/src/background-wake/wake-intent-hooks.test.ts +1 -1
- package/src/calls/__tests__/inbound-trust-reader.test.ts +110 -0
- package/src/calls/__tests__/relay-setup-router.test.ts +349 -65
- package/src/calls/guardian-dispatch.ts +10 -8
- package/src/calls/inbound-trust-reader.ts +56 -0
- package/src/calls/media-stream-server.ts +21 -0
- package/src/calls/relay-server.ts +231 -72
- package/src/calls/relay-setup-router.ts +57 -13
- package/src/calls/relay-verification.ts +7 -7
- package/src/calls/stt-hints.ts +9 -12
- package/src/calls/twilio-routes.ts +13 -3
- package/src/cli/commands/__tests__/cache.test.ts +8 -1
- package/src/cli/commands/cache.ts +194 -181
- package/src/cli/commands/contacts.ts +6 -24
- package/src/cli/commands/db/__tests__/repair.test.ts +15 -6
- package/src/cli/commands/db/__tests__/status.test.ts +7 -3
- package/src/cli/commands/db/status.ts +212 -33
- package/src/cli/commands/mcp.ts +252 -218
- package/src/cli/commands/memory/__tests__/memory-v3.test.ts +6 -1
- package/src/cli/commands/memory/__tests__/worker.test.ts +302 -0
- package/src/cli/commands/memory/index.ts +4 -0
- package/src/cli/commands/memory/memory-retrospective.ts +129 -0
- package/src/cli/commands/memory/memory-v3.ts +176 -4
- package/src/cli/commands/memory/worker.ts +175 -0
- package/src/cli/commands/plugins.ts +343 -14
- package/src/cli/lib/__tests__/install-from-github.test.ts +40 -0
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +160 -1
- package/src/cli/lib/__tests__/plugin-pin-history.test.ts +162 -0
- package/src/cli/lib/__tests__/toggle-plugin.test.ts +158 -0
- package/src/cli/lib/install-from-github.ts +47 -6
- package/src/cli/lib/list-installed-plugins.ts +179 -1
- package/src/cli/lib/plugin-marketplace.ts +11 -0
- package/src/cli/lib/plugin-pin-history.ts +257 -0
- package/src/cli/lib/toggle-plugin.ts +146 -0
- package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +143 -0
- package/src/config/__tests__/sync-gated-profiles.test.ts +2 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +15 -33
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +3 -8
- package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +64 -37
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +1 -1
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +14 -72
- package/src/config/bundled-skills/app-builder/references/examples/README.md +1 -2
- package/src/config/bundled-skills/contacts/SKILL.md +7 -12
- package/src/config/bundled-skills/messaging/tools/shared.ts +4 -1
- package/src/config/bundled-skills/system-storage-cleanup/SKILL.md +74 -0
- package/src/config/bundled-skills/workflows/SKILL.md +4 -3
- package/src/config/call-site-defaults.ts +11 -2
- package/src/config/feature-flag-registry.json +0 -8
- package/src/config/llm-resolver.ts +151 -14
- package/src/config/loader.ts +36 -5
- package/src/config/profile-dispatchability.ts +11 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
- package/src/config/schemas/call-site-catalog.ts +7 -0
- package/src/config/schemas/llm.ts +2 -0
- package/src/config/schemas/memory-lifecycle.ts +17 -3
- package/src/config/schemas/memory-v3.ts +7 -0
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/timeouts.ts +32 -0
- package/src/config/seed-inference-profiles.ts +147 -50
- package/src/config/skills.ts +27 -5
- package/src/config/sync-gated-profiles.ts +13 -1
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +312 -0
- package/src/contacts/contact-store.ts +21 -0
- package/src/contacts/contacts-write.ts +3 -0
- package/src/contacts/guardian-delivery-reader.ts +223 -0
- package/src/contacts/member-status.ts +9 -0
- package/src/credential-health/credential-health-service.ts +1 -5
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +44 -0
- package/src/daemon/app-source-watcher.ts +31 -18
- package/src/daemon/assistant-attachments.ts +94 -4
- package/src/daemon/conversation-agent-loop-handlers.ts +3 -0
- package/src/daemon/conversation-agent-loop.ts +18 -36
- package/src/daemon/conversation-process.ts +35 -16
- package/src/daemon/conversation-runtime-assembly.ts +91 -66
- package/src/daemon/conversation-surfaces.ts +273 -18
- package/src/daemon/conversation-tool-setup.ts +24 -64
- package/src/daemon/conversation.ts +149 -53
- package/src/daemon/disk-pressure-guard.ts +12 -2
- package/src/daemon/event-loop-watchdog.test.ts +85 -0
- package/src/daemon/event-loop-watchdog.ts +133 -0
- package/src/daemon/external-plugins-bootstrap.ts +26 -80
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a.test.ts +1 -1
- package/src/daemon/handlers/config-channels.ts +41 -27
- package/src/daemon/handlers/conversations.ts +84 -0
- package/src/daemon/handlers/shared.ts +7 -0
- package/src/daemon/lifecycle.ts +44 -5
- package/src/daemon/memory-v2-startup.test.ts +72 -0
- package/src/daemon/memory-v2-startup.ts +87 -19
- package/src/daemon/message-types/inbox.ts +0 -6
- package/src/daemon/message-types/messages.ts +0 -4
- package/src/daemon/message-types/surfaces.ts +12 -11
- package/src/daemon/server.ts +0 -4
- package/src/daemon/shutdown-handlers.ts +20 -0
- package/src/daemon/tool-setup-types.ts +7 -5
- package/src/daemon/trust-context.ts +6 -0
- package/src/daemon/wake-conversation-ops.ts +70 -0
- package/src/daemon/workspace-tools-watcher.ts +7 -3
- package/src/documents/document-comments-store.test.ts +1 -1
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +1 -1
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +6 -0
- package/src/heartbeat/heartbeat-service.ts +3 -4
- package/src/ipc/__tests__/attachment-ipc.test.ts +1 -1
- package/src/ipc/__tests__/browser-ipc.test.ts +73 -2
- package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
- package/src/ipc/__tests__/watcher-ipc.test.ts +59 -39
- package/src/ipc/assistant-server.ts +10 -2
- package/src/ipc/gateway-client.ts +2 -1
- package/src/ipc/routes/__tests__/invite-ipc-routes.test.ts +58 -0
- package/src/ipc/routes/invite-ipc-routes.ts +66 -0
- package/src/live-voice/__tests__/live-voice-archive.test.ts +1 -1
- package/src/memory/__tests__/activation-session-store.test.ts +1 -1
- package/src/memory/__tests__/auto-analysis-guard.test.ts +1 -1
- package/src/memory/__tests__/conversation-group-migration.test.ts +1 -1
- package/src/memory/__tests__/conversation-queries.test.ts +1 -1
- package/src/memory/__tests__/db-async-query.test.ts +1 -1
- package/src/memory/__tests__/db-logs-attach.test.ts +110 -0
- package/src/memory/__tests__/db-maintenance.test.ts +28 -36
- package/src/memory/__tests__/db-memory-attach.test.ts +113 -0
- package/src/memory/__tests__/find-analysis-conversation.test.ts +1 -1
- package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +1 -1
- package/src/memory/__tests__/fork-message-copy.test.ts +232 -0
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +3 -0
- package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +5 -5
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +8 -6
- package/src/memory/__tests__/memory-retrospective-job.test.ts +30 -37
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +69 -66
- package/src/memory/__tests__/memory-retrospective-state.test.ts +1 -1
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +1 -1
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +1 -1
- package/src/memory/__tests__/onboarding-events-store.test.ts +1 -1
- package/src/memory/__tests__/prompt-override.test.ts +192 -0
- package/src/memory/__tests__/table-relocation.test.ts +129 -0
- package/src/memory/conversation-crud.ts +461 -152
- package/src/memory/db-async-query.ts +89 -5
- package/src/memory/db-connection.ts +101 -18
- package/src/memory/db-init.ts +409 -234
- package/src/memory/db-maintenance.ts +43 -38
- package/src/memory/db-singleton.ts +45 -19
- package/src/memory/embedding-gemini.test.ts +3 -1
- package/src/memory/embedding-gemini.ts +18 -2
- package/src/memory/fork-message-copy.ts +170 -0
- package/src/memory/graph/__tests__/handle-remember-v2.test.ts +92 -0
- package/src/memory/graph/bootstrap.test.ts +6 -3
- package/src/memory/graph/retriever.test.ts +12 -12
- package/src/memory/graph/store.test.ts +15 -25
- package/src/memory/graph/store.ts +23 -14
- package/src/memory/graph/tool-handlers.ts +34 -5
- package/src/memory/graph/tools.ts +5 -2
- package/src/memory/indexer.ts +21 -9
- package/src/memory/job-handlers/cleanup.ts +10 -3
- package/src/memory/job-handlers/embedding.test.ts +4 -4
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +4 -4
- package/src/memory/jobs/embed-pkb-file.test.ts +7 -7
- package/src/memory/jobs-store.ts +36 -24
- package/src/memory/llm-request-log-store.ts +51 -19
- package/src/memory/llm-usage-store.ts +79 -21
- package/src/memory/memory-retrospective-job.ts +27 -19
- package/src/memory/memory-retrospective-startup-cleanup.ts +10 -2
- package/src/memory/migrations/{100-core-tables.ts → 000-core-tables.ts} +6 -10
- package/src/memory/migrations/014-backfill-inbox-thread-state.ts +13 -3
- package/src/memory/migrations/104-core-indexes.ts +1 -1
- package/src/memory/migrations/126-backfill-guardian-principal-id.ts +189 -196
- package/src/memory/migrations/127-guardian-principal-id-not-null.ts +98 -105
- package/src/memory/migrations/134-contacts-notes-column.ts +66 -69
- package/src/memory/migrations/135-backfill-contact-interaction-stats.ts +19 -22
- package/src/memory/migrations/136-drop-assistant-id-columns.ts +241 -219
- package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +204 -209
- package/src/memory/migrations/141-rename-verification-table.ts +45 -48
- package/src/memory/migrations/142-rename-verification-session-id-column.ts +16 -23
- package/src/memory/migrations/143-rename-guardian-verification-values.ts +23 -30
- package/src/memory/migrations/144-rename-voice-to-phone.ts +133 -136
- package/src/memory/migrations/145-drop-accounts-table.ts +4 -7
- package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +79 -82
- package/src/memory/migrations/148-drop-reminders-table.ts +3 -6
- package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +71 -78
- package/src/memory/migrations/157-invite-contact-id.ts +73 -76
- package/src/memory/migrations/162-guardian-timestamps-epoch-ms.ts +44 -58
- package/src/memory/migrations/169-rename-gmail-provider-key-to-google.ts +36 -43
- package/src/memory/migrations/174-rename-thread-starters-table.ts +30 -37
- package/src/memory/migrations/176-drop-capability-card-state.ts +17 -22
- package/src/memory/migrations/177-create-trace-events-table.ts +23 -28
- package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +36 -43
- package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +14 -21
- package/src/memory/migrations/191-backfill-audio-attachment-mime-types.ts +17 -24
- package/src/memory/migrations/192-contacts-user-file-column.ts +6 -9
- package/src/memory/migrations/193-add-source-type-columns.ts +33 -36
- package/src/memory/migrations/194-memory-recall-logs.ts +34 -39
- package/src/memory/migrations/196-strip-integration-prefix-from-provider-keys.ts +59 -66
- package/src/memory/migrations/199-guardian-request-enrichment-columns.ts +41 -48
- package/src/memory/migrations/204-rename-memory-graph-type-values.ts +11 -18
- package/src/memory/migrations/206-scrub-corrupted-image-attachments.ts +76 -83
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +135 -68
- package/src/memory/migrations/211-memory-recall-logs-query-context.ts +6 -11
- package/src/memory/migrations/212-llm-request-logs-created-at-index.ts +4 -9
- package/src/memory/migrations/217-conversation-host-access.ts +13 -18
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +86 -93
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +41 -48
- package/src/memory/migrations/230-acp-session-history.ts +23 -28
- package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +58 -62
- package/src/memory/migrations/232-activation-state.ts +11 -16
- package/src/memory/migrations/233-document-conversations.ts +20 -25
- package/src/memory/migrations/234-memory-v2-activation-logs.ts +26 -31
- package/src/memory/migrations/235-slack-compaction-watermark.ts +5 -10
- package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +6 -11
- package/src/memory/migrations/237-heartbeat-runs.ts +22 -27
- package/src/memory/migrations/239-trace-events-created-at-index.ts +4 -9
- package/src/memory/migrations/242-message-bookmarks.ts +17 -22
- package/src/memory/migrations/245-memory-retrospective-state.ts +8 -13
- package/src/memory/migrations/249-normalize-slack-external-content.ts +37 -41
- package/src/memory/migrations/251-a2a-tasks.ts +27 -32
- package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +12 -17
- package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +10 -15
- package/src/memory/migrations/256-memory-v2-injection-events.ts +70 -74
- package/src/memory/migrations/259-conversation-cleaned-at.ts +4 -9
- package/src/memory/migrations/260-rename-cleaned-at.ts +11 -16
- package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +3 -8
- package/src/memory/migrations/262-memory-v3-coactivation.ts +21 -26
- package/src/memory/migrations/263-memory-v3-auto-edges.ts +14 -19
- package/src/memory/migrations/270-schedule-description.ts +7 -12
- package/src/memory/migrations/272-acp-session-history-cwd.ts +8 -13
- package/src/memory/migrations/281-memory-retrospective-remembered-log.ts +8 -13
- package/src/memory/migrations/297-move-llm-request-logs-to-logs-db.ts +111 -0
- package/src/memory/migrations/298-move-memory-jobs-to-memory-db.ts +128 -0
- package/src/memory/migrations/299-canonical-guardian-deliveries-conversation-index.ts +19 -0
- package/src/memory/migrations/__tests__/014-backfill-inbox-thread-state.test.ts +108 -0
- package/src/memory/migrations/__tests__/136-drop-assistant-id-columns.test.ts +82 -0
- package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +224 -0
- package/src/memory/migrations/__tests__/297-move-llm-request-logs.test.ts +180 -0
- package/src/memory/migrations/__tests__/run-migrations.test.ts +333 -7
- package/src/memory/migrations/helpers/relocation.ts +227 -0
- package/src/memory/migrations/registry.ts +63 -0
- package/src/memory/migrations/run-migrations.ts +187 -16
- package/src/memory/migrations/schema-introspection.ts +14 -0
- package/src/memory/migrations/validate-migration-state.ts +50 -145
- package/src/memory/prompt-override.ts +129 -0
- package/src/memory/raw-query.ts +47 -2
- package/src/memory/skill-loaded-events-store.test.ts +1 -1
- package/src/memory/task-memory-cleanup.ts +62 -41
- package/src/memory/tool-executed-events-store.test.ts +1 -1
- package/src/memory/turn-trace-store.test.ts +1 -1
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +16 -15
- package/src/memory/v2/__tests__/cli-command-store.test.ts +25 -0
- package/src/memory/v2/__tests__/harness-compare.test.ts +1 -1
- package/src/memory/v2/__tests__/harness-oracle.test.ts +1 -1
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +1 -1
- package/src/memory/v2/__tests__/skill-store.test.ts +80 -0
- package/src/memory/v2/__tests__/sweep-job.test.ts +2 -2
- package/src/memory/v2/cli-command-store.ts +75 -38
- package/src/memory/v2/prompts/consolidation.ts +13 -82
- package/src/memory/v2/prompts/router.ts +21 -93
- package/src/memory/v2/skill-store.ts +68 -31
- package/src/memory/v3-eval/__tests__/eval-packets.test.ts +38 -0
- package/src/memory/v3-eval/__tests__/eval-tally.test.ts +139 -0
- package/src/memory/v3-eval/eval-packets.ts +197 -12
- package/src/memory/v3-eval/eval-tally.ts +234 -0
- package/src/memory/worker-control.ts +118 -0
- package/src/memory/worker-process.ts +72 -0
- package/src/messaging/provider.ts +10 -0
- package/src/messaging/providers/gmail/adapter.ts +1 -0
- package/src/messaging/providers/gmail/client.ts +13 -0
- package/src/messaging/providers/index.ts +1 -1
- package/src/messaging/providers/slack/send.test.ts +87 -39
- package/src/messaging/providers/slack/send.ts +84 -105
- package/src/notifications/README.md +9 -5
- package/src/notifications/__tests__/broadcaster.test.ts +16 -8
- package/src/notifications/__tests__/connected-channels.test.ts +114 -0
- package/src/notifications/__tests__/decision-engine.test.ts +78 -9
- package/src/notifications/__tests__/destination-resolver.test.ts +256 -0
- package/src/notifications/__tests__/deterministic-checks.test.ts +43 -1
- package/src/notifications/adapters/slack.ts +12 -10
- package/src/notifications/approval-card-builder.ts +81 -20
- package/src/notifications/approval-card-data.ts +8 -5
- package/src/notifications/broadcaster.ts +8 -1
- package/src/notifications/canonical-delivery-recorder.ts +7 -5
- package/src/notifications/conversation-candidates.ts +24 -59
- package/src/notifications/copy-composer.ts +48 -68
- package/src/notifications/decision-engine.ts +15 -7
- package/src/notifications/destination-resolver.ts +68 -24
- package/src/notifications/deterministic-checks.ts +19 -16
- package/src/notifications/emit-signal.ts +68 -15
- package/src/notifications/trusted-contact-payloads.ts +70 -0
- package/src/oauth/byo-connection.test.ts +9 -0
- package/src/oauth/connection-resolver.test.ts +174 -6
- package/src/oauth/connection-resolver.ts +132 -5
- package/src/oauth/oauth-store.ts +16 -3
- package/src/oauth/scope-utils.ts +39 -0
- package/src/permissions/question-prompter.test.ts +1 -1
- package/src/permissions/question-prompter.ts +7 -4
- package/src/plugin-api/index.ts +9 -4
- package/src/plugin-api/model-profiles.test.ts +123 -0
- package/src/plugin-api/model-profiles.ts +5 -1
- package/src/plugin-api/vision-support.test.ts +173 -0
- package/src/plugin-api/vision-support.ts +113 -0
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +90 -0
- package/src/plugins/defaults/advisor/__tests__/context-pack-gating.test.ts +106 -0
- package/src/plugins/defaults/advisor/__tests__/context-pack.test.ts +60 -0
- package/src/plugins/defaults/advisor/consult.ts +65 -6
- package/src/plugins/defaults/advisor/context-pack.ts +288 -0
- package/src/plugins/defaults/advisor/steering.ts +14 -2
- package/src/plugins/defaults/advisor/tools/advisor.ts +32 -5
- package/src/plugins/defaults/compaction/window-manager.ts +45 -64
- package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +13 -4
- package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +441 -0
- package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +57 -0
- package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +61 -0
- package/src/plugins/defaults/image-fallback/package.json +14 -0
- package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +108 -0
- package/src/plugins/defaults/image-fallback/src/caption-cache.ts +49 -0
- package/src/plugins/defaults/image-fallback/src/image-persist.ts +56 -0
- package/src/plugins/defaults/image-fallback/src/vision-caption.ts +120 -0
- package/src/plugins/defaults/index.ts +27 -0
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +14 -1
- package/src/plugins/defaults/memory-retrieval/injectors.ts +4 -4
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +134 -5
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +11 -2
- package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +146 -0
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +246 -19
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +8 -1
- package/src/plugins/external-plugin-loader.ts +47 -6
- package/src/plugins/mtime-cache.ts +772 -0
- package/src/plugins/pipeline.ts +7 -2
- package/src/plugins/registry.ts +16 -5
- package/src/plugins/user-loader.ts +22 -76
- package/src/prompts/persona-resolver.ts +29 -11
- package/src/prompts/system-prompt.ts +1 -1
- package/src/prompts/templates/system-sections.ts +4 -4
- package/src/providers/__tests__/count-tokens-forwarding.test.ts +98 -0
- package/src/providers/anthropic/client.ts +290 -185
- package/src/providers/call-site-routing.ts +14 -0
- package/src/providers/gemini/client.ts +43 -0
- package/src/providers/inference/adapter-factory.ts +6 -0
- package/src/providers/inference/connections.ts +6 -1
- package/src/providers/model-catalog.ts +53 -0
- package/src/providers/openai/responses-provider.ts +5 -0
- package/src/providers/openrouter/client.ts +5 -0
- package/src/providers/platform-proxy/constants.ts +5 -0
- package/src/providers/provider-send-message.ts +4 -0
- package/src/providers/ratelimit.ts +13 -0
- package/src/providers/retry.ts +14 -0
- package/src/providers/together/client.ts +35 -0
- package/src/providers/types.ts +25 -0
- package/src/providers/usage-tracking.ts +11 -0
- package/src/runtime/AGENTS.md +9 -1
- package/src/runtime/__tests__/agent-wake.test.ts +259 -4
- package/src/runtime/__tests__/guardian-vellum-migration.test.ts +181 -0
- package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +64 -0
- package/src/runtime/__tests__/local-principal-trust.test.ts +164 -0
- package/src/runtime/__tests__/slack-block-formatting.test.ts +39 -10
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +670 -0
- package/src/runtime/access-request-helper.ts +19 -39
- package/src/runtime/actor-trust-resolver.ts +8 -16
- package/src/runtime/agent-wake.ts +183 -60
- package/src/runtime/anchored-guardian.test.ts +156 -0
- package/src/runtime/anchored-guardian.ts +135 -0
- package/src/runtime/assistant-stream-state.ts +9 -2
- package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +99 -0
- package/src/runtime/auth/require-bound-guardian.ts +21 -11
- package/src/runtime/channel-reply-delivery.ts +6 -3
- package/src/runtime/channel-verification-service.ts +24 -0
- package/src/runtime/guardian-decision-types.ts +3 -22
- package/src/runtime/guardian-vellum-migration.ts +66 -7
- package/src/runtime/http-server.ts +1 -15
- package/src/runtime/invite-redemption-service.ts +155 -6
- package/src/runtime/invite-service.ts +113 -62
- package/src/runtime/local-actor-identity.ts +76 -11
- package/src/runtime/local-principal-trust.ts +52 -0
- package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +3 -0
- package/src/runtime/pending-interactions.ts +11 -1
- package/src/runtime/routes/__tests__/acp-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +277 -0
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +140 -0
- package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +26 -7
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +14 -10
- package/src/runtime/routes/__tests__/contact-routes-update-channel-relay.test.ts +164 -0
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +8 -8
- package/src/runtime/routes/__tests__/conversation-surface-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +1 -3
- package/src/runtime/routes/__tests__/invite-relay-routes.test.ts +240 -0
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +4 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +143 -0
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +163 -0
- package/src/runtime/routes/acp-routes-list.test.ts +4 -0
- package/src/runtime/routes/acp-routes.test.ts +5 -6
- package/src/runtime/routes/attachment-routes.ts +21 -17
- package/src/runtime/routes/browser-routes.ts +19 -1
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +5 -9
- package/src/runtime/routes/channel-verification-routes.ts +13 -2
- package/src/runtime/routes/contact-routes.ts +275 -164
- package/src/runtime/routes/conversation-query-routes.ts +15 -5
- package/src/runtime/routes/conversation-routes.ts +80 -66
- package/src/runtime/routes/conversation-starter-routes.ts +7 -8
- package/src/runtime/routes/events-routes.ts +2 -2
- package/src/runtime/routes/guardian-approval-interception.ts +13 -274
- package/src/runtime/routes/host-app-control-routes.ts +5 -4
- package/src/runtime/routes/host-bash-routes.ts +5 -4
- package/src/runtime/routes/host-browser-routes.ts +9 -11
- package/src/runtime/routes/host-cu-routes.ts +5 -4
- package/src/runtime/routes/host-file-routes.ts +5 -4
- package/src/runtime/routes/host-transfer-routes.ts +6 -6
- package/src/runtime/routes/http-adapter.ts +1 -1
- package/src/runtime/routes/inbound-message-handler.ts +21 -16
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +376 -0
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +86 -64
- package/src/runtime/routes/inbound-stages/admission-policy.ts +20 -5
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +16 -4
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +21 -8
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -3
- package/src/runtime/routes/llm-context-normalization.ts +71 -0
- package/src/runtime/routes/log-export-routes.ts +2 -2
- package/src/runtime/routes/mcp-auth-routes.ts +38 -15
- package/src/runtime/routes/memory-eval-routes.ts +92 -0
- package/src/runtime/routes/memory-item-routes.test.ts +12 -11
- package/src/runtime/routes/migration-routes.ts +51 -40
- package/src/runtime/routes/plugins-routes.ts +164 -8
- package/src/runtime/routes/schedule-routes.ts +1 -0
- package/src/runtime/routes/subagents-routes.ts +5 -0
- package/src/runtime/routes/surface-action-routes.ts +39 -51
- package/src/runtime/routes/usage-routes.ts +3 -0
- package/src/runtime/routes/work-items-routes.test.ts +1 -1
- package/src/runtime/slack-block-formatting.ts +46 -48
- package/src/runtime/trust-verdict-consumer.ts +210 -0
- package/src/schedule/scheduler.ts +6 -9
- package/src/signals/user-message.ts +16 -0
- package/src/subagent/manager.ts +9 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +1 -1
- package/src/tools/ask-question/ask-question-tool.test.ts +89 -52
- package/src/tools/ask-question/ask-question-tool.ts +27 -73
- package/src/tools/browser/__tests__/browser-status.test.ts +20 -0
- package/src/tools/browser/browser-execution.ts +16 -4
- package/src/tools/document/document-comment-tool.test.ts +1 -1
- package/src/tools/executor.ts +15 -3
- package/src/tools/host-terminal/host-shell.ts +28 -9
- package/src/tools/memory/register.test.ts +32 -0
- package/src/tools/skills/load.ts +43 -2
- package/src/tools/subagent/spawn.ts +4 -10
- package/src/tools/terminal/shell.ts +16 -5
- package/src/tools/tool-defaults.ts +2 -0
- package/src/tools/types.ts +18 -2
- package/src/tools/ui-surface/definitions.ts +0 -43
- package/src/util/fs-watcher-error.ts +36 -0
- package/src/util/log-redact.ts +2 -4
- package/src/util/logs-db-path.ts +22 -0
- package/src/util/memory-db-path.ts +23 -0
- package/src/util/platform.ts +5 -0
- package/src/watcher/providers/gmail.ts +7 -2
- package/src/workflows/engine-integration.test.ts +1 -1
- package/src/workflows/engine.test.ts +1 -1
- package/src/workflows/engine.ts +22 -0
- package/src/workflows/fanout-load.test.ts +1 -1
- package/src/workflows/journal-store.test.ts +1 -1
- package/src/workflows/leaf-runner.test.ts +40 -1
- package/src/workflows/leaf-runner.ts +26 -1
- package/src/workspace/git-service.ts +144 -29
- package/src/workspace/migrations/109-swap-quality-profile-to-glm-5p2.ts +121 -0
- package/src/workspace/migrations/110-flip-balanced-profile-to-together.ts +82 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/workspace/migrations/runner.ts +32 -2
- package/src/__tests__/access-request-decision.test.ts +0 -375
- package/src/__tests__/guardian-grant-minting.test.ts +0 -607
- package/src/__tests__/plugin-source-watcher.test.ts +0 -302
- package/src/api/events/turn-profile-auto-routed.ts +0 -28
- package/src/daemon/__tests__/switch-inference-profile-tool.test.ts +0 -107
- package/src/daemon/plugin-source-watcher.ts +0 -278
- package/src/daemon/switch-inference-profile-tool.ts +0 -62
- package/src/memory/guardian-approvals.ts +0 -361
- package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +0 -66
- package/src/memory/migrations/038-actor-token-records.ts +0 -45
- package/src/memory/migrations/039-actor-refresh-token-records.ts +0 -57
- package/src/memory/migrations/103-complex-migrations.ts +0 -23
- package/src/memory/migrations/113-late-migrations.ts +0 -30
- package/src/memory/migrations/index.ts +0 -301
- package/src/runtime/routes/access-request-decision.ts +0 -297
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +0 -963
- package/src/runtime/routes/channel-guardian-routes.ts +0 -19
- package/src/runtime/routes/guardian-expiry-sweep.ts +0 -132
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standalone entry point for the memory jobs worker as its own OS process.
|
|
3
|
+
*
|
|
4
|
+
* Spawned by `assistant memory worker start`. Loads config, starts the
|
|
5
|
+
* worker loop, writes a PID file, and stays alive until SIGTERM/SIGINT.
|
|
6
|
+
*
|
|
7
|
+
* The worker's internal `setTimeout` calls `.unref()`, which is correct
|
|
8
|
+
* inside the daemon (don't keep the daemon alive for the worker) but would
|
|
9
|
+
* cause this standalone process to exit immediately. A ref'd keep-alive
|
|
10
|
+
* interval prevents that.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { existsSync, unlinkSync, writeFileSync } from "node:fs";
|
|
14
|
+
|
|
15
|
+
import { getConfig } from "../config/loader.js";
|
|
16
|
+
import { getLogger } from "../util/logger.js";
|
|
17
|
+
import { getMemoryWorkerPidPath } from "../util/platform.js";
|
|
18
|
+
import { startMemoryJobsWorker } from "./jobs-worker.js";
|
|
19
|
+
|
|
20
|
+
const log = getLogger("memory-worker-process");
|
|
21
|
+
|
|
22
|
+
function cleanupPidFile(): void {
|
|
23
|
+
const pidPath = getMemoryWorkerPidPath();
|
|
24
|
+
try {
|
|
25
|
+
if (existsSync(pidPath)) unlinkSync(pidPath);
|
|
26
|
+
} catch {
|
|
27
|
+
// best-effort
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function main(): Promise<void> {
|
|
32
|
+
const config = getConfig();
|
|
33
|
+
const pidPath = getMemoryWorkerPidPath();
|
|
34
|
+
|
|
35
|
+
if (config.memory.enabled === false) {
|
|
36
|
+
log.info("Memory is disabled in config; worker process exiting");
|
|
37
|
+
process.exit(0);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Write PID file so `status` and `stop` can find us.
|
|
41
|
+
writeFileSync(pidPath, String(process.pid), { flag: "w" });
|
|
42
|
+
log.info({ pid: process.pid, pidPath }, "Memory worker process started");
|
|
43
|
+
|
|
44
|
+
const worker = startMemoryJobsWorker();
|
|
45
|
+
|
|
46
|
+
// Keep-alive: the worker's setTimeout timers are unref'd, so without
|
|
47
|
+
// this interval the process would exit immediately.
|
|
48
|
+
const keepAlive = setInterval(() => {}, 60_000);
|
|
49
|
+
|
|
50
|
+
const shutdown = (signal: string) => {
|
|
51
|
+
log.info({ signal }, "Memory worker process shutting down");
|
|
52
|
+
worker.stop();
|
|
53
|
+
clearInterval(keepAlive);
|
|
54
|
+
cleanupPidFile();
|
|
55
|
+
process.exit(0);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
59
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
60
|
+
|
|
61
|
+
// Clean up if the process exits unexpectedly through any other path.
|
|
62
|
+
process.on("exit", () => {
|
|
63
|
+
worker.stop();
|
|
64
|
+
cleanupPidFile();
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
void main().catch((err) => {
|
|
69
|
+
log.error({ err }, "Memory worker process failed to start");
|
|
70
|
+
cleanupPidFile();
|
|
71
|
+
process.exit(1);
|
|
72
|
+
});
|
|
@@ -29,6 +29,16 @@ export interface MessagingProvider {
|
|
|
29
29
|
/** Credential service name for token-manager (e.g. 'slack'). */
|
|
30
30
|
credentialService: string;
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Scopes a connection must carry for this provider's tools to work. Set when
|
|
34
|
+
* the credential service bundles several products behind one OAuth app and
|
|
35
|
+
* this provider only works with a subset (e.g. Gmail under the shared
|
|
36
|
+
* 'google' service needs Gmail scopes, not Calendar-only). Forwarded as
|
|
37
|
+
* `requiredScopes` to {@link resolveOAuthConnection} so a narrowly-scoped
|
|
38
|
+
* connection fails with an actionable "reconnect" error instead of a 403.
|
|
39
|
+
*/
|
|
40
|
+
requiredScopes?: string[];
|
|
41
|
+
|
|
32
42
|
// ── Universal operations (every platform must implement) ──────────
|
|
33
43
|
|
|
34
44
|
testConnection(connection?: OAuthConnection): Promise<ConnectionInfo>;
|
|
@@ -16,6 +16,19 @@ import type {
|
|
|
16
16
|
|
|
17
17
|
const GMAIL_BATCH_URL = "https://www.googleapis.com/batch/gmail/v1";
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Minimum Google OAuth scope a connection must carry for Gmail read access.
|
|
21
|
+
*
|
|
22
|
+
* The managed `google` OAuth app bundles Gmail + Calendar + Drive, but a
|
|
23
|
+
* connection can be granted a narrow subset (e.g. the onboarding check-in flow
|
|
24
|
+
* requests Calendar-only). Resolving against Gmail read access turns a
|
|
25
|
+
* downstream 403 into an actionable "reconnect Google and grant Gmail" error
|
|
26
|
+
* at resolution time when the selected connection cannot read Gmail.
|
|
27
|
+
*/
|
|
28
|
+
export const GMAIL_REQUIRED_SCOPES = [
|
|
29
|
+
"https://www.googleapis.com/auth/gmail.readonly",
|
|
30
|
+
];
|
|
31
|
+
|
|
19
32
|
/** Max sub-requests per batch HTTP call (Gmail API limit) */
|
|
20
33
|
const BATCH_SUB_LIMIT = 100;
|
|
21
34
|
/** Max concurrent batch calls */
|
|
@@ -197,7 +197,7 @@ async function deliverSlack(
|
|
|
197
197
|
if (text) {
|
|
198
198
|
const result = await sendSlackReply(chatId, text, {
|
|
199
199
|
threadTs,
|
|
200
|
-
blocks
|
|
200
|
+
blocks,
|
|
201
201
|
approval: payload.approval,
|
|
202
202
|
useBlocks: payload.useBlocks,
|
|
203
203
|
ephemeral: payload.ephemeral,
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
2
|
|
|
3
|
-
type
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
)
|
|
3
|
+
import type { KnownBlock } from "@slack/types";
|
|
4
|
+
|
|
5
|
+
// Derive the mock signature from the real export so it cannot drift from the
|
|
6
|
+
// production response shape (`SlackApiResponse`). A hand-rolled
|
|
7
|
+
// `Promise<Record<string, unknown>>` here would let a test pass against a
|
|
8
|
+
// response shape production never actually returns.
|
|
9
|
+
type CallSlackApi = typeof import("./api.js").callSlackApi;
|
|
7
10
|
|
|
8
11
|
const callSlackApiMock = mock<CallSlackApi>(async () => ({ ok: true }));
|
|
9
12
|
|
|
@@ -85,10 +88,16 @@ describe("sendSlackAssistantThreadStatus", () => {
|
|
|
85
88
|
|
|
86
89
|
describe("sendSlackReply update path", () => {
|
|
87
90
|
const messageTs = "1700000000.000100";
|
|
88
|
-
const
|
|
91
|
+
const threadTs = "1700000000.000001";
|
|
92
|
+
const blocks: KnownBlock[] = [
|
|
89
93
|
{ type: "section", text: { type: "mrkdwn", text: "Final reply" } },
|
|
90
94
|
];
|
|
91
95
|
|
|
96
|
+
const postMessageCalls = () =>
|
|
97
|
+
callSlackApiMock.mock.calls.filter(
|
|
98
|
+
(call) => call[0] === "chat.postMessage",
|
|
99
|
+
);
|
|
100
|
+
|
|
92
101
|
beforeEach(() => {
|
|
93
102
|
callSlackApiMock.mockReset();
|
|
94
103
|
callSlackApiMock.mockImplementation(async () => ({ ok: true }));
|
|
@@ -103,13 +112,13 @@ describe("sendSlackReply update path", () => {
|
|
|
103
112
|
|
|
104
113
|
const result = await sendSlackReply("C123", "Final reply", {
|
|
105
114
|
messageTs,
|
|
106
|
-
threadTs
|
|
115
|
+
threadTs,
|
|
107
116
|
blocks,
|
|
108
117
|
});
|
|
109
118
|
|
|
110
119
|
expect(result).toEqual({ ok: true, ts: messageTs });
|
|
111
120
|
// Two chat.update calls (with then without blocks); never chat.postMessage,
|
|
112
|
-
// so the
|
|
121
|
+
// so the message is edited in place rather than duplicated.
|
|
113
122
|
expect(callSlackApiMock).toHaveBeenCalledTimes(2);
|
|
114
123
|
expect(callSlackApiMock).toHaveBeenNthCalledWith(1, "chat.update", {
|
|
115
124
|
channel: "C123",
|
|
@@ -122,68 +131,107 @@ describe("sendSlackReply update path", () => {
|
|
|
122
131
|
text: "Final reply",
|
|
123
132
|
ts: messageTs,
|
|
124
133
|
});
|
|
125
|
-
|
|
126
|
-
(call) => call[0] === "chat.postMessage",
|
|
127
|
-
);
|
|
128
|
-
expect(postMessageCalls).toHaveLength(0);
|
|
134
|
+
expect(postMessageCalls()).toHaveLength(0);
|
|
129
135
|
});
|
|
130
136
|
|
|
131
|
-
test("
|
|
137
|
+
test("throws when the no-block update retry also fails, never posting a duplicate", async () => {
|
|
132
138
|
callSlackApiMock
|
|
133
139
|
.mockImplementationOnce(async () => {
|
|
134
140
|
throw new SlackApiError("invalid_blocks");
|
|
135
141
|
})
|
|
136
142
|
.mockImplementationOnce(async () => {
|
|
137
143
|
throw new SlackApiError("message_not_found");
|
|
138
|
-
})
|
|
139
|
-
.mockImplementationOnce(async () => ({
|
|
140
|
-
ok: true,
|
|
141
|
-
ts: "1700000000.000200",
|
|
142
|
-
}));
|
|
144
|
+
});
|
|
143
145
|
|
|
144
|
-
|
|
145
|
-
messageTs,
|
|
146
|
-
|
|
147
|
-
blocks,
|
|
148
|
-
});
|
|
146
|
+
await expect(
|
|
147
|
+
sendSlackReply("C123", "Final reply", { messageTs, threadTs, blocks }),
|
|
148
|
+
).rejects.toThrow();
|
|
149
149
|
|
|
150
|
-
|
|
151
|
-
|
|
150
|
+
// Two in-place chat.update attempts (with then without blocks), then give
|
|
151
|
+
// up — it must not fall back to chat.postMessage and duplicate the message.
|
|
152
|
+
expect(callSlackApiMock).toHaveBeenCalledTimes(2);
|
|
152
153
|
expect(callSlackApiMock.mock.calls[0]?.[0]).toBe("chat.update");
|
|
153
154
|
expect(callSlackApiMock.mock.calls[1]?.[0]).toBe("chat.update");
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
155
|
+
expect(postMessageCalls()).toHaveLength(0);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test("throws on a transient chat.update failure instead of posting a duplicate", async () => {
|
|
159
|
+
callSlackApiMock.mockImplementationOnce(async () => {
|
|
160
|
+
throw new SlackApiError("internal_error");
|
|
159
161
|
});
|
|
162
|
+
|
|
163
|
+
await expect(
|
|
164
|
+
sendSlackReply("C123", "Final reply", { messageTs, threadTs, blocks }),
|
|
165
|
+
).rejects.toThrow();
|
|
166
|
+
|
|
167
|
+
// A single failed chat.update, no chat.postMessage fallback: a transient
|
|
168
|
+
// failure must not spawn a "ghost" reply beside the message we failed to
|
|
169
|
+
// edit. Re-delivery is the delivery layer's job.
|
|
170
|
+
expect(callSlackApiMock).toHaveBeenCalledTimes(1);
|
|
171
|
+
expect(callSlackApiMock.mock.calls[0]?.[0]).toBe("chat.update");
|
|
172
|
+
expect(postMessageCalls()).toHaveLength(0);
|
|
160
173
|
});
|
|
161
174
|
|
|
162
|
-
test("
|
|
175
|
+
test("throws when the edit target is gone rather than re-posting it", async () => {
|
|
176
|
+
// Even when the target message no longer exists, this function does not
|
|
177
|
+
// post a fresh one — re-delivery is owned by the delivery layer, which
|
|
178
|
+
// would otherwise double-post.
|
|
179
|
+
callSlackApiMock.mockImplementationOnce(async () => {
|
|
180
|
+
throw new SlackApiError("message_not_found");
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
await expect(
|
|
184
|
+
sendSlackReply("C123", "Final reply", { messageTs, threadTs, blocks }),
|
|
185
|
+
).rejects.toThrow();
|
|
186
|
+
|
|
187
|
+
expect(callSlackApiMock).toHaveBeenCalledTimes(1);
|
|
188
|
+
expect(callSlackApiMock.mock.calls[0]?.[0]).toBe("chat.update");
|
|
189
|
+
expect(postMessageCalls()).toHaveLength(0);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
describe("sendSlackReply post path", () => {
|
|
194
|
+
const threadTs = "1700000000.000001";
|
|
195
|
+
const blocks: KnownBlock[] = [
|
|
196
|
+
{ type: "section", text: { type: "mrkdwn", text: "Fresh reply" } },
|
|
197
|
+
];
|
|
198
|
+
|
|
199
|
+
beforeEach(() => {
|
|
200
|
+
callSlackApiMock.mockReset();
|
|
201
|
+
callSlackApiMock.mockImplementation(async () => ({ ok: true }));
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test("retries chat.postMessage without blocks on invalid_blocks", async () => {
|
|
163
205
|
callSlackApiMock
|
|
164
206
|
.mockImplementationOnce(async () => {
|
|
165
|
-
throw new SlackApiError("
|
|
207
|
+
throw new SlackApiError("invalid_blocks");
|
|
166
208
|
})
|
|
167
209
|
.mockImplementationOnce(async () => ({
|
|
168
210
|
ok: true,
|
|
169
211
|
ts: "1700000000.000200",
|
|
170
212
|
}));
|
|
171
213
|
|
|
172
|
-
const result = await sendSlackReply("C123", "
|
|
173
|
-
|
|
174
|
-
threadTs: "1700000000.000001",
|
|
214
|
+
const result = await sendSlackReply("C123", "Fresh reply", {
|
|
215
|
+
threadTs,
|
|
175
216
|
blocks,
|
|
176
217
|
});
|
|
177
218
|
|
|
178
219
|
expect(result).toEqual({ ok: true, ts: "1700000000.000200" });
|
|
179
|
-
//
|
|
220
|
+
// Two chat.postMessage calls (with then without blocks); never chat.update.
|
|
180
221
|
expect(callSlackApiMock).toHaveBeenCalledTimes(2);
|
|
181
|
-
expect(callSlackApiMock
|
|
182
|
-
expect(callSlackApiMock).toHaveBeenNthCalledWith(2, "chat.postMessage", {
|
|
222
|
+
expect(callSlackApiMock).toHaveBeenNthCalledWith(1, "chat.postMessage", {
|
|
183
223
|
channel: "C123",
|
|
184
|
-
text: "
|
|
185
|
-
thread_ts:
|
|
224
|
+
text: "Fresh reply",
|
|
225
|
+
thread_ts: threadTs,
|
|
186
226
|
blocks,
|
|
187
227
|
});
|
|
228
|
+
expect(callSlackApiMock).toHaveBeenNthCalledWith(2, "chat.postMessage", {
|
|
229
|
+
channel: "C123",
|
|
230
|
+
text: "Fresh reply",
|
|
231
|
+
thread_ts: threadTs,
|
|
232
|
+
});
|
|
233
|
+
expect(
|
|
234
|
+
callSlackApiMock.mock.calls.filter((call) => call[0] === "chat.update"),
|
|
235
|
+
).toHaveLength(0);
|
|
188
236
|
});
|
|
189
237
|
});
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* attachments by calling the Slack Web API directly via ./api.ts.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import type { Button, KnownBlock } from "@slack/types";
|
|
9
10
|
import type { ApprovalUIMetadata } from "@vellumai/gateway-client";
|
|
10
11
|
|
|
11
12
|
import { getAttachmentContent } from "../../../memory/attachments-store.js";
|
|
@@ -27,24 +28,22 @@ const log = getLogger("slack-send");
|
|
|
27
28
|
const SLACK_MAX_ATTACHMENT_BYTES = 100 * 1024 * 1024;
|
|
28
29
|
|
|
29
30
|
// ---------------------------------------------------------------------------
|
|
30
|
-
// Approval Block Kit builder
|
|
31
|
+
// Approval Block Kit builder
|
|
31
32
|
// ---------------------------------------------------------------------------
|
|
32
33
|
|
|
33
34
|
function buildApprovalBlocks(
|
|
34
35
|
message: string,
|
|
35
36
|
approval: ApprovalUIMetadata,
|
|
36
|
-
):
|
|
37
|
+
): KnownBlock[] {
|
|
38
|
+
const buttons: Button[] = approval.actions.map((action) => ({
|
|
39
|
+
type: "button",
|
|
40
|
+
text: { type: "plain_text", text: action.label, emoji: true },
|
|
41
|
+
action_id: `apr:${approval.requestId}:${action.id}`,
|
|
42
|
+
value: `apr:${approval.requestId}:${action.id}`,
|
|
43
|
+
}));
|
|
37
44
|
return [
|
|
38
45
|
{ type: "section", text: { type: "mrkdwn", text: message } },
|
|
39
|
-
{
|
|
40
|
-
type: "actions",
|
|
41
|
-
elements: approval.actions.map((action) => ({
|
|
42
|
-
type: "button",
|
|
43
|
-
text: { type: "plain_text", text: action.label, emoji: true },
|
|
44
|
-
action_id: `apr:${approval.requestId}:${action.id}`,
|
|
45
|
-
value: `apr:${approval.requestId}:${action.id}`,
|
|
46
|
-
})),
|
|
47
|
-
},
|
|
46
|
+
{ type: "actions", elements: buttons },
|
|
48
47
|
{
|
|
49
48
|
type: "context",
|
|
50
49
|
elements: [
|
|
@@ -63,10 +62,10 @@ function buildApprovalBlocks(
|
|
|
63
62
|
|
|
64
63
|
function resolveBlocks(
|
|
65
64
|
text: string | undefined,
|
|
66
|
-
providedBlocks:
|
|
65
|
+
providedBlocks: KnownBlock[] | undefined,
|
|
67
66
|
approval: ApprovalUIMetadata | undefined,
|
|
68
67
|
useBlocks: boolean | undefined,
|
|
69
|
-
):
|
|
68
|
+
): KnownBlock[] {
|
|
70
69
|
if (Array.isArray(providedBlocks) && providedBlocks.length > 0) {
|
|
71
70
|
return providedBlocks;
|
|
72
71
|
}
|
|
@@ -110,7 +109,7 @@ async function uploadFileToSlack(
|
|
|
110
109
|
|
|
111
110
|
export interface SlackSendOptions {
|
|
112
111
|
threadTs?: string;
|
|
113
|
-
blocks?:
|
|
112
|
+
blocks?: KnownBlock[];
|
|
114
113
|
approval?: ApprovalUIMetadata;
|
|
115
114
|
useBlocks?: boolean;
|
|
116
115
|
ephemeral?: boolean;
|
|
@@ -121,11 +120,53 @@ export interface SlackSendOptions {
|
|
|
121
120
|
export interface SlackSendResult {
|
|
122
121
|
ok: boolean;
|
|
123
122
|
ts?: string;
|
|
124
|
-
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Call a Slack message API once, retrying a single time without Block Kit
|
|
127
|
+
* blocks if Slack rejects the payload with `invalid_blocks`.
|
|
128
|
+
*
|
|
129
|
+
* `invalid_blocks` faults the Block Kit payload, not the target — the retry
|
|
130
|
+
* repeats the *same* operation (same `chat.update` ts, same `chat.postMessage`
|
|
131
|
+
* thread) without blocks, so it edits/posts in place rather than spawning a
|
|
132
|
+
* second message. Any other error propagates to the caller.
|
|
133
|
+
*/
|
|
134
|
+
async function sendWithBlockFallback(
|
|
135
|
+
method: string,
|
|
136
|
+
baseBody: Record<string, unknown>,
|
|
137
|
+
blocks: KnownBlock[],
|
|
138
|
+
options: { fallbackWithoutBlocks: boolean },
|
|
139
|
+
): Promise<SlackSendResult> {
|
|
140
|
+
try {
|
|
141
|
+
const result = await callSlackApi(
|
|
142
|
+
method,
|
|
143
|
+
blocks.length > 0 ? { ...baseBody, blocks } : baseBody,
|
|
144
|
+
);
|
|
145
|
+
return { ok: true, ts: result.ts };
|
|
146
|
+
} catch (err) {
|
|
147
|
+
if (
|
|
148
|
+
options.fallbackWithoutBlocks &&
|
|
149
|
+
blocks.length > 0 &&
|
|
150
|
+
err instanceof SlackApiError &&
|
|
151
|
+
err.slackError === "invalid_blocks"
|
|
152
|
+
) {
|
|
153
|
+
log.warn({ method }, "Slack rejected blocks; retrying without blocks");
|
|
154
|
+
const result = await callSlackApi(method, baseBody);
|
|
155
|
+
return { ok: true, ts: result.ts };
|
|
156
|
+
}
|
|
157
|
+
throw err;
|
|
158
|
+
}
|
|
125
159
|
}
|
|
126
160
|
|
|
127
161
|
/**
|
|
128
162
|
* Send a Slack text message with optional Block Kit formatting.
|
|
163
|
+
*
|
|
164
|
+
* When `messageTs` is set this is strictly an in-place edit (`chat.update`),
|
|
165
|
+
* mirroring `editMessage()` in ./withdraw.ts: a failed edit throws and is
|
|
166
|
+
* never converted into a fresh `chat.postMessage`. Posting on failure would
|
|
167
|
+
* leave the original message beside a duplicate ("ghost") reply; re-delivery
|
|
168
|
+
* after a transient failure is the delivery layer's responsibility, not this
|
|
169
|
+
* function's.
|
|
129
170
|
*/
|
|
130
171
|
export async function sendSlackReply(
|
|
131
172
|
chatId: string,
|
|
@@ -139,107 +180,45 @@ export async function sendSlackReply(
|
|
|
139
180
|
options?.useBlocks,
|
|
140
181
|
);
|
|
141
182
|
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if (isUpdate) {
|
|
153
|
-
const updateBody: Record<string, unknown> = {
|
|
154
|
-
channel: chatId,
|
|
155
|
-
text,
|
|
156
|
-
ts: options!.messageTs,
|
|
157
|
-
};
|
|
158
|
-
if (blocks.length > 0) updateBody.blocks = blocks;
|
|
159
|
-
|
|
160
|
-
try {
|
|
161
|
-
const result = await callSlackApi("chat.update", updateBody);
|
|
162
|
-
log.info(
|
|
163
|
-
{ chatId, messageTs: options!.messageTs },
|
|
164
|
-
"Slack message updated",
|
|
165
|
-
);
|
|
166
|
-
return { ok: true, ts: result.ts };
|
|
167
|
-
} catch (err) {
|
|
168
|
-
if (
|
|
169
|
-
err instanceof SlackApiError &&
|
|
170
|
-
err.slackError === "invalid_blocks" &&
|
|
171
|
-
Array.isArray(updateBody.blocks) &&
|
|
172
|
-
updateBody.blocks.length > 0
|
|
173
|
-
) {
|
|
174
|
-
// `invalid_blocks` means Slack rejected the Block Kit payload, not the
|
|
175
|
-
// target message — the message still exists. Retry the update without
|
|
176
|
-
// blocks so it is edited in place. Posting a fresh message here would
|
|
177
|
-
// leave the original alongside a duplicate ("ghost") reply.
|
|
178
|
-
const retryBody: Record<string, unknown> = {
|
|
179
|
-
channel: chatId,
|
|
180
|
-
text,
|
|
181
|
-
ts: options!.messageTs,
|
|
182
|
-
};
|
|
183
|
-
try {
|
|
184
|
-
const retryResult = await callSlackApi("chat.update", retryBody);
|
|
185
|
-
log.info(
|
|
186
|
-
{ chatId, messageTs: options!.messageTs },
|
|
187
|
-
"Slack message updated without blocks after invalid_blocks",
|
|
188
|
-
);
|
|
189
|
-
return { ok: true, ts: retryResult.ts };
|
|
190
|
-
} catch (retryErr) {
|
|
191
|
-
log.warn(
|
|
192
|
-
{ err: retryErr, chatId, messageTs: options!.messageTs },
|
|
193
|
-
"Slack chat.update without blocks failed, falling back to chat.postMessage",
|
|
194
|
-
);
|
|
195
|
-
delete slackBody.blocks;
|
|
196
|
-
}
|
|
197
|
-
} else {
|
|
198
|
-
log.warn(
|
|
199
|
-
{ err, chatId, messageTs: options!.messageTs },
|
|
200
|
-
"Slack chat.update failed, falling back to chat.postMessage",
|
|
201
|
-
);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
183
|
+
const messageTs = options?.messageTs;
|
|
184
|
+
if (typeof messageTs === "string" && messageTs.length > 0) {
|
|
185
|
+
const result = await sendWithBlockFallback(
|
|
186
|
+
"chat.update",
|
|
187
|
+
{ channel: chatId, text, ts: messageTs },
|
|
188
|
+
blocks,
|
|
189
|
+
{ fallbackWithoutBlocks: true },
|
|
190
|
+
);
|
|
191
|
+
log.info({ chatId, messageTs }, "Slack message updated");
|
|
192
|
+
return result;
|
|
204
193
|
}
|
|
205
194
|
|
|
195
|
+
const postBase: Record<string, unknown> = { channel: chatId, text };
|
|
196
|
+
if (options?.threadTs) postBase.thread_ts = options.threadTs;
|
|
197
|
+
|
|
206
198
|
if (options?.ephemeral) {
|
|
207
199
|
if (!options.user)
|
|
208
200
|
throw new Error("user is required for ephemeral messages");
|
|
209
201
|
const result = await callSlackApi("chat.postEphemeral", {
|
|
210
|
-
...
|
|
202
|
+
...postBase,
|
|
203
|
+
...(blocks.length > 0 ? { blocks } : {}),
|
|
211
204
|
user: options.user,
|
|
212
205
|
});
|
|
213
206
|
return { ok: true, ts: result.ts };
|
|
214
207
|
}
|
|
215
208
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
!options?.ephemeral &&
|
|
230
|
-
Array.isArray(slackBody.blocks) &&
|
|
231
|
-
(slackBody.blocks as unknown[]).length > 0
|
|
232
|
-
) {
|
|
233
|
-
log.warn(
|
|
234
|
-
{ chatId },
|
|
235
|
-
"Retrying Slack delivery without blocks after invalid_blocks",
|
|
236
|
-
);
|
|
237
|
-
delete slackBody.blocks;
|
|
238
|
-
const result = await callSlackApi("chat.postMessage", slackBody);
|
|
239
|
-
return { ok: true, ts: result.ts };
|
|
240
|
-
}
|
|
241
|
-
throw err;
|
|
242
|
-
}
|
|
209
|
+
// Approval prompts carry their action buttons in `blocks`; dropping them on
|
|
210
|
+
// `invalid_blocks` would post a card with no way to respond, so only
|
|
211
|
+
// non-approval posts fall back to a block-free retry.
|
|
212
|
+
const result = await sendWithBlockFallback(
|
|
213
|
+
"chat.postMessage",
|
|
214
|
+
postBase,
|
|
215
|
+
blocks,
|
|
216
|
+
{
|
|
217
|
+
fallbackWithoutBlocks: !options?.approval,
|
|
218
|
+
},
|
|
219
|
+
);
|
|
220
|
+
log.info({ chatId, hasThreadTs: !!options?.threadTs }, "Slack message sent");
|
|
221
|
+
return result;
|
|
243
222
|
}
|
|
244
223
|
|
|
245
224
|
/**
|
|
@@ -5,7 +5,7 @@ Signal-driven notification architecture where producers emit free-form events an
|
|
|
5
5
|
## Lifecycle
|
|
6
6
|
|
|
7
7
|
```
|
|
8
|
-
Producer → NotificationSignal → Candidate Generation → Decision Engine (LLM) → Deterministic Checks → Broadcaster → Conversation Pairing → Adapters → Delivery
|
|
8
|
+
Producer → NotificationSignal → Source-Active Gate → Candidate Generation → Decision Engine (LLM) → Deterministic Checks → Broadcaster → Conversation Pairing → Adapters → Delivery
|
|
9
9
|
↑ ↓
|
|
10
10
|
Preference Summary notification_conversation_created SSE event
|
|
11
11
|
Conversation Candidates (creation-only — not emitted on reuse)
|
|
@@ -15,6 +15,8 @@ Producer → NotificationSignal → Candidate Generation → Decision Engine (LL
|
|
|
15
15
|
|
|
16
16
|
A producer calls `emitNotificationSignal()` with a free-form event name, attention hints (urgency, requiresAction, deadlineAt), and a context payload. The signal is persisted as a `notification_events` row.
|
|
17
17
|
|
|
18
|
+
Immediately after persistence, a **source-active pre-gate** runs (`checkSourceActiveSuppression`): when `visibleInSourceNow` is set — a hard, signal-only invariant the decision engine cannot override — the signal is suppressed and short-circuits here, before candidate generation and the LLM decision. This keeps an always-suppressed signal (e.g. trusted-contact `verification_sent`) from spending an LLM inference whose result would be discarded. The `notification_events` row is still written for the audit trail.
|
|
19
|
+
|
|
18
20
|
### 2. Candidate Generation
|
|
19
21
|
|
|
20
22
|
Before the decision engine runs, the system builds a **conversation candidate set** per channel (`conversation-candidates.ts`). This is a compact snapshot of recent notification-sourced conversations that the decision engine can choose to reuse instead of starting a new conversation.
|
|
@@ -58,12 +60,14 @@ Hard invariants that the LLM cannot override:
|
|
|
58
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.
|
|
59
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.
|
|
60
62
|
|
|
61
|
-
**Pre-send gate checks** (`deterministic-checks.ts`):
|
|
63
|
+
**Pre-send gate checks** (`deterministic-checks.ts`) — these all depend on the decision, so they run here, after it:
|
|
62
64
|
|
|
63
65
|
- **Schema validity** -- fail-closed if the decision is malformed
|
|
64
|
-
- **Source-active suppression** -- if the user is already viewing the source context, suppress
|
|
65
66
|
- **Channel availability** -- at least one selected channel must be connected
|
|
66
67
|
- **Deduplication** -- same `dedupeKey` within the dedupe window (1 hour default) is suppressed
|
|
68
|
+
- **Rendered copy quality** -- fail-closed on empty copy or a fallback leak (body equal to the raw event name)
|
|
69
|
+
|
|
70
|
+
Source-active suppression depends only on the signal, so it runs earlier — as the pre-decision gate in `emit-signal.ts` (see step 1), not as a pre-send check here.
|
|
67
71
|
|
|
68
72
|
### 5. Dispatch
|
|
69
73
|
|
|
@@ -409,13 +413,13 @@ All disambiguation messages are generated through `composeGuardianActionMessageG
|
|
|
409
413
|
| File | Purpose |
|
|
410
414
|
| ------------------------------- | ---------------------------------------------------------------------------------------------------------- |
|
|
411
415
|
| `../channels/config.ts` | Channel policy registry -- single source of truth for per-channel notification behavior |
|
|
412
|
-
| `emit-signal.ts` | Single entry point for producers; orchestrates the full pipeline
|
|
416
|
+
| `emit-signal.ts` | Single entry point for producers; orchestrates the full pipeline; runs the source-active pre-decision gate |
|
|
413
417
|
| `signal.ts` | `NotificationSignal` and `AttentionHints` type definitions |
|
|
414
418
|
| `types.ts` | Channel adapter interfaces, delivery types, decision output contract, `ConversationAction` union |
|
|
415
419
|
| `conversation-candidates.ts` | Builds per-channel candidate set of recent notification conversations for the decision engine |
|
|
416
420
|
| `conversation-pairing.ts` | Materializes conversation + message per delivery based on channel strategy |
|
|
417
421
|
| `decision-engine.ts` | LLM-based routing with forced tool_choice; deterministic fallback |
|
|
418
|
-
| `deterministic-checks.ts` |
|
|
422
|
+
| `deterministic-checks.ts` | Post-decision pre-send gate checks (schema, dedupe, channel availability, copy quality) |
|
|
419
423
|
| `runtime-dispatch.ts` | Dispatch gating (no-op decisions, empty channels) |
|
|
420
424
|
| `broadcaster.ts` | Fan-out to channel adapters with delivery audit trail; emits `notification_conversation_created` SSE event |
|
|
421
425
|
| `copy-composer.ts` | Template-based fallback notification copy when LLM copy is unavailable |
|
|
@@ -27,14 +27,22 @@ mock.module("../copy-composer.js", () => ({
|
|
|
27
27
|
composeFallbackCopy: () => composeFallbackReturn,
|
|
28
28
|
}));
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
30
|
+
// Stub only getGuardianDelivery; keep the real selectors so this mock is
|
|
31
|
+
// harmless if it leaks into destination-resolver.test.ts under a shared run.
|
|
32
|
+
const realGuardianReader = await import(
|
|
33
|
+
"../../contacts/guardian-delivery-reader.js"
|
|
34
|
+
);
|
|
35
|
+
mock.module("../../contacts/guardian-delivery-reader.js", () => ({
|
|
36
|
+
...realGuardianReader,
|
|
37
|
+
getGuardianDelivery: async () => null,
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
// Use the real destination-resolver (DB-free via the local-read stub below)
|
|
41
|
+
// so this mock does not leak into destination-resolver.test.ts under a shared
|
|
42
|
+
// bun-test invocation. With no guardian, the resolver still yields a vellum
|
|
43
|
+
// destination, which is all these tests exercise.
|
|
44
|
+
mock.module("../../contacts/contact-store.js", () => ({
|
|
45
|
+
findGuardianForChannel: () => null,
|
|
38
46
|
}));
|
|
39
47
|
|
|
40
48
|
mock.module("../conversation-pairing.js", () => ({
|