@vellumai/assistant 0.10.0 → 0.10.1-dev.202606240317.ea25efe
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +36 -37
- package/bun.lock +3 -0
- package/docs/workflows.md +12 -7
- package/eslint-rules/cli-no-daemon-internals.js +12 -0
- package/node_modules/@slack/types/LICENSE +23 -0
- package/node_modules/@slack/types/README.md +32 -0
- package/node_modules/@slack/types/dist/block-kit/block-elements.d.ts +953 -0
- package/node_modules/@slack/types/dist/block-kit/block-elements.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/block-elements.js +4 -0
- package/node_modules/@slack/types/dist/block-kit/block-elements.js.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/blocks.d.ts +474 -0
- package/node_modules/@slack/types/dist/block-kit/blocks.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/blocks.js +3 -0
- package/node_modules/@slack/types/dist/block-kit/blocks.js.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/composition-objects.d.ts +237 -0
- package/node_modules/@slack/types/dist/block-kit/composition-objects.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/composition-objects.js +4 -0
- package/node_modules/@slack/types/dist/block-kit/composition-objects.js.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/extensions.d.ts +88 -0
- package/node_modules/@slack/types/dist/block-kit/extensions.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/block-kit/extensions.js +3 -0
- package/node_modules/@slack/types/dist/block-kit/extensions.js.map +1 -0
- package/node_modules/@slack/types/dist/calls.d.ts +26 -0
- package/node_modules/@slack/types/dist/calls.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/calls.js +6 -0
- package/node_modules/@slack/types/dist/calls.js.map +1 -0
- package/node_modules/@slack/types/dist/chunk.d.ts +52 -0
- package/node_modules/@slack/types/dist/chunk.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/chunk.js +3 -0
- package/node_modules/@slack/types/dist/chunk.js.map +1 -0
- package/node_modules/@slack/types/dist/common/bot-profile.d.ts +12 -0
- package/node_modules/@slack/types/dist/common/bot-profile.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/common/bot-profile.js +3 -0
- package/node_modules/@slack/types/dist/common/bot-profile.js.map +1 -0
- package/node_modules/@slack/types/dist/common/status-emoji-display-info.d.ts +6 -0
- package/node_modules/@slack/types/dist/common/status-emoji-display-info.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/common/status-emoji-display-info.js +3 -0
- package/node_modules/@slack/types/dist/common/status-emoji-display-info.js.map +1 -0
- package/node_modules/@slack/types/dist/dialog.d.ts +36 -0
- package/node_modules/@slack/types/dist/dialog.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/dialog.js +3 -0
- package/node_modules/@slack/types/dist/dialog.js.map +1 -0
- package/node_modules/@slack/types/dist/events/app.d.ts +204 -0
- package/node_modules/@slack/types/dist/events/app.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/app.js +3 -0
- package/node_modules/@slack/types/dist/events/app.js.map +1 -0
- package/node_modules/@slack/types/dist/events/assistant.d.ts +29 -0
- package/node_modules/@slack/types/dist/events/assistant.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/assistant.js +3 -0
- package/node_modules/@slack/types/dist/events/assistant.js.map +1 -0
- package/node_modules/@slack/types/dist/events/call.d.ts +8 -0
- package/node_modules/@slack/types/dist/events/call.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/call.js +3 -0
- package/node_modules/@slack/types/dist/events/call.js.map +1 -0
- package/node_modules/@slack/types/dist/events/channel.d.ts +85 -0
- package/node_modules/@slack/types/dist/events/channel.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/channel.js +3 -0
- package/node_modules/@slack/types/dist/events/channel.js.map +1 -0
- package/node_modules/@slack/types/dist/events/dnd.d.ts +24 -0
- package/node_modules/@slack/types/dist/events/dnd.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/dnd.js +3 -0
- package/node_modules/@slack/types/dist/events/dnd.js.map +1 -0
- package/node_modules/@slack/types/dist/events/email.d.ts +6 -0
- package/node_modules/@slack/types/dist/events/email.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/email.js +3 -0
- package/node_modules/@slack/types/dist/events/email.js.map +1 -0
- package/node_modules/@slack/types/dist/events/emoji.d.ts +11 -0
- package/node_modules/@slack/types/dist/events/emoji.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/emoji.js +3 -0
- package/node_modules/@slack/types/dist/events/emoji.js.map +1 -0
- package/node_modules/@slack/types/dist/events/entity-details-requested.d.ts +21 -0
- package/node_modules/@slack/types/dist/events/entity-details-requested.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/entity-details-requested.js +3 -0
- package/node_modules/@slack/types/dist/events/entity-details-requested.js.map +1 -0
- package/node_modules/@slack/types/dist/events/file.d.ts +60 -0
- package/node_modules/@slack/types/dist/events/file.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/file.js +4 -0
- package/node_modules/@slack/types/dist/events/file.js.map +1 -0
- package/node_modules/@slack/types/dist/events/function.d.ts +33 -0
- package/node_modules/@slack/types/dist/events/function.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/function.js +3 -0
- package/node_modules/@slack/types/dist/events/function.js.map +1 -0
- package/node_modules/@slack/types/dist/events/grid-migration.d.ts +9 -0
- package/node_modules/@slack/types/dist/events/grid-migration.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/grid-migration.js +3 -0
- package/node_modules/@slack/types/dist/events/grid-migration.js.map +1 -0
- package/node_modules/@slack/types/dist/events/group.d.ts +55 -0
- package/node_modules/@slack/types/dist/events/group.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/group.js +3 -0
- package/node_modules/@slack/types/dist/events/group.js.map +1 -0
- package/node_modules/@slack/types/dist/events/im.d.ts +26 -0
- package/node_modules/@slack/types/dist/events/im.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/im.js +3 -0
- package/node_modules/@slack/types/dist/events/im.js.map +1 -0
- package/node_modules/@slack/types/dist/events/index.d.ts +60 -0
- package/node_modules/@slack/types/dist/events/index.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/index.js +43 -0
- package/node_modules/@slack/types/dist/events/index.js.map +1 -0
- package/node_modules/@slack/types/dist/events/invite.d.ts +20 -0
- package/node_modules/@slack/types/dist/events/invite.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/invite.js +3 -0
- package/node_modules/@slack/types/dist/events/invite.js.map +1 -0
- package/node_modules/@slack/types/dist/events/link-shared.d.ts +16 -0
- package/node_modules/@slack/types/dist/events/link-shared.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/link-shared.js +3 -0
- package/node_modules/@slack/types/dist/events/link-shared.js.map +1 -0
- package/node_modules/@slack/types/dist/events/member.d.ts +19 -0
- package/node_modules/@slack/types/dist/events/member.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/member.js +3 -0
- package/node_modules/@slack/types/dist/events/member.js.map +1 -0
- package/node_modules/@slack/types/dist/events/message-metadata.d.ts +38 -0
- package/node_modules/@slack/types/dist/events/message-metadata.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/message-metadata.js +3 -0
- package/node_modules/@slack/types/dist/events/message-metadata.js.map +1 -0
- package/node_modules/@slack/types/dist/events/message.d.ts +306 -0
- package/node_modules/@slack/types/dist/events/message.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/message.js +3 -0
- package/node_modules/@slack/types/dist/events/message.js.map +1 -0
- package/node_modules/@slack/types/dist/events/pin.d.ts +60 -0
- package/node_modules/@slack/types/dist/events/pin.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/pin.js +3 -0
- package/node_modules/@slack/types/dist/events/pin.js.map +1 -0
- package/node_modules/@slack/types/dist/events/reaction.d.ts +23 -0
- package/node_modules/@slack/types/dist/events/reaction.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/reaction.js +3 -0
- package/node_modules/@slack/types/dist/events/reaction.js.map +1 -0
- package/node_modules/@slack/types/dist/events/shared-channel.d.ts +134 -0
- package/node_modules/@slack/types/dist/events/shared-channel.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/shared-channel.js +3 -0
- package/node_modules/@slack/types/dist/events/shared-channel.js.map +1 -0
- package/node_modules/@slack/types/dist/events/star.d.ts +13 -0
- package/node_modules/@slack/types/dist/events/star.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/star.js +3 -0
- package/node_modules/@slack/types/dist/events/star.js.map +1 -0
- package/node_modules/@slack/types/dist/events/steps-from-apps.d.ts +82 -0
- package/node_modules/@slack/types/dist/events/steps-from-apps.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/steps-from-apps.js +3 -0
- package/node_modules/@slack/types/dist/events/steps-from-apps.js.map +1 -0
- package/node_modules/@slack/types/dist/events/subteam.d.ts +66 -0
- package/node_modules/@slack/types/dist/events/subteam.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/subteam.js +3 -0
- package/node_modules/@slack/types/dist/events/subteam.js.map +1 -0
- package/node_modules/@slack/types/dist/events/team.d.ts +99 -0
- package/node_modules/@slack/types/dist/events/team.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/team.js +3 -0
- package/node_modules/@slack/types/dist/events/team.js.map +1 -0
- package/node_modules/@slack/types/dist/events/token.d.ts +8 -0
- package/node_modules/@slack/types/dist/events/token.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/token.js +3 -0
- package/node_modules/@slack/types/dist/events/token.js.map +1 -0
- package/node_modules/@slack/types/dist/events/user.d.ts +313 -0
- package/node_modules/@slack/types/dist/events/user.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/events/user.js +3 -0
- package/node_modules/@slack/types/dist/events/user.js.map +1 -0
- package/node_modules/@slack/types/dist/index.d.ts +12 -0
- package/node_modules/@slack/types/dist/index.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/index.js +28 -0
- package/node_modules/@slack/types/dist/index.js.map +1 -0
- package/node_modules/@slack/types/dist/message-attachments.d.ts +171 -0
- package/node_modules/@slack/types/dist/message-attachments.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/message-attachments.js +3 -0
- package/node_modules/@slack/types/dist/message-attachments.js.map +1 -0
- package/node_modules/@slack/types/dist/message-metadata.d.ts +281 -0
- package/node_modules/@slack/types/dist/message-metadata.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/message-metadata.js +27 -0
- package/node_modules/@slack/types/dist/message-metadata.js.map +1 -0
- package/node_modules/@slack/types/dist/views.d.ts +71 -0
- package/node_modules/@slack/types/dist/views.d.ts.map +1 -0
- package/node_modules/@slack/types/dist/views.js +3 -0
- package/node_modules/@slack/types/dist/views.js.map +1 -0
- package/node_modules/@slack/types/package.json +47 -0
- package/node_modules/@vellumai/gateway-client/bun.lock +3 -0
- package/node_modules/@vellumai/gateway-client/package.json +1 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +69 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +91 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +96 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +162 -0
- package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +48 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +8 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +28 -0
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +4 -2
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +3 -2
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +95 -0
- package/openapi.yaml +458 -18
- package/package.json +2 -1
- package/scripts/memory-inspect.ts +24 -14
- package/scripts/test.sh +36 -15
- package/src/__tests__/access-request-seed-content-blocks.test.ts +83 -103
- package/src/__tests__/activation-early-marking.test.ts +1 -1
- package/src/__tests__/actor-token-service.test.ts +39 -17
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +1 -40
- package/src/__tests__/agent-loop-compaction-events.test.ts +0 -1
- package/src/__tests__/agent-loop-compaction-strip.test.ts +0 -1
- package/src/__tests__/agent-loop-exit-reason.test.ts +0 -1
- package/src/__tests__/agent-loop-pushes-post-hook-prompt.test.ts +306 -0
- package/src/__tests__/agent-loop-regrowth-guard.test.ts +0 -1
- package/src/__tests__/agent-loop.test.ts +3 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +2 -0
- package/src/__tests__/anthropic-provider.test.ts +210 -9
- package/src/__tests__/app-builder-skill-instructions.test.ts +47 -5
- package/src/__tests__/app-conversation-ids-backfill.test.ts +1 -1
- package/src/__tests__/app-source-watcher.test.ts +30 -10
- package/src/__tests__/approval-cascade.test.ts +6 -0
- package/src/__tests__/approval-interception-trust-gates.test.ts +151 -0
- package/src/__tests__/approval-primitive.test.ts +1 -1
- package/src/__tests__/approval-routes-http.test.ts +1 -1
- package/src/__tests__/assistant-attachments.test.ts +155 -0
- package/src/__tests__/assistant-event-hub-machine-name.test.ts +2 -4
- package/src/__tests__/assistant-events-sse-hardening.test.ts +1 -1
- package/src/__tests__/assistant-events-sse-shed.test.ts +1 -1
- package/src/__tests__/attachment-upload-trusted-source.test.ts +13 -8
- package/src/__tests__/attachments-store.test.ts +1 -1
- package/src/__tests__/audit-log-rotation.test.ts +50 -54
- package/src/__tests__/auth-fallback-events-store.test.ts +1 -1
- package/src/__tests__/auto-analysis-end-to-end.test.ts +9 -14
- package/src/__tests__/background-shell-bash.test.ts +4 -1
- package/src/__tests__/background-shell-host-bash.test.ts +17 -3
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -0
- package/src/__tests__/call-controller.test.ts +20 -1
- package/src/__tests__/call-conversation-messages.test.ts +1 -1
- package/src/__tests__/call-domain.test.ts +1 -1
- package/src/__tests__/call-pointer-messages.test.ts +3 -4
- package/src/__tests__/call-recovery.test.ts +1 -1
- package/src/__tests__/call-routes-http.test.ts +1 -1
- package/src/__tests__/call-store.test.ts +1 -1
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
- package/src/__tests__/canonical-guardian-store.test.ts +24 -1
- package/src/__tests__/card-surface-data.test.ts +60 -0
- package/src/__tests__/channel-approval-routes.test.ts +73 -1119
- package/src/__tests__/channel-delivery-store.test.ts +1 -1
- package/src/__tests__/channel-guardian.test.ts +291 -641
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +1 -2
- package/src/__tests__/channel-retry-sweep.test.ts +1 -1
- package/src/__tests__/compaction-events.test.ts +6 -0
- package/src/__tests__/compaction-trail-store.test.ts +6 -5
- package/src/__tests__/compaction.benchmark.test.ts +0 -1
- package/src/__tests__/compactor-image-manifest-trust.test.ts +1 -1
- package/src/__tests__/config-loader-backfill.test.ts +188 -52
- package/src/__tests__/config-schema.test.ts +35 -0
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +1 -2
- package/src/__tests__/contact-store-user-file.test.ts +2 -2
- package/src/__tests__/contacts-relay-reads.test.ts +409 -0
- package/src/__tests__/contacts-tools.test.ts +4 -4
- package/src/__tests__/contacts-write.test.ts +1 -2
- package/src/__tests__/context-search-conversations-source.test.ts +1 -1
- package/src/__tests__/context-window-manager-compact-retry.test.ts +6 -2
- package/src/__tests__/context-window-manager-overflow-rung.test.ts +6 -2
- package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +3 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +3 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +3 -0
- package/src/__tests__/conversation-agent-loop.test.ts +7 -0
- package/src/__tests__/conversation-attachments.test.ts +2 -5
- package/src/__tests__/conversation-attention-store.test.ts +1 -1
- package/src/__tests__/conversation-attention-telegram.test.ts +1 -2
- package/src/__tests__/conversation-clear-safety.test.ts +1 -1
- package/src/__tests__/conversation-confirmation-signals.test.ts +6 -0
- package/src/__tests__/conversation-crud-inference-profile.test.ts +1 -1
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +12 -19
- package/src/__tests__/conversation-disk-view-integration.test.ts +1 -1
- package/src/__tests__/conversation-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-fork-crud.test.ts +10 -8
- package/src/__tests__/conversation-fork-retrospective.test.ts +250 -0
- package/src/__tests__/conversation-fork-route.test.ts +1 -1
- package/src/__tests__/conversation-inference-profile-list.test.ts +1 -1
- package/src/__tests__/conversation-inference-profile-route.test.ts +1 -1
- package/src/__tests__/conversation-init.benchmark.test.ts +1 -1
- package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-lifecycle.test.ts +117 -0
- package/src/__tests__/conversation-list-source.test.ts +3 -3
- package/src/__tests__/conversation-process-callsite.test.ts +6 -14
- package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
- package/src/__tests__/conversation-queue.test.ts +95 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +12 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +12 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +115 -12
- package/src/__tests__/conversation-slash-queue.test.ts +6 -0
- package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
- package/src/__tests__/conversation-speed-override.test.ts +6 -0
- package/src/__tests__/conversation-starter-routes.test.ts +5 -5
- package/src/__tests__/conversation-store.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +4 -4
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +352 -0
- package/src/__tests__/conversation-sync-tags.test.ts +1 -1
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +47 -0
- package/src/__tests__/conversation-usage.test.ts +1 -1
- package/src/__tests__/conversation-wipe.test.ts +9 -8
- package/src/__tests__/conversation-workspace-cache-state.test.ts +6 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
- package/src/__tests__/conversations-import-system-filter.test.ts +1 -1
- package/src/__tests__/copy-composer-tc-templates.test.ts +17 -0
- package/src/__tests__/credential-security-invariants.test.ts +0 -1
- package/src/__tests__/db-acp-history.test.ts +2 -2
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +5 -7
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +6 -7
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +5 -10
- package/src/__tests__/db-migration-rollback.test.ts +129 -39
- package/src/__tests__/db-proxy-transaction.test.ts +1 -1
- package/src/__tests__/db-schedule-syntax-migration.test.ts +0 -11
- package/src/__tests__/db-test-helpers.ts +36 -19
- package/src/__tests__/delete-propagation.test.ts +1 -1
- package/src/__tests__/deterministic-verification-control-plane.test.ts +28 -8
- package/src/__tests__/disk-pressure-guard.test.ts +41 -0
- package/src/__tests__/disk-pressure-tools.test.ts +41 -1
- package/src/__tests__/dm-backfill.test.ts +1 -1
- package/src/__tests__/drop-capability-card-state-migration.test.ts +0 -8
- package/src/__tests__/dynamic-page-surface.test.ts +0 -94
- package/src/__tests__/edit-propagation.test.ts +1 -1
- package/src/__tests__/emit-signal-routing-intent.test.ts +93 -5
- package/src/__tests__/empty-response-hook.test.ts +42 -0
- package/src/__tests__/events-client-registration.test.ts +1 -1
- package/src/__tests__/events-dev-bypass-actor.test.ts +7 -1
- package/src/__tests__/followup-tools.test.ts +1 -1
- package/src/__tests__/gemini-count-tokens.test.ts +70 -0
- package/src/__tests__/guardian-action-sweep.test.ts +9 -2
- package/src/__tests__/guardian-binding-drift-heal.test.ts +76 -11
- package/src/__tests__/guardian-card-withdrawal.test.ts +1 -1
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +1 -1
- package/src/__tests__/guardian-dispatch.test.ts +96 -2
- package/src/__tests__/guardian-outbound-http.test.ts +20 -12
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
- package/src/__tests__/guardian-routing-state.test.ts +1 -2
- package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -1
- package/src/__tests__/headless-browser-mode.test.ts +2 -2
- package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
- package/src/__tests__/heartbeat-service.test.ts +6 -0
- package/src/__tests__/helpers/channel-test-adapter.ts +92 -0
- package/src/__tests__/host-app-control-routes.test.ts +24 -30
- package/src/__tests__/host-bash-routes.test.ts +31 -41
- package/src/__tests__/host-browser-routes.test.ts +26 -32
- package/src/__tests__/host-cu-routes-targeted.test.ts +25 -33
- package/src/__tests__/host-file-routes-targeted.test.ts +40 -52
- package/src/__tests__/host-transfer-routes-targeted.test.ts +31 -43
- package/src/__tests__/http-conversation-lineage.test.ts +1 -1
- package/src/__tests__/http-user-message-parity.test.ts +165 -8
- package/src/__tests__/image-recovery-hook.test.ts +1 -1
- package/src/__tests__/inbound-invite-redemption.test.ts +1 -2
- package/src/__tests__/inbound-trust-verdict.test.ts +254 -0
- package/src/__tests__/inference-profile-reaper.test.ts +1 -1
- package/src/__tests__/inference-profile-session-handler.test.ts +1 -1
- package/src/__tests__/inference-profile-session-ipc.test.ts +1 -1
- package/src/__tests__/injector-chain.test.ts +1 -1
- package/src/__tests__/injector-disk-pressure.test.ts +11 -6
- package/src/__tests__/internal-telemetry-routes.test.ts +1 -1
- package/src/__tests__/invite-redemption-service.test.ts +244 -43
- package/src/__tests__/invite-routes-http.test.ts +35 -186
- package/src/__tests__/invite-service-ipc.test.ts +287 -0
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +5 -5
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +9 -12
- package/src/__tests__/list-messages-attachments.test.ts +42 -1
- package/src/__tests__/list-messages-client-message-id.test.ts +1 -1
- package/src/__tests__/list-messages-hidden-metadata.test.ts +1 -1
- package/src/__tests__/list-messages-page-latest.test.ts +1 -1
- package/src/__tests__/list-messages-tool-merge.test.ts +1 -1
- package/src/__tests__/llm-context-normalization.test.ts +105 -0
- package/src/__tests__/llm-context-route-provider.test.ts +69 -4
- package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +9 -5
- package/src/__tests__/llm-request-log-call-site.test.ts +6 -6
- package/src/__tests__/llm-request-log-turn-query.test.ts +27 -13
- package/src/__tests__/llm-resolver.test.ts +205 -5
- package/src/__tests__/llm-usage-store.test.ts +65 -1
- package/src/__tests__/log-export-routes.test.ts +1 -1
- package/src/__tests__/log-export-workspace.test.ts +3 -3
- package/src/__tests__/media-stream-server-integration.test.ts +127 -0
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +5 -5
- package/src/__tests__/memory-recall-log-store.test.ts +1 -1
- package/src/__tests__/memory-upsert-concurrency.test.ts +3 -4
- package/src/__tests__/messages-after-tiebreaker.test.ts +1 -1
- package/src/__tests__/migration-import-from-url.test.ts +2 -2
- package/src/__tests__/mtime-cache.test.ts +375 -0
- package/src/__tests__/non-member-access-request.test.ts +190 -19
- package/src/__tests__/notification-broadcaster.test.ts +4 -0
- package/src/__tests__/notification-candidate-guardian-context.test.ts +203 -0
- package/src/__tests__/notification-decision-recipient-context.test.ts +33 -32
- package/src/__tests__/notification-deep-link.test.ts +4 -0
- package/src/__tests__/notification-guardian-path.test.ts +20 -1
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +1 -1
- package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
- package/src/__tests__/oauth-provider-visibility.test.ts +1 -1
- package/src/__tests__/oauth-store.test.ts +1 -1
- package/src/__tests__/pending-interactions-resolved-event.test.ts +7 -4
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +1 -1
- package/src/__tests__/persist-unsendable-image.test.ts +1 -1
- package/src/__tests__/persona-resolver.test.ts +39 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +1 -1
- package/src/__tests__/playbook-execution.test.ts +1 -1
- package/src/__tests__/playbook-tools.test.ts +1 -1
- package/src/__tests__/plugin-api-model-profiles.test.ts +74 -21
- package/src/__tests__/plugin-bootstrap.test.ts +78 -0
- package/src/__tests__/provider-platform-proxy-integration.test.ts +25 -5
- package/src/__tests__/provider-usage-tracking.test.ts +40 -1
- package/src/__tests__/prune-old-conversations-job.test.ts +1 -1
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/registry.test.ts +3 -0
- package/src/__tests__/relay-server.test.ts +1026 -73
- package/src/__tests__/runtime-attachment-metadata.test.ts +9 -1
- package/src/__tests__/runtime-events-sse-bilingual.test.ts +7 -9
- package/src/__tests__/runtime-events-sse-parity.test.ts +1 -1
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +1 -1
- package/src/__tests__/runtime-events-sse.test.ts +1 -1
- package/src/__tests__/schedule-retry.test.ts +1 -1
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +1 -1
- package/src/__tests__/schedule-routes.test.ts +1 -1
- package/src/__tests__/schedule-store.test.ts +1 -1
- package/src/__tests__/schedule-tools.test.ts +1 -1
- package/src/__tests__/scheduler-disk-pressure.test.ts +1 -1
- package/src/__tests__/scheduler-recurrence.test.ts +1 -1
- package/src/__tests__/scheduler-reuse-conversation.test.ts +1 -1
- package/src/__tests__/scheduler-wake.test.ts +2 -1
- package/src/__tests__/scoped-approval-grants.test.ts +1 -1
- package/src/__tests__/scoped-grant-security-matrix.test.ts +5 -5
- package/src/__tests__/scrub-corrupted-image-attachments.test.ts +0 -8
- package/src/__tests__/secret-ingress-http.test.ts +12 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -0
- package/src/__tests__/send-endpoint-busy.test.ts +31 -9
- package/src/__tests__/sequence-store.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +40 -1
- package/src/__tests__/settings-routes.test.ts +11 -10
- package/src/__tests__/skill-load-tool.test.ts +72 -0
- package/src/__tests__/skills.test.ts +44 -0
- package/src/__tests__/slack-inbound-verification.test.ts +48 -5
- package/src/__tests__/slack-messaging-token-resolution.test.ts +13 -2
- package/src/__tests__/slack-reaction-canonical-approval.test.ts +1 -1
- package/src/__tests__/sse-actor-principal-guardian-source.test.ts +102 -0
- package/src/__tests__/steer-on-enqueue-question.test.ts +181 -0
- package/src/__tests__/stt-hints.test.ts +44 -13
- package/src/__tests__/subagent-detail.test.ts +27 -0
- package/src/__tests__/subagent-disposal.test.ts +65 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +2 -73
- package/src/__tests__/subagent-tools.test.ts +1 -31
- package/src/__tests__/system-prompt.test.ts +1 -1
- package/src/__tests__/system-storage-cleanup-skill.test.ts +56 -0
- package/src/__tests__/task-compiler.test.ts +1 -1
- package/src/__tests__/task-management-tools.test.ts +1 -1
- package/src/__tests__/task-memory-cleanup.test.ts +9 -6
- package/src/__tests__/task-scheduler.test.ts +1 -1
- package/src/__tests__/thread-backfill.test.ts +1 -1
- package/src/__tests__/tool-approval-handler.test.ts +1 -1
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +2 -0
- package/src/__tests__/tool-executor.test.ts +37 -1
- package/src/__tests__/tool-grant-request-escalation.test.ts +1 -2
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +73 -1
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +34 -34
- package/src/__tests__/trusted-contact-multichannel.test.ts +1 -2
- package/src/__tests__/trusted-contact-verification.test.ts +1 -1
- package/src/__tests__/turn-boundary-resolution.test.ts +3 -3
- package/src/__tests__/turn-events-store.test.ts +1 -1
- package/src/__tests__/twilio-routes.test.ts +98 -3
- package/src/__tests__/usage-cache-backfill-migration.test.ts +20 -10
- package/src/__tests__/usage-routes.test.ts +1 -1
- package/src/__tests__/user-plugin-loader.test.ts +34 -29
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
- package/src/__tests__/voice-invite-redemption.test.ts +134 -36
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +1 -1
- package/src/__tests__/voice-session-bridge.test.ts +1 -1
- package/src/__tests__/workspace-git-service.test.ts +114 -1
- package/src/__tests__/workspace-heartbeat-service.test.ts +45 -0
- package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +1 -1
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +1 -1
- package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +88 -18
- package/src/__tests__/workspace-migration-108-drop-balanced-economy-profile.test.ts +6 -6
- package/src/__tests__/workspace-migration-109-swap-quality-profile-to-glm-5p2.test.ts +281 -0
- package/src/__tests__/workspace-migration-110-flip-balanced-profile-to-together.test.ts +167 -0
- package/src/__tests__/workspace-migrations-runner.test.ts +55 -0
- package/src/__tests__/workspace-tool-loader.test.ts +3 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +1 -1
- package/src/a2a/__tests__/task-store.test.ts +1 -1
- package/src/acp/__tests__/session-manager-persistence.test.ts +1 -1
- package/src/acp/__tests__/session-manager-resume.test.ts +22 -11
- package/src/acp/__tests__/session-manager-startup.test.ts +1 -1
- package/src/acp/__tests__/session-manager.test.ts +72 -1
- package/src/acp/index.ts +10 -0
- package/src/acp/session-manager.ts +35 -0
- package/src/agent/loop-exclusive-tool.test.ts +150 -0
- package/src/agent/loop.ts +101 -27
- package/src/api/constants/sse-replay.ts +41 -0
- package/src/api/events/ui-surface-show.ts +8 -3
- package/src/api/index.ts +7 -6
- package/src/api/responses/conversation-message.ts +4 -0
- package/src/api/responses/llm-request-log-entry.ts +25 -0
- package/src/api/responses/subagent-detail.ts +17 -0
- package/src/api/surfaces.ts +33 -0
- package/src/approvals/AGENTS.md +1 -2
- package/src/approvals/guardian-decision-primitive.ts +13 -210
- package/src/approvals/guardian-request-resolvers.ts +104 -58
- package/src/background-wake/wake-intent-hooks.test.ts +1 -1
- package/src/calls/__tests__/inbound-trust-reader.test.ts +110 -0
- package/src/calls/__tests__/relay-setup-router.test.ts +349 -65
- package/src/calls/guardian-dispatch.ts +10 -8
- package/src/calls/inbound-trust-reader.ts +56 -0
- package/src/calls/media-stream-server.ts +21 -0
- package/src/calls/relay-server.ts +231 -72
- package/src/calls/relay-setup-router.ts +57 -13
- package/src/calls/relay-verification.ts +7 -7
- package/src/calls/stt-hints.ts +9 -12
- package/src/calls/twilio-routes.ts +13 -3
- package/src/cli/commands/__tests__/cache.test.ts +8 -1
- package/src/cli/commands/cache.ts +194 -181
- package/src/cli/commands/contacts.ts +6 -24
- package/src/cli/commands/db/__tests__/repair.test.ts +15 -6
- package/src/cli/commands/db/__tests__/status.test.ts +7 -3
- package/src/cli/commands/db/status.ts +212 -33
- package/src/cli/commands/mcp.ts +252 -218
- package/src/cli/commands/memory/__tests__/memory-v3.test.ts +6 -1
- package/src/cli/commands/memory/__tests__/worker.test.ts +302 -0
- package/src/cli/commands/memory/index.ts +4 -0
- package/src/cli/commands/memory/memory-retrospective.ts +129 -0
- package/src/cli/commands/memory/memory-v3.ts +176 -4
- package/src/cli/commands/memory/worker.ts +175 -0
- package/src/cli/commands/plugins.ts +343 -14
- package/src/cli/lib/__tests__/install-from-github.test.ts +40 -0
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +160 -1
- package/src/cli/lib/__tests__/plugin-pin-history.test.ts +162 -0
- package/src/cli/lib/__tests__/toggle-plugin.test.ts +158 -0
- package/src/cli/lib/install-from-github.ts +47 -6
- package/src/cli/lib/list-installed-plugins.ts +179 -1
- package/src/cli/lib/plugin-marketplace.ts +11 -0
- package/src/cli/lib/plugin-pin-history.ts +257 -0
- package/src/cli/lib/toggle-plugin.ts +146 -0
- package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +143 -0
- package/src/config/__tests__/sync-gated-profiles.test.ts +2 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +15 -33
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +3 -8
- package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +64 -37
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +1 -1
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +14 -72
- package/src/config/bundled-skills/app-builder/references/examples/README.md +1 -2
- package/src/config/bundled-skills/contacts/SKILL.md +7 -12
- package/src/config/bundled-skills/messaging/tools/shared.ts +4 -1
- package/src/config/bundled-skills/system-storage-cleanup/SKILL.md +74 -0
- package/src/config/bundled-skills/workflows/SKILL.md +4 -3
- package/src/config/call-site-defaults.ts +11 -2
- package/src/config/feature-flag-registry.json +0 -8
- package/src/config/llm-resolver.ts +151 -14
- package/src/config/loader.ts +36 -5
- package/src/config/profile-dispatchability.ts +11 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
- package/src/config/schemas/call-site-catalog.ts +7 -0
- package/src/config/schemas/llm.ts +2 -0
- package/src/config/schemas/memory-lifecycle.ts +17 -3
- package/src/config/schemas/memory-v3.ts +7 -0
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/timeouts.ts +32 -0
- package/src/config/seed-inference-profiles.ts +147 -50
- package/src/config/skills.ts +27 -5
- package/src/config/sync-gated-profiles.ts +13 -1
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +312 -0
- package/src/contacts/contact-store.ts +21 -0
- package/src/contacts/contacts-write.ts +3 -0
- package/src/contacts/guardian-delivery-reader.ts +223 -0
- package/src/contacts/member-status.ts +9 -0
- package/src/credential-health/credential-health-service.ts +1 -5
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +44 -0
- package/src/daemon/app-source-watcher.ts +31 -18
- package/src/daemon/assistant-attachments.ts +94 -4
- package/src/daemon/conversation-agent-loop-handlers.ts +3 -0
- package/src/daemon/conversation-agent-loop.ts +18 -36
- package/src/daemon/conversation-process.ts +35 -16
- package/src/daemon/conversation-runtime-assembly.ts +91 -66
- package/src/daemon/conversation-surfaces.ts +273 -18
- package/src/daemon/conversation-tool-setup.ts +24 -64
- package/src/daemon/conversation.ts +149 -53
- package/src/daemon/disk-pressure-guard.ts +12 -2
- package/src/daemon/event-loop-watchdog.test.ts +85 -0
- package/src/daemon/event-loop-watchdog.ts +133 -0
- package/src/daemon/external-plugins-bootstrap.ts +26 -80
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a.test.ts +1 -1
- package/src/daemon/handlers/config-channels.ts +41 -27
- package/src/daemon/handlers/conversations.ts +84 -0
- package/src/daemon/handlers/shared.ts +7 -0
- package/src/daemon/lifecycle.ts +44 -5
- package/src/daemon/memory-v2-startup.test.ts +72 -0
- package/src/daemon/memory-v2-startup.ts +87 -19
- package/src/daemon/message-types/inbox.ts +0 -6
- package/src/daemon/message-types/messages.ts +0 -4
- package/src/daemon/message-types/surfaces.ts +12 -11
- package/src/daemon/server.ts +0 -4
- package/src/daemon/shutdown-handlers.ts +20 -0
- package/src/daemon/tool-setup-types.ts +7 -5
- package/src/daemon/trust-context.ts +6 -0
- package/src/daemon/wake-conversation-ops.ts +70 -0
- package/src/daemon/workspace-tools-watcher.ts +7 -3
- package/src/documents/document-comments-store.test.ts +1 -1
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +1 -1
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +6 -0
- package/src/heartbeat/heartbeat-service.ts +3 -4
- package/src/ipc/__tests__/attachment-ipc.test.ts +1 -1
- package/src/ipc/__tests__/browser-ipc.test.ts +73 -2
- package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
- package/src/ipc/__tests__/watcher-ipc.test.ts +59 -39
- package/src/ipc/assistant-server.ts +10 -2
- package/src/ipc/gateway-client.ts +2 -1
- package/src/ipc/routes/__tests__/invite-ipc-routes.test.ts +58 -0
- package/src/ipc/routes/invite-ipc-routes.ts +66 -0
- package/src/live-voice/__tests__/live-voice-archive.test.ts +1 -1
- package/src/memory/__tests__/activation-session-store.test.ts +1 -1
- package/src/memory/__tests__/auto-analysis-guard.test.ts +1 -1
- package/src/memory/__tests__/conversation-group-migration.test.ts +1 -1
- package/src/memory/__tests__/conversation-queries.test.ts +1 -1
- package/src/memory/__tests__/db-async-query.test.ts +1 -1
- package/src/memory/__tests__/db-logs-attach.test.ts +110 -0
- package/src/memory/__tests__/db-maintenance.test.ts +28 -36
- package/src/memory/__tests__/db-memory-attach.test.ts +113 -0
- package/src/memory/__tests__/find-analysis-conversation.test.ts +1 -1
- package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +1 -1
- package/src/memory/__tests__/fork-message-copy.test.ts +232 -0
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +3 -0
- package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +5 -5
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +8 -6
- package/src/memory/__tests__/memory-retrospective-job.test.ts +30 -37
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +69 -66
- package/src/memory/__tests__/memory-retrospective-state.test.ts +1 -1
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +1 -1
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +1 -1
- package/src/memory/__tests__/onboarding-events-store.test.ts +1 -1
- package/src/memory/__tests__/prompt-override.test.ts +192 -0
- package/src/memory/__tests__/table-relocation.test.ts +129 -0
- package/src/memory/conversation-crud.ts +461 -152
- package/src/memory/db-async-query.ts +89 -5
- package/src/memory/db-connection.ts +101 -18
- package/src/memory/db-init.ts +409 -234
- package/src/memory/db-maintenance.ts +43 -38
- package/src/memory/db-singleton.ts +45 -19
- package/src/memory/embedding-gemini.test.ts +3 -1
- package/src/memory/embedding-gemini.ts +18 -2
- package/src/memory/fork-message-copy.ts +170 -0
- package/src/memory/graph/__tests__/handle-remember-v2.test.ts +92 -0
- package/src/memory/graph/bootstrap.test.ts +6 -3
- package/src/memory/graph/retriever.test.ts +12 -12
- package/src/memory/graph/store.test.ts +15 -25
- package/src/memory/graph/store.ts +23 -14
- package/src/memory/graph/tool-handlers.ts +34 -5
- package/src/memory/graph/tools.ts +5 -2
- package/src/memory/indexer.ts +21 -9
- package/src/memory/job-handlers/cleanup.ts +10 -3
- package/src/memory/job-handlers/embedding.test.ts +4 -4
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +4 -4
- package/src/memory/jobs/embed-pkb-file.test.ts +7 -7
- package/src/memory/jobs-store.ts +36 -24
- package/src/memory/llm-request-log-store.ts +51 -19
- package/src/memory/llm-usage-store.ts +79 -21
- package/src/memory/memory-retrospective-job.ts +27 -19
- package/src/memory/memory-retrospective-startup-cleanup.ts +10 -2
- package/src/memory/migrations/{100-core-tables.ts → 000-core-tables.ts} +6 -10
- package/src/memory/migrations/014-backfill-inbox-thread-state.ts +13 -3
- package/src/memory/migrations/104-core-indexes.ts +1 -1
- package/src/memory/migrations/126-backfill-guardian-principal-id.ts +189 -196
- package/src/memory/migrations/127-guardian-principal-id-not-null.ts +98 -105
- package/src/memory/migrations/134-contacts-notes-column.ts +66 -69
- package/src/memory/migrations/135-backfill-contact-interaction-stats.ts +19 -22
- package/src/memory/migrations/136-drop-assistant-id-columns.ts +241 -219
- package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +204 -209
- package/src/memory/migrations/141-rename-verification-table.ts +45 -48
- package/src/memory/migrations/142-rename-verification-session-id-column.ts +16 -23
- package/src/memory/migrations/143-rename-guardian-verification-values.ts +23 -30
- package/src/memory/migrations/144-rename-voice-to-phone.ts +133 -136
- package/src/memory/migrations/145-drop-accounts-table.ts +4 -7
- package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +79 -82
- package/src/memory/migrations/148-drop-reminders-table.ts +3 -6
- package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +71 -78
- package/src/memory/migrations/157-invite-contact-id.ts +73 -76
- package/src/memory/migrations/162-guardian-timestamps-epoch-ms.ts +44 -58
- package/src/memory/migrations/169-rename-gmail-provider-key-to-google.ts +36 -43
- package/src/memory/migrations/174-rename-thread-starters-table.ts +30 -37
- package/src/memory/migrations/176-drop-capability-card-state.ts +17 -22
- package/src/memory/migrations/177-create-trace-events-table.ts +23 -28
- package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +36 -43
- package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +14 -21
- package/src/memory/migrations/191-backfill-audio-attachment-mime-types.ts +17 -24
- package/src/memory/migrations/192-contacts-user-file-column.ts +6 -9
- package/src/memory/migrations/193-add-source-type-columns.ts +33 -36
- package/src/memory/migrations/194-memory-recall-logs.ts +34 -39
- package/src/memory/migrations/196-strip-integration-prefix-from-provider-keys.ts +59 -66
- package/src/memory/migrations/199-guardian-request-enrichment-columns.ts +41 -48
- package/src/memory/migrations/204-rename-memory-graph-type-values.ts +11 -18
- package/src/memory/migrations/206-scrub-corrupted-image-attachments.ts +76 -83
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +135 -68
- package/src/memory/migrations/211-memory-recall-logs-query-context.ts +6 -11
- package/src/memory/migrations/212-llm-request-logs-created-at-index.ts +4 -9
- package/src/memory/migrations/217-conversation-host-access.ts +13 -18
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +86 -93
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +41 -48
- package/src/memory/migrations/230-acp-session-history.ts +23 -28
- package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +58 -62
- package/src/memory/migrations/232-activation-state.ts +11 -16
- package/src/memory/migrations/233-document-conversations.ts +20 -25
- package/src/memory/migrations/234-memory-v2-activation-logs.ts +26 -31
- package/src/memory/migrations/235-slack-compaction-watermark.ts +5 -10
- package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +6 -11
- package/src/memory/migrations/237-heartbeat-runs.ts +22 -27
- package/src/memory/migrations/239-trace-events-created-at-index.ts +4 -9
- package/src/memory/migrations/242-message-bookmarks.ts +17 -22
- package/src/memory/migrations/245-memory-retrospective-state.ts +8 -13
- package/src/memory/migrations/249-normalize-slack-external-content.ts +37 -41
- package/src/memory/migrations/251-a2a-tasks.ts +27 -32
- package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +12 -17
- package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +10 -15
- package/src/memory/migrations/256-memory-v2-injection-events.ts +70 -74
- package/src/memory/migrations/259-conversation-cleaned-at.ts +4 -9
- package/src/memory/migrations/260-rename-cleaned-at.ts +11 -16
- package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +3 -8
- package/src/memory/migrations/262-memory-v3-coactivation.ts +21 -26
- package/src/memory/migrations/263-memory-v3-auto-edges.ts +14 -19
- package/src/memory/migrations/270-schedule-description.ts +7 -12
- package/src/memory/migrations/272-acp-session-history-cwd.ts +8 -13
- package/src/memory/migrations/281-memory-retrospective-remembered-log.ts +8 -13
- package/src/memory/migrations/297-move-llm-request-logs-to-logs-db.ts +111 -0
- package/src/memory/migrations/298-move-memory-jobs-to-memory-db.ts +128 -0
- package/src/memory/migrations/299-canonical-guardian-deliveries-conversation-index.ts +19 -0
- package/src/memory/migrations/__tests__/014-backfill-inbox-thread-state.test.ts +108 -0
- package/src/memory/migrations/__tests__/136-drop-assistant-id-columns.test.ts +82 -0
- package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +224 -0
- package/src/memory/migrations/__tests__/297-move-llm-request-logs.test.ts +180 -0
- package/src/memory/migrations/__tests__/run-migrations.test.ts +333 -7
- package/src/memory/migrations/helpers/relocation.ts +227 -0
- package/src/memory/migrations/registry.ts +63 -0
- package/src/memory/migrations/run-migrations.ts +187 -16
- package/src/memory/migrations/schema-introspection.ts +14 -0
- package/src/memory/migrations/validate-migration-state.ts +50 -145
- package/src/memory/prompt-override.ts +129 -0
- package/src/memory/raw-query.ts +47 -2
- package/src/memory/skill-loaded-events-store.test.ts +1 -1
- package/src/memory/task-memory-cleanup.ts +62 -41
- package/src/memory/tool-executed-events-store.test.ts +1 -1
- package/src/memory/turn-trace-store.test.ts +1 -1
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +16 -15
- package/src/memory/v2/__tests__/cli-command-store.test.ts +25 -0
- package/src/memory/v2/__tests__/harness-compare.test.ts +1 -1
- package/src/memory/v2/__tests__/harness-oracle.test.ts +1 -1
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +1 -1
- package/src/memory/v2/__tests__/skill-store.test.ts +80 -0
- package/src/memory/v2/__tests__/sweep-job.test.ts +2 -2
- package/src/memory/v2/cli-command-store.ts +75 -38
- package/src/memory/v2/prompts/consolidation.ts +13 -82
- package/src/memory/v2/prompts/router.ts +21 -93
- package/src/memory/v2/skill-store.ts +68 -31
- package/src/memory/v3-eval/__tests__/eval-packets.test.ts +38 -0
- package/src/memory/v3-eval/__tests__/eval-tally.test.ts +139 -0
- package/src/memory/v3-eval/eval-packets.ts +197 -12
- package/src/memory/v3-eval/eval-tally.ts +234 -0
- package/src/memory/worker-control.ts +118 -0
- package/src/memory/worker-process.ts +72 -0
- package/src/messaging/provider.ts +10 -0
- package/src/messaging/providers/gmail/adapter.ts +1 -0
- package/src/messaging/providers/gmail/client.ts +13 -0
- package/src/messaging/providers/index.ts +1 -1
- package/src/messaging/providers/slack/send.test.ts +87 -39
- package/src/messaging/providers/slack/send.ts +84 -105
- package/src/notifications/README.md +9 -5
- package/src/notifications/__tests__/broadcaster.test.ts +16 -8
- package/src/notifications/__tests__/connected-channels.test.ts +114 -0
- package/src/notifications/__tests__/decision-engine.test.ts +78 -9
- package/src/notifications/__tests__/destination-resolver.test.ts +256 -0
- package/src/notifications/__tests__/deterministic-checks.test.ts +43 -1
- package/src/notifications/adapters/slack.ts +12 -10
- package/src/notifications/approval-card-builder.ts +81 -20
- package/src/notifications/approval-card-data.ts +8 -5
- package/src/notifications/broadcaster.ts +8 -1
- package/src/notifications/canonical-delivery-recorder.ts +7 -5
- package/src/notifications/conversation-candidates.ts +24 -59
- package/src/notifications/copy-composer.ts +48 -68
- package/src/notifications/decision-engine.ts +15 -7
- package/src/notifications/destination-resolver.ts +68 -24
- package/src/notifications/deterministic-checks.ts +19 -16
- package/src/notifications/emit-signal.ts +68 -15
- package/src/notifications/trusted-contact-payloads.ts +70 -0
- package/src/oauth/byo-connection.test.ts +9 -0
- package/src/oauth/connection-resolver.test.ts +174 -6
- package/src/oauth/connection-resolver.ts +132 -5
- package/src/oauth/oauth-store.ts +16 -3
- package/src/oauth/scope-utils.ts +39 -0
- package/src/permissions/question-prompter.test.ts +1 -1
- package/src/permissions/question-prompter.ts +7 -4
- package/src/plugin-api/index.ts +9 -4
- package/src/plugin-api/model-profiles.test.ts +123 -0
- package/src/plugin-api/model-profiles.ts +5 -1
- package/src/plugin-api/vision-support.test.ts +173 -0
- package/src/plugin-api/vision-support.ts +113 -0
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +90 -0
- package/src/plugins/defaults/advisor/__tests__/context-pack-gating.test.ts +106 -0
- package/src/plugins/defaults/advisor/__tests__/context-pack.test.ts +60 -0
- package/src/plugins/defaults/advisor/consult.ts +65 -6
- package/src/plugins/defaults/advisor/context-pack.ts +288 -0
- package/src/plugins/defaults/advisor/steering.ts +14 -2
- package/src/plugins/defaults/advisor/tools/advisor.ts +32 -5
- package/src/plugins/defaults/compaction/window-manager.ts +45 -64
- package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +13 -4
- package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +441 -0
- package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +57 -0
- package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +61 -0
- package/src/plugins/defaults/image-fallback/package.json +14 -0
- package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +108 -0
- package/src/plugins/defaults/image-fallback/src/caption-cache.ts +49 -0
- package/src/plugins/defaults/image-fallback/src/image-persist.ts +56 -0
- package/src/plugins/defaults/image-fallback/src/vision-caption.ts +120 -0
- package/src/plugins/defaults/index.ts +27 -0
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +14 -1
- package/src/plugins/defaults/memory-retrieval/injectors.ts +4 -4
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +134 -5
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +11 -2
- package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +146 -0
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +246 -19
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +8 -1
- package/src/plugins/external-plugin-loader.ts +47 -6
- package/src/plugins/mtime-cache.ts +772 -0
- package/src/plugins/pipeline.ts +7 -2
- package/src/plugins/registry.ts +16 -5
- package/src/plugins/user-loader.ts +22 -76
- package/src/prompts/persona-resolver.ts +29 -11
- package/src/prompts/system-prompt.ts +1 -1
- package/src/prompts/templates/system-sections.ts +4 -4
- package/src/providers/__tests__/count-tokens-forwarding.test.ts +98 -0
- package/src/providers/anthropic/client.ts +290 -185
- package/src/providers/call-site-routing.ts +14 -0
- package/src/providers/gemini/client.ts +43 -0
- package/src/providers/inference/adapter-factory.ts +6 -0
- package/src/providers/inference/connections.ts +6 -1
- package/src/providers/model-catalog.ts +53 -0
- package/src/providers/openai/responses-provider.ts +5 -0
- package/src/providers/openrouter/client.ts +5 -0
- package/src/providers/platform-proxy/constants.ts +5 -0
- package/src/providers/provider-send-message.ts +4 -0
- package/src/providers/ratelimit.ts +13 -0
- package/src/providers/retry.ts +14 -0
- package/src/providers/together/client.ts +35 -0
- package/src/providers/types.ts +25 -0
- package/src/providers/usage-tracking.ts +11 -0
- package/src/runtime/AGENTS.md +9 -1
- package/src/runtime/__tests__/agent-wake.test.ts +259 -4
- package/src/runtime/__tests__/guardian-vellum-migration.test.ts +181 -0
- package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +64 -0
- package/src/runtime/__tests__/local-principal-trust.test.ts +164 -0
- package/src/runtime/__tests__/slack-block-formatting.test.ts +39 -10
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +670 -0
- package/src/runtime/access-request-helper.ts +19 -39
- package/src/runtime/actor-trust-resolver.ts +8 -16
- package/src/runtime/agent-wake.ts +183 -60
- package/src/runtime/anchored-guardian.test.ts +156 -0
- package/src/runtime/anchored-guardian.ts +135 -0
- package/src/runtime/assistant-stream-state.ts +9 -2
- package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +99 -0
- package/src/runtime/auth/require-bound-guardian.ts +21 -11
- package/src/runtime/channel-reply-delivery.ts +6 -3
- package/src/runtime/channel-verification-service.ts +24 -0
- package/src/runtime/guardian-decision-types.ts +3 -22
- package/src/runtime/guardian-vellum-migration.ts +66 -7
- package/src/runtime/http-server.ts +1 -15
- package/src/runtime/invite-redemption-service.ts +155 -6
- package/src/runtime/invite-service.ts +113 -62
- package/src/runtime/local-actor-identity.ts +76 -11
- package/src/runtime/local-principal-trust.ts +52 -0
- package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +3 -0
- package/src/runtime/pending-interactions.ts +11 -1
- package/src/runtime/routes/__tests__/acp-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +277 -0
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +140 -0
- package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +26 -7
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +14 -10
- package/src/runtime/routes/__tests__/contact-routes-update-channel-relay.test.ts +164 -0
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +8 -8
- package/src/runtime/routes/__tests__/conversation-surface-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +1 -3
- package/src/runtime/routes/__tests__/invite-relay-routes.test.ts +240 -0
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +4 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +143 -0
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +163 -0
- package/src/runtime/routes/acp-routes-list.test.ts +4 -0
- package/src/runtime/routes/acp-routes.test.ts +5 -6
- package/src/runtime/routes/attachment-routes.ts +21 -17
- package/src/runtime/routes/browser-routes.ts +19 -1
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +5 -9
- package/src/runtime/routes/channel-verification-routes.ts +13 -2
- package/src/runtime/routes/contact-routes.ts +275 -164
- package/src/runtime/routes/conversation-query-routes.ts +15 -5
- package/src/runtime/routes/conversation-routes.ts +80 -66
- package/src/runtime/routes/conversation-starter-routes.ts +7 -8
- package/src/runtime/routes/events-routes.ts +2 -2
- package/src/runtime/routes/guardian-approval-interception.ts +13 -274
- package/src/runtime/routes/host-app-control-routes.ts +5 -4
- package/src/runtime/routes/host-bash-routes.ts +5 -4
- package/src/runtime/routes/host-browser-routes.ts +9 -11
- package/src/runtime/routes/host-cu-routes.ts +5 -4
- package/src/runtime/routes/host-file-routes.ts +5 -4
- package/src/runtime/routes/host-transfer-routes.ts +6 -6
- package/src/runtime/routes/http-adapter.ts +1 -1
- package/src/runtime/routes/inbound-message-handler.ts +21 -16
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +376 -0
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +86 -64
- package/src/runtime/routes/inbound-stages/admission-policy.ts +20 -5
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +16 -4
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +21 -8
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -3
- package/src/runtime/routes/llm-context-normalization.ts +71 -0
- package/src/runtime/routes/log-export-routes.ts +2 -2
- package/src/runtime/routes/mcp-auth-routes.ts +38 -15
- package/src/runtime/routes/memory-eval-routes.ts +92 -0
- package/src/runtime/routes/memory-item-routes.test.ts +12 -11
- package/src/runtime/routes/migration-routes.ts +51 -40
- package/src/runtime/routes/plugins-routes.ts +164 -8
- package/src/runtime/routes/schedule-routes.ts +1 -0
- package/src/runtime/routes/subagents-routes.ts +5 -0
- package/src/runtime/routes/surface-action-routes.ts +39 -51
- package/src/runtime/routes/usage-routes.ts +3 -0
- package/src/runtime/routes/work-items-routes.test.ts +1 -1
- package/src/runtime/slack-block-formatting.ts +46 -48
- package/src/runtime/trust-verdict-consumer.ts +210 -0
- package/src/schedule/scheduler.ts +6 -9
- package/src/signals/user-message.ts +16 -0
- package/src/subagent/manager.ts +9 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +1 -1
- package/src/tools/ask-question/ask-question-tool.test.ts +89 -52
- package/src/tools/ask-question/ask-question-tool.ts +27 -73
- package/src/tools/browser/__tests__/browser-status.test.ts +20 -0
- package/src/tools/browser/browser-execution.ts +16 -4
- package/src/tools/document/document-comment-tool.test.ts +1 -1
- package/src/tools/executor.ts +15 -3
- package/src/tools/host-terminal/host-shell.ts +28 -9
- package/src/tools/memory/register.test.ts +32 -0
- package/src/tools/skills/load.ts +43 -2
- package/src/tools/subagent/spawn.ts +4 -10
- package/src/tools/terminal/shell.ts +16 -5
- package/src/tools/tool-defaults.ts +2 -0
- package/src/tools/types.ts +18 -2
- package/src/tools/ui-surface/definitions.ts +0 -43
- package/src/util/fs-watcher-error.ts +36 -0
- package/src/util/log-redact.ts +2 -4
- package/src/util/logs-db-path.ts +22 -0
- package/src/util/memory-db-path.ts +23 -0
- package/src/util/platform.ts +5 -0
- package/src/watcher/providers/gmail.ts +7 -2
- package/src/workflows/engine-integration.test.ts +1 -1
- package/src/workflows/engine.test.ts +1 -1
- package/src/workflows/engine.ts +22 -0
- package/src/workflows/fanout-load.test.ts +1 -1
- package/src/workflows/journal-store.test.ts +1 -1
- package/src/workflows/leaf-runner.test.ts +40 -1
- package/src/workflows/leaf-runner.ts +26 -1
- package/src/workspace/git-service.ts +144 -29
- package/src/workspace/migrations/109-swap-quality-profile-to-glm-5p2.ts +121 -0
- package/src/workspace/migrations/110-flip-balanced-profile-to-together.ts +82 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/workspace/migrations/runner.ts +32 -2
- package/src/__tests__/access-request-decision.test.ts +0 -375
- package/src/__tests__/guardian-grant-minting.test.ts +0 -607
- package/src/__tests__/plugin-source-watcher.test.ts +0 -302
- package/src/api/events/turn-profile-auto-routed.ts +0 -28
- package/src/daemon/__tests__/switch-inference-profile-tool.test.ts +0 -107
- package/src/daemon/plugin-source-watcher.ts +0 -278
- package/src/daemon/switch-inference-profile-tool.ts +0 -62
- package/src/memory/guardian-approvals.ts +0 -361
- package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +0 -66
- package/src/memory/migrations/038-actor-token-records.ts +0 -45
- package/src/memory/migrations/039-actor-refresh-token-records.ts +0 -57
- package/src/memory/migrations/103-complex-migrations.ts +0 -23
- package/src/memory/migrations/113-late-migrations.ts +0 -30
- package/src/memory/migrations/index.ts +0 -301
- package/src/runtime/routes/access-request-decision.ts +0 -297
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +0 -963
- package/src/runtime/routes/channel-guardian-routes.ts +0 -19
- package/src/runtime/routes/guardian-expiry-sweep.ts +0 -132
|
@@ -1,963 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Guardian callback decision strategy: handles inbound messages from a
|
|
3
|
-
* guardian sender who has pending guardian approval requests. Routes through
|
|
4
|
-
* callback buttons or the conversational engine.
|
|
5
|
-
*/
|
|
6
|
-
import { applyGuardianDecision } from "../../../approvals/guardian-decision-primitive.js";
|
|
7
|
-
import type { ChannelId } from "../../../channels/types.js";
|
|
8
|
-
import { findContactChannel } from "../../../contacts/contact-store.js";
|
|
9
|
-
import {
|
|
10
|
-
getAllPendingApprovalsByGuardianChat,
|
|
11
|
-
getApprovalRequestById,
|
|
12
|
-
getPendingApprovalByRequestAndGuardianChat,
|
|
13
|
-
type GuardianApprovalRequest,
|
|
14
|
-
} from "../../../memory/guardian-approvals.js";
|
|
15
|
-
import { emitNotificationSignal } from "../../../notifications/emit-signal.js";
|
|
16
|
-
import type { NotificationSourceChannel } from "../../../notifications/signal.js";
|
|
17
|
-
import { getLogger } from "../../../util/logger.js";
|
|
18
|
-
import { runApprovalConversationTurn } from "../../approval-conversation-turn.js";
|
|
19
|
-
import { composeApprovalMessageGenerative } from "../../approval-message-composer.js";
|
|
20
|
-
import type {
|
|
21
|
-
ApprovalAction,
|
|
22
|
-
ApprovalDecisionResult,
|
|
23
|
-
} from "../../channel-approval-types.js";
|
|
24
|
-
import { deliverChannelReply } from "../../gateway-client.js";
|
|
25
|
-
import type {
|
|
26
|
-
ApprovalConversationContext,
|
|
27
|
-
ApprovalConversationGenerator,
|
|
28
|
-
ApprovalCopyGenerator,
|
|
29
|
-
} from "../../http-types.js";
|
|
30
|
-
import {
|
|
31
|
-
deliverVerificationCodeToGuardian,
|
|
32
|
-
deliverVerificationCodeToRequester,
|
|
33
|
-
type DeliveryResult,
|
|
34
|
-
handleAccessRequestDecision,
|
|
35
|
-
notifyRequesterOfApproval,
|
|
36
|
-
notifyRequesterOfDeliveryFailure,
|
|
37
|
-
notifyRequesterOfDenial,
|
|
38
|
-
} from "../access-request-decision.js";
|
|
39
|
-
import { parseCallbackData } from "../channel-route-shared.js";
|
|
40
|
-
import {
|
|
41
|
-
deliverIdentityMismatchReply,
|
|
42
|
-
deliverStaleApprovalReply,
|
|
43
|
-
} from "../guardian-approval-reply-helpers.js";
|
|
44
|
-
|
|
45
|
-
const log = getLogger("runtime-http");
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Resolve the Slack ephemeral user ID when the source channel is Slack.
|
|
49
|
-
* Returns `undefined` for non-Slack channels.
|
|
50
|
-
*/
|
|
51
|
-
function slackEphemeralUserId(
|
|
52
|
-
sourceChannel: ChannelId,
|
|
53
|
-
userId: string | undefined,
|
|
54
|
-
): string | undefined {
|
|
55
|
-
return sourceChannel === "slack" && userId ? userId : undefined;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export interface GuardianCallbackDecisionParams {
|
|
59
|
-
content: string;
|
|
60
|
-
callbackData?: string;
|
|
61
|
-
conversationExternalId: string;
|
|
62
|
-
sourceChannel: ChannelId;
|
|
63
|
-
actorExternalId: string;
|
|
64
|
-
replyCallbackUrl: string;
|
|
65
|
-
assistantId: string;
|
|
66
|
-
approvalCopyGenerator?: ApprovalCopyGenerator;
|
|
67
|
-
approvalConversationGenerator?: ApprovalConversationGenerator;
|
|
68
|
-
/** Original approval message timestamp (Slack ts) for editing after resolution. */
|
|
69
|
-
approvalMessageTs?: string;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export interface ApprovalInterceptionResult {
|
|
73
|
-
handled: boolean;
|
|
74
|
-
type?:
|
|
75
|
-
| "decision_applied"
|
|
76
|
-
| "assistant_turn"
|
|
77
|
-
| "guardian_decision_applied"
|
|
78
|
-
| "stale_ignored";
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Handle a guardian sender's message when there are pending guardian approval
|
|
83
|
-
* requests targeting this chat. Returns `{ handled: true }` when the message
|
|
84
|
-
* was consumed, or `null` when no guardian approval was found and the caller
|
|
85
|
-
* should fall through to standard approval interception.
|
|
86
|
-
*/
|
|
87
|
-
export async function handleGuardianCallbackDecision(
|
|
88
|
-
params: GuardianCallbackDecisionParams,
|
|
89
|
-
): Promise<ApprovalInterceptionResult | null> {
|
|
90
|
-
const {
|
|
91
|
-
content,
|
|
92
|
-
callbackData,
|
|
93
|
-
conversationExternalId,
|
|
94
|
-
sourceChannel,
|
|
95
|
-
actorExternalId,
|
|
96
|
-
replyCallbackUrl,
|
|
97
|
-
assistantId,
|
|
98
|
-
approvalCopyGenerator,
|
|
99
|
-
approvalConversationGenerator,
|
|
100
|
-
approvalMessageTs,
|
|
101
|
-
} = params;
|
|
102
|
-
|
|
103
|
-
// Reactions have their own deterministic emoji-to-action mapping in
|
|
104
|
-
// `handleApprovalInterception`. Return null immediately so reaction
|
|
105
|
-
// callbackData never enters the conversational engine below, which would
|
|
106
|
-
// misclassify `reaction:white_check_mark` etc. as plain text and only
|
|
107
|
-
// ever produce `approve_once`/`reject`.
|
|
108
|
-
if (callbackData?.startsWith("reaction:")) {
|
|
109
|
-
return null;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Callback/button path: deterministic and takes priority.
|
|
113
|
-
let callbackDecision: ApprovalDecisionResult | null = null;
|
|
114
|
-
if (callbackData) {
|
|
115
|
-
callbackDecision = parseCallbackData(callbackData, sourceChannel);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// When a callback button provides a request ID, use the scoped lookup so
|
|
119
|
-
// the decision resolves to exactly the right approval even when
|
|
120
|
-
// multiple approvals target the same guardian chat.
|
|
121
|
-
let guardianApproval = callbackDecision?.requestId
|
|
122
|
-
? getPendingApprovalByRequestAndGuardianChat(
|
|
123
|
-
callbackDecision.requestId,
|
|
124
|
-
sourceChannel,
|
|
125
|
-
conversationExternalId,
|
|
126
|
-
)
|
|
127
|
-
: null;
|
|
128
|
-
|
|
129
|
-
// When the scoped lookup didn't resolve an approval (either because
|
|
130
|
-
// there was no callback or the requestId pointed to a stale/expired request),
|
|
131
|
-
// fall back to checking all pending approvals for this guardian chat.
|
|
132
|
-
if (!guardianApproval && callbackDecision) {
|
|
133
|
-
const allPending = getAllPendingApprovalsByGuardianChat(
|
|
134
|
-
sourceChannel,
|
|
135
|
-
conversationExternalId,
|
|
136
|
-
);
|
|
137
|
-
if (allPending.length === 1) {
|
|
138
|
-
guardianApproval = allPending[0];
|
|
139
|
-
} else if (allPending.length > 1) {
|
|
140
|
-
// The callback targeted a stale/expired request but the guardian has other
|
|
141
|
-
// pending approvals. Inform them the clicked approval is no longer valid.
|
|
142
|
-
await deliverStaleApprovalReply({
|
|
143
|
-
scenario: "guardian_disambiguation",
|
|
144
|
-
sourceChannel,
|
|
145
|
-
replyCallbackUrl,
|
|
146
|
-
chatId: conversationExternalId,
|
|
147
|
-
assistantId,
|
|
148
|
-
approvalCopyGenerator,
|
|
149
|
-
logger: log,
|
|
150
|
-
errorLogMessage:
|
|
151
|
-
"Failed to deliver stale callback disambiguation notice",
|
|
152
|
-
extraContext: { pendingCount: allPending.length },
|
|
153
|
-
errorLogContext: { conversationExternalId },
|
|
154
|
-
ephemeralUserId: slackEphemeralUserId(sourceChannel, actorExternalId),
|
|
155
|
-
});
|
|
156
|
-
return { handled: true, type: "stale_ignored" };
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// For plain-text messages (no callback), check if there are any pending
|
|
161
|
-
// approvals for this guardian chat to route through the conversation engine.
|
|
162
|
-
if (!guardianApproval && !callbackDecision) {
|
|
163
|
-
const allPending = getAllPendingApprovalsByGuardianChat(
|
|
164
|
-
sourceChannel,
|
|
165
|
-
conversationExternalId,
|
|
166
|
-
);
|
|
167
|
-
if (allPending.length === 1) {
|
|
168
|
-
guardianApproval = allPending[0];
|
|
169
|
-
} else if (allPending.length > 1) {
|
|
170
|
-
// Multiple pending — pick the first approval matching this sender as
|
|
171
|
-
// primary context. The conversation engine sees all matching approvals
|
|
172
|
-
// via pendingApprovals and can disambiguate.
|
|
173
|
-
guardianApproval =
|
|
174
|
-
allPending.find((a) => a.guardianExternalUserId === actorExternalId) ??
|
|
175
|
-
allPending[0];
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
if (!guardianApproval) {
|
|
180
|
-
return null;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Validate that the sender is the specific guardian who was assigned
|
|
184
|
-
// this approval request. This is a defense-in-depth check — the
|
|
185
|
-
// trustClass check above already verifies the sender is a guardian,
|
|
186
|
-
// but this catches edge cases like binding rotation between request
|
|
187
|
-
// creation and decision.
|
|
188
|
-
if (actorExternalId !== guardianApproval.guardianExternalUserId) {
|
|
189
|
-
log.warn(
|
|
190
|
-
{
|
|
191
|
-
conversationExternalId,
|
|
192
|
-
actorExternalId,
|
|
193
|
-
expectedGuardian: guardianApproval.guardianExternalUserId,
|
|
194
|
-
},
|
|
195
|
-
"Non-guardian sender attempted to act on guardian approval request",
|
|
196
|
-
);
|
|
197
|
-
await deliverIdentityMismatchReply({
|
|
198
|
-
sourceChannel,
|
|
199
|
-
replyCallbackUrl,
|
|
200
|
-
chatId: conversationExternalId,
|
|
201
|
-
assistantId,
|
|
202
|
-
approvalCopyGenerator,
|
|
203
|
-
logger: log,
|
|
204
|
-
errorLogMessage: "Failed to deliver guardian identity rejection notice",
|
|
205
|
-
errorLogContext: { conversationExternalId },
|
|
206
|
-
ephemeralUserId: slackEphemeralUserId(sourceChannel, actorExternalId),
|
|
207
|
-
});
|
|
208
|
-
return { handled: true, type: "guardian_decision_applied" };
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
if (callbackDecision) {
|
|
212
|
-
return handleCallbackDecision({
|
|
213
|
-
guardianApproval,
|
|
214
|
-
callbackDecision,
|
|
215
|
-
actorExternalId,
|
|
216
|
-
sourceChannel,
|
|
217
|
-
replyCallbackUrl,
|
|
218
|
-
assistantId,
|
|
219
|
-
approvalCopyGenerator,
|
|
220
|
-
approvalMessageTs,
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// ── Conversational engine for guardian plain-text messages ──
|
|
225
|
-
const allGuardianPending = getAllPendingApprovalsByGuardianChat(
|
|
226
|
-
sourceChannel,
|
|
227
|
-
conversationExternalId,
|
|
228
|
-
);
|
|
229
|
-
// Only present approvals that belong to this sender so the engine
|
|
230
|
-
// does not offer disambiguation for requests assigned to a rotated
|
|
231
|
-
// guardian the sender cannot act on.
|
|
232
|
-
const senderPending = allGuardianPending.filter(
|
|
233
|
-
(a) => a.guardianExternalUserId === actorExternalId,
|
|
234
|
-
);
|
|
235
|
-
const effectivePending =
|
|
236
|
-
senderPending.length > 0 ? senderPending : allGuardianPending;
|
|
237
|
-
|
|
238
|
-
if (effectivePending.length > 0 && content && approvalConversationGenerator) {
|
|
239
|
-
return handleConversationalDecision({
|
|
240
|
-
guardianApproval,
|
|
241
|
-
allGuardianPending,
|
|
242
|
-
effectivePending,
|
|
243
|
-
actorExternalId,
|
|
244
|
-
sourceChannel,
|
|
245
|
-
conversationExternalId,
|
|
246
|
-
replyCallbackUrl,
|
|
247
|
-
content,
|
|
248
|
-
assistantId,
|
|
249
|
-
approvalCopyGenerator,
|
|
250
|
-
approvalConversationGenerator,
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// Guardian sent a plain-text message with pending approvals but the
|
|
255
|
-
// conversational engine is unavailable. Return a handled result with a
|
|
256
|
-
// generative reply so the guardian gets feedback instead of the message being
|
|
257
|
-
// silently swallowed by the standard approval flow.
|
|
258
|
-
//
|
|
259
|
-
// Exclude callback/reaction payloads (e.g. `reaction:+1`) — these carry
|
|
260
|
-
// `callbackData` and must fall through so `handleApprovalInterception` can
|
|
261
|
-
// route them to the deterministic reaction handler.
|
|
262
|
-
if (effectivePending.length > 0 && content && !callbackData) {
|
|
263
|
-
try {
|
|
264
|
-
const text = await composeApprovalMessageGenerative(
|
|
265
|
-
{
|
|
266
|
-
scenario: "guardian_text_unavailable",
|
|
267
|
-
channel: sourceChannel,
|
|
268
|
-
},
|
|
269
|
-
{},
|
|
270
|
-
approvalCopyGenerator,
|
|
271
|
-
);
|
|
272
|
-
const fallbackPayload: Parameters<typeof deliverChannelReply>[1] = {
|
|
273
|
-
chatId: conversationExternalId,
|
|
274
|
-
text,
|
|
275
|
-
assistantId,
|
|
276
|
-
};
|
|
277
|
-
const guardianFallbackEphemeral = slackEphemeralUserId(
|
|
278
|
-
sourceChannel,
|
|
279
|
-
actorExternalId,
|
|
280
|
-
);
|
|
281
|
-
if (guardianFallbackEphemeral) {
|
|
282
|
-
fallbackPayload.ephemeral = true;
|
|
283
|
-
fallbackPayload.user = guardianFallbackEphemeral;
|
|
284
|
-
}
|
|
285
|
-
await deliverChannelReply(replyCallbackUrl, fallbackPayload);
|
|
286
|
-
} catch (err) {
|
|
287
|
-
log.error(
|
|
288
|
-
{ err, conversationExternalId },
|
|
289
|
-
"Failed to deliver guardian fallback reply",
|
|
290
|
-
);
|
|
291
|
-
}
|
|
292
|
-
return { handled: true, type: "assistant_turn" };
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// No content — nothing actionable.
|
|
296
|
-
return null;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// ---------------------------------------------------------------------------
|
|
300
|
-
// Callback decision handler
|
|
301
|
-
// ---------------------------------------------------------------------------
|
|
302
|
-
|
|
303
|
-
async function handleCallbackDecision(params: {
|
|
304
|
-
guardianApproval: GuardianApprovalRequest;
|
|
305
|
-
callbackDecision: ApprovalDecisionResult;
|
|
306
|
-
actorExternalId: string;
|
|
307
|
-
sourceChannel: ChannelId;
|
|
308
|
-
replyCallbackUrl: string;
|
|
309
|
-
assistantId: string;
|
|
310
|
-
approvalCopyGenerator?: ApprovalCopyGenerator;
|
|
311
|
-
approvalMessageTs?: string;
|
|
312
|
-
}): Promise<ApprovalInterceptionResult> {
|
|
313
|
-
const {
|
|
314
|
-
guardianApproval,
|
|
315
|
-
callbackDecision,
|
|
316
|
-
actorExternalId,
|
|
317
|
-
sourceChannel,
|
|
318
|
-
replyCallbackUrl,
|
|
319
|
-
assistantId,
|
|
320
|
-
approvalCopyGenerator,
|
|
321
|
-
approvalMessageTs,
|
|
322
|
-
} = params;
|
|
323
|
-
|
|
324
|
-
// Access request approvals don't have a pending interaction in the
|
|
325
|
-
// session tracker, so they need a separate decision path that creates
|
|
326
|
-
// a verification session instead of resuming an agent loop.
|
|
327
|
-
if (guardianApproval.toolName === "ingress_access_request") {
|
|
328
|
-
const accessResult = await handleAccessRequestApproval(
|
|
329
|
-
guardianApproval,
|
|
330
|
-
callbackDecision.action === "reject" ? "deny" : "approve",
|
|
331
|
-
actorExternalId,
|
|
332
|
-
replyCallbackUrl,
|
|
333
|
-
assistantId,
|
|
334
|
-
);
|
|
335
|
-
return accessResult;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// Apply the decision through the unified guardian decision primitive.
|
|
339
|
-
// The primitive handles approval info capture, record update, and scoped grant minting.
|
|
340
|
-
const result = await applyGuardianDecision({
|
|
341
|
-
approval: guardianApproval,
|
|
342
|
-
decision: callbackDecision,
|
|
343
|
-
actorPrincipalId: undefined, // Callback path — principal not available at this layer
|
|
344
|
-
actorExternalUserId: actorExternalId, // Channel-native ID (Telegram user ID, phone, etc.)
|
|
345
|
-
actorChannel: sourceChannel,
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
if (result.applied) {
|
|
349
|
-
// Notify the requester's chat about the outcome with the tool name
|
|
350
|
-
const decisionOutcome: "approved" | "denied" =
|
|
351
|
-
callbackDecision.action === "reject" ? "denied" : "approved";
|
|
352
|
-
const outcomeText = await composeApprovalMessageGenerative(
|
|
353
|
-
{
|
|
354
|
-
scenario: "guardian_decision_outcome",
|
|
355
|
-
decision: decisionOutcome,
|
|
356
|
-
toolName: guardianApproval.toolName,
|
|
357
|
-
channel: sourceChannel,
|
|
358
|
-
},
|
|
359
|
-
{},
|
|
360
|
-
approvalCopyGenerator,
|
|
361
|
-
);
|
|
362
|
-
try {
|
|
363
|
-
const outcomePayload: Parameters<typeof deliverChannelReply>[1] = {
|
|
364
|
-
chatId: guardianApproval.requesterChatId,
|
|
365
|
-
text: outcomeText,
|
|
366
|
-
assistantId,
|
|
367
|
-
};
|
|
368
|
-
const requesterEphemeral = slackEphemeralUserId(
|
|
369
|
-
sourceChannel,
|
|
370
|
-
guardianApproval.requesterExternalUserId,
|
|
371
|
-
);
|
|
372
|
-
if (requesterEphemeral) {
|
|
373
|
-
outcomePayload.ephemeral = true;
|
|
374
|
-
outcomePayload.user = requesterEphemeral;
|
|
375
|
-
}
|
|
376
|
-
await deliverChannelReply(replyCallbackUrl, outcomePayload);
|
|
377
|
-
} catch (err) {
|
|
378
|
-
log.error(
|
|
379
|
-
{ err, conversationId: guardianApproval.conversationId },
|
|
380
|
-
"Failed to notify requester of guardian decision",
|
|
381
|
-
);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
// Edit the original Slack approval message to show the decision and
|
|
385
|
-
// remove stale action buttons. This prevents users from clicking
|
|
386
|
-
// buttons that have already been resolved.
|
|
387
|
-
if (sourceChannel === "slack" && approvalMessageTs) {
|
|
388
|
-
editSlackApprovalMessage({
|
|
389
|
-
replyCallbackUrl,
|
|
390
|
-
chatId: guardianApproval.guardianChatId,
|
|
391
|
-
messageTs: approvalMessageTs,
|
|
392
|
-
decision: decisionOutcome,
|
|
393
|
-
assistantId,
|
|
394
|
-
conversationId: guardianApproval.conversationId,
|
|
395
|
-
});
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
// Post-decision delivery is handled by the onEvent callback
|
|
399
|
-
// in the session that registered the pending interaction.
|
|
400
|
-
return { handled: true, type: "guardian_decision_applied" };
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
// Race condition: callback arrived after request was already resolved.
|
|
404
|
-
// On Slack, edit the original message to show it's resolved and remove
|
|
405
|
-
// stale buttons so the guardian isn't left with actionable UI that does
|
|
406
|
-
// nothing. Also send an ephemeral error message for visibility.
|
|
407
|
-
if (sourceChannel === "slack" && approvalMessageTs) {
|
|
408
|
-
// Re-read the approval from DB to get the actual resolved status.
|
|
409
|
-
// The in-memory `guardianApproval` was loaded via a pending-status
|
|
410
|
-
// filter and is still "pending" even though it was resolved by
|
|
411
|
-
// another process.
|
|
412
|
-
const refreshed = getApprovalRequestById(guardianApproval.id);
|
|
413
|
-
const resolvedStatus =
|
|
414
|
-
refreshed?.status === "approved" ? "approved" : "denied";
|
|
415
|
-
editSlackApprovalMessage({
|
|
416
|
-
replyCallbackUrl,
|
|
417
|
-
chatId: guardianApproval.guardianChatId,
|
|
418
|
-
messageTs: approvalMessageTs,
|
|
419
|
-
decision: resolvedStatus,
|
|
420
|
-
assistantId,
|
|
421
|
-
conversationId: guardianApproval.conversationId,
|
|
422
|
-
});
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
// Deliver a visible ephemeral error so the user sees feedback (JARVIS-299).
|
|
426
|
-
if (sourceChannel === "slack") {
|
|
427
|
-
try {
|
|
428
|
-
await deliverChannelReply(replyCallbackUrl, {
|
|
429
|
-
chatId: guardianApproval.guardianChatId,
|
|
430
|
-
text: "This approval request has already been resolved.",
|
|
431
|
-
assistantId,
|
|
432
|
-
ephemeral: true,
|
|
433
|
-
user: actorExternalId,
|
|
434
|
-
});
|
|
435
|
-
} catch (err) {
|
|
436
|
-
log.error(
|
|
437
|
-
{ err, conversationId: guardianApproval.conversationId },
|
|
438
|
-
"Failed to deliver stale approval ephemeral notice",
|
|
439
|
-
);
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
return { handled: true, type: "stale_ignored" };
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
// ---------------------------------------------------------------------------
|
|
447
|
-
// Conversational engine decision handler
|
|
448
|
-
// ---------------------------------------------------------------------------
|
|
449
|
-
|
|
450
|
-
async function handleConversationalDecision(params: {
|
|
451
|
-
guardianApproval: GuardianApprovalRequest;
|
|
452
|
-
allGuardianPending: GuardianApprovalRequest[];
|
|
453
|
-
effectivePending: GuardianApprovalRequest[];
|
|
454
|
-
actorExternalId: string;
|
|
455
|
-
sourceChannel: ChannelId;
|
|
456
|
-
conversationExternalId: string;
|
|
457
|
-
replyCallbackUrl: string;
|
|
458
|
-
content: string;
|
|
459
|
-
assistantId: string;
|
|
460
|
-
approvalCopyGenerator?: ApprovalCopyGenerator;
|
|
461
|
-
approvalConversationGenerator: ApprovalConversationGenerator;
|
|
462
|
-
}): Promise<ApprovalInterceptionResult> {
|
|
463
|
-
const {
|
|
464
|
-
guardianApproval,
|
|
465
|
-
allGuardianPending,
|
|
466
|
-
effectivePending,
|
|
467
|
-
actorExternalId,
|
|
468
|
-
sourceChannel,
|
|
469
|
-
conversationExternalId,
|
|
470
|
-
replyCallbackUrl,
|
|
471
|
-
content,
|
|
472
|
-
assistantId,
|
|
473
|
-
approvalCopyGenerator,
|
|
474
|
-
approvalConversationGenerator,
|
|
475
|
-
} = params;
|
|
476
|
-
|
|
477
|
-
const guardianAllowedActions = ["approve_once", "reject"];
|
|
478
|
-
const engineContext: ApprovalConversationContext = {
|
|
479
|
-
toolName: guardianApproval.toolName,
|
|
480
|
-
allowedActions: guardianAllowedActions,
|
|
481
|
-
role: "guardian",
|
|
482
|
-
pendingApprovals: effectivePending.map((a) => ({
|
|
483
|
-
requestId: a.requestId!,
|
|
484
|
-
toolName: a.toolName,
|
|
485
|
-
})),
|
|
486
|
-
userMessage: content,
|
|
487
|
-
};
|
|
488
|
-
|
|
489
|
-
const engineResult = await runApprovalConversationTurn(
|
|
490
|
-
engineContext,
|
|
491
|
-
approvalConversationGenerator,
|
|
492
|
-
);
|
|
493
|
-
|
|
494
|
-
if (engineResult.disposition === "keep_pending") {
|
|
495
|
-
// Non-decision follow-up (clarification, disambiguation, etc.)
|
|
496
|
-
try {
|
|
497
|
-
const keepPendingPayload: Parameters<typeof deliverChannelReply>[1] = {
|
|
498
|
-
chatId: conversationExternalId,
|
|
499
|
-
text: engineResult.replyText,
|
|
500
|
-
assistantId,
|
|
501
|
-
};
|
|
502
|
-
const guardianEphemeral = slackEphemeralUserId(
|
|
503
|
-
sourceChannel,
|
|
504
|
-
actorExternalId,
|
|
505
|
-
);
|
|
506
|
-
if (guardianEphemeral) {
|
|
507
|
-
keepPendingPayload.ephemeral = true;
|
|
508
|
-
keepPendingPayload.user = guardianEphemeral;
|
|
509
|
-
}
|
|
510
|
-
await deliverChannelReply(replyCallbackUrl, keepPendingPayload);
|
|
511
|
-
} catch (err) {
|
|
512
|
-
log.error(
|
|
513
|
-
{ err, conversationId: guardianApproval.conversationId },
|
|
514
|
-
"Failed to deliver guardian conversation reply",
|
|
515
|
-
);
|
|
516
|
-
}
|
|
517
|
-
return { handled: true, type: "assistant_turn" };
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
// Decision-bearing disposition from the engine
|
|
521
|
-
const decisionAction = engineResult.disposition as ApprovalAction;
|
|
522
|
-
|
|
523
|
-
// Resolve the target approval: use targetRequestId from the engine if
|
|
524
|
-
// provided, otherwise use the single guardian approval.
|
|
525
|
-
const targetApproval = engineResult.targetRequestId
|
|
526
|
-
? (allGuardianPending.find(
|
|
527
|
-
(a) => a.requestId === engineResult.targetRequestId,
|
|
528
|
-
) ?? guardianApproval)
|
|
529
|
-
: guardianApproval;
|
|
530
|
-
|
|
531
|
-
// Re-validate guardian identity against the resolved target. The
|
|
532
|
-
// engine may select a different pending approval (via targetRequestId)
|
|
533
|
-
// that was assigned to a different guardian. Without this check a
|
|
534
|
-
// currently bound guardian could act on a request assigned to a
|
|
535
|
-
// previous guardian after a binding rotation.
|
|
536
|
-
if (actorExternalId !== targetApproval.guardianExternalUserId) {
|
|
537
|
-
log.warn(
|
|
538
|
-
{
|
|
539
|
-
conversationExternalId,
|
|
540
|
-
actorExternalId,
|
|
541
|
-
expectedGuardian: targetApproval.guardianExternalUserId,
|
|
542
|
-
targetRequestId: engineResult.targetRequestId,
|
|
543
|
-
},
|
|
544
|
-
"Guardian identity mismatch on engine-selected target approval",
|
|
545
|
-
);
|
|
546
|
-
await deliverIdentityMismatchReply({
|
|
547
|
-
sourceChannel,
|
|
548
|
-
replyCallbackUrl,
|
|
549
|
-
chatId: conversationExternalId,
|
|
550
|
-
assistantId,
|
|
551
|
-
approvalCopyGenerator,
|
|
552
|
-
logger: log,
|
|
553
|
-
errorLogMessage:
|
|
554
|
-
"Failed to deliver guardian identity mismatch notice for engine target",
|
|
555
|
-
errorLogContext: { conversationExternalId },
|
|
556
|
-
ephemeralUserId: slackEphemeralUserId(sourceChannel, actorExternalId),
|
|
557
|
-
});
|
|
558
|
-
return { handled: true, type: "guardian_decision_applied" };
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
// Access request approvals need a separate decision path.
|
|
562
|
-
if (targetApproval.toolName === "ingress_access_request") {
|
|
563
|
-
const accessResult = await handleAccessRequestApproval(
|
|
564
|
-
targetApproval,
|
|
565
|
-
decisionAction === "reject" ? "deny" : "approve",
|
|
566
|
-
actorExternalId,
|
|
567
|
-
replyCallbackUrl,
|
|
568
|
-
assistantId,
|
|
569
|
-
);
|
|
570
|
-
return accessResult;
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
const engineDecision: ApprovalDecisionResult = {
|
|
574
|
-
action: decisionAction,
|
|
575
|
-
source: "plain_text",
|
|
576
|
-
...(engineResult.targetRequestId
|
|
577
|
-
? { requestId: engineResult.targetRequestId }
|
|
578
|
-
: {}),
|
|
579
|
-
};
|
|
580
|
-
|
|
581
|
-
// Apply the decision through the unified guardian decision primitive.
|
|
582
|
-
const result = await applyGuardianDecision({
|
|
583
|
-
approval: targetApproval,
|
|
584
|
-
decision: engineDecision,
|
|
585
|
-
actorPrincipalId: undefined, // Callback path — principal not available at this layer
|
|
586
|
-
actorExternalUserId: actorExternalId, // Channel-native ID (Telegram user ID, phone, etc.)
|
|
587
|
-
actorChannel: sourceChannel,
|
|
588
|
-
});
|
|
589
|
-
|
|
590
|
-
if (result.applied) {
|
|
591
|
-
// Notify the requester's chat about the outcome
|
|
592
|
-
const outcomeText = await composeApprovalMessageGenerative(
|
|
593
|
-
{
|
|
594
|
-
scenario: "guardian_decision_outcome",
|
|
595
|
-
decision: decisionAction === "reject" ? "denied" : "approved",
|
|
596
|
-
toolName: targetApproval.toolName,
|
|
597
|
-
channel: sourceChannel,
|
|
598
|
-
},
|
|
599
|
-
{},
|
|
600
|
-
approvalCopyGenerator,
|
|
601
|
-
);
|
|
602
|
-
try {
|
|
603
|
-
const requesterOutcomePayload: Parameters<typeof deliverChannelReply>[1] =
|
|
604
|
-
{
|
|
605
|
-
chatId: targetApproval.requesterChatId,
|
|
606
|
-
text: outcomeText,
|
|
607
|
-
assistantId,
|
|
608
|
-
};
|
|
609
|
-
const requesterEphemeral = slackEphemeralUserId(
|
|
610
|
-
sourceChannel,
|
|
611
|
-
targetApproval.requesterExternalUserId,
|
|
612
|
-
);
|
|
613
|
-
if (requesterEphemeral) {
|
|
614
|
-
requesterOutcomePayload.ephemeral = true;
|
|
615
|
-
requesterOutcomePayload.user = requesterEphemeral;
|
|
616
|
-
}
|
|
617
|
-
await deliverChannelReply(replyCallbackUrl, requesterOutcomePayload);
|
|
618
|
-
} catch (err) {
|
|
619
|
-
log.error(
|
|
620
|
-
{ err, conversationId: targetApproval.conversationId },
|
|
621
|
-
"Failed to notify requester of guardian decision",
|
|
622
|
-
);
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
// Deliver the engine's reply to the guardian
|
|
626
|
-
try {
|
|
627
|
-
const guardianReplyPayload: Parameters<typeof deliverChannelReply>[1] = {
|
|
628
|
-
chatId: conversationExternalId,
|
|
629
|
-
text: engineResult.replyText,
|
|
630
|
-
assistantId,
|
|
631
|
-
};
|
|
632
|
-
const guardianEphemeral = slackEphemeralUserId(
|
|
633
|
-
sourceChannel,
|
|
634
|
-
actorExternalId,
|
|
635
|
-
);
|
|
636
|
-
if (guardianEphemeral) {
|
|
637
|
-
guardianReplyPayload.ephemeral = true;
|
|
638
|
-
guardianReplyPayload.user = guardianEphemeral;
|
|
639
|
-
}
|
|
640
|
-
await deliverChannelReply(replyCallbackUrl, guardianReplyPayload);
|
|
641
|
-
} catch (err) {
|
|
642
|
-
log.error(
|
|
643
|
-
{ err, conversationId: targetApproval.conversationId },
|
|
644
|
-
"Failed to deliver guardian decision reply",
|
|
645
|
-
);
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
return { handled: true, type: "guardian_decision_applied" };
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
// Race condition: request was already resolved. Deliver a stale notice
|
|
652
|
-
// instead of the engine's optimistic reply.
|
|
653
|
-
await deliverStaleApprovalReply({
|
|
654
|
-
scenario: "approval_already_resolved",
|
|
655
|
-
sourceChannel,
|
|
656
|
-
replyCallbackUrl,
|
|
657
|
-
chatId: conversationExternalId,
|
|
658
|
-
assistantId,
|
|
659
|
-
approvalCopyGenerator,
|
|
660
|
-
logger: log,
|
|
661
|
-
errorLogMessage: "Failed to deliver stale guardian approval notice",
|
|
662
|
-
errorLogContext: { conversationId: targetApproval.conversationId },
|
|
663
|
-
ephemeralUserId: slackEphemeralUserId(sourceChannel, actorExternalId),
|
|
664
|
-
});
|
|
665
|
-
|
|
666
|
-
return { handled: true, type: "stale_ignored" };
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
// ---------------------------------------------------------------------------
|
|
670
|
-
// Slack approval message edit helper
|
|
671
|
-
// ---------------------------------------------------------------------------
|
|
672
|
-
|
|
673
|
-
/**
|
|
674
|
-
* Fire-and-forget: edit the original Slack approval message to show the
|
|
675
|
-
* decision outcome and remove stale action buttons. Uses `chat.update` via
|
|
676
|
-
* the gateway deliver endpoint with `messageTs`.
|
|
677
|
-
*
|
|
678
|
-
* The status line replaces the inline buttons so users see the result
|
|
679
|
-
* inline without any actionable UI remaining.
|
|
680
|
-
*/
|
|
681
|
-
function editSlackApprovalMessage(params: {
|
|
682
|
-
replyCallbackUrl: string;
|
|
683
|
-
chatId: string;
|
|
684
|
-
messageTs: string;
|
|
685
|
-
decision: "approved" | "denied";
|
|
686
|
-
assistantId: string;
|
|
687
|
-
conversationId: string;
|
|
688
|
-
}): void {
|
|
689
|
-
const {
|
|
690
|
-
replyCallbackUrl,
|
|
691
|
-
chatId,
|
|
692
|
-
messageTs,
|
|
693
|
-
decision,
|
|
694
|
-
assistantId,
|
|
695
|
-
conversationId,
|
|
696
|
-
} = params;
|
|
697
|
-
|
|
698
|
-
const statusEmoji = decision === "approved" ? "\u2713" : "\u2717";
|
|
699
|
-
const statusLabel = decision === "approved" ? "Approved" : "Denied";
|
|
700
|
-
const statusText = `${statusEmoji} ${statusLabel}`;
|
|
701
|
-
|
|
702
|
-
// Build Block Kit blocks matching the resolved approval layout:
|
|
703
|
-
// a section with the status text and a context line with the decision.
|
|
704
|
-
// This replaces the original approval prompt's action buttons with a
|
|
705
|
-
// read-only status display.
|
|
706
|
-
const blocks = [
|
|
707
|
-
{
|
|
708
|
-
type: "section",
|
|
709
|
-
text: { type: "mrkdwn", text: statusText },
|
|
710
|
-
},
|
|
711
|
-
{
|
|
712
|
-
type: "context",
|
|
713
|
-
elements: [{ type: "mrkdwn", text: `${statusEmoji} ${statusLabel}` }],
|
|
714
|
-
},
|
|
715
|
-
];
|
|
716
|
-
|
|
717
|
-
deliverChannelReply(replyCallbackUrl, {
|
|
718
|
-
chatId,
|
|
719
|
-
text: statusText,
|
|
720
|
-
blocks,
|
|
721
|
-
messageTs,
|
|
722
|
-
assistantId,
|
|
723
|
-
}).catch((err) => {
|
|
724
|
-
log.error(
|
|
725
|
-
{ err, conversationId, messageTs },
|
|
726
|
-
"Failed to edit Slack approval message after resolution",
|
|
727
|
-
);
|
|
728
|
-
});
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
// ---------------------------------------------------------------------------
|
|
732
|
-
// Access request decision helper
|
|
733
|
-
// ---------------------------------------------------------------------------
|
|
734
|
-
|
|
735
|
-
/**
|
|
736
|
-
* Handle a guardian's decision on an `ingress_access_request` approval.
|
|
737
|
-
* Delegates to the access-request-decision module and orchestrates
|
|
738
|
-
* notification delivery.
|
|
739
|
-
*
|
|
740
|
-
* On approve: creates a verification session, delivers the code to the
|
|
741
|
-
* guardian, and notifies the requester to expect a code.
|
|
742
|
-
*
|
|
743
|
-
* On deny: marks the request as denied and notifies the requester.
|
|
744
|
-
*/
|
|
745
|
-
async function handleAccessRequestApproval(
|
|
746
|
-
approval: GuardianApprovalRequest,
|
|
747
|
-
action: "approve" | "deny",
|
|
748
|
-
decidedByExternalUserId: string,
|
|
749
|
-
replyCallbackUrl: string,
|
|
750
|
-
assistantId: string,
|
|
751
|
-
): Promise<ApprovalInterceptionResult> {
|
|
752
|
-
const decisionResult = handleAccessRequestDecision(
|
|
753
|
-
approval,
|
|
754
|
-
action,
|
|
755
|
-
decidedByExternalUserId,
|
|
756
|
-
);
|
|
757
|
-
|
|
758
|
-
if (decisionResult.type === "stale" || decisionResult.type === "idempotent") {
|
|
759
|
-
return { handled: true, type: "stale_ignored" };
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
// Resolve display names from the contacts database for enriched payloads
|
|
763
|
-
const requesterContactResult = approval.requesterExternalUserId
|
|
764
|
-
? findContactChannel({
|
|
765
|
-
channelType: approval.channel,
|
|
766
|
-
address: approval.requesterExternalUserId,
|
|
767
|
-
})
|
|
768
|
-
: null;
|
|
769
|
-
const requesterDisplayName =
|
|
770
|
-
requesterContactResult?.contact.displayName ?? null;
|
|
771
|
-
|
|
772
|
-
const decidedByContactResult = decidedByExternalUserId
|
|
773
|
-
? findContactChannel({
|
|
774
|
-
channelType: approval.channel,
|
|
775
|
-
address: decidedByExternalUserId,
|
|
776
|
-
})
|
|
777
|
-
: null;
|
|
778
|
-
const decidedByDisplayName =
|
|
779
|
-
decidedByContactResult?.contact.displayName ?? null;
|
|
780
|
-
|
|
781
|
-
if (decisionResult.type === "denied") {
|
|
782
|
-
await notifyRequesterOfDenial({
|
|
783
|
-
replyCallbackUrl,
|
|
784
|
-
requesterChatId: approval.requesterChatId,
|
|
785
|
-
assistantId,
|
|
786
|
-
channel: approval.channel,
|
|
787
|
-
requesterExternalUserId: approval.requesterExternalUserId,
|
|
788
|
-
});
|
|
789
|
-
|
|
790
|
-
// Emit both guardian_decision and denied signals so all lifecycle
|
|
791
|
-
// observers are notified of the denial.
|
|
792
|
-
const deniedPayload = {
|
|
793
|
-
sourceChannel: approval.channel as NotificationSourceChannel,
|
|
794
|
-
requesterExternalUserId: approval.requesterExternalUserId,
|
|
795
|
-
requesterChatId: approval.requesterChatId,
|
|
796
|
-
decidedByExternalUserId,
|
|
797
|
-
requesterDisplayName,
|
|
798
|
-
decidedByDisplayName,
|
|
799
|
-
decision: "denied" as const,
|
|
800
|
-
};
|
|
801
|
-
|
|
802
|
-
void emitNotificationSignal({
|
|
803
|
-
sourceEventName: "ingress.trusted_contact.guardian_decision",
|
|
804
|
-
sourceChannel: approval.channel as NotificationSourceChannel,
|
|
805
|
-
sourceContextId: approval.conversationId,
|
|
806
|
-
attentionHints: {
|
|
807
|
-
requiresAction: false,
|
|
808
|
-
urgency: "medium",
|
|
809
|
-
isAsyncBackground: false,
|
|
810
|
-
visibleInSourceNow: false,
|
|
811
|
-
},
|
|
812
|
-
contextPayload: deniedPayload,
|
|
813
|
-
dedupeKey: `trusted-contact:guardian-decision:${approval.id}`,
|
|
814
|
-
});
|
|
815
|
-
|
|
816
|
-
void emitNotificationSignal({
|
|
817
|
-
sourceEventName: "ingress.trusted_contact.denied",
|
|
818
|
-
sourceChannel: approval.channel as NotificationSourceChannel,
|
|
819
|
-
sourceContextId: approval.conversationId,
|
|
820
|
-
attentionHints: {
|
|
821
|
-
requiresAction: false,
|
|
822
|
-
urgency: "low",
|
|
823
|
-
isAsyncBackground: false,
|
|
824
|
-
visibleInSourceNow: false,
|
|
825
|
-
},
|
|
826
|
-
contextPayload: deniedPayload,
|
|
827
|
-
dedupeKey: `trusted-contact:denied:${approval.id}`,
|
|
828
|
-
});
|
|
829
|
-
|
|
830
|
-
return { handled: true, type: "guardian_decision_applied" };
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
// Approved: deliver the verification code to the guardian and notify the requester.
|
|
834
|
-
const requesterIdentifier =
|
|
835
|
-
requesterDisplayName || approval.requesterExternalUserId;
|
|
836
|
-
|
|
837
|
-
let codeDelivered = true;
|
|
838
|
-
if (decisionResult.verificationCode) {
|
|
839
|
-
const deliveryResult: DeliveryResult =
|
|
840
|
-
await deliverVerificationCodeToGuardian({
|
|
841
|
-
replyCallbackUrl,
|
|
842
|
-
guardianChatId: approval.guardianChatId,
|
|
843
|
-
requesterIdentifier,
|
|
844
|
-
verificationCode: decisionResult.verificationCode,
|
|
845
|
-
assistantId,
|
|
846
|
-
});
|
|
847
|
-
if (!deliveryResult.ok) {
|
|
848
|
-
log.error(
|
|
849
|
-
{ reason: deliveryResult.reason, approvalId: approval.id },
|
|
850
|
-
"Skipping requester notification — verification code was not delivered to guardian",
|
|
851
|
-
);
|
|
852
|
-
codeDelivered = false;
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
// On Slack, auto-deliver the verification code directly to the requester's
|
|
857
|
-
// DM so the guardian doesn't have to manually share it. The identity binding
|
|
858
|
-
// still protects against abuse — only the bound user can consume the code.
|
|
859
|
-
let requesterCodeDelivered = false;
|
|
860
|
-
if (
|
|
861
|
-
codeDelivered &&
|
|
862
|
-
approval.channel === "slack" &&
|
|
863
|
-
decisionResult.verificationCode
|
|
864
|
-
) {
|
|
865
|
-
const requesterCodeResult = await deliverVerificationCodeToRequester({
|
|
866
|
-
replyCallbackUrl,
|
|
867
|
-
requesterChatId: approval.requesterChatId,
|
|
868
|
-
verificationCode: decisionResult.verificationCode,
|
|
869
|
-
assistantId,
|
|
870
|
-
channel: approval.channel,
|
|
871
|
-
requesterExternalUserId: approval.requesterExternalUserId,
|
|
872
|
-
});
|
|
873
|
-
if (requesterCodeResult.ok) {
|
|
874
|
-
requesterCodeDelivered = true;
|
|
875
|
-
} else {
|
|
876
|
-
log.error(
|
|
877
|
-
{ reason: requesterCodeResult.reason, approvalId: approval.id },
|
|
878
|
-
"Failed to auto-deliver verification code to requester on Slack",
|
|
879
|
-
);
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
// Skip the separate approval notification when the requester already
|
|
884
|
-
// received the verification code directly (on Slack both messages go
|
|
885
|
-
// to the same DM, so sending both is redundant).
|
|
886
|
-
if (codeDelivered && !requesterCodeDelivered) {
|
|
887
|
-
await notifyRequesterOfApproval({
|
|
888
|
-
replyCallbackUrl,
|
|
889
|
-
requesterChatId: approval.requesterChatId,
|
|
890
|
-
assistantId,
|
|
891
|
-
channel: approval.channel,
|
|
892
|
-
requesterExternalUserId: approval.requesterExternalUserId,
|
|
893
|
-
});
|
|
894
|
-
} else if (!codeDelivered) {
|
|
895
|
-
// Let the requester know something went wrong without revealing details
|
|
896
|
-
await notifyRequesterOfDeliveryFailure({
|
|
897
|
-
replyCallbackUrl,
|
|
898
|
-
requesterChatId: approval.requesterChatId,
|
|
899
|
-
assistantId,
|
|
900
|
-
channel: approval.channel,
|
|
901
|
-
requesterExternalUserId: approval.requesterExternalUserId,
|
|
902
|
-
});
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
// Don't emit guardian_decision for approvals that still require code
|
|
906
|
-
// verification — the guardian already received the code, and emitting
|
|
907
|
-
// this signal prematurely causes the notification pipeline to deliver
|
|
908
|
-
// a confusing "approved" message before the requester has verified.
|
|
909
|
-
// The guardian_decision signal should only fire once access is fully granted
|
|
910
|
-
// (i.e. after code consumption), which is handled in the verification path.
|
|
911
|
-
if (!decisionResult.verificationSessionId) {
|
|
912
|
-
void emitNotificationSignal({
|
|
913
|
-
sourceEventName: "ingress.trusted_contact.guardian_decision",
|
|
914
|
-
sourceChannel: approval.channel as NotificationSourceChannel,
|
|
915
|
-
sourceContextId: approval.conversationId,
|
|
916
|
-
attentionHints: {
|
|
917
|
-
requiresAction: false,
|
|
918
|
-
urgency: "medium",
|
|
919
|
-
isAsyncBackground: false,
|
|
920
|
-
visibleInSourceNow: false,
|
|
921
|
-
},
|
|
922
|
-
contextPayload: {
|
|
923
|
-
sourceChannel: approval.channel as NotificationSourceChannel,
|
|
924
|
-
requesterExternalUserId: approval.requesterExternalUserId,
|
|
925
|
-
requesterChatId: approval.requesterChatId,
|
|
926
|
-
decidedByExternalUserId,
|
|
927
|
-
requesterDisplayName,
|
|
928
|
-
decidedByDisplayName,
|
|
929
|
-
decision: "approved",
|
|
930
|
-
},
|
|
931
|
-
dedupeKey: `trusted-contact:guardian-decision:${approval.id}`,
|
|
932
|
-
});
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
// Emit verification_sent with visibleInSourceNow=true so the notification
|
|
936
|
-
// pipeline suppresses delivery — the guardian already received the
|
|
937
|
-
// verification code directly. Without this flag, the pipeline generates
|
|
938
|
-
// a redundant LLM message like "Good news! Your request has been approved."
|
|
939
|
-
if (decisionResult.verificationSessionId && codeDelivered) {
|
|
940
|
-
void emitNotificationSignal({
|
|
941
|
-
sourceEventName: "ingress.trusted_contact.verification_sent",
|
|
942
|
-
sourceChannel: approval.channel as NotificationSourceChannel,
|
|
943
|
-
sourceContextId: approval.conversationId,
|
|
944
|
-
attentionHints: {
|
|
945
|
-
requiresAction: false,
|
|
946
|
-
urgency: "low",
|
|
947
|
-
isAsyncBackground: true,
|
|
948
|
-
visibleInSourceNow: true,
|
|
949
|
-
},
|
|
950
|
-
contextPayload: {
|
|
951
|
-
sourceChannel: approval.channel as NotificationSourceChannel,
|
|
952
|
-
requesterExternalUserId: approval.requesterExternalUserId,
|
|
953
|
-
requesterChatId: approval.requesterChatId,
|
|
954
|
-
requesterDisplayName,
|
|
955
|
-
decidedByDisplayName,
|
|
956
|
-
verificationSessionId: decisionResult.verificationSessionId,
|
|
957
|
-
},
|
|
958
|
-
dedupeKey: `trusted-contact:verification-sent:${decisionResult.verificationSessionId}`,
|
|
959
|
-
});
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
return { handled: true, type: "guardian_decision_applied" };
|
|
963
|
-
}
|