@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
|
@@ -7,18 +7,73 @@
|
|
|
7
7
|
* supplies its domain-specific data (title, subtitle, metadata, etc.)
|
|
8
8
|
* without duplicating the card structure or action wiring.
|
|
9
9
|
*
|
|
10
|
-
* The
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
10
|
+
* The `[ui_surface, text]` block pair is described by {@link ApprovalCardBlockSchema}
|
|
11
|
+
* so the builder returns a schema-derived type rather than `unknown[]`: the card
|
|
12
|
+
* `data` composes the canonical {@link CardSurfaceDataSchema} and actions reuse
|
|
13
|
+
* the canonical {@link SurfaceActionSchema}. Actions use the
|
|
14
|
+
* `apr:<requestId>:<action>` callback format consumed by
|
|
15
|
+
* `surface-action-routes.ts` → `processGuardianDecision`.
|
|
14
16
|
*/
|
|
15
17
|
|
|
18
|
+
import { z } from "zod";
|
|
19
|
+
|
|
20
|
+
import {
|
|
21
|
+
type SurfaceAction,
|
|
22
|
+
SurfaceActionSchema,
|
|
23
|
+
} from "../api/events/ui-surface-show.js";
|
|
24
|
+
import {
|
|
25
|
+
type CardSurfaceData,
|
|
26
|
+
CardSurfaceDataSchema,
|
|
27
|
+
} from "../daemon/message-types/surfaces.js";
|
|
28
|
+
|
|
29
|
+
// ── Seed content block schema ─────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The interactive `ui_surface` card block clients render via
|
|
33
|
+
* `SurfaceRouter → CardSurface`. `data` is the canonical card surface data;
|
|
34
|
+
* `actions` reuse the canonical surface action schema.
|
|
35
|
+
*/
|
|
36
|
+
export const ApprovalCardSurfaceBlockSchema = z.object({
|
|
37
|
+
type: z.literal("ui_surface"),
|
|
38
|
+
surfaceId: z.string(),
|
|
39
|
+
surfaceType: z.literal("card"),
|
|
40
|
+
title: z.string(),
|
|
41
|
+
data: CardSurfaceDataSchema,
|
|
42
|
+
actions: z.array(SurfaceActionSchema).optional(),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The plain-text fallback block, flagged so the display projector
|
|
47
|
+
* (`renderHistoryContent`) keeps it in flat `.text` but omits it from the
|
|
48
|
+
* rendered `contentBlocks` — without it a surface-capable client would render
|
|
49
|
+
* the card AND a duplicate text line.
|
|
50
|
+
*/
|
|
51
|
+
export const ApprovalCardFallbackBlockSchema = z.object({
|
|
52
|
+
type: z.literal("text"),
|
|
53
|
+
text: z.string(),
|
|
54
|
+
_surfaceFallback: z.literal(true),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
/** The `[ui_surface, text]` seed block pair produced for a guardian card. */
|
|
58
|
+
export const ApprovalCardBlockSchema = z.discriminatedUnion("type", [
|
|
59
|
+
ApprovalCardSurfaceBlockSchema,
|
|
60
|
+
ApprovalCardFallbackBlockSchema,
|
|
61
|
+
]);
|
|
62
|
+
|
|
63
|
+
export type ApprovalCardSurfaceBlock = z.infer<
|
|
64
|
+
typeof ApprovalCardSurfaceBlockSchema
|
|
65
|
+
>;
|
|
66
|
+
export type ApprovalCardFallbackBlock = z.infer<
|
|
67
|
+
typeof ApprovalCardFallbackBlockSchema
|
|
68
|
+
>;
|
|
69
|
+
export type ApprovalCardBlock = z.infer<typeof ApprovalCardBlockSchema>;
|
|
70
|
+
|
|
16
71
|
// ── Public types ────────────────────────────────────────────────────────────
|
|
17
72
|
|
|
18
73
|
export interface ApprovalCardParams {
|
|
19
74
|
/** Prefix for `surfaceId` — combined with `requestId` to form e.g. "access-request-abc123". */
|
|
20
75
|
surfaceIdPrefix: string;
|
|
21
|
-
/** Top-level card title shown in the surface header (e.g. "Access Request", "Tool
|
|
76
|
+
/** Top-level card title shown in the surface header (e.g. "Access Request", "Tool approval"). */
|
|
22
77
|
cardTitle: string;
|
|
23
78
|
/** Primary line inside the card (typically the requester's display name). */
|
|
24
79
|
requesterName: string;
|
|
@@ -40,10 +95,13 @@ export interface ApprovalCardParams {
|
|
|
40
95
|
* Build a `[ui_surface, text]` block pair for a guardian approval notification.
|
|
41
96
|
*
|
|
42
97
|
* The `ui_surface` block renders as a card with Approve/Reject buttons in
|
|
43
|
-
* clients that support Surface rendering. The `text` block
|
|
44
|
-
* plain-text fallback
|
|
98
|
+
* clients that support Surface rendering. The `text` block is the card's
|
|
99
|
+
* plain-text fallback — it feeds the model, search indexing, CLI display, and
|
|
100
|
+
* channel replies, which read it as ordinary text.
|
|
45
101
|
*/
|
|
46
|
-
export function buildApprovalCardBlocks(
|
|
102
|
+
export function buildApprovalCardBlocks(
|
|
103
|
+
params: ApprovalCardParams,
|
|
104
|
+
): ApprovalCardBlock[] {
|
|
47
105
|
const {
|
|
48
106
|
surfaceIdPrefix,
|
|
49
107
|
cardTitle,
|
|
@@ -55,7 +113,7 @@ export function buildApprovalCardBlocks(params: ApprovalCardParams): unknown[] {
|
|
|
55
113
|
fallbackText,
|
|
56
114
|
} = params;
|
|
57
115
|
|
|
58
|
-
const actions = requestId
|
|
116
|
+
const actions: SurfaceAction[] | undefined = requestId
|
|
59
117
|
? [
|
|
60
118
|
{
|
|
61
119
|
id: `apr:${requestId}:approve_once`,
|
|
@@ -70,23 +128,26 @@ export function buildApprovalCardBlocks(params: ApprovalCardParams): unknown[] {
|
|
|
70
128
|
]
|
|
71
129
|
: undefined;
|
|
72
130
|
|
|
73
|
-
const
|
|
74
|
-
|
|
131
|
+
const data: CardSurfaceData = {
|
|
132
|
+
title: requesterName,
|
|
133
|
+
subtitle,
|
|
134
|
+
body,
|
|
135
|
+
metadata,
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const surfaceBlock: ApprovalCardSurfaceBlock = {
|
|
139
|
+
type: "ui_surface",
|
|
75
140
|
surfaceId: `${surfaceIdPrefix}-${requestId ?? "unknown"}`,
|
|
76
|
-
surfaceType: "card"
|
|
141
|
+
surfaceType: "card",
|
|
77
142
|
title: cardTitle,
|
|
78
|
-
data
|
|
79
|
-
title: requesterName,
|
|
80
|
-
subtitle,
|
|
81
|
-
body,
|
|
82
|
-
metadata,
|
|
83
|
-
},
|
|
143
|
+
data,
|
|
84
144
|
...(actions ? { actions } : {}),
|
|
85
145
|
};
|
|
86
146
|
|
|
87
|
-
const textBlock = {
|
|
88
|
-
type: "text"
|
|
147
|
+
const textBlock: ApprovalCardFallbackBlock = {
|
|
148
|
+
type: "text",
|
|
89
149
|
text: fallbackText,
|
|
150
|
+
_surfaceFallback: true,
|
|
90
151
|
};
|
|
91
152
|
|
|
92
153
|
return [surfaceBlock, textBlock];
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
parseAccessRequestPayload,
|
|
20
20
|
} from "./access-request-copy.js";
|
|
21
21
|
import {
|
|
22
|
+
type ApprovalCardBlock,
|
|
22
23
|
type ApprovalCardParams,
|
|
23
24
|
buildApprovalCardBlocks,
|
|
24
25
|
} from "./approval-card-builder.js";
|
|
@@ -285,7 +286,9 @@ export function resolveApprovalCardData(
|
|
|
285
286
|
}
|
|
286
287
|
|
|
287
288
|
/** Render resolved approval card data into Surface `[ui_surface, text]` blocks. */
|
|
288
|
-
export function renderApprovalCardData(
|
|
289
|
+
export function renderApprovalCardData(
|
|
290
|
+
data: ApprovalCardData,
|
|
291
|
+
): ApprovalCardBlock[] {
|
|
289
292
|
return buildApprovalCardBlocks(data.card);
|
|
290
293
|
}
|
|
291
294
|
|
|
@@ -300,7 +303,7 @@ export function renderApprovalCardData(data: ApprovalCardData): unknown[] {
|
|
|
300
303
|
*/
|
|
301
304
|
export function buildAccessRequestSeedContentBlocks(
|
|
302
305
|
payload: Record<string, unknown>,
|
|
303
|
-
):
|
|
306
|
+
): ApprovalCardBlock[] {
|
|
304
307
|
return renderApprovalCardData({
|
|
305
308
|
kind: "access_request",
|
|
306
309
|
card: resolveAccessRequestCard(payload),
|
|
@@ -318,13 +321,13 @@ export function buildAccessRequestSeedContentBlocks(
|
|
|
318
321
|
*/
|
|
319
322
|
export function buildToolApprovalSeedContentBlocks(
|
|
320
323
|
payload: GuardianQuestionPayload,
|
|
321
|
-
):
|
|
324
|
+
): ApprovalCardBlock[] | null;
|
|
322
325
|
export function buildToolApprovalSeedContentBlocks(
|
|
323
326
|
payload: Record<string, unknown>,
|
|
324
|
-
):
|
|
327
|
+
): ApprovalCardBlock[] | null;
|
|
325
328
|
export function buildToolApprovalSeedContentBlocks(
|
|
326
329
|
payload: GuardianQuestionPayload | Record<string, unknown>,
|
|
327
|
-
):
|
|
330
|
+
): ApprovalCardBlock[] | null {
|
|
328
331
|
const data = resolveApprovalCardData(
|
|
329
332
|
"guardian.question",
|
|
330
333
|
payload as Record<string, unknown>,
|
|
@@ -91,11 +91,12 @@ export function recordApprovalCardDelivery(
|
|
|
91
91
|
* that row's id as `vellumDeliveryId` and it is reused (only its status applied)
|
|
92
92
|
* — otherwise the vellum row is created here from the result.
|
|
93
93
|
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
94
|
+
* Every result records the internal `conversationId` the card is shown in, so a
|
|
95
|
+
* conversation's pending cards can be found uniformly regardless of channel.
|
|
96
|
+
* Channel results additionally carry the chat (`destination`) and channel-native
|
|
97
|
+
* id (`messageId`) used to match inbound replies/reactions; a blank `destination`
|
|
98
|
+
* is recorded as unknown rather than persisting the literal channel name as a
|
|
99
|
+
* chat id. Status is diagnostic — the read paths key off addressing, not status.
|
|
99
100
|
*
|
|
100
101
|
* Returns the vellum delivery id (passed in, or created here) so a caller can
|
|
101
102
|
* record its own "pipeline produced no vellum delivery" fallback.
|
|
@@ -123,6 +124,7 @@ export function recordGuardianRequestDeliveries(params: {
|
|
|
123
124
|
deliveryId = recordApprovalCardDelivery({
|
|
124
125
|
requestId,
|
|
125
126
|
channel: result.channel,
|
|
127
|
+
conversationId: result.conversationId,
|
|
126
128
|
chatId: result.destination.length > 0 ? result.destination : undefined,
|
|
127
129
|
messageId: result.messageId,
|
|
128
130
|
})?.id;
|
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
* needs for a routing decision, not full conversation contents.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { and,
|
|
13
|
+
import { and, desc, eq, isNotNull } from "drizzle-orm";
|
|
14
14
|
|
|
15
|
+
import { listPendingRequestsByConversationScope } from "../memory/canonical-guardian-store.js";
|
|
15
16
|
import { getDb } from "../memory/db-connection.js";
|
|
16
17
|
import {
|
|
17
|
-
channelGuardianApprovalRequests,
|
|
18
18
|
conversations,
|
|
19
19
|
notificationDecisions,
|
|
20
20
|
notificationDeliveries,
|
|
@@ -169,74 +169,39 @@ function buildCandidatesForChannel(
|
|
|
169
169
|
if (candidates.length >= MAX_CANDIDATES_PER_CHANNEL) break;
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
//
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
172
|
+
// Enrich each candidate with its count of pending guardian requests. The
|
|
173
|
+
// canonical store owns the addressing convention and counts by conversation
|
|
174
|
+
// scope: the request's source conversation plus any conversation its card was
|
|
175
|
+
// delivered to (e.g. an access request whose synthetic source id differs from
|
|
176
|
+
// the in-app card's destination conversation).
|
|
177
|
+
//
|
|
178
|
+
// Best-effort per candidate: guardian context is supplementary, so a lookup
|
|
179
|
+
// failure degrades that candidate to "no context" (logged) rather than
|
|
180
|
+
// propagating to the per-channel catch in `buildConversationCandidates`,
|
|
181
|
+
// which would discard the channel's whole candidate set.
|
|
182
|
+
for (const candidate of candidates) {
|
|
183
|
+
try {
|
|
184
|
+
const pendingCount = listPendingRequestsByConversationScope(
|
|
185
|
+
candidate.conversationId,
|
|
186
|
+
candidate.channel,
|
|
187
|
+
).length;
|
|
179
188
|
if (pendingCount > 0) {
|
|
180
189
|
candidate.guardianContext = {
|
|
181
190
|
pendingUnresolvedRequestCount: pendingCount,
|
|
182
191
|
};
|
|
183
192
|
}
|
|
193
|
+
} catch (err) {
|
|
194
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
195
|
+
log.warn(
|
|
196
|
+
{ err: errMsg, conversationId: candidate.conversationId },
|
|
197
|
+
"Failed to enrich candidate with guardian context",
|
|
198
|
+
);
|
|
184
199
|
}
|
|
185
200
|
}
|
|
186
201
|
|
|
187
202
|
return candidates;
|
|
188
203
|
}
|
|
189
204
|
|
|
190
|
-
// -- Guardian context enrichment ----------------------------------------------
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Batch-count pending guardian approval requests for multiple conversations
|
|
194
|
-
* in a single query. Returns a map from conversationId to pending count
|
|
195
|
-
* (only entries with count > 0 are included).
|
|
196
|
-
*/
|
|
197
|
-
function batchCountPendingByConversation(
|
|
198
|
-
conversationIds: string[],
|
|
199
|
-
): Map<string, number> {
|
|
200
|
-
const result = new Map<string, number>();
|
|
201
|
-
if (conversationIds.length === 0) return result;
|
|
202
|
-
|
|
203
|
-
try {
|
|
204
|
-
const db = getDb();
|
|
205
|
-
|
|
206
|
-
const rows = db
|
|
207
|
-
.select({
|
|
208
|
-
conversationId: channelGuardianApprovalRequests.conversationId,
|
|
209
|
-
count: count(),
|
|
210
|
-
})
|
|
211
|
-
.from(channelGuardianApprovalRequests)
|
|
212
|
-
.where(
|
|
213
|
-
and(
|
|
214
|
-
inArray(
|
|
215
|
-
channelGuardianApprovalRequests.conversationId,
|
|
216
|
-
conversationIds,
|
|
217
|
-
),
|
|
218
|
-
eq(channelGuardianApprovalRequests.status, "pending"),
|
|
219
|
-
),
|
|
220
|
-
)
|
|
221
|
-
.groupBy(channelGuardianApprovalRequests.conversationId)
|
|
222
|
-
.all();
|
|
223
|
-
|
|
224
|
-
for (const row of rows) {
|
|
225
|
-
if (row.count > 0) {
|
|
226
|
-
result.set(row.conversationId, row.count);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
} catch (err) {
|
|
230
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
231
|
-
log.warn(
|
|
232
|
-
{ err: errMsg },
|
|
233
|
-
"Failed to batch-query guardian context for candidates",
|
|
234
|
-
);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return result;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
205
|
// -- Prompt serialization -----------------------------------------------------
|
|
241
206
|
|
|
242
207
|
/**
|
|
@@ -29,6 +29,7 @@ import type {
|
|
|
29
29
|
NotificationSignal,
|
|
30
30
|
NotificationSourceEventName,
|
|
31
31
|
} from "./signal.js";
|
|
32
|
+
import { parseTrustedContactDecisionPayload } from "./trusted-contact-payloads.js";
|
|
32
33
|
import type { NotificationChannel, RenderedChannelCopy } from "./types.js";
|
|
33
34
|
|
|
34
35
|
type CopyTemplate = (payload: Record<string, unknown>) => RenderedChannelCopy;
|
|
@@ -52,6 +53,35 @@ export function deriveTitle(body: string): string {
|
|
|
52
53
|
: candidate.trim();
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Build a display label for a trusted-contact actor (requester or decider),
|
|
58
|
+
* preferring the display name, then a Slack `<@id>` mention for raw Slack user
|
|
59
|
+
* IDs, then the raw id, then a generic fallback. The result is sanitized for
|
|
60
|
+
* safe inclusion in notification copy.
|
|
61
|
+
*/
|
|
62
|
+
function formatTrustedContactActor(
|
|
63
|
+
displayName: string | null | undefined,
|
|
64
|
+
externalUserId: string | null | undefined,
|
|
65
|
+
sourceChannel: string | null | undefined,
|
|
66
|
+
fallback: string,
|
|
67
|
+
): string {
|
|
68
|
+
const name =
|
|
69
|
+
typeof displayName === "string" && displayName.length > 0
|
|
70
|
+
? displayName
|
|
71
|
+
: undefined;
|
|
72
|
+
const slackMention =
|
|
73
|
+
sourceChannel === "slack" &&
|
|
74
|
+
typeof externalUserId === "string" &&
|
|
75
|
+
/^U[A-Z0-9]+$/i.test(externalUserId)
|
|
76
|
+
? `<@${externalUserId}>`
|
|
77
|
+
: undefined;
|
|
78
|
+
const rawId =
|
|
79
|
+
typeof externalUserId === "string" && externalUserId.length > 0
|
|
80
|
+
? externalUserId
|
|
81
|
+
: undefined;
|
|
82
|
+
return sanitizeIdentityField(name ?? slackMention ?? rawId ?? fallback);
|
|
83
|
+
}
|
|
84
|
+
|
|
55
85
|
// Templates keyed by dot-separated sourceEventName strings matching producers.
|
|
56
86
|
const TEMPLATES: Partial<Record<NotificationSourceEventName, CopyTemplate>> = {
|
|
57
87
|
"schedule.notify": (payload) => ({
|
|
@@ -168,53 +198,20 @@ const TEMPLATES: Partial<Record<NotificationSourceEventName, CopyTemplate>> = {
|
|
|
168
198
|
},
|
|
169
199
|
|
|
170
200
|
"ingress.trusted_contact.guardian_decision": (payload) => {
|
|
171
|
-
const
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const requesterDisplayName =
|
|
178
|
-
typeof payload.requesterDisplayName === "string" &&
|
|
179
|
-
payload.requesterDisplayName.length > 0
|
|
180
|
-
? payload.requesterDisplayName
|
|
181
|
-
: undefined;
|
|
182
|
-
const requesterExternalUserId =
|
|
183
|
-
typeof payload.requesterExternalUserId === "string" &&
|
|
184
|
-
payload.requesterExternalUserId.length > 0
|
|
185
|
-
? payload.requesterExternalUserId
|
|
186
|
-
: undefined;
|
|
187
|
-
const requesterLabel = sanitizeIdentityField(
|
|
188
|
-
requesterDisplayName ??
|
|
189
|
-
(sourceChannel === "slack" &&
|
|
190
|
-
requesterExternalUserId &&
|
|
191
|
-
/^U[A-Z0-9]+$/i.test(requesterExternalUserId)
|
|
192
|
-
? `<@${requesterExternalUserId}>`
|
|
193
|
-
: requesterExternalUserId) ??
|
|
194
|
-
"Someone",
|
|
201
|
+
const parsed = parseTrustedContactDecisionPayload(payload);
|
|
202
|
+
const requesterLabel = formatTrustedContactActor(
|
|
203
|
+
parsed?.requesterDisplayName,
|
|
204
|
+
parsed?.requesterExternalUserId,
|
|
205
|
+
parsed?.sourceChannel,
|
|
206
|
+
"Someone",
|
|
195
207
|
);
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
: undefined;
|
|
202
|
-
const decidedByExternalUserId =
|
|
203
|
-
typeof payload.decidedByExternalUserId === "string" &&
|
|
204
|
-
payload.decidedByExternalUserId.length > 0
|
|
205
|
-
? payload.decidedByExternalUserId
|
|
206
|
-
: undefined;
|
|
207
|
-
const decidedByLabel = sanitizeIdentityField(
|
|
208
|
-
decidedByDisplayName ??
|
|
209
|
-
(sourceChannel === "slack" &&
|
|
210
|
-
decidedByExternalUserId &&
|
|
211
|
-
/^U[A-Z0-9]+$/i.test(decidedByExternalUserId)
|
|
212
|
-
? `<@${decidedByExternalUserId}>`
|
|
213
|
-
: decidedByExternalUserId) ??
|
|
214
|
-
"a guardian",
|
|
208
|
+
const decidedByLabel = formatTrustedContactActor(
|
|
209
|
+
parsed?.decidedByDisplayName,
|
|
210
|
+
parsed?.decidedByExternalUserId,
|
|
211
|
+
parsed?.sourceChannel,
|
|
212
|
+
"a guardian",
|
|
215
213
|
);
|
|
216
|
-
|
|
217
|
-
const verb = decision === "approved" ? "approved" : "denied";
|
|
214
|
+
const verb = parsed?.decision === "approved" ? "approved" : "denied";
|
|
218
215
|
return {
|
|
219
216
|
title: "Trusted Contact Decision",
|
|
220
217
|
body: `${requesterLabel}'s access request has been ${verb} by ${decidedByLabel}.`,
|
|
@@ -222,29 +219,12 @@ const TEMPLATES: Partial<Record<NotificationSourceEventName, CopyTemplate>> = {
|
|
|
222
219
|
},
|
|
223
220
|
|
|
224
221
|
"ingress.trusted_contact.denied": (payload) => {
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
typeof payload.requesterDisplayName === "string" &&
|
|
232
|
-
payload.requesterDisplayName.length > 0
|
|
233
|
-
? payload.requesterDisplayName
|
|
234
|
-
: undefined;
|
|
235
|
-
const requesterExternalUserId =
|
|
236
|
-
typeof payload.requesterExternalUserId === "string" &&
|
|
237
|
-
payload.requesterExternalUserId.length > 0
|
|
238
|
-
? payload.requesterExternalUserId
|
|
239
|
-
: undefined;
|
|
240
|
-
const requesterLabel = sanitizeIdentityField(
|
|
241
|
-
requesterDisplayName ??
|
|
242
|
-
(sourceChannel === "slack" &&
|
|
243
|
-
requesterExternalUserId &&
|
|
244
|
-
/^U[A-Z0-9]+$/i.test(requesterExternalUserId)
|
|
245
|
-
? `<@${requesterExternalUserId}>`
|
|
246
|
-
: requesterExternalUserId) ??
|
|
247
|
-
"Someone",
|
|
222
|
+
const parsed = parseTrustedContactDecisionPayload(payload);
|
|
223
|
+
const requesterLabel = formatTrustedContactActor(
|
|
224
|
+
parsed?.requesterDisplayName,
|
|
225
|
+
parsed?.requesterExternalUserId,
|
|
226
|
+
parsed?.sourceChannel,
|
|
227
|
+
"Someone",
|
|
248
228
|
);
|
|
249
229
|
|
|
250
230
|
return {
|
|
@@ -3,8 +3,13 @@
|
|
|
3
3
|
*
|
|
4
4
|
* These checks run after the decision engine produces a NotificationDecision
|
|
5
5
|
* and before the broadcaster dispatches. They enforce hard invariants that
|
|
6
|
-
* the LLM cannot override: channel availability,
|
|
7
|
-
*
|
|
6
|
+
* the LLM cannot override: channel availability, deduplication, schema
|
|
7
|
+
* validity, and rendered-copy quality.
|
|
8
|
+
*
|
|
9
|
+
* Source-active suppression is also a hard invariant, but it depends only on
|
|
10
|
+
* the signal — not on the decision — so `emitNotificationSignal` runs it as a
|
|
11
|
+
* pre-decision gate, short-circuiting before the expensive LLM stage rather
|
|
12
|
+
* than discarding the decision after it. See `checkSourceActiveSuppression`.
|
|
8
13
|
*/
|
|
9
14
|
|
|
10
15
|
import { and, eq } from "drizzle-orm";
|
|
@@ -52,17 +57,7 @@ export async function runDeterministicChecks(
|
|
|
52
57
|
return schemaCheck;
|
|
53
58
|
}
|
|
54
59
|
|
|
55
|
-
// Check 2:
|
|
56
|
-
const sourceActiveCheck = checkSourceActiveSuppression(signal);
|
|
57
|
-
if (!sourceActiveCheck.passed) {
|
|
58
|
-
log.info(
|
|
59
|
-
{ signalId: signal.signalId, reason: sourceActiveCheck.reason },
|
|
60
|
-
"Deterministic check failed: source active",
|
|
61
|
-
);
|
|
62
|
-
return sourceActiveCheck;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Check 3: Channel availability
|
|
60
|
+
// Check 2: Channel availability
|
|
66
61
|
const channelCheck = checkChannelAvailability(
|
|
67
62
|
decision,
|
|
68
63
|
context.connectedChannels,
|
|
@@ -75,7 +70,7 @@ export async function runDeterministicChecks(
|
|
|
75
70
|
return channelCheck;
|
|
76
71
|
}
|
|
77
72
|
|
|
78
|
-
// Check
|
|
73
|
+
// Check 3: Dedupe
|
|
79
74
|
const dedupeCheck = checkDedupe(
|
|
80
75
|
signal,
|
|
81
76
|
decision,
|
|
@@ -89,7 +84,7 @@ export async function runDeterministicChecks(
|
|
|
89
84
|
return dedupeCheck;
|
|
90
85
|
}
|
|
91
86
|
|
|
92
|
-
// Check
|
|
87
|
+
// Check 4: Rendered copy quality (fail-closed)
|
|
93
88
|
const copyCheck = checkRenderedCopyQuality(signal, decision);
|
|
94
89
|
if (!copyCheck.passed) {
|
|
95
90
|
log.info(
|
|
@@ -151,8 +146,16 @@ function checkDecisionSchema(decision: NotificationDecision): CheckResult {
|
|
|
151
146
|
/**
|
|
152
147
|
* If the user is already looking at the source context (visibleInSourceNow),
|
|
153
148
|
* suppress the notification to avoid redundant alerts.
|
|
149
|
+
*
|
|
150
|
+
* This depends only on the signal, not on the decision, so the outcome is
|
|
151
|
+
* knowable before the decision engine runs. `emitNotificationSignal` calls it
|
|
152
|
+
* as a pre-decision gate to short-circuit statically-suppressed signals
|
|
153
|
+
* (e.g. trusted-contact `verification_sent`) before paying for an LLM
|
|
154
|
+
* inference whose result would be discarded. Exported for that caller.
|
|
154
155
|
*/
|
|
155
|
-
function checkSourceActiveSuppression(
|
|
156
|
+
export function checkSourceActiveSuppression(
|
|
157
|
+
signal: NotificationSignal,
|
|
158
|
+
): CheckResult {
|
|
156
159
|
if (signal.attentionHints.visibleInSourceNow) {
|
|
157
160
|
return {
|
|
158
161
|
passed: false,
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
import { enforceRoutingIntent, evaluateSignal } from "./decision-engine.js";
|
|
28
28
|
import { updateDecision } from "./decisions-store.js";
|
|
29
29
|
import {
|
|
30
|
+
checkSourceActiveSuppression,
|
|
30
31
|
type DeterministicCheckContext,
|
|
31
32
|
runDeterministicChecks,
|
|
32
33
|
} from "./deterministic-checks.js";
|
|
@@ -209,7 +210,12 @@ export interface EmitSignalResult {
|
|
|
209
210
|
|
|
210
211
|
/**
|
|
211
212
|
* Emit a notification signal through the full pipeline:
|
|
212
|
-
* createEvent ->
|
|
213
|
+
* createEvent -> (source-active pre-gate) -> evaluateSignal ->
|
|
214
|
+
* runDeterministicChecks -> dispatchDecision.
|
|
215
|
+
*
|
|
216
|
+
* Source-active suppression runs before the decision engine: it depends only
|
|
217
|
+
* on the signal, so a statically-suppressed signal short-circuits here without
|
|
218
|
+
* paying for an LLM inference whose result would be discarded downstream.
|
|
213
219
|
*
|
|
214
220
|
* Fire-and-forget safe by default: errors are caught and logged unless
|
|
215
221
|
* `throwOnError` is enabled by the caller.
|
|
@@ -261,6 +267,28 @@ export async function emitNotificationSignal<TEventName extends string>(
|
|
|
261
267
|
};
|
|
262
268
|
}
|
|
263
269
|
|
|
270
|
+
// Step 1.5: Source-active pre-gate. visibleInSourceNow is a hard invariant
|
|
271
|
+
// the decision engine cannot override, and it depends only on the signal —
|
|
272
|
+
// so when it is set, the outcome is predetermined: suppress. Short-circuit
|
|
273
|
+
// before the (LLM-backed) decision stage so statically-suppressed signals
|
|
274
|
+
// (e.g. trusted-contact verification_sent) never incur an inference, a
|
|
275
|
+
// discarded decision row, or an LLM-dependent home-feed mirror. The event
|
|
276
|
+
// row persisted above preserves the lifecycle/audit trail.
|
|
277
|
+
const sourceActiveCheck = checkSourceActiveSuppression(signal);
|
|
278
|
+
if (!sourceActiveCheck.passed) {
|
|
279
|
+
log.info(
|
|
280
|
+
{ signalId, reason: sourceActiveCheck.reason },
|
|
281
|
+
"Signal suppressed before decision stage (source-active)",
|
|
282
|
+
);
|
|
283
|
+
return {
|
|
284
|
+
signalId,
|
|
285
|
+
deduplicated: false,
|
|
286
|
+
dispatched: false,
|
|
287
|
+
reason: `Signal suppressed: ${sourceActiveCheck.reason}`,
|
|
288
|
+
deliveryResults: [],
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
264
292
|
// Step 2: Evaluate the signal through the decision engine
|
|
265
293
|
const connectedChannels = getConnectedChannels();
|
|
266
294
|
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed context payloads for the trusted-contact lifecycle notification signals.
|
|
3
|
+
*
|
|
4
|
+
* These `ingress.trusted_contact.*` signals are emitted from the canonical
|
|
5
|
+
* resolver (`approvals/guardian-request-resolvers.ts`), and the decision
|
|
6
|
+
* payload is read back by the notification copy-composer. A single zod schema
|
|
7
|
+
* is the source of truth for both sides, so the producer cannot drift from the
|
|
8
|
+
* consumer.
|
|
9
|
+
*
|
|
10
|
+
* Identity fields are nullable: producers populate them (using "" for an
|
|
11
|
+
* unknown id), but a payload read back off persisted JSON may legitimately
|
|
12
|
+
* carry a null/absent identity, and the copy-composer degrades per-field. Only
|
|
13
|
+
* `sourceChannel` and `decision` are strict — they gate routing and rendering.
|
|
14
|
+
*
|
|
15
|
+
* Shapes are zod schemas (single source of truth for runtime validation and
|
|
16
|
+
* TypeScript types), matching the `guardian.question` payload pattern.
|
|
17
|
+
* https://zod.dev/?id=basic-usage
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { z } from "zod";
|
|
21
|
+
|
|
22
|
+
import { NotificationSourceChannelSchema } from "./signal.js";
|
|
23
|
+
|
|
24
|
+
/** Identity fields shared by every trusted-contact lifecycle payload. */
|
|
25
|
+
const TrustedContactIdentitySchema = z.object({
|
|
26
|
+
sourceChannel: NotificationSourceChannelSchema,
|
|
27
|
+
requesterExternalUserId: z.string().nullable(),
|
|
28
|
+
requesterChatId: z.string().nullable(),
|
|
29
|
+
requesterDisplayName: z.string().nullable(),
|
|
30
|
+
decidedByDisplayName: z.string().nullable(),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Payload for `ingress.trusted_contact.guardian_decision` and
|
|
35
|
+
* `ingress.trusted_contact.denied` — the guardian's verdict on an access
|
|
36
|
+
* request. The deny path emits both events from one object; the approve path
|
|
37
|
+
* emits `guardian_decision` with `decision: "approved"` (identical shape).
|
|
38
|
+
*/
|
|
39
|
+
export const TrustedContactDecisionPayloadSchema =
|
|
40
|
+
TrustedContactIdentitySchema.extend({
|
|
41
|
+
decidedByExternalUserId: z.string().nullable(),
|
|
42
|
+
decision: z.enum(["approved", "denied"]),
|
|
43
|
+
});
|
|
44
|
+
export type TrustedContactDecisionPayload = z.infer<
|
|
45
|
+
typeof TrustedContactDecisionPayloadSchema
|
|
46
|
+
>;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Payload for `ingress.trusted_contact.verification_sent` — the verification
|
|
50
|
+
* code was minted and delivered. Carries the session id; no `decision`.
|
|
51
|
+
*/
|
|
52
|
+
export const TrustedContactVerificationSentPayloadSchema =
|
|
53
|
+
TrustedContactIdentitySchema.extend({
|
|
54
|
+
verificationSessionId: z.string(),
|
|
55
|
+
});
|
|
56
|
+
export type TrustedContactVerificationSentPayload = z.infer<
|
|
57
|
+
typeof TrustedContactVerificationSentPayloadSchema
|
|
58
|
+
>;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Parse an unknown context payload as a trusted-contact decision payload.
|
|
62
|
+
* Returns the typed payload on success, or `null` when the shape doesn't match
|
|
63
|
+
* — the copy-composer falls back to generic copy in that case.
|
|
64
|
+
*/
|
|
65
|
+
export function parseTrustedContactDecisionPayload(
|
|
66
|
+
payload: Record<string, unknown>,
|
|
67
|
+
): TrustedContactDecisionPayload | null {
|
|
68
|
+
const result = TrustedContactDecisionPayloadSchema.safeParse(payload);
|
|
69
|
+
return result.success ? result.data : null;
|
|
70
|
+
}
|
|
@@ -113,6 +113,15 @@ mock.module("./oauth-store.js", () => ({
|
|
|
113
113
|
if (opts?.account && conn.accountInfo !== opts.account) return undefined;
|
|
114
114
|
return conn;
|
|
115
115
|
},
|
|
116
|
+
getActiveConnections: (
|
|
117
|
+
service: string,
|
|
118
|
+
opts?: { clientId?: string; account?: string },
|
|
119
|
+
) => {
|
|
120
|
+
const conn = mockConnections.get(service);
|
|
121
|
+
if (!conn) return [];
|
|
122
|
+
if (opts?.account && conn.accountInfo !== opts.account) return [];
|
|
123
|
+
return [conn];
|
|
124
|
+
},
|
|
116
125
|
getConnection: (id: string) => {
|
|
117
126
|
for (const conn of mockConnections.values()) {
|
|
118
127
|
if (conn.id === id) return conn;
|