@vellumai/assistant 0.10.0 → 0.10.1-staging.1
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 +6 -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__/trust-verdict-contract.test.ts +65 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +162 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +8 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +14 -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 +78 -0
- package/openapi.yaml +345 -18
- package/package.json +2 -1
- package/scripts/memory-inspect.ts +24 -14
- 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 +3 -3
- 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 +143 -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 +1 -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__/channel-approval-routes.test.ts +73 -1119
- package/src/__tests__/channel-delivery-store.test.ts +1 -1
- package/src/__tests__/channel-guardian.test.ts +265 -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 +183 -51
- package/src/__tests__/config-schema.test.ts +34 -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 +3 -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 +6 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +1 -1
- 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 +1 -1
- package/src/__tests__/conversation-sync-tags.test.ts +1 -1
- 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 +26 -8
- 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__/edit-propagation.test.ts +1 -1
- package/src/__tests__/emit-signal-routing-intent.test.ts +83 -0
- package/src/__tests__/empty-response-hook.test.ts +42 -0
- package/src/__tests__/events-client-registration.test.ts +1 -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 +1 -1
- 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 +1 -1
- package/src/__tests__/guardian-outbound-http.test.ts +7 -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 +98 -0
- package/src/__tests__/http-conversation-lineage.test.ts +1 -1
- 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-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-usage-store.test.ts +40 -1
- package/src/__tests__/log-export-routes.test.ts +1 -1
- package/src/__tests__/log-export-workspace.test.ts +3 -3
- 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 +1 -2
- package/src/__tests__/notification-candidate-guardian-context.test.ts +203 -0
- package/src/__tests__/notification-guardian-path.test.ts +1 -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__/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 +1 -1
- package/src/__tests__/prune-old-conversations-job.test.ts +1 -1
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/relay-server.test.ts +357 -56
- package/src/__tests__/runtime-attachment-metadata.test.ts +10 -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-routes-platform-proxy.test.ts +1 -0
- package/src/__tests__/send-endpoint-busy.test.ts +1 -1
- 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__/slack-inbound-verification.test.ts +1 -3
- 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__/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 +32 -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 +2 -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/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.ts +45 -27
- package/src/api/index.ts +0 -6
- 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 +88 -62
- package/src/calls/inbound-trust-reader.ts +40 -0
- package/src/calls/relay-server.ts +65 -23
- package/src/calls/relay-setup-router.ts +20 -6
- package/src/calls/relay-verification.ts +7 -7
- 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/memory/__tests__/memory-v3.test.ts +6 -1
- package/src/cli/commands/memory/index.ts +2 -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/plugins.ts +268 -11
- package/src/cli/lib/__tests__/install-from-github.test.ts +40 -0
- 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/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__/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/profile-dispatchability.ts +11 -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 +5 -3
- package/src/config/schemas/timeouts.ts +24 -0
- package/src/config/seed-inference-profiles.ts +133 -45
- package/src/config/sync-gated-profiles.ts +13 -1
- package/src/contacts/contact-store.ts +21 -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 +9 -36
- package/src/daemon/conversation-runtime-assembly.ts +91 -66
- package/src/daemon/conversation-tool-setup.ts +20 -63
- package/src/daemon/conversation.ts +144 -52
- 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 +32 -18
- package/src/daemon/handlers/conversations.ts +7 -0
- package/src/daemon/handlers/shared.ts +7 -0
- package/src/daemon/lifecycle.ts +16 -3
- 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 +18 -8
- package/src/daemon/server.ts +0 -4
- package/src/daemon/tool-setup-types.ts +0 -7
- 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__/watcher-ipc.test.ts +59 -39
- package/src/ipc/assistant-server.ts +8 -0
- 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__/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/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 +31 -1
- 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/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 +227 -230
- 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 +50 -57
- 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__/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/validate-migration-state.ts +50 -145
- 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__/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__/sweep-job.test.ts +2 -2
- 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/messaging/provider.ts +10 -0
- package/src/messaging/providers/gmail/adapter.ts +1 -0
- package/src/messaging/providers/gmail/client.ts +14 -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__/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/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/deterministic-checks.ts +19 -16
- package/src/notifications/emit-signal.ts +29 -1
- 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 +146 -6
- package/src/oauth/connection-resolver.ts +132 -5
- package/src/oauth/oauth-store.ts +16 -3
- package/src/oauth/scope-utils.ts +21 -0
- 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 +149 -0
- package/src/plugin-api/vision-support.ts +78 -0
- 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 +302 -0
- package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +103 -0
- package/src/plugins/defaults/image-fallback/package.json +14 -0
- package/src/plugins/defaults/image-fallback/src/caption-cache.ts +49 -0
- package/src/plugins/defaults/image-fallback/src/image-persist.ts +59 -0
- package/src/plugins/defaults/image-fallback/src/vision-caption.ts +120 -0
- package/src/plugins/defaults/index.ts +23 -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/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 +254 -185
- package/src/providers/call-site-routing.ts +10 -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 +37 -0
- package/src/providers/platform-proxy/constants.ts +5 -0
- package/src/providers/ratelimit.ts +9 -0
- package/src/providers/retry.ts +10 -0
- package/src/providers/together/client.ts +35 -0
- package/src/providers/types.ts +16 -0
- package/src/providers/usage-tracking.ts +7 -0
- package/src/runtime/AGENTS.md +9 -1
- package/src/runtime/__tests__/agent-wake.test.ts +259 -4
- package/src/runtime/__tests__/slack-block-formatting.test.ts +39 -10
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +417 -0
- package/src/runtime/actor-trust-resolver.ts +8 -16
- package/src/runtime/agent-wake.ts +183 -60
- package/src/runtime/channel-reply-delivery.ts +6 -3
- package/src/runtime/guardian-decision-types.ts +3 -22
- 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/migrations/__tests__/vbundle-builder-fd-leak.test.ts +3 -0
- 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/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 +12 -1
- 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 +24 -3
- package/src/runtime/routes/conversation-starter-routes.ts +7 -8
- package/src/runtime/routes/guardian-approval-interception.ts +13 -274
- package/src/runtime/routes/inbound-message-handler.ts +20 -15
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +285 -0
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +45 -34
- package/src/runtime/routes/inbound-stages/admission-policy.ts +20 -5
- package/src/runtime/routes/log-export-routes.ts +2 -2
- 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/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 +172 -0
- package/src/schedule/scheduler.ts +6 -9
- package/src/telemetry/usage-telemetry-reporter.test.ts +1 -1
- package/src/tools/ask-question/ask-question-tool.test.ts +60 -52
- package/src/tools/ask-question/ask-question-tool.ts +14 -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/types.ts +1 -0
- package/src/util/fs-watcher-error.ts +36 -0
- package/src/util/logs-db-path.ts +22 -0
- package/src/util/memory-db-path.ts +23 -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
|
@@ -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 |
|
|
@@ -20,13 +20,14 @@ import { getDb } from "../../memory/db-connection.js";
|
|
|
20
20
|
import { initializeDb } from "../../memory/db-init.js";
|
|
21
21
|
import { notificationEvents } from "../../memory/schema.js";
|
|
22
22
|
import {
|
|
23
|
+
checkSourceActiveSuppression,
|
|
23
24
|
type DeterministicCheckContext,
|
|
24
25
|
runDeterministicChecks,
|
|
25
26
|
} from "../deterministic-checks.js";
|
|
26
27
|
import type { NotificationSignal } from "../signal.js";
|
|
27
28
|
import type { NotificationDecision } from "../types.js";
|
|
28
29
|
|
|
29
|
-
initializeDb();
|
|
30
|
+
await initializeDb();
|
|
30
31
|
|
|
31
32
|
beforeEach(() => {
|
|
32
33
|
getDb().delete(notificationEvents).run();
|
|
@@ -284,3 +285,44 @@ describe("checkRenderedCopyQuality (via runDeterministicChecks)", () => {
|
|
|
284
285
|
expect(result.reason).toContain("fallback leak");
|
|
285
286
|
});
|
|
286
287
|
});
|
|
288
|
+
|
|
289
|
+
describe("checkSourceActiveSuppression (pre-decision gate)", () => {
|
|
290
|
+
test("fails when visibleInSourceNow is set", () => {
|
|
291
|
+
const result = checkSourceActiveSuppression(
|
|
292
|
+
makeSignal({
|
|
293
|
+
attentionHints: {
|
|
294
|
+
requiresAction: false,
|
|
295
|
+
urgency: "low",
|
|
296
|
+
isAsyncBackground: true,
|
|
297
|
+
visibleInSourceNow: true,
|
|
298
|
+
},
|
|
299
|
+
}),
|
|
300
|
+
);
|
|
301
|
+
expect(result.passed).toBe(false);
|
|
302
|
+
expect(result.reason).toContain("Source-active suppression");
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
test("passes when visibleInSourceNow is false", () => {
|
|
306
|
+
expect(checkSourceActiveSuppression(makeSignal()).passed).toBe(true);
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
test("runDeterministicChecks does not suppress source-active signals (handled by the pre-decision gate)", async () => {
|
|
310
|
+
// Source-active suppression is enforced by the pre-decision gate in
|
|
311
|
+
// emitNotificationSignal, not by this stage. A source-active signal
|
|
312
|
+
// evaluated here therefore passes — this stage only validates the decision.
|
|
313
|
+
const signal = makeSignal({
|
|
314
|
+
attentionHints: {
|
|
315
|
+
requiresAction: false,
|
|
316
|
+
urgency: "low",
|
|
317
|
+
isAsyncBackground: true,
|
|
318
|
+
visibleInSourceNow: true,
|
|
319
|
+
},
|
|
320
|
+
});
|
|
321
|
+
const result = await runDeterministicChecks(
|
|
322
|
+
signal,
|
|
323
|
+
makeDecision(),
|
|
324
|
+
context,
|
|
325
|
+
);
|
|
326
|
+
expect(result.passed).toBe(true);
|
|
327
|
+
});
|
|
328
|
+
});
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
* https://docs.slack.dev/reference/block-kit/blocks/card-block
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
+
import type { Button, CardBlock, ContextBlock, KnownBlock } from "@slack/types";
|
|
16
|
+
|
|
15
17
|
import { sendSlackReply } from "../../messaging/providers/slack/send.js";
|
|
16
18
|
import type { ApprovalUIMetadata } from "../../runtime/channel-approval-types.js";
|
|
17
19
|
import { getLogger } from "../../util/logger.js";
|
|
@@ -39,7 +41,7 @@ const log = getLogger("notif-adapter-slack");
|
|
|
39
41
|
// ---------------------------------------------------------------------------
|
|
40
42
|
|
|
41
43
|
/** Build action buttons for a Slack Card block from approval metadata. */
|
|
42
|
-
function buildCardActions(approval: ApprovalUIMetadata):
|
|
44
|
+
function buildCardActions(approval: ApprovalUIMetadata): Button[] {
|
|
43
45
|
return approval.actions.map((action) => ({
|
|
44
46
|
type: "button",
|
|
45
47
|
text: { type: "plain_text", text: action.label, emoji: true },
|
|
@@ -80,7 +82,7 @@ function buildAccessRequestBody(view: AccessRequestCardView): string {
|
|
|
80
82
|
/** Source-channel context block with Slack permalink when available. */
|
|
81
83
|
function buildSourceContextBlock(
|
|
82
84
|
view: AccessRequestCardView,
|
|
83
|
-
):
|
|
85
|
+
): ContextBlock | undefined {
|
|
84
86
|
if (view.sourceChannel !== "slack" || !view.conversationExternalId) {
|
|
85
87
|
return undefined;
|
|
86
88
|
}
|
|
@@ -107,7 +109,7 @@ function buildSourceContextBlock(
|
|
|
107
109
|
/** Stable requester identifier context block (external ID when it adds info). */
|
|
108
110
|
function buildRequesterIdBlock(
|
|
109
111
|
view: AccessRequestCardView,
|
|
110
|
-
):
|
|
112
|
+
): ContextBlock | undefined {
|
|
111
113
|
const safeExternalId = view.externalId;
|
|
112
114
|
if (!safeExternalId) return undefined;
|
|
113
115
|
|
|
@@ -134,10 +136,10 @@ function buildRequesterIdBlock(
|
|
|
134
136
|
*/
|
|
135
137
|
function buildAccessRequestCardBlocks(
|
|
136
138
|
payload: ChannelDeliveryPayload,
|
|
137
|
-
):
|
|
139
|
+
): KnownBlock[] {
|
|
138
140
|
const approval = payload.approvalContext!;
|
|
139
141
|
const view = buildAccessRequestCardView(payload.accessRequestContext!);
|
|
140
|
-
const blocks:
|
|
142
|
+
const blocks: KnownBlock[] = [];
|
|
141
143
|
|
|
142
144
|
const subtitle = buildAccessRequestSubtitle(view);
|
|
143
145
|
const body = buildAccessRequestBody(view);
|
|
@@ -147,7 +149,7 @@ function buildAccessRequestCardBlocks(
|
|
|
147
149
|
? truncate(view.warnings.map((w) => `:warning: ${w}`).join(" · "), 200)
|
|
148
150
|
: undefined;
|
|
149
151
|
|
|
150
|
-
const card:
|
|
152
|
+
const card: CardBlock = {
|
|
151
153
|
type: "card",
|
|
152
154
|
title: { type: "mrkdwn", text: "Access Request" },
|
|
153
155
|
subtitle: { type: "mrkdwn", text: subtitle },
|
|
@@ -211,9 +213,9 @@ function buildAccessRequestCardBlocks(
|
|
|
211
213
|
function buildToolApprovalCardBlocks(
|
|
212
214
|
payload: ChannelDeliveryPayload,
|
|
213
215
|
messageText: string,
|
|
214
|
-
):
|
|
216
|
+
): KnownBlock[] {
|
|
215
217
|
const approval = payload.approvalContext!;
|
|
216
|
-
const blocks:
|
|
218
|
+
const blocks: KnownBlock[] = [];
|
|
217
219
|
|
|
218
220
|
const details = approval.permissionDetails;
|
|
219
221
|
const toolName = details?.toolName;
|
|
@@ -226,7 +228,7 @@ function buildToolApprovalCardBlocks(
|
|
|
226
228
|
}
|
|
227
229
|
|
|
228
230
|
const needsOverflow = messageText.length > 200;
|
|
229
|
-
const card:
|
|
231
|
+
const card: CardBlock = {
|
|
230
232
|
type: "card",
|
|
231
233
|
title: {
|
|
232
234
|
type: "mrkdwn",
|
|
@@ -266,7 +268,7 @@ function buildToolApprovalCardBlocks(
|
|
|
266
268
|
export function buildApprovalNotificationBlocks(
|
|
267
269
|
payload: ChannelDeliveryPayload,
|
|
268
270
|
messageText: string,
|
|
269
|
-
):
|
|
271
|
+
): KnownBlock[] {
|
|
270
272
|
if (
|
|
271
273
|
payload.sourceEventName === "ingress.access_request" &&
|
|
272
274
|
payload.accessRequestContext != null
|