@vellumai/assistant 0.4.26 → 0.4.30
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/.env.example +2 -2
- package/AGENTS.md +5 -0
- package/ARCHITECTURE.md +207 -105
- package/Dockerfile +1 -1
- package/README.md +111 -113
- package/bun.lock +0 -3
- package/docs/architecture/integrations.md +0 -1
- package/docs/architecture/memory.md +100 -63
- package/docs/error-handling.md +71 -0
- package/docs/runbook-trusted-contacts.md +89 -52
- package/docs/trusted-contact-access.md +48 -46
- package/package.json +3 -3
- package/scripts/compare-benchmarks.sh +12 -5
- package/scripts/ipc/check-swift-decoder-drift.ts +5 -3
- package/scripts/test.sh +89 -5
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +50 -37
- package/src/__tests__/access-request-decision.test.ts +0 -1
- package/src/__tests__/account-registry.test.ts +1 -1
- package/src/__tests__/actor-token-service.test.ts +40 -26
- package/src/__tests__/agent-loop-thinking.test.ts +29 -13
- package/src/__tests__/agent-loop.test.ts +2 -1
- package/src/__tests__/app-builder-tool-scripts.test.ts +1 -1
- package/src/__tests__/app-executors.test.ts +7 -17
- package/src/__tests__/approval-routes-http.test.ts +2 -2
- package/src/__tests__/asset-materialize-tool.test.ts +7 -7
- package/src/__tests__/asset-search-tool.test.ts +7 -7
- package/src/__tests__/assistant-feature-flags-integration.test.ts +18 -10
- package/src/__tests__/browser-fill-credential.test.ts +1 -1
- package/src/__tests__/browser-skill-endstate.test.ts +10 -1
- package/src/__tests__/bundled-skill-retrieval-guard.test.ts +218 -0
- package/src/__tests__/call-controller.test.ts +99 -69
- package/src/__tests__/call-start-guardian-guard.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +157 -114
- package/src/__tests__/channel-approval.test.ts +8 -0
- package/src/__tests__/channel-approvals.test.ts +39 -1
- package/src/__tests__/channel-guardian.test.ts +176 -275
- package/src/__tests__/channel-readiness-service.test.ts +6 -2
- package/src/__tests__/channel-reply-delivery.test.ts +33 -2
- package/src/__tests__/channel-retry-sweep.test.ts +14 -14
- package/src/__tests__/checker.test.ts +12 -31
- package/src/__tests__/claude-code-tool-profiles.test.ts +1 -1
- package/src/__tests__/commit-message-enrichment-service.test.ts +71 -59
- package/src/__tests__/compaction.benchmark.test.ts +6 -2
- package/src/__tests__/computer-use-tools.test.ts +1 -1
- package/src/__tests__/config-schema.test.ts +66 -7
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +29 -29
- package/src/__tests__/contacts-tools.test.ts +63 -2
- package/src/__tests__/context-overflow-approval.test.ts +141 -0
- package/src/__tests__/context-overflow-policy.test.ts +171 -0
- package/src/__tests__/context-overflow-reducer.test.ts +533 -0
- package/src/__tests__/context-window-manager.test.ts +97 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +38 -46
- package/src/__tests__/conversation-pairing.test.ts +2 -2
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +214 -10
- package/src/__tests__/conversation-routes.test.ts +4 -7
- package/src/__tests__/credential-broker-browser-fill.test.ts +13 -2
- package/src/__tests__/credential-security-e2e.test.ts +1 -1
- package/src/__tests__/credential-security-invariants.test.ts +1 -1
- package/src/__tests__/credential-vault-unit.test.ts +1 -1
- package/src/__tests__/credential-vault.test.ts +11 -8
- package/src/__tests__/daemon-lifecycle.test.ts +2 -2
- package/src/__tests__/daemon-server-session-init.test.ts +6 -6
- package/src/__tests__/delete-managed-skill-tool.test.ts +1 -1
- package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -2
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +9 -0
- package/src/__tests__/emit-signal-routing-intent.test.ts +4 -0
- package/src/__tests__/encrypted-store.test.ts +10 -7
- package/src/__tests__/ephemeral-permissions.test.ts +3 -3
- package/src/__tests__/file-edit-tool.test.ts +1 -1
- package/src/__tests__/file-read-tool.test.ts +1 -1
- package/src/__tests__/file-write-tool.test.ts +1 -1
- package/src/__tests__/fixtures/credential-security-fixtures.ts +87 -64
- package/src/__tests__/fixtures/media-reuse-fixtures.ts +37 -31
- package/src/__tests__/fixtures/mock-signup-server.ts +171 -115
- package/src/__tests__/fixtures/proxy-fixtures.ts +39 -39
- package/src/__tests__/followup-tools.test.ts +1 -1
- package/src/__tests__/gateway-only-guard.test.ts +4 -0
- package/src/__tests__/gemini-image-service.test.ts +2 -2
- package/src/__tests__/guardian-actions-endpoint.test.ts +543 -1
- package/src/__tests__/guardian-control-plane-policy.test.ts +15 -15
- package/src/__tests__/guardian-dispatch.test.ts +79 -1
- package/src/__tests__/guardian-grant-minting.test.ts +20 -20
- package/src/__tests__/guardian-outbound-http.test.ts +1 -2
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +0 -41
- package/src/__tests__/guardian-routing-invariants.test.ts +36 -16
- package/src/__tests__/guardian-routing-state.test.ts +36 -52
- package/src/__tests__/guardian-verification-intent-routing.test.ts +4 -6
- package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +6 -8
- package/src/__tests__/handle-user-message-secret-resume.test.ts +39 -1
- package/src/__tests__/handlers-cu-observation-blob.test.ts +21 -10
- package/src/__tests__/handlers-telegram-config.test.ts +14 -14
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +23 -2
- package/src/__tests__/headless-browser-interactions.test.ts +1 -1
- package/src/__tests__/headless-browser-navigate.test.ts +1 -1
- package/src/__tests__/headless-browser-read-tools.test.ts +1 -1
- package/src/__tests__/headless-browser-snapshot.test.ts +1 -1
- package/src/__tests__/heartbeat-service.test.ts +45 -2
- package/src/__tests__/host-file-edit-tool.test.ts +1 -1
- package/src/__tests__/host-file-read-tool.test.ts +1 -1
- package/src/__tests__/host-file-write-tool.test.ts +1 -1
- package/src/__tests__/host-shell-tool.test.ts +1 -1
- package/src/__tests__/inbound-invite-redemption.test.ts +17 -19
- package/src/__tests__/ingress-reconcile.test.ts +2 -2
- package/src/__tests__/integrations-cli.test.ts +232 -0
- package/src/__tests__/intent-routing.test.ts +7 -5
- package/src/__tests__/invite-redemption-service.test.ts +5 -4
- package/src/__tests__/{ingress-routes-http.test.ts → invite-routes-http.test.ts} +42 -321
- package/src/__tests__/ipc-snapshot.test.ts +32 -31
- package/src/__tests__/managed-skill-lifecycle.test.ts +1 -1
- package/src/__tests__/mcp-cli.test.ts +136 -57
- package/src/__tests__/mcp-client-auth.test.ts +95 -0
- package/src/__tests__/media-generate-image.test.ts +2 -2
- package/src/__tests__/media-reuse-story.e2e.test.ts +8 -8
- package/src/__tests__/memory-regressions.test.ts +6 -6
- package/src/__tests__/messaging-send-tool.test.ts +1 -1
- package/src/__tests__/migration-cross-version-compatibility.test.ts +1855 -0
- package/src/__tests__/migration-export-http.test.ts +540 -0
- package/src/__tests__/migration-import-commit-http.test.ts +823 -0
- package/src/__tests__/migration-import-preflight-http.test.ts +755 -0
- package/src/__tests__/migration-parity-persistence.test.ts +1854 -0
- package/src/__tests__/migration-transport.test.ts +904 -0
- package/src/__tests__/migration-validate-http.test.ts +698 -0
- package/src/__tests__/migration-wizard.test.ts +1289 -0
- package/src/__tests__/nl-approval-parser.test.ts +305 -0
- package/src/__tests__/non-member-access-request.test.ts +17 -17
- package/src/__tests__/notification-decision-strategy.test.ts +110 -2
- package/src/__tests__/notification-deep-link.test.ts +18 -0
- package/src/__tests__/notification-guardian-path.test.ts +0 -1
- package/src/__tests__/oauth-provider-profiles.test.ts +34 -0
- package/src/__tests__/oauth2-gateway-transport.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__/provider-error-scenarios.test.ts +68 -0
- package/src/__tests__/provider-streaming.benchmark.test.ts +3 -1
- package/src/__tests__/proxy-approval-callback.test.ts +1 -1
- package/src/__tests__/qdrant-manager.test.ts +40 -11
- package/src/__tests__/rebind-secrets-screen.test.ts +839 -0
- package/src/__tests__/recording-handler.test.ts +2 -2
- package/src/__tests__/recording-intent-handler.test.ts +3 -3
- package/src/__tests__/recording-state-machine.test.ts +2 -2
- package/src/__tests__/relay-server.test.ts +507 -228
- package/src/__tests__/reminder-store.test.ts +8 -0
- package/src/__tests__/reminder.test.ts +8 -0
- package/src/__tests__/{resolve-guardian-trust-class.test.ts → resolve-trust-class.test.ts} +11 -17
- package/src/__tests__/retry-after-extraction.test.ts +111 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +1 -1
- package/src/__tests__/schedule-tools.test.ts +1 -1
- package/src/__tests__/script-proxy-certs.test.ts +1 -1
- package/src/__tests__/script-proxy-connect-tunnel.test.ts +2 -3
- package/src/__tests__/script-proxy-decision-trace.test.ts +2 -2
- package/src/__tests__/script-proxy-http-forwarder.test.ts +1 -1
- package/src/__tests__/script-proxy-injection-runtime.test.ts +5 -5
- package/src/__tests__/script-proxy-mitm-handler.test.ts +4 -4
- package/src/__tests__/script-proxy-policy-runtime.test.ts +2 -2
- package/src/__tests__/script-proxy-policy.test.ts +2 -2
- package/src/__tests__/script-proxy-profile-template-fallback.test.ts +127 -0
- package/src/__tests__/script-proxy-session-manager.test.ts +4 -7
- package/src/__tests__/script-proxy-session-runtime.test.ts +1 -6
- package/src/__tests__/secret-onetime-send.test.ts +4 -4
- package/src/__tests__/secret-scanner-executor.test.ts +2 -2
- package/src/__tests__/send-endpoint-busy.test.ts +11 -9
- package/src/__tests__/send-notification-tool.test.ts +2 -2
- package/src/__tests__/session-abort-tool-results.test.ts +17 -2
- package/src/__tests__/session-agent-loop.test.ts +456 -35
- package/src/__tests__/session-confirmation-signals.test.ts +3 -2
- package/src/__tests__/session-conflict-gate.test.ts +20 -3
- package/src/__tests__/session-init.benchmark.test.ts +2 -2
- package/src/__tests__/session-load-history-repair.test.ts +7 -7
- package/src/__tests__/session-media-retry.test.ts +147 -0
- package/src/__tests__/session-pre-run-repair.test.ts +17 -2
- package/src/__tests__/session-profile-injection.test.ts +20 -3
- package/src/__tests__/session-provider-retry-repair.test.ts +86 -6
- package/src/__tests__/session-queue.test.ts +33 -18
- package/src/__tests__/session-runtime-assembly.test.ts +147 -1
- package/src/__tests__/session-runtime-workspace.test.ts +40 -0
- package/src/__tests__/session-slash-known.test.ts +21 -3
- package/src/__tests__/session-slash-queue.test.ts +17 -2
- package/src/__tests__/session-slash-unknown.test.ts +17 -2
- package/src/__tests__/session-surfaces-deselection.test.ts +208 -0
- package/src/__tests__/session-workspace-cache-state.test.ts +2 -2
- package/src/__tests__/session-workspace-injection.test.ts +17 -2
- package/src/__tests__/session-workspace-tool-tracking.test.ts +17 -2
- package/src/__tests__/shell-credential-ref.test.ts +1 -1
- package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +9 -5
- package/src/__tests__/skill-feature-flags.test.ts +18 -12
- package/src/__tests__/skill-load-feature-flag.test.ts +5 -4
- package/src/__tests__/skill-load-tool.test.ts +1 -1
- package/src/__tests__/skill-script-runner-host.test.ts +1 -1
- package/src/__tests__/skill-script-runner-sandbox.test.ts +1 -1
- package/src/__tests__/skill-script-runner.test.ts +1 -1
- package/src/__tests__/skill-tool-factory.test.ts +1 -1
- package/src/__tests__/slack-block-formatting.test.ts +100 -0
- package/src/__tests__/slack-inbound-verification.test.ts +346 -0
- package/src/__tests__/slack-reaction-approvals.test.ts +77 -0
- package/src/__tests__/slack-skill.test.ts +4 -2
- package/src/__tests__/starter-task-flow.test.ts +0 -1
- package/src/__tests__/subagent-tools.test.ts +3 -3
- package/src/__tests__/swarm-recursion.test.ts +1 -1
- package/src/__tests__/swarm-session-integration.test.ts +1 -1
- package/src/__tests__/swarm-tool.test.ts +1 -1
- package/src/__tests__/task-management-tools.test.ts +1 -1
- package/src/__tests__/task-tools.test.ts +1 -1
- package/src/__tests__/terminal-tools.test.ts +1 -1
- package/src/__tests__/test-support/browser-skill-harness.ts +39 -27
- package/src/__tests__/test-support/computer-use-skill-harness.ts +14 -14
- package/src/__tests__/tool-approval-handler.test.ts +15 -15
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -1
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -2
- package/src/__tests__/tool-executor-shell-integration.test.ts +1 -1
- package/src/__tests__/tool-executor.test.ts +23 -182
- package/src/__tests__/tool-grant-request-escalation.test.ts +11 -11
- package/src/__tests__/tool-permission-simulate-handler.test.ts +4 -4
- package/src/__tests__/transfer-progress-screen.test.ts +1180 -0
- package/src/__tests__/trust-context-guards.test.ts +25 -29
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +23 -21
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +37 -40
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +29 -25
- package/src/__tests__/trusted-contact-multichannel.test.ts +25 -24
- package/src/__tests__/trusted-contact-verification.test.ts +64 -76
- package/src/__tests__/turn-commit.test.ts +18 -18
- package/src/__tests__/twilio-provider.test.ts +7 -7
- package/src/__tests__/validation-results-screen.test.ts +1107 -0
- package/src/__tests__/view-image-tool.test.ts +1 -1
- package/src/__tests__/voice-invite-redemption.test.ts +4 -3
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +12 -12
- package/src/__tests__/voice-session-bridge.test.ts +24 -24
- package/src/agent/attachments.ts +3 -1
- package/src/agent/loop.ts +13 -13
- package/src/agent/message-types.ts +13 -7
- package/src/amazon/cart.ts +59 -32
- package/src/amazon/checkout.ts +25 -14
- package/src/amazon/client.ts +61 -58
- package/src/amazon/product-details.ts +3 -3
- package/src/amazon/request-extractor.ts +46 -31
- package/src/amazon/search.ts +6 -4
- package/src/amazon/session.ts +33 -24
- package/src/approvals/AGENTS.md +26 -0
- package/src/approvals/approval-primitive.ts +87 -64
- package/src/approvals/guardian-decision-primitive.ts +172 -81
- package/src/approvals/guardian-request-resolvers.ts +262 -155
- package/src/autonomy/autonomy-resolver.ts +7 -5
- package/src/autonomy/autonomy-store.ts +34 -19
- package/src/autonomy/disposition-mapper.ts +5 -5
- package/src/autonomy/index.ts +6 -6
- package/src/autonomy/types.ts +7 -3
- package/src/browser-extension-relay/client.ts +50 -19
- package/src/browser-extension-relay/protocol.ts +11 -11
- package/src/browser-extension-relay/server.ts +45 -20
- package/src/bundler/app-bundler.ts +75 -50
- package/src/bundler/bundle-scanner.ts +145 -41
- package/src/bundler/bundle-signer.ts +16 -14
- package/src/bundler/signature-verifier.ts +36 -33
- package/src/calls/call-constants.ts +10 -3
- package/src/calls/call-controller.ts +473 -214
- package/src/calls/call-conversation-messages.ts +25 -15
- package/src/calls/call-domain.ts +401 -148
- package/src/calls/call-pointer-message-composer.ts +26 -21
- package/src/calls/call-pointer-messages.ts +52 -28
- package/src/calls/call-recovery.ts +53 -37
- package/src/calls/call-state-machine.ts +37 -7
- package/src/calls/call-state.ts +35 -13
- package/src/calls/call-store.ts +165 -77
- package/src/calls/elevenlabs-client.ts +39 -20
- package/src/calls/guardian-action-sweep.ts +42 -24
- package/src/calls/guardian-dispatch.ts +79 -56
- package/src/calls/guardian-question-copy.ts +28 -23
- package/src/calls/relay-server.ts +1149 -532
- package/src/calls/speaker-identification.ts +21 -15
- package/src/calls/twilio-config.ts +34 -17
- package/src/calls/twilio-provider.ts +108 -55
- package/src/calls/twilio-rest.ts +212 -100
- package/src/calls/twilio-routes.ts +165 -92
- package/src/calls/types.ts +55 -7
- package/src/calls/voice-quality.ts +6 -4
- package/src/calls/voice-session-bridge.ts +181 -133
- package/src/channels/config.ts +18 -14
- package/src/channels/types.ts +38 -10
- package/src/cli/amazon.ts +333 -227
- package/src/cli/config-commands.ts +236 -146
- package/src/cli/core-commands.ts +403 -329
- package/src/cli/email-guardrails.ts +38 -19
- package/src/cli/email.ts +207 -153
- package/src/cli/influencer.ts +58 -56
- package/src/cli/integrations.ts +306 -0
- package/src/cli/ipc-client.ts +24 -19
- package/src/cli/map.ts +176 -129
- package/src/cli/mcp.ts +260 -152
- package/src/cli/sequence.ts +165 -107
- package/src/cli/twitter.ts +302 -218
- package/src/cli.ts +418 -279
- package/src/commands/cc-command-registry.ts +52 -27
- package/src/config/agent-schema.ts +217 -134
- package/src/config/assistant-feature-flags.ts +23 -18
- package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +19 -0
- package/src/config/bundled-skills/app-builder/SKILL.md +193 -1500
- package/src/config/bundled-skills/app-builder/TOOLS.json +70 -18
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +7 -4
- package/src/config/bundled-skills/app-builder/tools/app-delete.ts +6 -3
- package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +7 -4
- package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +6 -3
- package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +6 -3
- package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +7 -4
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +6 -3
- package/src/config/bundled-skills/app-builder/tools/app-query.ts +6 -3
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +6 -3
- package/src/config/bundled-skills/browser/TOOLS.json +59 -2
- package/src/config/bundled-skills/browser/tools/browser-click.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-close.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-extract.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-hover.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-navigate.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-press-key.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-scroll.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-select-option.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-type.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +13 -6
- package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +5 -2
- package/src/config/bundled-skills/chatgpt-import/TOOLS.json +4 -0
- package/src/config/bundled-skills/claude-code/TOOLS.json +4 -0
- package/src/config/bundled-skills/claude-code/tools/claude-code.ts +5 -2
- package/src/config/bundled-skills/computer-use/SKILL.md +2 -2
- package/src/config/bundled-skills/computer-use/TOOLS.json +50 -2
- package/src/config/bundled-skills/computer-use/tools/computer-use-click.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-done.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-double-click.ts +10 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-drag.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-key.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-open-app.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-request-control.ts +10 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-respond.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-right-click.ts +10 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-run-applescript.ts +10 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-scroll.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-type-text.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-wait.ts +6 -3
- package/src/config/bundled-skills/configure-settings/SKILL.md +28 -14
- package/src/config/bundled-skills/contacts/SKILL.md +453 -15
- package/src/config/bundled-skills/contacts/TOOLS.json +22 -2
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +79 -20
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +55 -18
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +64 -19
- package/src/config/bundled-skills/document/TOOLS.json +8 -0
- package/src/config/bundled-skills/document/tools/document-create.ts +5 -2
- package/src/config/bundled-skills/document/tools/document-update.ts +5 -2
- package/src/config/bundled-skills/doordash/doordash-cli.ts +17 -7
- package/src/config/bundled-skills/email-setup/SKILL.md +12 -9
- package/src/config/bundled-skills/followups/TOOLS.json +12 -0
- package/src/config/bundled-skills/followups/tools/followup-create.ts +5 -2
- package/src/config/bundled-skills/followups/tools/followup-list.ts +5 -2
- package/src/config/bundled-skills/followups/tools/followup-resolve.ts +5 -2
- package/src/config/bundled-skills/google-calendar/TOOLS.json +124 -26
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +44 -32
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +11 -5
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +13 -7
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +11 -5
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +13 -7
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +28 -12
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +6 -4
- package/src/config/bundled-skills/google-calendar/types.ts +3 -3
- package/src/config/bundled-skills/guardian-verify-setup/SKILL.md +88 -33
- package/src/config/bundled-skills/image-studio/TOOLS.json +12 -2
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +48 -25
- package/src/config/bundled-skills/knowledge-graph/TOOLS.json +13 -3
- package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +60 -35
- package/src/config/bundled-skills/mcp-setup/SKILL.md +75 -0
- package/src/config/bundled-skills/media-processing/SKILL.md +55 -15
- package/src/config/bundled-skills/media-processing/TOOLS.json +48 -2
- package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +12 -10
- package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +34 -19
- package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +82 -66
- package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +148 -0
- package/src/config/bundled-skills/media-processing/services/concurrency-pool.ts +1 -1
- package/src/config/bundled-skills/media-processing/services/cost-tracker.ts +8 -3
- package/src/config/bundled-skills/media-processing/services/gemini-map.ts +117 -53
- package/src/config/bundled-skills/media-processing/services/gemini-video.ts +273 -0
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +185 -97
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +32 -27
- package/src/config/bundled-skills/media-processing/services/reduce.ts +101 -24
- package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +121 -55
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +58 -24
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +198 -92
- package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +98 -70
- package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +59 -19
- package/src/config/bundled-skills/media-processing/tools/media-status.ts +26 -10
- package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +29 -14
- package/src/config/bundled-skills/messaging/SKILL.md +7 -5
- package/src/config/bundled-skills/messaging/TOOLS.json +232 -186
- package/src/config/bundled-skills/messaging/tools/gmail-archive-by-query.ts +31 -13
- package/src/config/bundled-skills/messaging/tools/gmail-archive.ts +16 -10
- package/src/config/bundled-skills/messaging/tools/gmail-batch-label.ts +18 -9
- package/src/config/bundled-skills/messaging/tools/gmail-download-attachment.ts +23 -16
- package/src/config/bundled-skills/messaging/tools/gmail-draft.ts +28 -12
- package/src/config/bundled-skills/messaging/tools/gmail-filters.ts +41 -21
- package/src/config/bundled-skills/messaging/tools/gmail-follow-up.ts +44 -23
- package/src/config/bundled-skills/messaging/tools/gmail-forward.ts +73 -33
- package/src/config/bundled-skills/messaging/tools/gmail-label.ts +15 -9
- package/src/config/bundled-skills/messaging/tools/gmail-list-attachments.ts +22 -14
- package/src/config/bundled-skills/messaging/tools/gmail-outreach-scan.ts +99 -50
- package/src/config/bundled-skills/messaging/tools/gmail-send-draft.ts +14 -8
- package/src/config/bundled-skills/messaging/tools/gmail-send-with-attachments.ts +63 -44
- package/src/config/bundled-skills/messaging/tools/gmail-sender-digest.ts +90 -46
- package/src/config/bundled-skills/messaging/tools/gmail-summarize-thread.ts +43 -22
- package/src/config/bundled-skills/messaging/tools/gmail-trash.ts +15 -9
- package/src/config/bundled-skills/messaging/tools/gmail-triage.ts +51 -22
- package/src/config/bundled-skills/messaging/tools/gmail-unsubscribe.ts +62 -26
- package/src/config/bundled-skills/messaging/tools/gmail-vacation.ts +34 -19
- package/src/config/bundled-skills/messaging/tools/google-contacts.ts +32 -16
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-activity.ts +10 -4
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +91 -47
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +21 -9
- package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +9 -3
- package/src/config/bundled-skills/messaging/tools/messaging-draft.ts +30 -17
- package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +10 -4
- package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +14 -6
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +16 -5
- package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +63 -36
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +10 -4
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +30 -12
- package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +48 -29
- package/src/config/bundled-skills/messaging/tools/scan-result-store.ts +20 -6
- package/src/config/bundled-skills/messaging/tools/send-notification.ts +1 -1
- package/src/config/bundled-skills/messaging/tools/sequence-analytics.ts +59 -22
- package/src/config/bundled-skills/messaging/tools/sequence-cancel.ts +13 -7
- package/src/config/bundled-skills/messaging/tools/sequence-create.ts +27 -12
- package/src/config/bundled-skills/messaging/tools/sequence-delete.ts +14 -6
- package/src/config/bundled-skills/messaging/tools/sequence-enroll.ts +30 -11
- package/src/config/bundled-skills/messaging/tools/sequence-enrollment-list.ts +16 -8
- package/src/config/bundled-skills/messaging/tools/sequence-get.ts +31 -13
- package/src/config/bundled-skills/messaging/tools/sequence-import.ts +38 -22
- package/src/config/bundled-skills/messaging/tools/sequence-list.ts +16 -7
- package/src/config/bundled-skills/messaging/tools/sequence-pause.ts +29 -10
- package/src/config/bundled-skills/messaging/tools/sequence-resume.ts +16 -8
- package/src/config/bundled-skills/messaging/tools/sequence-update.ts +35 -16
- package/src/config/bundled-skills/messaging/tools/shared.ts +26 -12
- package/src/config/bundled-skills/notifications/SKILL.md +3 -2
- package/src/config/bundled-skills/notifications/TOOLS.json +7 -13
- package/src/config/bundled-skills/notifications/tools/send-notification.ts +69 -34
- package/src/config/bundled-skills/notifications/tools/shared.ts +1 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +46 -48
- package/src/config/bundled-skills/phone-calls/TOOLS.json +13 -1
- package/src/config/bundled-skills/phone-calls/tools/call-end.ts +1 -1
- package/src/config/bundled-skills/phone-calls/tools/call-start.ts +1 -1
- package/src/config/bundled-skills/phone-calls/tools/call-status.ts +1 -1
- package/src/config/bundled-skills/playbooks/TOOLS.json +16 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +91 -51
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +30 -16
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +66 -27
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +89 -42
- package/src/config/bundled-skills/public-ingress/SKILL.md +26 -19
- package/src/config/bundled-skills/reminder/TOOLS.json +15 -2
- package/src/config/bundled-skills/reminder/tools/reminder-cancel.ts +5 -2
- package/src/config/bundled-skills/reminder/tools/reminder-create.ts +5 -2
- package/src/config/bundled-skills/reminder/tools/reminder-list.ts +5 -2
- package/src/config/bundled-skills/schedule/SKILL.md +33 -15
- package/src/config/bundled-skills/schedule/TOOLS.json +17 -1
- package/src/config/bundled-skills/schedule/tools/schedule-create.ts +5 -2
- package/src/config/bundled-skills/schedule/tools/schedule-delete.ts +5 -2
- package/src/config/bundled-skills/schedule/tools/schedule-list.ts +5 -2
- package/src/config/bundled-skills/schedule/tools/schedule-update.ts +5 -2
- package/src/config/bundled-skills/screen-recording/SKILL.md +11 -3
- package/src/config/bundled-skills/self-upgrade/SKILL.md +9 -8
- package/src/config/bundled-skills/slack/SKILL.md +30 -1
- package/src/config/bundled-skills/slack/TOOLS.json +122 -17
- package/src/config/bundled-skills/slack/tools/shared.ts +7 -5
- package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +11 -5
- package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +11 -5
- package/src/config/bundled-skills/slack/tools/slack-channel-permissions.ts +146 -0
- package/src/config/bundled-skills/slack/tools/slack-configure-channels.ts +46 -16
- package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +11 -5
- package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +28 -0
- package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +12 -6
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +120 -0
- package/src/config/bundled-skills/slack-app-setup/SKILL.md +200 -0
- package/src/config/bundled-skills/sms-setup/SKILL.md +5 -8
- package/src/config/bundled-skills/subagent/TOOLS.json +22 -2
- package/src/config/bundled-skills/subagent/tools/subagent-abort.ts +5 -2
- package/src/config/bundled-skills/subagent/tools/subagent-message.ts +5 -2
- package/src/config/bundled-skills/subagent/tools/subagent-read.ts +5 -2
- package/src/config/bundled-skills/subagent/tools/subagent-spawn.ts +5 -2
- package/src/config/bundled-skills/subagent/tools/subagent-status.ts +5 -2
- package/src/config/bundled-skills/tasks/TOOLS.json +86 -14
- package/src/config/bundled-skills/tasks/tools/task-delete.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-list-add.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-list-show.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-list-update.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-list.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-run.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-save.ts +5 -2
- package/src/config/bundled-skills/telegram-setup/SKILL.md +7 -8
- package/src/config/bundled-skills/transcribe/TOOLS.json +4 -0
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +232 -127
- package/src/config/bundled-skills/twilio-setup/SKILL.md +7 -12
- package/src/config/bundled-skills/twitter/SKILL.md +19 -2
- package/src/config/bundled-skills/voice-setup/SKILL.md +5 -5
- package/src/config/bundled-skills/watcher/TOOLS.json +20 -0
- package/src/config/bundled-skills/watcher/tools/watcher-create.ts +5 -2
- package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +5 -2
- package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +5 -2
- package/src/config/bundled-skills/watcher/tools/watcher-list.ts +5 -2
- package/src/config/bundled-skills/watcher/tools/watcher-update.ts +5 -2
- package/src/config/bundled-skills/weather/TOOLS.json +4 -0
- package/src/config/bundled-skills/weather/tools/get-weather.ts +5 -2
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/calls-schema.ts +108 -63
- package/src/config/channel-permission-profiles.ts +155 -0
- package/src/config/computer-use-prompt.ts +7 -7
- package/src/config/core-schema.ts +239 -155
- package/src/config/defaults.ts +2 -2
- package/src/config/elevenlabs-schema.ts +15 -15
- package/src/config/env-registry.ts +33 -33
- package/src/config/env.ts +4 -1
- package/src/config/feature-flag-registry.json +31 -7
- package/src/config/loader.ts +118 -58
- package/src/config/mcp-schema.ts +29 -15
- package/src/config/memory-schema.ts +434 -229
- package/src/config/notifications-schema.ts +4 -4
- package/src/config/sandbox-schema.ts +2 -2
- package/src/config/schema.ts +12 -2
- package/src/config/skill-state.ts +27 -15
- package/src/config/skills-schema.ts +72 -23
- package/src/config/skills.ts +303 -143
- package/src/config/system-prompt.ts +25 -6
- package/src/config/types.ts +1 -1
- package/src/config/update-bulletin-format.ts +3 -3
- package/src/config/update-bulletin-state.ts +15 -6
- package/src/config/update-bulletin-template-path.ts +8 -4
- package/src/config/update-bulletin.ts +33 -14
- package/src/config/user-reference.ts +8 -8
- package/src/contacts/contact-events.ts +21 -0
- package/src/contacts/contact-store.ts +813 -100
- package/src/contacts/contacts-write.ts +287 -0
- package/src/contacts/index.ts +13 -4
- package/src/contacts/startup-migration.ts +21 -0
- package/src/contacts/types.ts +73 -2
- package/src/context/token-estimator.ts +54 -31
- package/src/context/tool-result-truncation.ts +41 -7
- package/src/context/window-manager.ts +225 -120
- package/src/daemon/approval-generators.ts +83 -55
- package/src/daemon/approved-devices-store.ts +33 -20
- package/src/daemon/assistant-attachments.ts +157 -101
- package/src/daemon/auth-manager.ts +17 -15
- package/src/daemon/classifier.ts +117 -46
- package/src/daemon/computer-use-session.ts +316 -187
- package/src/daemon/config-watcher.ts +91 -44
- package/src/daemon/connection-policy.ts +18 -10
- package/src/daemon/context-overflow-approval.ts +48 -0
- package/src/daemon/context-overflow-policy.ts +50 -0
- package/src/daemon/context-overflow-reducer.ts +300 -0
- package/src/daemon/daemon-control.ts +79 -51
- package/src/daemon/date-context.ts +119 -69
- package/src/daemon/dictation-profile-store.ts +94 -48
- package/src/daemon/dictation-text-processing.ts +33 -12
- package/src/daemon/doordash-steps.ts +92 -49
- package/src/daemon/guardian-action-generators.ts +62 -46
- package/src/daemon/guardian-verification-intent.ts +35 -19
- package/src/daemon/handlers/apps.ts +258 -113
- package/src/daemon/handlers/avatar.ts +20 -15
- package/src/daemon/handlers/computer-use.ts +82 -39
- package/src/daemon/handlers/config-channels.ts +146 -69
- package/src/daemon/handlers/config-heartbeat.ts +114 -59
- package/src/daemon/handlers/config-inbox.ts +213 -160
- package/src/daemon/handlers/config-ingress.ts +127 -55
- package/src/daemon/handlers/config-integrations.ts +145 -88
- package/src/daemon/handlers/config-model.ts +58 -22
- package/src/daemon/handlers/config-platform.ts +40 -16
- package/src/daemon/handlers/config-scheduling.ts +109 -48
- package/src/daemon/handlers/config-slack-channel.ts +67 -35
- package/src/daemon/handlers/config-slack.ts +21 -20
- package/src/daemon/handlers/config-telegram.ts +100 -70
- package/src/daemon/handlers/config-tools.ts +103 -55
- package/src/daemon/handlers/config-trust.ts +50 -20
- package/src/daemon/handlers/config.ts +72 -24
- package/src/daemon/handlers/contacts.ts +163 -0
- package/src/daemon/handlers/diagnostics.ts +90 -48
- package/src/daemon/handlers/documents.ts +74 -46
- package/src/daemon/handlers/guardian-actions.ts +57 -77
- package/src/daemon/handlers/home-base.ts +19 -16
- package/src/daemon/handlers/identity.ts +65 -45
- package/src/daemon/handlers/index.ts +78 -54
- package/src/daemon/handlers/misc.ts +664 -234
- package/src/daemon/handlers/navigate-settings.ts +14 -11
- package/src/daemon/handlers/oauth-connect.ts +48 -35
- package/src/daemon/handlers/open-bundle-handler.ts +31 -24
- package/src/daemon/handlers/pairing.ts +51 -25
- package/src/daemon/handlers/publish.ts +55 -33
- package/src/daemon/handlers/recording.ts +378 -162
- package/src/daemon/handlers/sessions.ts +922 -423
- package/src/daemon/handlers/shared.ts +202 -117
- package/src/daemon/handlers/signing.ts +25 -6
- package/src/daemon/handlers/subagents.ts +117 -56
- package/src/daemon/handlers/twitter-auth.ts +70 -49
- package/src/daemon/handlers/work-items.ts +264 -112
- package/src/daemon/handlers/workspace-files.ts +27 -20
- package/src/daemon/handlers.ts +2 -2
- package/src/daemon/history-repair.ts +16 -15
- package/src/daemon/identity-helpers.ts +4 -4
- package/src/daemon/install-cli-launchers.ts +33 -22
- package/src/daemon/ipc-blob-store.ts +38 -24
- package/src/daemon/ipc-contract/apps.ts +61 -50
- package/src/daemon/ipc-contract/computer-use.ts +47 -37
- package/src/daemon/ipc-contract/contacts.ts +69 -0
- package/src/daemon/ipc-contract/diagnostics.ts +14 -14
- package/src/daemon/ipc-contract/documents.ts +8 -8
- package/src/daemon/ipc-contract/guardian-actions.ts +4 -4
- package/src/daemon/ipc-contract/inbox.ts +12 -71
- package/src/daemon/ipc-contract/integrations.ts +57 -44
- package/src/daemon/ipc-contract/memory.ts +3 -5
- package/src/daemon/ipc-contract/messages.ts +95 -69
- package/src/daemon/ipc-contract/notifications.ts +10 -6
- package/src/daemon/ipc-contract/pairing.ts +8 -8
- package/src/daemon/ipc-contract/schedules.ts +20 -20
- package/src/daemon/ipc-contract/sessions.ts +89 -57
- package/src/daemon/ipc-contract/settings.ts +12 -7
- package/src/daemon/ipc-contract/shared.ts +9 -7
- package/src/daemon/ipc-contract/skills.ts +46 -26
- package/src/daemon/ipc-contract/subagents.ts +9 -9
- package/src/daemon/ipc-contract/surfaces.ts +0 -1
- package/src/daemon/ipc-contract/trust.ts +11 -11
- package/src/daemon/ipc-contract/work-items.ts +33 -28
- package/src/daemon/ipc-contract/workspace.ts +28 -21
- package/src/daemon/ipc-contract-inventory.json +10 -4
- package/src/daemon/ipc-contract-inventory.ts +29 -26
- package/src/daemon/ipc-contract.ts +111 -44
- package/src/daemon/ipc-handler.ts +27 -19
- package/src/daemon/ipc-protocol.ts +22 -12
- package/src/daemon/ipc-validate.ts +91 -46
- package/src/daemon/lifecycle.ts +39 -3
- package/src/daemon/main.ts +10 -8
- package/src/daemon/media-visibility-policy.ts +3 -1
- package/src/daemon/pairing-store.ts +72 -40
- package/src/daemon/providers-setup.ts +35 -25
- package/src/daemon/recording-executor.ts +37 -30
- package/src/daemon/recording-intent-fallback.ts +58 -28
- package/src/daemon/recording-intent.ts +71 -61
- package/src/daemon/ride-shotgun-handler.ts +201 -121
- package/src/daemon/seed-files.ts +28 -17
- package/src/daemon/server.ts +23 -14
- package/src/daemon/session-agent-loop-handlers.ts +270 -135
- package/src/daemon/session-agent-loop.ts +796 -253
- package/src/daemon/session-attachments.ts +109 -40
- package/src/daemon/session-conflict-gate.ts +72 -28
- package/src/daemon/session-dynamic-profile.ts +36 -22
- package/src/daemon/session-error.ts +68 -45
- package/src/daemon/session-evictor.ts +17 -10
- package/src/daemon/session-history.ts +201 -89
- package/src/daemon/session-lifecycle.ts +80 -44
- package/src/daemon/session-media-retry.ts +104 -42
- package/src/daemon/session-memory.ts +77 -55
- package/src/daemon/session-messaging.ts +261 -111
- package/src/daemon/session-notifiers.ts +57 -45
- package/src/daemon/session-process.ts +370 -154
- package/src/daemon/session-queue-manager.ts +30 -13
- package/src/daemon/session-runtime-assembly.ts +61 -15
- package/src/daemon/session-skill-tools.ts +84 -36
- package/src/daemon/session-slash.ts +178 -113
- package/src/daemon/session-surfaces.ts +498 -212
- package/src/daemon/session-tool-setup.ts +24 -16
- package/src/daemon/session-usage.ts +26 -13
- package/src/daemon/session-workspace.ts +7 -4
- package/src/daemon/session.ts +18 -19
- package/src/daemon/shutdown-handlers.ts +36 -33
- package/src/daemon/tls-certs.ts +90 -57
- package/src/daemon/tool-side-effects.ts +97 -65
- package/src/daemon/trace-emitter.ts +8 -7
- package/src/daemon/video-thumbnail.ts +55 -25
- package/src/daemon/watch-handler.ts +164 -86
- package/src/email/provider.ts +1 -1
- package/src/email/providers/agentmail.ts +87 -45
- package/src/email/providers/index.ts +19 -14
- package/src/email/service.ts +52 -24
- package/src/email/types.ts +2 -2
- package/src/errors.ts +1 -1
- package/src/events/bus.ts +30 -10
- package/src/events/domain-events.ts +20 -13
- package/src/events/index.ts +6 -6
- package/src/events/tool-audit-listener.ts +34 -20
- package/src/events/tool-domain-event-publisher.ts +22 -20
- package/src/events/tool-metrics-listener.ts +26 -21
- package/src/events/tool-notification-listener.ts +5 -5
- package/src/events/tool-profiling-listener.ts +33 -23
- package/src/events/tool-trace-listener.ts +70 -46
- package/src/export/formatter.ts +38 -32
- package/src/followups/followup-store.ts +43 -36
- package/src/followups/index.ts +2 -2
- package/src/followups/types.ts +1 -1
- package/src/gallery/default-gallery.ts +37 -34
- package/src/gallery/gallery-manifest.ts +9 -9
- package/src/heartbeat/heartbeat-service.ts +59 -37
- package/src/home-base/app-link-store.ts +14 -12
- package/src/home-base/bootstrap.ts +14 -8
- package/src/home-base/prebuilt/seed.ts +34 -26
- package/src/home-base/prebuilt-home-base-updater.ts +14 -8
- package/src/hooks/cli.ts +56 -43
- package/src/hooks/config.ts +27 -14
- package/src/hooks/discovery.ts +53 -33
- package/src/hooks/manager.ts +50 -26
- package/src/hooks/runner.ts +35 -29
- package/src/hooks/templates.ts +38 -15
- package/src/hooks/types.ts +13 -13
- package/src/inbound/platform-callback-registration.ts +21 -15
- package/src/inbound/public-ingress-urls.ts +9 -6
- package/src/index.ts +20 -19
- package/src/influencer/client.ts +261 -117
- package/src/instrument.ts +3 -1
- package/src/logfire.ts +64 -39
- package/src/mcp/client.ts +107 -55
- package/src/mcp/manager.ts +45 -18
- package/src/mcp/mcp-oauth-provider.ts +114 -62
- package/src/media/gemini-image-service.ts +75 -23
- package/src/memory/account-store.ts +16 -9
- package/src/memory/admin.ts +87 -57
- package/src/memory/app-git-service.ts +77 -47
- package/src/memory/app-store.ts +148 -78
- package/src/memory/attachments-store.ts +123 -53
- package/src/memory/canonical-guardian-store.ts +190 -48
- package/src/memory/channel-delivery-store.ts +5 -5
- package/src/memory/channel-guardian-store.ts +31 -16
- package/src/memory/checkpoints.ts +14 -7
- package/src/memory/clarification-resolver.ts +219 -104
- package/src/memory/conflict-intent.ts +74 -23
- package/src/memory/conflict-policy.ts +20 -7
- package/src/memory/conflict-store.ts +144 -94
- package/src/memory/contradiction-checker.ts +257 -132
- package/src/memory/conversation-attention-store.ts +74 -32
- package/src/memory/conversation-bootstrap.ts +28 -0
- package/src/memory/conversation-crud.ts +12 -5
- package/src/memory/conversation-display-order-migration.ts +7 -7
- package/src/memory/conversation-key-store.ts +18 -13
- package/src/memory/conversation-queries.ts +130 -52
- package/src/memory/conversation-store.ts +43 -26
- package/src/memory/conversation-title-service.ts +89 -66
- package/src/memory/db-init.ts +94 -2
- package/src/memory/db.ts +10 -3
- package/src/memory/delivery-channels.ts +12 -6
- package/src/memory/delivery-crud.ts +26 -12
- package/src/memory/delivery-status.ts +19 -16
- package/src/memory/embedding-backend.ts +205 -77
- package/src/memory/embedding-gemini.ts +23 -10
- package/src/memory/embedding-local.ts +89 -44
- package/src/memory/embedding-ollama.ts +25 -13
- package/src/memory/embedding-openai.ts +20 -11
- package/src/memory/embedding-runtime-manager.ts +163 -90
- package/src/memory/entity-extractor.ts +185 -123
- package/src/memory/external-conversation-store.ts +30 -12
- package/src/memory/fingerprint.ts +2 -2
- package/src/memory/fts-reconciler.ts +57 -28
- package/src/memory/guardian-action-store.ts +162 -100
- package/src/memory/guardian-approvals.ts +63 -129
- package/src/memory/guardian-rate-limits.ts +20 -9
- package/src/memory/guardian-verification.ts +82 -35
- package/src/memory/indexer.ts +96 -55
- package/src/memory/{ingress-invite-store.ts → invite-store.ts} +28 -169
- package/src/memory/items-extractor.ts +313 -157
- package/src/memory/job-handlers/backfill.ts +116 -63
- package/src/memory/job-handlers/cleanup.ts +64 -41
- package/src/memory/job-handlers/conflict.ts +90 -49
- package/src/memory/job-handlers/embedding.ts +32 -17
- package/src/memory/job-handlers/extraction.ts +58 -33
- package/src/memory/job-handlers/index-maintenance.ts +31 -17
- package/src/memory/job-handlers/media-processing.ts +65 -24
- package/src/memory/job-handlers/summarization.ts +186 -128
- package/src/memory/job-utils.ts +100 -57
- package/src/memory/jobs-store.ts +235 -142
- package/src/memory/jobs-worker.ts +167 -83
- package/src/memory/llm-request-log-store.ts +13 -11
- package/src/memory/llm-usage-store.ts +35 -26
- package/src/memory/media-store.ts +151 -44
- package/src/memory/message-content.ts +28 -18
- package/src/memory/migrations/001-job-deferrals.ts +11 -5
- package/src/memory/migrations/002-tool-invocations-fk.ts +14 -6
- package/src/memory/migrations/003-memory-fts-backfill.ts +11 -5
- package/src/memory/migrations/004-entity-relation-dedup.ts +17 -11
- package/src/memory/migrations/005-fingerprint-scope-unique.ts +36 -21
- package/src/memory/migrations/006-scope-salted-fingerprints.ts +35 -20
- package/src/memory/migrations/007-assistant-id-to-self.ts +40 -27
- package/src/memory/migrations/008-remove-assistant-id-columns.ts +58 -36
- package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +36 -22
- package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +21 -11
- package/src/memory/migrations/011-call-sessions-provider-sid-dedup.ts +30 -15
- package/src/memory/migrations/012-call-sessions-add-initiated-from.ts +4 -2
- package/src/memory/migrations/013-guardian-action-tables.ts +29 -11
- package/src/memory/migrations/014-backfill-inbox-thread-state.ts +35 -21
- package/src/memory/migrations/015-drop-active-search-index.ts +17 -11
- package/src/memory/migrations/016-memory-segments-indexes.ts +7 -3
- package/src/memory/migrations/017-memory-items-indexes.ts +4 -2
- package/src/memory/migrations/018-remaining-table-indexes.ts +13 -5
- package/src/memory/migrations/019-notification-tables-schema-migration.ts +34 -20
- package/src/memory/migrations/020-rename-macos-ios-channel-to-vellum.ts +87 -53
- package/src/memory/migrations/021-conversation-status-indexes.ts +7 -3
- package/src/memory/migrations/022-add-origin-interface.ts +4 -2
- package/src/memory/migrations/023-memory-item-sources-indexes.ts +4 -2
- package/src/memory/migrations/024-embedding-vector-blob.ts +34 -18
- package/src/memory/migrations/025-messages-fts-backfill.ts +11 -5
- package/src/memory/migrations/026-guardian-verification-sessions.ts +80 -14
- package/src/memory/migrations/026a-embeddings-nullable-vector-json.ts +42 -26
- package/src/memory/migrations/027-notification-delivery-pairing-columns.ts +22 -8
- package/src/memory/migrations/027a-guardian-bootstrap-token.ts +11 -3
- package/src/memory/migrations/028-call-session-mode.ts +13 -3
- package/src/memory/migrations/028-notification-delivery-client-ack.ts +22 -8
- package/src/memory/migrations/029-channel-inbound-delivered-segments.ts +7 -3
- package/src/memory/migrations/030-guardian-action-followup.ts +46 -8
- package/src/memory/migrations/030-guardian-verification-purpose.ts +4 -2
- package/src/memory/migrations/031-conversations-thread-type-index.ts +4 -2
- package/src/memory/migrations/032-guardian-delivery-conversation-index.ts +4 -2
- package/src/memory/migrations/032-notification-delivery-thread-decision.ts +22 -8
- package/src/memory/migrations/033-scoped-approval-grants.ts +1 -1
- package/src/memory/migrations/034-guardian-action-tool-metadata.ts +15 -3
- package/src/memory/migrations/035-guardian-action-supersession.ts +15 -3
- package/src/memory/migrations/036-normalize-phone-identities.ts +101 -87
- package/src/memory/migrations/037-voice-invite-columns.ts +22 -4
- package/src/memory/migrations/038-actor-token-records.ts +5 -9
- package/src/memory/migrations/039-actor-refresh-token-records.ts +7 -13
- package/src/memory/migrations/100-core-tables.ts +1 -1
- package/src/memory/migrations/101-watchers-and-logs.ts +1 -1
- package/src/memory/migrations/103-complex-migrations.ts +9 -9
- package/src/memory/migrations/104-core-indexes.ts +188 -64
- package/src/memory/migrations/105-contacts-and-triage.ts +28 -10
- package/src/memory/migrations/106-call-sessions.ts +58 -16
- package/src/memory/migrations/107-followups.ts +16 -6
- package/src/memory/migrations/108-tasks-and-work-items.ts +43 -11
- package/src/memory/migrations/109-external-conversation-bindings.ts +11 -5
- package/src/memory/migrations/110-channel-guardian.ts +48 -10
- package/src/memory/migrations/111-media-assets.ts +52 -18
- package/src/memory/migrations/112-assistant-inbox.ts +32 -12
- package/src/memory/migrations/113-late-migrations.ts +12 -12
- package/src/memory/migrations/114-notifications.ts +28 -12
- package/src/memory/migrations/115-sequences.ts +10 -4
- package/src/memory/migrations/116-messages-fts.ts +1 -1
- package/src/memory/migrations/117-conversation-attention.ts +16 -6
- package/src/memory/migrations/118-reminder-routing-intent.ts +7 -3
- package/src/memory/migrations/119-schema-indexes-and-columns.ts +35 -15
- package/src/memory/migrations/120-fk-cascade-rebuilds.ts +36 -17
- package/src/memory/migrations/121-canonical-guardian-requests.ts +25 -9
- package/src/memory/migrations/122-canonical-guardian-requester-chat-id.ts +11 -3
- package/src/memory/migrations/123-canonical-guardian-deliveries-destination-index.ts +4 -2
- package/src/memory/migrations/124-voice-invite-display-metadata.ts +15 -3
- package/src/memory/migrations/125-guardian-principal-id-columns.ts +22 -4
- package/src/memory/migrations/126-backfill-guardian-principal-id.ts +174 -126
- package/src/memory/migrations/127-guardian-principal-id-not-null.ts +58 -42
- package/src/memory/migrations/128-contacts-role-principal.ts +26 -0
- package/src/memory/migrations/129-contact-channels-access-fields.ts +105 -0
- package/src/memory/migrations/130-contact-channels-type-ext-chat-id-index.ts +15 -0
- package/src/memory/migrations/131-drop-legacy-member-guardian-tables.ts +134 -0
- package/src/memory/migrations/132-contacts-assistant-id.ts +21 -0
- package/src/memory/migrations/133-assistant-contact-metadata.ts +21 -0
- package/src/memory/migrations/index.ts +83 -73
- package/src/memory/migrations/registry.ts +53 -37
- package/src/memory/migrations/validate-migration-state.ts +73 -46
- package/src/memory/profile-compiler.ts +58 -24
- package/src/memory/published-pages-store.ts +12 -16
- package/src/memory/qdrant-circuit-breaker.ts +28 -20
- package/src/memory/qdrant-client.ts +99 -63
- package/src/memory/qdrant-manager.ts +89 -57
- package/src/memory/query-builder.ts +9 -7
- package/src/memory/raw-query.ts +63 -14
- package/src/memory/recall-cache.ts +15 -8
- package/src/memory/retrieval-budget.ts +0 -1
- package/src/memory/retriever.ts +385 -192
- package/src/memory/schema-migration.ts +1 -1
- package/src/memory/schema.ts +56 -56
- package/src/memory/scoped-approval-grants.ts +99 -45
- package/src/memory/search/entity.ts +102 -40
- package/src/memory/search/formatting.ts +70 -52
- package/src/memory/search/lexical.ts +82 -43
- package/src/memory/search/ranking.ts +103 -39
- package/src/memory/search/semantic.ts +59 -35
- package/src/memory/search/types.ts +8 -8
- package/src/memory/segmenter.ts +20 -12
- package/src/memory/shared-app-links-store.ts +21 -16
- package/src/memory/slack-thread-store.ts +187 -0
- package/src/memory/task-memory-cleanup.ts +18 -8
- package/src/memory/tool-usage-store.ts +27 -19
- package/src/memory/validation.ts +4 -2
- package/src/messaging/activity-analyzer.ts +7 -7
- package/src/messaging/draft-store.ts +13 -10
- package/src/messaging/email-classifier.ts +73 -37
- package/src/messaging/index.ts +3 -3
- package/src/messaging/outreach-classifier.ts +76 -38
- package/src/messaging/provider-types.ts +2 -4
- package/src/messaging/provider.ts +37 -8
- package/src/messaging/providers/gmail/adapter.ts +183 -66
- package/src/messaging/providers/gmail/client.ts +3 -1
- package/src/messaging/providers/gmail/mime-builder.ts +21 -19
- package/src/messaging/providers/gmail/people-client.ts +22 -9
- package/src/messaging/providers/gmail/types.ts +6 -6
- package/src/messaging/providers/slack/adapter.ts +93 -43
- package/src/messaging/providers/slack/client.ts +165 -48
- package/src/messaging/providers/slack/types.ts +10 -0
- package/src/messaging/providers/sms/adapter.ts +76 -40
- package/src/messaging/providers/sms/client.ts +4 -4
- package/src/messaging/providers/telegram-bot/adapter.ts +52 -30
- package/src/messaging/providers/telegram-bot/client.ts +7 -7
- package/src/messaging/providers/whatsapp/adapter.ts +58 -31
- package/src/messaging/providers/whatsapp/client.ts +4 -4
- package/src/messaging/registry.ts +9 -5
- package/src/messaging/style-analyzer.ts +69 -39
- package/src/messaging/thread-summarizer.ts +101 -53
- package/src/messaging/triage-engine.ts +111 -82
- package/src/messaging/types.ts +10 -10
- package/src/migrations/config-merge.ts +18 -10
- package/src/migrations/data-layout.ts +35 -22
- package/src/migrations/data-merge.ts +17 -7
- package/src/migrations/hooks-merge.ts +43 -16
- package/src/migrations/index.ts +6 -6
- package/src/migrations/log.ts +9 -5
- package/src/migrations/skills-merge.ts +17 -7
- package/src/migrations/workspace-layout.ts +39 -25
- package/src/notifications/AGENTS.md +5 -0
- package/src/notifications/adapters/macos.ts +21 -14
- package/src/notifications/adapters/slack.ts +90 -0
- package/src/notifications/adapters/sms.ts +28 -15
- package/src/notifications/adapters/telegram.ts +24 -15
- package/src/notifications/broadcaster.ts +108 -52
- package/src/notifications/conversation-pairing.ts +64 -29
- package/src/notifications/copy-composer.ts +165 -95
- package/src/notifications/decision-engine.ts +353 -147
- package/src/notifications/decisions-store.ts +26 -10
- package/src/notifications/deliveries-store.ts +23 -13
- package/src/notifications/destination-resolver.ts +83 -24
- package/src/notifications/deterministic-checks.ts +78 -27
- package/src/notifications/emit-signal.ts +95 -41
- package/src/notifications/events-store.ts +13 -7
- package/src/notifications/guardian-question-mode.ts +125 -75
- package/src/notifications/preference-extractor.ts +85 -53
- package/src/notifications/preference-summary.ts +31 -18
- package/src/notifications/preferences-store.ts +29 -18
- package/src/notifications/runtime-dispatch.ts +22 -12
- package/src/notifications/signal.ts +4 -4
- package/src/notifications/thread-candidates.ts +59 -23
- package/src/notifications/thread-seed-composer.ts +45 -27
- package/src/notifications/types.ts +19 -10
- package/src/oauth/connect-orchestrator.ts +105 -54
- package/src/oauth/connect-types.ts +3 -3
- package/src/oauth/provider-profiles.ts +102 -59
- package/src/oauth/scope-policy.ts +5 -2
- package/src/oauth/token-persistence.ts +58 -24
- package/src/outbound-proxy/certs.ts +284 -0
- package/src/outbound-proxy/config.ts +94 -0
- package/src/outbound-proxy/connect-tunnel.ts +84 -0
- package/src/outbound-proxy/health.ts +62 -0
- package/src/outbound-proxy/host-pattern-match.ts +67 -0
- package/src/outbound-proxy/http-forwarder.ts +162 -0
- package/src/outbound-proxy/index.ts +80 -0
- package/src/outbound-proxy/logging.ts +193 -0
- package/src/outbound-proxy/mitm-handler.ts +292 -0
- package/src/outbound-proxy/policy.ts +172 -0
- package/src/outbound-proxy/router.ts +64 -0
- package/src/outbound-proxy/server.ts +145 -0
- package/src/outbound-proxy/types.ts +150 -0
- package/src/permissions/checker.ts +481 -189
- package/src/permissions/defaults.ts +135 -108
- package/src/permissions/prompter.ts +53 -27
- package/src/permissions/secret-prompter.ts +21 -15
- package/src/permissions/shell-identity.ts +47 -16
- package/src/permissions/trust-store.ts +185 -73
- package/src/permissions/types.ts +22 -12
- package/src/permissions/workspace-policy.ts +47 -38
- package/src/playbooks/index.ts +10 -2
- package/src/playbooks/playbook-compiler.ts +30 -24
- package/src/playbooks/types.ts +11 -8
- package/src/providers/anthropic/client.ts +328 -168
- package/src/providers/failover.ts +57 -22
- package/src/providers/fireworks/client.ts +9 -5
- package/src/providers/gemini/client.ts +61 -39
- package/src/providers/model-intents.ts +40 -33
- package/src/providers/ollama/client.ts +7 -7
- package/src/providers/openai/client.ts +109 -68
- package/src/providers/openrouter/client.ts +9 -5
- package/src/providers/provider-send-message.ts +59 -27
- package/src/providers/ratelimit.ts +25 -8
- package/src/providers/registry.ts +86 -38
- package/src/providers/retry.ts +93 -37
- package/src/providers/stream-timeout.ts +5 -3
- package/src/providers/types.ts +7 -6
- package/src/runtime/AGENTS.md +42 -0
- package/src/runtime/access-request-helper.ts +118 -68
- package/src/runtime/actor-refresh-token-store.ts +21 -16
- package/src/runtime/actor-token-store.ts +25 -18
- package/src/runtime/actor-trust-resolver.ts +191 -80
- package/src/runtime/approval-conversation-turn.ts +39 -26
- package/src/runtime/approval-message-composer.ts +116 -84
- package/src/runtime/assistant-event-hub.ts +25 -6
- package/src/runtime/assistant-event.ts +4 -4
- package/src/runtime/assistant-scope.ts +1 -1
- package/src/runtime/auth/__tests__/guard-tests.test.ts +36 -14
- package/src/runtime/auth/context.ts +8 -7
- package/src/runtime/auth/credential-service.ts +60 -38
- package/src/runtime/auth/external-assistant-id.ts +16 -8
- package/src/runtime/auth/index.ts +23 -16
- package/src/runtime/auth/require-bound-guardian.ts +44 -0
- package/src/runtime/auth/route-policy.ts +166 -104
- package/src/runtime/auth/scopes.ts +22 -29
- package/src/runtime/auth/subject.ts +19 -13
- package/src/runtime/auth/token-service.ts +3 -3
- package/src/runtime/auth/types.ts +23 -23
- package/src/runtime/channel-approval-parser.ts +37 -14
- package/src/runtime/channel-approval-types.ts +30 -4
- package/src/runtime/channel-approvals.ts +49 -23
- package/src/runtime/channel-guardian-service.ts +144 -103
- package/src/runtime/channel-invite-transport.ts +5 -3
- package/src/runtime/channel-invite-transports/telegram.ts +16 -10
- package/src/runtime/channel-invite-transports/voice.ts +7 -7
- package/src/runtime/channel-readiness-service.ts +139 -90
- package/src/runtime/channel-readiness-types.ts +4 -2
- package/src/runtime/channel-reply-delivery.ts +83 -14
- package/src/runtime/channel-retry-sweep.ts +111 -62
- package/src/runtime/confirmation-request-guardian-bridge.ts +73 -54
- package/src/runtime/gateway-client.ts +122 -55
- package/src/runtime/gateway-internal-client.ts +86 -0
- package/src/runtime/guardian-action-conversation-turn.ts +34 -18
- package/src/runtime/guardian-action-followup-executor.ts +115 -45
- package/src/runtime/guardian-action-grant-minter.ts +40 -24
- package/src/runtime/guardian-action-message-composer.ts +105 -84
- package/src/runtime/guardian-action-service.ts +127 -0
- package/src/runtime/guardian-decision-types.ts +28 -13
- package/src/runtime/guardian-outbound-actions.ts +9 -0
- package/src/runtime/guardian-reply-router.ts +274 -145
- package/src/runtime/guardian-vellum-migration.ts +38 -24
- package/src/runtime/guardian-verification-templates.ts +24 -12
- package/src/runtime/http-router.ts +175 -0
- package/src/runtime/http-server.ts +913 -680
- package/src/runtime/http-types.ts +2 -2
- package/src/runtime/invite-redemption-service.ts +211 -134
- package/src/runtime/invite-redemption-templates.ts +18 -11
- package/src/runtime/{ingress-service.ts → invite-service.ts} +92 -151
- package/src/runtime/local-actor-identity.ts +73 -55
- package/src/runtime/middleware/auth.ts +25 -14
- package/src/runtime/middleware/error-handler.ts +15 -11
- package/src/runtime/middleware/rate-limiter.ts +23 -17
- package/src/runtime/middleware/request-logger.ts +4 -4
- package/src/runtime/middleware/twilio-validation.ts +29 -20
- package/src/runtime/migrations/migration-transport.ts +575 -0
- package/src/runtime/migrations/migration-wizard.ts +715 -0
- package/src/runtime/migrations/rebind-secrets-screen.ts +351 -0
- package/src/runtime/migrations/transfer-progress-screen.ts +321 -0
- package/src/runtime/migrations/validation-results-screen.ts +467 -0
- package/src/runtime/migrations/vbundle-builder.ts +295 -0
- package/src/runtime/migrations/vbundle-import-analyzer.ts +212 -0
- package/src/runtime/migrations/vbundle-importer.ts +339 -0
- package/src/runtime/migrations/vbundle-validator.ts +356 -0
- package/src/runtime/nl-approval-parser.ts +138 -0
- package/src/runtime/pending-interactions.ts +16 -7
- package/src/runtime/routes/access-request-decision.ts +73 -52
- package/src/runtime/routes/app-routes.ts +56 -38
- package/src/runtime/routes/approval-routes.ts +144 -92
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +930 -0
- package/src/runtime/routes/approval-strategies/guardian-legacy-fallback-strategy.ts +82 -0
- package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +151 -0
- package/src/runtime/routes/attachment-routes.ts +59 -48
- package/src/runtime/routes/brain-graph-routes.ts +85 -69
- package/src/runtime/routes/call-routes.ts +79 -38
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +10 -10
- package/src/runtime/routes/channel-delivery-routes.ts +19 -14
- package/src/runtime/routes/channel-guardian-routes.ts +3 -3
- package/src/runtime/routes/channel-inbound-routes.ts +2 -2
- package/src/runtime/routes/channel-readiness-routes.ts +12 -6
- package/src/runtime/routes/channel-route-shared.ts +67 -25
- package/src/runtime/routes/channel-routes.ts +4 -6
- package/src/runtime/routes/contact-routes.ts +374 -17
- package/src/runtime/routes/conversation-attention-routes.ts +57 -28
- package/src/runtime/routes/conversation-routes.ts +321 -174
- package/src/runtime/routes/debug-routes.ts +14 -10
- package/src/runtime/routes/events-routes.ts +90 -57
- package/src/runtime/routes/global-search-routes.ts +266 -0
- package/src/runtime/routes/guardian-action-routes.ts +112 -113
- package/src/runtime/routes/guardian-approval-interception.ts +325 -874
- package/src/runtime/routes/guardian-approval-prompt.ts +40 -24
- package/src/runtime/routes/guardian-approval-reply-helpers.ts +135 -0
- package/src/runtime/routes/guardian-bootstrap-routes.ts +55 -36
- package/src/runtime/routes/guardian-expiry-sweep.ts +63 -37
- package/src/runtime/routes/guardian-refresh-routes.ts +40 -19
- package/src/runtime/routes/identity-routes.ts +71 -42
- package/src/runtime/routes/inbound-conversation.ts +17 -11
- package/src/runtime/routes/inbound-message-handler.ts +305 -1459
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +880 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +600 -0
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +214 -0
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +116 -0
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +167 -0
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +185 -0
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +132 -0
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +340 -0
- package/src/runtime/routes/integration-routes.ts +60 -21
- package/src/runtime/routes/invite-routes.ts +140 -0
- package/src/runtime/routes/migration-routes.ts +434 -0
- package/src/runtime/routes/pairing-routes.ts +157 -79
- package/src/runtime/routes/secret-routes.ts +6 -2
- package/src/runtime/routes/twilio-routes.ts +443 -249
- package/src/runtime/slack-block-formatting.ts +176 -0
- package/src/runtime/tool-grant-request-helper.ts +36 -27
- package/src/runtime/{guardian-context-resolver.ts → trust-context-resolver.ts} +29 -41
- package/src/schedule/integration-status.ts +44 -9
- package/src/schedule/recurrence-engine.ts +47 -24
- package/src/schedule/recurrence-types.ts +12 -7
- package/src/schedule/schedule-store.ts +166 -83
- package/src/schedule/scheduler.ts +37 -24
- package/src/security/encrypted-store.ts +68 -38
- package/src/security/keychain.ts +183 -120
- package/src/security/oauth-callback-registry.ts +3 -3
- package/src/security/oauth2.ts +226 -138
- package/src/security/redaction.ts +24 -24
- package/src/security/secret-allowlist.ts +46 -21
- package/src/security/secret-ingress.ts +15 -7
- package/src/security/secret-scanner.ts +193 -104
- package/src/security/secure-keys.ts +9 -3
- package/src/security/token-manager.ts +99 -40
- package/src/security/tool-approval-digest.ts +3 -3
- package/src/sequence/analytics.ts +52 -27
- package/src/sequence/engine.ts +135 -72
- package/src/sequence/guardrails.ts +32 -20
- package/src/sequence/importer.ts +75 -37
- package/src/sequence/reply-matcher.ts +36 -18
- package/src/sequence/store.ts +137 -75
- package/src/sequence/types.ts +30 -16
- package/src/services/published-app-updater.ts +26 -16
- package/src/services/vercel-deploy.ts +19 -15
- package/src/skills/active-skill-tools.ts +3 -3
- package/src/skills/clawhub.ts +178 -90
- package/src/skills/include-graph.ts +24 -17
- package/src/skills/managed-store.ts +89 -42
- package/src/skills/path-classifier.ts +10 -10
- package/src/skills/remote-skill-policy.ts +31 -22
- package/src/skills/slash-commands.ts +36 -30
- package/src/skills/tool-manifest.ts +60 -31
- package/src/skills/version-hash.ts +25 -15
- package/src/slack/slack-webhook.ts +19 -15
- package/src/subagent/index.ts +4 -8
- package/src/subagent/manager.ts +119 -69
- package/src/subagent/types.ts +9 -12
- package/src/swarm/backend-claude-code.ts +124 -45
- package/src/swarm/checkpoint.ts +36 -16
- package/src/swarm/graph-utils.ts +1 -3
- package/src/swarm/index.ts +38 -19
- package/src/swarm/limits.ts +13 -4
- package/src/swarm/orchestrator.ts +108 -57
- package/src/swarm/plan-validator.ts +23 -17
- package/src/swarm/router-planner.ts +51 -22
- package/src/swarm/router-prompts.ts +4 -1
- package/src/swarm/synthesizer.ts +26 -18
- package/src/swarm/types.ts +14 -4
- package/src/swarm/worker-backend.ts +36 -26
- package/src/swarm/worker-prompts.ts +13 -9
- package/src/swarm/worker-runner.ts +40 -34
- package/src/tasks/candidate-store.ts +14 -6
- package/src/tasks/ephemeral-permissions.ts +9 -5
- package/src/tasks/task-compiler.ts +41 -38
- package/src/tasks/task-runner.ts +54 -26
- package/src/tasks/task-scheduler.ts +1 -1
- package/src/tasks/task-store.ts +20 -7
- package/src/tasks/tool-sanitizer.ts +3 -3
- package/src/tools/apps/definitions.ts +23 -15
- package/src/tools/apps/executors.ts +122 -40
- package/src/tools/apps/open-proxy.ts +5 -5
- package/src/tools/apps/registry.ts +2 -2
- package/src/tools/assets/materialize.ts +59 -41
- package/src/tools/assets/search.ts +86 -48
- package/src/tools/browser/api-map.ts +52 -36
- package/src/tools/browser/auth-cache.ts +21 -18
- package/src/tools/browser/auth-detector.ts +43 -28
- package/src/tools/browser/auto-navigate.ts +149 -68
- package/src/tools/browser/browser-execution.ts +9 -3
- package/src/tools/browser/headless-browser.ts +287 -150
- package/src/tools/browser/jit-auth.ts +37 -21
- package/src/tools/browser/network-recorder.ts +138 -56
- package/src/tools/browser/recording-store.ts +22 -15
- package/src/tools/browser/runtime-check.ts +8 -5
- package/src/tools/browser/x-auto-navigate.ts +88 -47
- package/src/tools/calls/call-end.ts +10 -7
- package/src/tools/calls/call-start.ts +30 -20
- package/src/tools/calls/call-status.ts +8 -5
- package/src/tools/claude-code/claude-code.ts +301 -165
- package/src/tools/computer-use/definitions.ts +175 -130
- package/src/tools/computer-use/registry.ts +2 -2
- package/src/tools/computer-use/request-computer-control.ts +21 -13
- package/src/tools/computer-use/skill-proxy-bridge.ts +1 -1
- package/src/tools/credentials/account-registry.ts +52 -35
- package/src/tools/credentials/broker-types.ts +1 -1
- package/src/tools/credentials/broker.ts +97 -55
- package/src/tools/credentials/domain-policy.ts +5 -2
- package/src/tools/credentials/host-pattern-match.ts +15 -8
- package/src/tools/credentials/metadata-store.ts +93 -43
- package/src/tools/credentials/policy-types.ts +5 -2
- package/src/tools/credentials/policy-validate.ts +21 -14
- package/src/tools/credentials/post-connect-hooks.ts +18 -7
- package/src/tools/credentials/resolve.ts +11 -10
- package/src/tools/credentials/selection.ts +30 -25
- package/src/tools/credentials/tool-policy.ts +5 -2
- package/src/tools/credentials/vault.ts +538 -185
- package/src/tools/document/document-tool.ts +23 -17
- package/src/tools/document/editor-template.ts +12 -7
- package/src/tools/execution-target.ts +13 -10
- package/src/tools/execution-timeout.ts +6 -5
- package/src/tools/executor.ts +141 -74
- package/src/tools/filesystem/edit.ts +82 -45
- package/src/tools/filesystem/fuzzy-match.ts +70 -32
- package/src/tools/filesystem/read.ts +46 -28
- package/src/tools/filesystem/view-image.ts +86 -42
- package/src/tools/filesystem/write.ts +53 -32
- package/src/tools/followups/followup_create.ts +43 -17
- package/src/tools/followups/followup_list.ts +28 -13
- package/src/tools/followups/followup_resolve.ts +9 -6
- package/src/tools/guardian-control-plane-policy.ts +15 -14
- package/src/tools/host-filesystem/edit.ts +77 -42
- package/src/tools/host-filesystem/read.ts +52 -33
- package/src/tools/host-filesystem/write.ts +50 -29
- package/src/tools/host-terminal/host-shell.ts +97 -61
- package/src/tools/mcp/mcp-tool-factory.ts +21 -14
- package/src/tools/memory/definitions.ts +60 -28
- package/src/tools/memory/handlers.ts +149 -77
- package/src/tools/memory/register.ts +39 -16
- package/src/tools/network/__tests__/web-search.test.ts +236 -177
- package/src/tools/network/domain-normalize.ts +13 -9
- package/src/tools/network/script-proxy/__tests__/logging.test.ts +193 -123
- package/src/tools/network/script-proxy/__tests__/policy.test.ts +225 -127
- package/src/tools/network/script-proxy/index.ts +1 -17
- package/src/tools/network/script-proxy/session-manager.ts +178 -86
- package/src/tools/network/url-safety.ts +56 -34
- package/src/tools/network/web-fetch.ts +273 -155
- package/src/tools/network/web-search.ts +166 -81
- package/src/tools/permission-checker.ts +24 -25
- package/src/tools/policy-context.ts +8 -5
- package/src/tools/registry.ts +73 -46
- package/src/tools/reminder/reminder-store.ts +65 -44
- package/src/tools/reminder/reminder.ts +76 -35
- package/src/tools/schedule/create.ts +44 -21
- package/src/tools/schedule/delete.ts +8 -5
- package/src/tools/schedule/list.ts +39 -19
- package/src/tools/schedule/update.ts +49 -26
- package/src/tools/secret-detection-handler.ts +130 -49
- package/src/tools/sensitive-output-placeholders.ts +15 -8
- package/src/tools/shared/filesystem/edit-engine.ts +45 -14
- package/src/tools/shared/filesystem/errors.ts +18 -18
- package/src/tools/shared/filesystem/file-ops-service.ts +59 -32
- package/src/tools/shared/filesystem/format-diff.ts +21 -11
- package/src/tools/shared/filesystem/path-policy.ts +17 -13
- package/src/tools/shared/filesystem/size-guard.ts +8 -4
- package/src/tools/shared/filesystem/types.ts +2 -2
- package/src/tools/shared/shell-output.ts +4 -3
- package/src/tools/side-effects.ts +36 -28
- package/src/tools/skills/delete-managed.ts +30 -17
- package/src/tools/skills/load.ts +88 -46
- package/src/tools/skills/sandbox-runner.ts +62 -46
- package/src/tools/skills/scaffold-managed.ts +98 -48
- package/src/tools/skills/script-contract.ts +5 -2
- package/src/tools/skills/skill-script-runner.ts +29 -13
- package/src/tools/skills/skill-tool-factory.ts +20 -10
- package/src/tools/subagent/abort.ts +10 -4
- package/src/tools/subagent/message.ts +14 -8
- package/src/tools/subagent/read.ts +20 -11
- package/src/tools/subagent/spawn.ts +14 -6
- package/src/tools/subagent/status.ts +7 -4
- package/src/tools/swarm/delegate.ts +75 -49
- package/src/tools/system/avatar-generator.ts +46 -33
- package/src/tools/system/navigate-settings.ts +29 -19
- package/src/tools/system/open-system-settings.ts +30 -20
- package/src/tools/system/request-permission.ts +59 -44
- package/src/tools/system/version.ts +27 -16
- package/src/tools/system/voice-config.ts +116 -53
- package/src/tools/tasks/index.ts +8 -8
- package/src/tools/tasks/task-delete.ts +61 -22
- package/src/tools/tasks/task-list.ts +23 -11
- package/src/tools/tasks/task-run.ts +41 -16
- package/src/tools/tasks/task-save.ts +27 -10
- package/src/tools/tasks/work-item-enqueue.ts +114 -48
- package/src/tools/tasks/work-item-list.ts +20 -10
- package/src/tools/tasks/work-item-remove.ts +49 -15
- package/src/tools/tasks/work-item-run.ts +34 -13
- package/src/tools/tasks/work-item-update.ts +84 -31
- package/src/tools/terminal/backends/native.ts +64 -35
- package/src/tools/terminal/backends/types.ts +6 -2
- package/src/tools/terminal/parser.ts +200 -125
- package/src/tools/terminal/safe-env.ts +27 -21
- package/src/tools/terminal/sandbox-diagnostics.ts +31 -13
- package/src/tools/terminal/sandbox.ts +10 -6
- package/src/tools/terminal/shell.ts +134 -68
- package/src/tools/tool-approval-handler.ts +239 -140
- package/src/tools/types.ts +79 -22
- package/src/tools/ui-surface/definitions.ts +124 -89
- package/src/tools/ui-surface/registry.ts +2 -2
- package/src/tools/watch/screen-watch.ts +50 -32
- package/src/tools/watch/watch-state.ts +41 -15
- package/src/tools/watcher/create.ts +37 -15
- package/src/tools/watcher/delete.ts +9 -6
- package/src/tools/watcher/digest.ts +10 -6
- package/src/tools/watcher/list.ts +37 -14
- package/src/tools/watcher/update.ts +33 -18
- package/src/tools/weather/service.ts +331 -174
- package/src/twitter/client.ts +261 -138
- package/src/twitter/oauth-client.ts +17 -13
- package/src/twitter/router.ts +51 -23
- package/src/twitter/session.ts +27 -18
- package/src/types/qrcode.d.ts +6 -3
- package/src/usage/actors.ts +16 -16
- package/src/usage/types.ts +3 -3
- package/src/util/bundled-asset.ts +10 -6
- package/src/util/canonicalize-identity.ts +11 -4
- package/src/util/clipboard.ts +7 -7
- package/src/util/content-id.ts +3 -3
- package/src/util/debounce.ts +3 -2
- package/src/util/diff.ts +55 -33
- package/src/util/errors.ts +31 -27
- package/src/util/fs.ts +8 -2
- package/src/util/log-redact.ts +12 -12
- package/src/util/logger.ts +112 -51
- package/src/util/network-info.ts +13 -5
- package/src/util/object.ts +4 -2
- package/src/util/phone.ts +4 -4
- package/src/util/platform.ts +80 -58
- package/src/util/pricing.ts +49 -31
- package/src/util/retry.ts +39 -7
- package/src/util/row-mapper.ts +7 -4
- package/src/util/silently.ts +7 -4
- package/src/util/spawn.ts +48 -0
- package/src/util/spinner.ts +9 -7
- package/src/util/time.ts +16 -3
- package/src/util/truncate.ts +1 -1
- package/src/util/voice-code.ts +6 -4
- package/src/util/xml.ts +5 -1
- package/src/version.ts +12 -8
- package/src/watcher/engine.ts +71 -44
- package/src/watcher/provider-registry.ts +1 -1
- package/src/watcher/providers/github.ts +40 -23
- package/src/watcher/providers/gmail.ts +59 -38
- package/src/watcher/providers/google-calendar.ts +62 -48
- package/src/watcher/providers/linear.ts +219 -150
- package/src/watcher/providers/slack.ts +125 -29
- package/src/watcher/watcher-store.ts +75 -55
- package/src/work-items/work-item-runner.ts +62 -29
- package/src/work-items/work-item-store.ts +137 -47
- package/src/workspace/commit-message-enrichment-service.ts +65 -25
- package/src/workspace/commit-message-provider.ts +14 -12
- package/src/workspace/git-service.ts +355 -239
- package/src/workspace/heartbeat-service.ts +74 -37
- package/src/workspace/provider-commit-message-generator.ts +95 -70
- package/src/workspace/top-level-renderer.ts +10 -8
- package/src/workspace/top-level-scanner.ts +9 -3
- package/src/workspace/turn-commit.ts +63 -36
- package/src/__tests__/ingress-member-store.test.ts +0 -294
- package/src/__tests__/script-proxy-router.test.ts +0 -215
- package/src/config/bundled-skills/trusted-contacts/SKILL.md +0 -372
- package/src/memory/guardian-bindings.ts +0 -158
- package/src/memory/ingress-member-store.ts +0 -352
- package/src/runtime/routes/ingress-routes.ts +0 -229
- package/src/tools/network/script-proxy/__tests__/router.test.ts +0 -77
- package/src/tools/network/script-proxy/certs.ts +0 -7
- package/src/tools/network/script-proxy/connect-tunnel.ts +0 -1
- package/src/tools/network/script-proxy/http-forwarder.ts +0 -2
- package/src/tools/network/script-proxy/logging.ts +0 -12
- package/src/tools/network/script-proxy/mitm-handler.ts +0 -2
- package/src/tools/network/script-proxy/policy.ts +0 -4
- package/src/tools/network/script-proxy/router.ts +0 -2
- package/src/tools/network/script-proxy/server.ts +0 -5
- package/src/tools/network/script-proxy/types.ts +0 -19
|
@@ -1,52 +1,47 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Approval interception: checks for pending approvals and handles inbound
|
|
3
3
|
* messages as decisions, reminders, or conversational follow-ups.
|
|
4
|
+
*
|
|
5
|
+
* This module is the top-level dispatcher. It delegates to strategy modules:
|
|
6
|
+
* - guardian-callback-strategy.ts — guardian callback button and text decisions
|
|
7
|
+
* - guardian-text-engine-strategy.ts — conversational engine for plain-text messages
|
|
8
|
+
* - guardian-legacy-fallback-strategy.ts — deterministic parser fallback
|
|
4
9
|
*/
|
|
5
|
-
import { applyGuardianDecision } from
|
|
6
|
-
import type { ChannelId } from
|
|
10
|
+
import { applyGuardianDecision } from "../../approvals/guardian-decision-primitive.js";
|
|
11
|
+
import type { ChannelId } from "../../channels/types.js";
|
|
12
|
+
import type { TrustContext } from "../../daemon/session-runtime-assembly.js";
|
|
7
13
|
import {
|
|
8
|
-
getAllPendingApprovalsByGuardianChat,
|
|
9
|
-
getPendingApprovalByRequestAndGuardianChat,
|
|
10
14
|
getPendingApprovalForRequest,
|
|
11
15
|
getUnresolvedApprovalForRequest,
|
|
12
|
-
type GuardianApprovalRequest,
|
|
13
16
|
updateApprovalDecision,
|
|
14
|
-
} from
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import { parseApprovalDecision } from '../channel-approval-parser.js';
|
|
20
|
-
import type {
|
|
21
|
-
ApprovalAction,
|
|
22
|
-
ApprovalDecisionResult,
|
|
23
|
-
} from '../channel-approval-types.js';
|
|
17
|
+
} from "../../memory/channel-guardian-store.js";
|
|
18
|
+
import { getLogger } from "../../util/logger.js";
|
|
19
|
+
import { runApprovalConversationTurn } from "../approval-conversation-turn.js";
|
|
20
|
+
import { composeApprovalMessageGenerative } from "../approval-message-composer.js";
|
|
21
|
+
import type { ApprovalDecisionResult } from "../channel-approval-types.js";
|
|
24
22
|
import {
|
|
25
23
|
getApprovalInfoByConversation,
|
|
26
24
|
getChannelApprovalPrompt,
|
|
27
25
|
handleChannelDecision,
|
|
28
|
-
} from
|
|
29
|
-
import { deliverChannelReply } from
|
|
26
|
+
} from "../channel-approvals.js";
|
|
27
|
+
import { deliverChannelReply } from "../gateway-client.js";
|
|
30
28
|
import type {
|
|
31
29
|
ApprovalConversationContext,
|
|
32
30
|
ApprovalConversationGenerator,
|
|
33
31
|
ApprovalCopyGenerator,
|
|
34
|
-
} from
|
|
35
|
-
import {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
notifyRequesterOfApproval,
|
|
40
|
-
notifyRequesterOfDeliveryFailure,
|
|
41
|
-
notifyRequesterOfDenial,
|
|
42
|
-
} from './access-request-decision.js';
|
|
32
|
+
} from "../http-types.js";
|
|
33
|
+
import { parseApprovalIntent } from "../nl-approval-parser.js";
|
|
34
|
+
import { handleGuardianCallbackDecision } from "./approval-strategies/guardian-callback-strategy.js";
|
|
35
|
+
import { handleGuardianLegacyFallback } from "./approval-strategies/guardian-legacy-fallback-strategy.js";
|
|
36
|
+
import { handleGuardianTextEngineDecision } from "./approval-strategies/guardian-text-engine-strategy.js";
|
|
43
37
|
import {
|
|
44
38
|
buildGuardianDenyContext,
|
|
45
|
-
type GuardianContext,
|
|
46
39
|
parseCallbackData,
|
|
47
|
-
|
|
40
|
+
parseReactionCallbackData,
|
|
41
|
+
} from "./channel-route-shared.js";
|
|
42
|
+
import { deliverStaleApprovalReply } from "./guardian-approval-reply-helpers.js";
|
|
48
43
|
|
|
49
|
-
const log = getLogger(
|
|
44
|
+
const log = getLogger("runtime-http");
|
|
50
45
|
|
|
51
46
|
export interface ApprovalInterceptionParams {
|
|
52
47
|
conversationId: string;
|
|
@@ -57,7 +52,7 @@ export interface ApprovalInterceptionParams {
|
|
|
57
52
|
actorExternalId?: string;
|
|
58
53
|
replyCallbackUrl: string;
|
|
59
54
|
bearerToken?: string;
|
|
60
|
-
|
|
55
|
+
trustCtx: TrustContext;
|
|
61
56
|
assistantId: string;
|
|
62
57
|
approvalCopyGenerator?: ApprovalCopyGenerator;
|
|
63
58
|
approvalConversationGenerator?: ApprovalConversationGenerator;
|
|
@@ -65,7 +60,11 @@ export interface ApprovalInterceptionParams {
|
|
|
65
60
|
|
|
66
61
|
export interface ApprovalInterceptionResult {
|
|
67
62
|
handled: boolean;
|
|
68
|
-
type?:
|
|
63
|
+
type?:
|
|
64
|
+
| "decision_applied"
|
|
65
|
+
| "assistant_turn"
|
|
66
|
+
| "guardian_decision_applied"
|
|
67
|
+
| "stale_ignored";
|
|
69
68
|
}
|
|
70
69
|
|
|
71
70
|
/**
|
|
@@ -90,7 +89,7 @@ export async function handleApprovalInterception(
|
|
|
90
89
|
actorExternalId,
|
|
91
90
|
replyCallbackUrl,
|
|
92
91
|
bearerToken,
|
|
93
|
-
|
|
92
|
+
trustCtx,
|
|
94
93
|
assistantId,
|
|
95
94
|
approvalCopyGenerator,
|
|
96
95
|
approvalConversationGenerator,
|
|
@@ -99,450 +98,50 @@ export async function handleApprovalInterception(
|
|
|
99
98
|
// ── Guardian approval decision path ──
|
|
100
99
|
// When the sender is the guardian and there's a pending guardian approval
|
|
101
100
|
// request targeting this chat, the message might be a decision on behalf
|
|
102
|
-
// of a non-guardian requester.
|
|
103
|
-
if (
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
101
|
+
// of a non-guardian requester. Delegated to the guardian callback strategy.
|
|
102
|
+
if (trustCtx.trustClass === "guardian" && actorExternalId) {
|
|
103
|
+
const guardianResult = await handleGuardianCallbackDecision({
|
|
104
|
+
content,
|
|
105
|
+
callbackData,
|
|
106
|
+
conversationExternalId,
|
|
107
|
+
sourceChannel,
|
|
108
|
+
actorExternalId,
|
|
109
|
+
replyCallbackUrl,
|
|
110
|
+
bearerToken,
|
|
111
|
+
assistantId,
|
|
112
|
+
approvalCopyGenerator,
|
|
113
|
+
approvalConversationGenerator,
|
|
114
|
+
});
|
|
115
|
+
if (guardianResult) {
|
|
116
|
+
return guardianResult;
|
|
111
117
|
}
|
|
118
|
+
}
|
|
112
119
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (!guardianApproval && callbackDecision) {
|
|
124
|
-
const allPending = getAllPendingApprovalsByGuardianChat(sourceChannel, conversationExternalId, assistantId);
|
|
125
|
-
if (allPending.length === 1) {
|
|
126
|
-
guardianApproval = allPending[0];
|
|
127
|
-
} else if (allPending.length > 1) {
|
|
128
|
-
// The callback targeted a stale/expired request but the guardian has other
|
|
129
|
-
// pending approvals. Inform them the clicked approval is no longer valid.
|
|
130
|
-
try {
|
|
131
|
-
const staleText = await composeApprovalMessageGenerative({
|
|
132
|
-
scenario: 'guardian_disambiguation',
|
|
133
|
-
pendingCount: allPending.length,
|
|
134
|
-
channel: sourceChannel,
|
|
135
|
-
}, {}, approvalCopyGenerator);
|
|
136
|
-
await deliverChannelReply(replyCallbackUrl, {
|
|
137
|
-
chatId: conversationExternalId,
|
|
138
|
-
text: staleText,
|
|
139
|
-
assistantId,
|
|
140
|
-
}, bearerToken);
|
|
141
|
-
} catch (err) {
|
|
142
|
-
log.error({ err, conversationExternalId }, 'Failed to deliver stale callback disambiguation notice');
|
|
143
|
-
}
|
|
144
|
-
return { handled: true, type: 'stale_ignored' };
|
|
145
|
-
}
|
|
120
|
+
// ── Slack reaction path ──
|
|
121
|
+
// Reactions produce `callbackData` of the form `reaction:<emoji_name>`.
|
|
122
|
+
// Handled before the pendingPrompt guard because guardian reactions arrive
|
|
123
|
+
// on the guardian's chat (guardianChatId), not the requester's conversation,
|
|
124
|
+
// so getChannelApprovalPrompt(conversationId) would return null.
|
|
125
|
+
// Only guardians can approve via reaction — non-guardian reactions are
|
|
126
|
+
// silently ignored to prevent self-approval.
|
|
127
|
+
if (callbackData?.startsWith("reaction:")) {
|
|
128
|
+
if (trustCtx.trustClass !== "guardian") {
|
|
129
|
+
return { handled: true, type: "stale_ignored" };
|
|
146
130
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const allPending = getAllPendingApprovalsByGuardianChat(sourceChannel, conversationExternalId, assistantId);
|
|
152
|
-
if (allPending.length === 1) {
|
|
153
|
-
guardianApproval = allPending[0];
|
|
154
|
-
} else if (allPending.length > 1) {
|
|
155
|
-
// Multiple pending — pick the first approval matching this sender as
|
|
156
|
-
// primary context. The conversation engine sees all matching approvals
|
|
157
|
-
// via pendingApprovals and can disambiguate.
|
|
158
|
-
guardianApproval = allPending.find(a => a.guardianExternalUserId === actorExternalId) ?? allPending[0];
|
|
159
|
-
}
|
|
131
|
+
const reactionDecision = parseReactionCallbackData(callbackData);
|
|
132
|
+
if (!reactionDecision) {
|
|
133
|
+
// Unknown emoji — ignore silently
|
|
134
|
+
return { handled: true, type: "stale_ignored" };
|
|
160
135
|
}
|
|
161
|
-
|
|
162
|
-
if (
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
if (actorExternalId !== guardianApproval.guardianExternalUserId) {
|
|
169
|
-
log.warn(
|
|
170
|
-
{ conversationExternalId, actorExternalId, expectedGuardian: guardianApproval.guardianExternalUserId },
|
|
171
|
-
'Non-guardian sender attempted to act on guardian approval request',
|
|
172
|
-
);
|
|
173
|
-
try {
|
|
174
|
-
const mismatchText = await composeApprovalMessageGenerative({
|
|
175
|
-
scenario: 'guardian_identity_mismatch',
|
|
176
|
-
channel: sourceChannel,
|
|
177
|
-
}, {}, approvalCopyGenerator);
|
|
178
|
-
await deliverChannelReply(replyCallbackUrl, {
|
|
179
|
-
chatId: conversationExternalId,
|
|
180
|
-
text: mismatchText,
|
|
181
|
-
assistantId,
|
|
182
|
-
}, bearerToken);
|
|
183
|
-
} catch (err) {
|
|
184
|
-
log.error({ err, conversationExternalId }, 'Failed to deliver guardian identity rejection notice');
|
|
185
|
-
}
|
|
186
|
-
return { handled: true, type: 'guardian_decision_applied' };
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
if (callbackDecision) {
|
|
190
|
-
// Access request approvals don't have a pending interaction in the
|
|
191
|
-
// session tracker, so they need a separate decision path that creates
|
|
192
|
-
// a verification session instead of resuming an agent loop.
|
|
193
|
-
if (guardianApproval.toolName === 'ingress_access_request') {
|
|
194
|
-
const accessResult = await handleAccessRequestApproval(
|
|
195
|
-
guardianApproval,
|
|
196
|
-
callbackDecision.action === 'reject' ? 'deny' : 'approve',
|
|
197
|
-
actorExternalId,
|
|
198
|
-
replyCallbackUrl,
|
|
199
|
-
assistantId,
|
|
200
|
-
bearerToken,
|
|
201
|
-
);
|
|
202
|
-
return accessResult;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// Apply the decision through the unified guardian decision primitive.
|
|
206
|
-
// The primitive handles approve_always downgrade, approval info capture,
|
|
207
|
-
// record update, and scoped grant minting.
|
|
208
|
-
const result = applyGuardianDecision({
|
|
209
|
-
approval: guardianApproval,
|
|
210
|
-
decision: callbackDecision,
|
|
211
|
-
actorExternalUserId: actorExternalId,
|
|
212
|
-
actorChannel: sourceChannel,
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
if (result.applied) {
|
|
216
|
-
// Notify the requester's chat about the outcome with the tool name
|
|
217
|
-
const effectiveAction = callbackDecision.action === 'approve_always' ? 'approve_once' : callbackDecision.action;
|
|
218
|
-
const outcomeText = await composeApprovalMessageGenerative({
|
|
219
|
-
scenario: 'guardian_decision_outcome',
|
|
220
|
-
decision: effectiveAction === 'reject' ? 'denied' : 'approved',
|
|
221
|
-
toolName: guardianApproval.toolName,
|
|
222
|
-
channel: sourceChannel,
|
|
223
|
-
}, {}, approvalCopyGenerator);
|
|
224
|
-
try {
|
|
225
|
-
await deliverChannelReply(replyCallbackUrl, {
|
|
226
|
-
chatId: guardianApproval.requesterChatId,
|
|
227
|
-
text: outcomeText,
|
|
228
|
-
assistantId,
|
|
229
|
-
}, bearerToken);
|
|
230
|
-
} catch (err) {
|
|
231
|
-
log.error({ err, conversationId: guardianApproval.conversationId }, 'Failed to notify requester of guardian decision');
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// Post-decision delivery is handled by the onEvent callback
|
|
235
|
-
// in the session that registered the pending interaction.
|
|
236
|
-
return { handled: true, type: 'guardian_decision_applied' };
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// Race condition: callback arrived after request was already resolved.
|
|
240
|
-
return { handled: true, type: 'stale_ignored' };
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// ── Conversational engine for guardian plain-text messages ──
|
|
244
|
-
// Gather all pending guardian approvals for this chat so the engine
|
|
245
|
-
// can handle disambiguation when multiple are pending.
|
|
246
|
-
const allGuardianPending = getAllPendingApprovalsByGuardianChat(sourceChannel, conversationExternalId, assistantId);
|
|
247
|
-
// Only present approvals that belong to this sender so the engine
|
|
248
|
-
// does not offer disambiguation for requests assigned to a rotated
|
|
249
|
-
// guardian the sender cannot act on.
|
|
250
|
-
const senderPending = allGuardianPending.filter(a => a.guardianExternalUserId === actorExternalId);
|
|
251
|
-
const effectivePending = senderPending.length > 0 ? senderPending : allGuardianPending;
|
|
252
|
-
if (effectivePending.length > 0 && approvalConversationGenerator && content) {
|
|
253
|
-
const guardianAllowedActions = ['approve_once', 'reject'];
|
|
254
|
-
const engineContext: ApprovalConversationContext = {
|
|
255
|
-
toolName: guardianApproval.toolName,
|
|
256
|
-
allowedActions: guardianAllowedActions,
|
|
257
|
-
role: 'guardian',
|
|
258
|
-
pendingApprovals: effectivePending.map((a) => ({ requestId: a.requestId ?? a.runId, toolName: a.toolName })),
|
|
259
|
-
userMessage: content,
|
|
260
|
-
};
|
|
261
|
-
|
|
262
|
-
const engineResult = await runApprovalConversationTurn(engineContext, approvalConversationGenerator);
|
|
263
|
-
|
|
264
|
-
if (engineResult.disposition === 'keep_pending') {
|
|
265
|
-
// Non-decision follow-up (clarification, disambiguation, etc.)
|
|
266
|
-
try {
|
|
267
|
-
await deliverChannelReply(replyCallbackUrl, {
|
|
268
|
-
chatId: conversationExternalId,
|
|
269
|
-
text: engineResult.replyText,
|
|
270
|
-
assistantId,
|
|
271
|
-
}, bearerToken);
|
|
272
|
-
} catch (err) {
|
|
273
|
-
log.error({ err, conversationId: guardianApproval.conversationId }, 'Failed to deliver guardian conversation reply');
|
|
274
|
-
}
|
|
275
|
-
return { handled: true, type: 'assistant_turn' };
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// Decision-bearing disposition from the engine
|
|
279
|
-
let decisionAction = engineResult.disposition as ApprovalAction;
|
|
280
|
-
|
|
281
|
-
// Belt-and-suspenders: guardians cannot use broad allow modes even if
|
|
282
|
-
// the engine returns them (the engine's allowedActions validation should
|
|
283
|
-
// already prevent this, but enforce it here too).
|
|
284
|
-
if (decisionAction === 'approve_always' || decisionAction === 'approve_10m' || decisionAction === 'approve_thread') {
|
|
285
|
-
decisionAction = 'approve_once';
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// Resolve the target approval: use targetRequestId from the engine if
|
|
289
|
-
// provided, otherwise use the single guardian approval.
|
|
290
|
-
const targetApproval = engineResult.targetRequestId
|
|
291
|
-
? allGuardianPending.find((a) => (a.requestId ?? a.runId) === engineResult.targetRequestId) ?? guardianApproval
|
|
292
|
-
: guardianApproval;
|
|
293
|
-
|
|
294
|
-
// Re-validate guardian identity against the resolved target. The
|
|
295
|
-
// engine may select a different pending approval (via targetRequestId)
|
|
296
|
-
// that was assigned to a different guardian. Without this check a
|
|
297
|
-
// currently bound guardian could act on a request assigned to a
|
|
298
|
-
// previous guardian after a binding rotation.
|
|
299
|
-
if (actorExternalId !== targetApproval.guardianExternalUserId) {
|
|
300
|
-
log.warn(
|
|
301
|
-
{ conversationExternalId, actorExternalId, expectedGuardian: targetApproval.guardianExternalUserId, targetRequestId: engineResult.targetRequestId },
|
|
302
|
-
'Guardian identity mismatch on engine-selected target approval',
|
|
303
|
-
);
|
|
304
|
-
try {
|
|
305
|
-
const mismatchText = await composeApprovalMessageGenerative({
|
|
306
|
-
scenario: 'guardian_identity_mismatch',
|
|
307
|
-
channel: sourceChannel,
|
|
308
|
-
}, {}, approvalCopyGenerator);
|
|
309
|
-
await deliverChannelReply(replyCallbackUrl, {
|
|
310
|
-
chatId: conversationExternalId,
|
|
311
|
-
text: mismatchText,
|
|
312
|
-
assistantId,
|
|
313
|
-
}, bearerToken);
|
|
314
|
-
} catch (err) {
|
|
315
|
-
log.error({ err, conversationExternalId }, 'Failed to deliver guardian identity mismatch notice for engine target');
|
|
316
|
-
}
|
|
317
|
-
return { handled: true, type: 'guardian_decision_applied' };
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// Access request approvals need a separate decision path.
|
|
321
|
-
if (targetApproval.toolName === 'ingress_access_request') {
|
|
322
|
-
const accessResult = await handleAccessRequestApproval(
|
|
323
|
-
targetApproval,
|
|
324
|
-
decisionAction === 'reject' ? 'deny' : 'approve',
|
|
325
|
-
actorExternalId,
|
|
326
|
-
replyCallbackUrl,
|
|
327
|
-
assistantId,
|
|
328
|
-
bearerToken,
|
|
329
|
-
);
|
|
330
|
-
return accessResult;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
const engineDecision: ApprovalDecisionResult = {
|
|
334
|
-
action: decisionAction,
|
|
335
|
-
source: 'plain_text',
|
|
336
|
-
...(engineResult.targetRequestId ? { requestId: engineResult.targetRequestId } : {}),
|
|
337
|
-
};
|
|
338
|
-
|
|
339
|
-
// Apply the decision through the unified guardian decision primitive.
|
|
340
|
-
const result = applyGuardianDecision({
|
|
341
|
-
approval: targetApproval,
|
|
342
|
-
decision: engineDecision,
|
|
343
|
-
actorExternalUserId: actorExternalId,
|
|
344
|
-
actorChannel: sourceChannel,
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
if (result.applied) {
|
|
348
|
-
// Notify the requester's chat about the outcome
|
|
349
|
-
const outcomeText = await composeApprovalMessageGenerative({
|
|
350
|
-
scenario: 'guardian_decision_outcome',
|
|
351
|
-
decision: decisionAction === 'reject' ? 'denied' : 'approved',
|
|
352
|
-
toolName: targetApproval.toolName,
|
|
353
|
-
channel: sourceChannel,
|
|
354
|
-
}, {}, approvalCopyGenerator);
|
|
355
|
-
try {
|
|
356
|
-
await deliverChannelReply(replyCallbackUrl, {
|
|
357
|
-
chatId: targetApproval.requesterChatId,
|
|
358
|
-
text: outcomeText,
|
|
359
|
-
assistantId,
|
|
360
|
-
}, bearerToken);
|
|
361
|
-
} catch (err) {
|
|
362
|
-
log.error({ err, conversationId: targetApproval.conversationId }, 'Failed to notify requester of guardian decision');
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
// Deliver the engine's reply to the guardian
|
|
366
|
-
try {
|
|
367
|
-
await deliverChannelReply(replyCallbackUrl, {
|
|
368
|
-
chatId: conversationExternalId,
|
|
369
|
-
text: engineResult.replyText,
|
|
370
|
-
assistantId,
|
|
371
|
-
}, bearerToken);
|
|
372
|
-
} catch (err) {
|
|
373
|
-
log.error({ err, conversationId: targetApproval.conversationId }, 'Failed to deliver guardian decision reply');
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
return { handled: true, type: 'guardian_decision_applied' };
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
// Race condition: request was already resolved. Deliver a stale notice
|
|
380
|
-
// instead of the engine's optimistic reply.
|
|
381
|
-
try {
|
|
382
|
-
const staleText = await composeApprovalMessageGenerative({
|
|
383
|
-
scenario: 'approval_already_resolved',
|
|
384
|
-
channel: sourceChannel,
|
|
385
|
-
}, {}, approvalCopyGenerator);
|
|
386
|
-
await deliverChannelReply(replyCallbackUrl, {
|
|
387
|
-
chatId: conversationExternalId,
|
|
388
|
-
text: staleText,
|
|
389
|
-
assistantId,
|
|
390
|
-
}, bearerToken);
|
|
391
|
-
} catch (err) {
|
|
392
|
-
log.error({ err, conversationId: targetApproval.conversationId }, 'Failed to deliver stale guardian approval notice');
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
return { handled: true, type: 'stale_ignored' };
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
// ── Legacy fallback when no conversational engine is available ──
|
|
399
|
-
// Use the deterministic parser to handle guardian plain-text so that
|
|
400
|
-
// simple yes/no replies still work when the engine is not injected.
|
|
401
|
-
if (content && !approvalConversationGenerator) {
|
|
402
|
-
const legacyGuardianDecision = parseApprovalDecision(content);
|
|
403
|
-
if (legacyGuardianDecision) {
|
|
404
|
-
// Guardians cannot approve_always — downgrade to approve_once.
|
|
405
|
-
if (legacyGuardianDecision.action === 'approve_always') {
|
|
406
|
-
legacyGuardianDecision.action = 'approve_once';
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
// Resolve the target approval: when a [ref:<requestId>] tag is
|
|
410
|
-
// present, look up the specific pending approval by that requestId
|
|
411
|
-
// so the decision applies to the correct conversation even when
|
|
412
|
-
// multiple guardian approvals are pending.
|
|
413
|
-
let targetLegacyApproval = guardianApproval;
|
|
414
|
-
if (legacyGuardianDecision.requestId) {
|
|
415
|
-
const resolvedByRequest = getPendingApprovalByRequestAndGuardianChat(
|
|
416
|
-
legacyGuardianDecision.requestId,
|
|
417
|
-
sourceChannel,
|
|
418
|
-
conversationExternalId,
|
|
419
|
-
assistantId,
|
|
420
|
-
);
|
|
421
|
-
if (!resolvedByRequest) {
|
|
422
|
-
// The referenced request doesn't match any pending guardian
|
|
423
|
-
// approval — it may have expired or already been resolved.
|
|
424
|
-
try {
|
|
425
|
-
const staleText = await composeApprovalMessageGenerative({
|
|
426
|
-
scenario: 'guardian_disambiguation',
|
|
427
|
-
channel: sourceChannel,
|
|
428
|
-
}, {}, approvalCopyGenerator);
|
|
429
|
-
await deliverChannelReply(replyCallbackUrl, {
|
|
430
|
-
chatId: conversationExternalId,
|
|
431
|
-
text: staleText,
|
|
432
|
-
assistantId,
|
|
433
|
-
}, bearerToken);
|
|
434
|
-
} catch (err) {
|
|
435
|
-
log.error({ err, conversationExternalId }, 'Failed to deliver stale approval notice (legacy path)');
|
|
436
|
-
}
|
|
437
|
-
return { handled: true, type: 'stale_ignored' };
|
|
438
|
-
}
|
|
439
|
-
targetLegacyApproval = resolvedByRequest;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
// Re-validate guardian identity against the resolved target.
|
|
443
|
-
// The default guardianApproval was already checked, but a
|
|
444
|
-
// requestId-resolved approval may belong to a different guardian.
|
|
445
|
-
if (actorExternalId !== targetLegacyApproval.guardianExternalUserId) {
|
|
446
|
-
log.warn(
|
|
447
|
-
{ conversationExternalId, actorExternalId, expectedGuardian: targetLegacyApproval.guardianExternalUserId, requestId: legacyGuardianDecision.requestId },
|
|
448
|
-
'Guardian identity mismatch on legacy ref-resolved target approval',
|
|
449
|
-
);
|
|
450
|
-
try {
|
|
451
|
-
const mismatchText = await composeApprovalMessageGenerative({
|
|
452
|
-
scenario: 'guardian_identity_mismatch',
|
|
453
|
-
channel: sourceChannel,
|
|
454
|
-
}, {}, approvalCopyGenerator);
|
|
455
|
-
await deliverChannelReply(replyCallbackUrl, {
|
|
456
|
-
chatId: conversationExternalId,
|
|
457
|
-
text: mismatchText,
|
|
458
|
-
assistantId,
|
|
459
|
-
}, bearerToken);
|
|
460
|
-
} catch (err) {
|
|
461
|
-
log.error({ err, conversationExternalId }, 'Failed to deliver guardian identity mismatch notice (legacy path)');
|
|
462
|
-
}
|
|
463
|
-
return { handled: true, type: 'guardian_decision_applied' };
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
// Access request approvals need a separate decision path.
|
|
467
|
-
if (targetLegacyApproval.toolName === 'ingress_access_request') {
|
|
468
|
-
const accessResult = await handleAccessRequestApproval(
|
|
469
|
-
targetLegacyApproval,
|
|
470
|
-
legacyGuardianDecision.action === 'reject' ? 'deny' : 'approve',
|
|
471
|
-
actorExternalId,
|
|
472
|
-
replyCallbackUrl,
|
|
473
|
-
assistantId,
|
|
474
|
-
bearerToken,
|
|
475
|
-
);
|
|
476
|
-
return accessResult;
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
// Apply the decision through the unified guardian decision primitive.
|
|
480
|
-
const result = applyGuardianDecision({
|
|
481
|
-
approval: targetLegacyApproval,
|
|
482
|
-
decision: legacyGuardianDecision,
|
|
483
|
-
actorExternalUserId: actorExternalId,
|
|
484
|
-
actorChannel: sourceChannel,
|
|
485
|
-
});
|
|
486
|
-
|
|
487
|
-
if (result.applied) {
|
|
488
|
-
// Notify the requester's chat about the outcome
|
|
489
|
-
const outcomeText = await composeApprovalMessageGenerative({
|
|
490
|
-
scenario: 'guardian_decision_outcome',
|
|
491
|
-
decision: legacyGuardianDecision.action === 'reject' ? 'denied' : 'approved',
|
|
492
|
-
toolName: targetLegacyApproval.toolName,
|
|
493
|
-
channel: sourceChannel,
|
|
494
|
-
}, {}, approvalCopyGenerator);
|
|
495
|
-
try {
|
|
496
|
-
await deliverChannelReply(replyCallbackUrl, {
|
|
497
|
-
chatId: targetLegacyApproval.requesterChatId,
|
|
498
|
-
text: outcomeText,
|
|
499
|
-
assistantId,
|
|
500
|
-
}, bearerToken);
|
|
501
|
-
} catch (err) {
|
|
502
|
-
log.error({ err, conversationId: targetLegacyApproval.conversationId }, 'Failed to notify requester of guardian decision (legacy path)');
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
return { handled: true, type: 'guardian_decision_applied' };
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
// Race condition: request was already resolved. Deliver stale notice.
|
|
509
|
-
try {
|
|
510
|
-
const staleText = await composeApprovalMessageGenerative({
|
|
511
|
-
scenario: 'approval_already_resolved',
|
|
512
|
-
channel: sourceChannel,
|
|
513
|
-
}, {}, approvalCopyGenerator);
|
|
514
|
-
await deliverChannelReply(replyCallbackUrl, {
|
|
515
|
-
chatId: conversationExternalId,
|
|
516
|
-
text: staleText,
|
|
517
|
-
assistantId,
|
|
518
|
-
}, bearerToken);
|
|
519
|
-
} catch (err) {
|
|
520
|
-
log.error({ err, conversationId: targetLegacyApproval.conversationId }, 'Failed to deliver stale guardian legacy fallback notice');
|
|
521
|
-
}
|
|
522
|
-
return { handled: true, type: 'stale_ignored' };
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
// No decision could be parsed — send a generic reminder to the guardian
|
|
526
|
-
try {
|
|
527
|
-
const reminderText = await composeApprovalMessageGenerative({
|
|
528
|
-
scenario: 'reminder_prompt',
|
|
529
|
-
toolName: guardianApproval.toolName,
|
|
530
|
-
channel: sourceChannel,
|
|
531
|
-
}, {}, approvalCopyGenerator);
|
|
532
|
-
await deliverChannelReply(replyCallbackUrl, {
|
|
533
|
-
chatId: conversationExternalId,
|
|
534
|
-
text: reminderText,
|
|
535
|
-
assistantId,
|
|
536
|
-
}, bearerToken);
|
|
537
|
-
} catch (err) {
|
|
538
|
-
log.error({ err, conversationId: guardianApproval.conversationId }, 'Failed to deliver guardian reminder (legacy path)');
|
|
539
|
-
}
|
|
540
|
-
return { handled: true, type: 'assistant_turn' };
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
// No content and no engine — nothing to do, fall through to standard
|
|
544
|
-
// approval interception below.
|
|
136
|
+
const pending = getApprovalInfoByConversation(conversationId);
|
|
137
|
+
if (pending.length === 0) {
|
|
138
|
+
return { handled: true, type: "stale_ignored" };
|
|
139
|
+
}
|
|
140
|
+
const result = handleChannelDecision(conversationId, reactionDecision);
|
|
141
|
+
if (result.applied) {
|
|
142
|
+
return { handled: true, type: "decision_applied" };
|
|
545
143
|
}
|
|
144
|
+
return { handled: true, type: "stale_ignored" };
|
|
546
145
|
}
|
|
547
146
|
|
|
548
147
|
// ── Standard approval interception (existing flow) ──
|
|
@@ -553,7 +152,8 @@ export async function handleApprovalInterception(
|
|
|
553
152
|
// unknown trust + explicit denial reason (`no_identity` / `no_binding`).
|
|
554
153
|
// Unknown without a denial reason means identity-known, non-member sender
|
|
555
154
|
// in a shared channel; that case must not force-reject someone else's request.
|
|
556
|
-
const isLegacyUnverifiedSender =
|
|
155
|
+
const isLegacyUnverifiedSender =
|
|
156
|
+
trustCtx.trustClass === "unknown" && !!trustCtx.denialReason;
|
|
557
157
|
|
|
558
158
|
// When the sender is from a legacy-unverified channel actor, auto-deny any
|
|
559
159
|
// pending confirmation and block self-approval.
|
|
@@ -562,14 +162,14 @@ export async function handleApprovalInterception(
|
|
|
562
162
|
if (pending.length > 0) {
|
|
563
163
|
handleChannelDecision(
|
|
564
164
|
conversationId,
|
|
565
|
-
{ action:
|
|
165
|
+
{ action: "reject", source: "plain_text" },
|
|
566
166
|
buildGuardianDenyContext(
|
|
567
167
|
pending[0].toolName,
|
|
568
|
-
|
|
168
|
+
trustCtx.denialReason ?? "no_binding",
|
|
569
169
|
sourceChannel,
|
|
570
170
|
),
|
|
571
171
|
);
|
|
572
|
-
return { handled: true, type:
|
|
172
|
+
return { handled: true, type: "decision_applied" };
|
|
573
173
|
}
|
|
574
174
|
}
|
|
575
175
|
|
|
@@ -579,12 +179,15 @@ export async function handleApprovalInterception(
|
|
|
579
179
|
//
|
|
580
180
|
// Include identity-known, non-member senders (`unknown` without denialReason)
|
|
581
181
|
// so shared-channel participants can't approve/deny someone else's pending request.
|
|
582
|
-
const isIdentityKnownNonGuardian =
|
|
583
|
-
|
|
182
|
+
const isIdentityKnownNonGuardian =
|
|
183
|
+
trustCtx.trustClass === "trusted_contact" ||
|
|
184
|
+
(trustCtx.trustClass === "unknown" && !trustCtx.denialReason);
|
|
584
185
|
if (isIdentityKnownNonGuardian) {
|
|
585
186
|
const pending = getApprovalInfoByConversation(conversationId);
|
|
586
187
|
if (pending.length > 0) {
|
|
587
|
-
const guardianApprovalForRequest = getPendingApprovalForRequest(
|
|
188
|
+
const guardianApprovalForRequest = getPendingApprovalForRequest(
|
|
189
|
+
pending[0].requestId,
|
|
190
|
+
);
|
|
588
191
|
if (guardianApprovalForRequest) {
|
|
589
192
|
// Allow the requester to cancel their own pending guardian request.
|
|
590
193
|
// Only reject/cancel is permitted — self-approval is still blocked.
|
|
@@ -599,24 +202,30 @@ export async function handleApprovalInterception(
|
|
|
599
202
|
if (approvalConversationGenerator) {
|
|
600
203
|
const cancelContext: ApprovalConversationContext = {
|
|
601
204
|
toolName: pending[0].toolName,
|
|
602
|
-
allowedActions: [
|
|
603
|
-
role:
|
|
604
|
-
pendingApprovals: pending.map(p => ({
|
|
205
|
+
allowedActions: ["reject"],
|
|
206
|
+
role: "requester",
|
|
207
|
+
pendingApprovals: pending.map((p) => ({
|
|
208
|
+
requestId: p.requestId,
|
|
209
|
+
toolName: p.toolName,
|
|
210
|
+
})),
|
|
605
211
|
userMessage: content,
|
|
606
212
|
};
|
|
607
|
-
const cancelResult = await runApprovalConversationTurn(
|
|
608
|
-
|
|
213
|
+
const cancelResult = await runApprovalConversationTurn(
|
|
214
|
+
cancelContext,
|
|
215
|
+
approvalConversationGenerator,
|
|
216
|
+
);
|
|
217
|
+
if (cancelResult.disposition === "reject") {
|
|
609
218
|
requesterCancelIntent = true;
|
|
610
219
|
cancelReplyText = cancelResult.replyText;
|
|
611
|
-
} else if (cancelResult.disposition ===
|
|
220
|
+
} else if (cancelResult.disposition === "keep_pending") {
|
|
612
221
|
requesterFollowupReplyText = cancelResult.replyText;
|
|
613
222
|
}
|
|
614
223
|
}
|
|
615
224
|
|
|
616
225
|
if (requesterCancelIntent) {
|
|
617
226
|
const rejectDecision: ApprovalDecisionResult = {
|
|
618
|
-
action:
|
|
619
|
-
source:
|
|
227
|
+
action: "reject",
|
|
228
|
+
source: "plain_text",
|
|
620
229
|
};
|
|
621
230
|
// Apply the cancel decision through the unified primitive.
|
|
622
231
|
// The primitive handles record update and (no-op) grant logic.
|
|
@@ -628,119 +237,152 @@ export async function handleApprovalInterception(
|
|
|
628
237
|
});
|
|
629
238
|
if (cancelApplyResult.applied) {
|
|
630
239
|
// Notify requester
|
|
631
|
-
const replyText =
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
240
|
+
const replyText =
|
|
241
|
+
cancelReplyText ??
|
|
242
|
+
(await composeApprovalMessageGenerative(
|
|
243
|
+
{
|
|
244
|
+
scenario: "requester_cancel",
|
|
245
|
+
toolName: pending[0].toolName,
|
|
246
|
+
channel: sourceChannel,
|
|
247
|
+
},
|
|
248
|
+
{},
|
|
249
|
+
approvalCopyGenerator,
|
|
250
|
+
));
|
|
636
251
|
try {
|
|
637
|
-
await deliverChannelReply(
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
252
|
+
await deliverChannelReply(
|
|
253
|
+
replyCallbackUrl,
|
|
254
|
+
{
|
|
255
|
+
chatId: conversationExternalId,
|
|
256
|
+
text: replyText,
|
|
257
|
+
assistantId,
|
|
258
|
+
},
|
|
259
|
+
bearerToken,
|
|
260
|
+
);
|
|
642
261
|
} catch (err) {
|
|
643
|
-
log.error(
|
|
262
|
+
log.error(
|
|
263
|
+
{ err, conversationId },
|
|
264
|
+
"Failed to deliver requester cancel notice",
|
|
265
|
+
);
|
|
644
266
|
}
|
|
645
267
|
|
|
646
268
|
// Notify guardian that the request was cancelled
|
|
647
269
|
try {
|
|
648
|
-
const guardianNotice = await composeApprovalMessageGenerative(
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
270
|
+
const guardianNotice = await composeApprovalMessageGenerative(
|
|
271
|
+
{
|
|
272
|
+
scenario: "guardian_decision_outcome",
|
|
273
|
+
decision: "denied",
|
|
274
|
+
toolName: pending[0].toolName,
|
|
275
|
+
channel: sourceChannel,
|
|
276
|
+
},
|
|
277
|
+
{},
|
|
278
|
+
approvalCopyGenerator,
|
|
279
|
+
);
|
|
280
|
+
await deliverChannelReply(
|
|
281
|
+
replyCallbackUrl,
|
|
282
|
+
{
|
|
283
|
+
chatId: guardianApprovalForRequest.guardianChatId,
|
|
284
|
+
text: guardianNotice,
|
|
285
|
+
assistantId,
|
|
286
|
+
},
|
|
287
|
+
bearerToken,
|
|
288
|
+
);
|
|
659
289
|
} catch (err) {
|
|
660
|
-
log.error(
|
|
290
|
+
log.error(
|
|
291
|
+
{ err, conversationId },
|
|
292
|
+
"Failed to notify guardian of requester cancellation",
|
|
293
|
+
);
|
|
661
294
|
}
|
|
662
295
|
|
|
663
|
-
return { handled: true, type:
|
|
296
|
+
return { handled: true, type: "decision_applied" };
|
|
664
297
|
}
|
|
665
298
|
|
|
666
299
|
// Race condition: approval was already resolved elsewhere.
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
}
|
|
680
|
-
return { handled: true, type:
|
|
300
|
+
await deliverStaleApprovalReply({
|
|
301
|
+
scenario: "approval_already_resolved",
|
|
302
|
+
sourceChannel,
|
|
303
|
+
replyCallbackUrl,
|
|
304
|
+
chatId: conversationExternalId,
|
|
305
|
+
assistantId,
|
|
306
|
+
bearerToken,
|
|
307
|
+
approvalCopyGenerator,
|
|
308
|
+
logger: log,
|
|
309
|
+
errorLogMessage:
|
|
310
|
+
"Failed to deliver stale requester-cancel notice",
|
|
311
|
+
errorLogContext: { conversationId },
|
|
312
|
+
});
|
|
313
|
+
return { handled: true, type: "stale_ignored" };
|
|
681
314
|
}
|
|
682
315
|
|
|
683
316
|
if (requesterFollowupReplyText) {
|
|
684
317
|
try {
|
|
685
|
-
await deliverChannelReply(
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
318
|
+
await deliverChannelReply(
|
|
319
|
+
replyCallbackUrl,
|
|
320
|
+
{
|
|
321
|
+
chatId: conversationExternalId,
|
|
322
|
+
text: requesterFollowupReplyText,
|
|
323
|
+
assistantId,
|
|
324
|
+
},
|
|
325
|
+
bearerToken,
|
|
326
|
+
);
|
|
690
327
|
} catch (err) {
|
|
691
|
-
log.error(
|
|
328
|
+
log.error(
|
|
329
|
+
{ err, conversationId },
|
|
330
|
+
"Failed to deliver requester follow-up reply while awaiting guardian",
|
|
331
|
+
);
|
|
692
332
|
}
|
|
693
|
-
return { handled: true, type:
|
|
333
|
+
return { handled: true, type: "assistant_turn" };
|
|
694
334
|
}
|
|
695
335
|
}
|
|
696
336
|
|
|
697
337
|
// Not a cancel intent — tell the requester their request is pending
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
}
|
|
711
|
-
return { handled: true, type:
|
|
338
|
+
await deliverStaleApprovalReply({
|
|
339
|
+
scenario: "request_pending_guardian",
|
|
340
|
+
sourceChannel,
|
|
341
|
+
replyCallbackUrl,
|
|
342
|
+
chatId: conversationExternalId,
|
|
343
|
+
assistantId,
|
|
344
|
+
bearerToken,
|
|
345
|
+
approvalCopyGenerator,
|
|
346
|
+
logger: log,
|
|
347
|
+
errorLogMessage:
|
|
348
|
+
"Failed to deliver guardian-pending notice to requester",
|
|
349
|
+
errorLogContext: { conversationId },
|
|
350
|
+
});
|
|
351
|
+
return { handled: true, type: "assistant_turn" };
|
|
712
352
|
}
|
|
713
353
|
|
|
714
354
|
// Check for an expired-but-unresolved guardian approval. If the approval
|
|
715
355
|
// expired without a guardian decision, auto-deny and transition
|
|
716
356
|
// the approval to 'expired'. Without this, the requester could bypass
|
|
717
357
|
// guardian-only controls by simply waiting for the TTL to elapse.
|
|
718
|
-
const unresolvedApproval = getUnresolvedApprovalForRequest(
|
|
358
|
+
const unresolvedApproval = getUnresolvedApprovalForRequest(
|
|
359
|
+
pending[0].requestId,
|
|
360
|
+
);
|
|
719
361
|
if (unresolvedApproval) {
|
|
720
|
-
updateApprovalDecision(unresolvedApproval.id, { status:
|
|
362
|
+
updateApprovalDecision(unresolvedApproval.id, { status: "expired" });
|
|
721
363
|
|
|
722
364
|
// Auto-deny the underlying request so it does not remain actionable
|
|
723
365
|
const expiredDecision: ApprovalDecisionResult = {
|
|
724
|
-
action:
|
|
725
|
-
source:
|
|
366
|
+
action: "reject",
|
|
367
|
+
source: "plain_text",
|
|
726
368
|
};
|
|
727
369
|
handleChannelDecision(conversationId, expiredDecision);
|
|
728
370
|
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
}
|
|
743
|
-
return { handled: true, type:
|
|
371
|
+
await deliverStaleApprovalReply({
|
|
372
|
+
scenario: "guardian_expired_requester",
|
|
373
|
+
sourceChannel,
|
|
374
|
+
replyCallbackUrl,
|
|
375
|
+
chatId: conversationExternalId,
|
|
376
|
+
assistantId,
|
|
377
|
+
bearerToken,
|
|
378
|
+
approvalCopyGenerator,
|
|
379
|
+
logger: log,
|
|
380
|
+
errorLogMessage:
|
|
381
|
+
"Failed to deliver guardian-expiry notice to requester",
|
|
382
|
+
extraContext: { toolName: pending[0].toolName },
|
|
383
|
+
errorLogContext: { conversationId },
|
|
384
|
+
});
|
|
385
|
+
return { handled: true, type: "decision_applied" };
|
|
744
386
|
}
|
|
745
387
|
|
|
746
388
|
// Guard: non-guardian actors with a guardian binding must not self-approve
|
|
@@ -751,29 +393,60 @@ export async function handleApprovalInterception(
|
|
|
751
393
|
// persisted, any non-guardian actor could otherwise fall through to the
|
|
752
394
|
// standard conversational engine / legacy parser and resolve their own
|
|
753
395
|
// pending request via handleChannelDecision.
|
|
754
|
-
if (
|
|
396
|
+
if (
|
|
397
|
+
trustCtx.trustClass !== "guardian" &&
|
|
398
|
+
trustCtx.guardianExternalUserId
|
|
399
|
+
) {
|
|
755
400
|
log.info(
|
|
756
|
-
{
|
|
757
|
-
|
|
401
|
+
{
|
|
402
|
+
conversationId,
|
|
403
|
+
conversationExternalId,
|
|
404
|
+
guardianExternalUserId: trustCtx.guardianExternalUserId,
|
|
405
|
+
},
|
|
406
|
+
"Blocking non-guardian self-approval: pending confirmation exists but guardian approval row not yet created",
|
|
758
407
|
);
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
}
|
|
772
|
-
return { handled: true, type:
|
|
408
|
+
await deliverStaleApprovalReply({
|
|
409
|
+
scenario: "request_pending_guardian",
|
|
410
|
+
sourceChannel,
|
|
411
|
+
replyCallbackUrl,
|
|
412
|
+
chatId: conversationExternalId,
|
|
413
|
+
assistantId,
|
|
414
|
+
bearerToken,
|
|
415
|
+
approvalCopyGenerator,
|
|
416
|
+
logger: log,
|
|
417
|
+
errorLogMessage:
|
|
418
|
+
"Failed to deliver guardian-pending notice to non-guardian actor (pre-row guard)",
|
|
419
|
+
errorLogContext: { conversationId },
|
|
420
|
+
});
|
|
421
|
+
return { handled: true, type: "assistant_turn" };
|
|
773
422
|
}
|
|
774
423
|
}
|
|
775
424
|
}
|
|
776
425
|
|
|
426
|
+
// ── Slack reaction path ──
|
|
427
|
+
// Reactions produce `callbackData` of the form `reaction:<emoji_name>`.
|
|
428
|
+
// Only guardians can approve via reaction — non-guardian reactions are
|
|
429
|
+
// silently ignored to prevent self-approval.
|
|
430
|
+
if (callbackData?.startsWith("reaction:")) {
|
|
431
|
+
if (trustCtx.trustClass !== "guardian") {
|
|
432
|
+
return { handled: true, type: "stale_ignored" };
|
|
433
|
+
}
|
|
434
|
+
const reactionDecision = parseReactionCallbackData(callbackData);
|
|
435
|
+
if (!reactionDecision) {
|
|
436
|
+
// Unknown emoji — ignore silently
|
|
437
|
+
return { handled: true, type: "stale_ignored" };
|
|
438
|
+
}
|
|
439
|
+
const pending = getApprovalInfoByConversation(conversationId);
|
|
440
|
+
if (pending.length === 0) {
|
|
441
|
+
return { handled: true, type: "stale_ignored" };
|
|
442
|
+
}
|
|
443
|
+
const result = handleChannelDecision(conversationId, reactionDecision);
|
|
444
|
+
if (result.applied) {
|
|
445
|
+
return { handled: true, type: "decision_applied" };
|
|
446
|
+
}
|
|
447
|
+
return { handled: true, type: "stale_ignored" };
|
|
448
|
+
}
|
|
449
|
+
|
|
777
450
|
// Try to extract a decision from callback data (button press) first.
|
|
778
451
|
// Callback/button path remains deterministic and takes priority.
|
|
779
452
|
if (callbackData) {
|
|
@@ -784,12 +457,15 @@ export async function handleApprovalInterception(
|
|
|
784
457
|
// previous approval prompt) must not apply to a different pending interaction.
|
|
785
458
|
if (cbDecision.requestId) {
|
|
786
459
|
const pending = getApprovalInfoByConversation(conversationId);
|
|
787
|
-
if (
|
|
460
|
+
if (
|
|
461
|
+
pending.length === 0 ||
|
|
462
|
+
!pending.some((p) => p.requestId === cbDecision.requestId)
|
|
463
|
+
) {
|
|
788
464
|
log.warn(
|
|
789
465
|
{ conversationId, callbackRequestId: cbDecision.requestId },
|
|
790
|
-
|
|
466
|
+
"Callback request ID does not match any pending interaction, ignoring stale button press",
|
|
791
467
|
);
|
|
792
|
-
return { handled: true, type:
|
|
468
|
+
return { handled: true, type: "stale_ignored" };
|
|
793
469
|
}
|
|
794
470
|
}
|
|
795
471
|
|
|
@@ -798,321 +474,96 @@ export async function handleApprovalInterception(
|
|
|
798
474
|
if (result.applied) {
|
|
799
475
|
// Post-decision delivery is handled by the onEvent callback
|
|
800
476
|
// in the session that registered the pending interaction.
|
|
801
|
-
return { handled: true, type:
|
|
477
|
+
return { handled: true, type: "decision_applied" };
|
|
802
478
|
}
|
|
803
479
|
|
|
804
480
|
// Race condition: request was already resolved between the stale check
|
|
805
481
|
// above and the decision attempt.
|
|
806
|
-
return { handled: true, type:
|
|
482
|
+
return { handled: true, type: "stale_ignored" };
|
|
807
483
|
}
|
|
808
484
|
}
|
|
809
485
|
|
|
810
486
|
// ── Conversational approval engine for plain-text messages ──
|
|
811
|
-
//
|
|
812
|
-
//
|
|
813
|
-
// and respond conversationally.
|
|
487
|
+
// Delegates to the text engine strategy which classifies natural language
|
|
488
|
+
// and responds conversationally.
|
|
814
489
|
const pending = getApprovalInfoByConversation(conversationId);
|
|
815
490
|
if (pending.length > 0 && approvalConversationGenerator && content) {
|
|
816
491
|
const allowedActions = pendingPrompt.actions.map((a) => a.id);
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
pendingApprovals: pending.map((p) => ({ requestId: p.requestId, toolName: p.toolName })),
|
|
822
|
-
userMessage: content,
|
|
823
|
-
};
|
|
824
|
-
|
|
825
|
-
const engineResult = await runApprovalConversationTurn(engineContext, approvalConversationGenerator);
|
|
826
|
-
|
|
827
|
-
if (engineResult.disposition === 'keep_pending') {
|
|
828
|
-
// Non-decision follow-up — deliver the engine's reply and keep the request pending
|
|
829
|
-
try {
|
|
830
|
-
await deliverChannelReply(replyCallbackUrl, {
|
|
831
|
-
chatId: conversationExternalId,
|
|
832
|
-
text: engineResult.replyText,
|
|
833
|
-
assistantId,
|
|
834
|
-
}, bearerToken);
|
|
835
|
-
} catch (err) {
|
|
836
|
-
log.error({ err, conversationId }, 'Failed to deliver approval conversation reply');
|
|
837
|
-
}
|
|
838
|
-
return { handled: true, type: 'assistant_turn' };
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
// Decision-bearing disposition — map to ApprovalDecisionResult and apply
|
|
842
|
-
const decisionAction = engineResult.disposition as ApprovalAction;
|
|
843
|
-
const engineDecision: ApprovalDecisionResult = {
|
|
844
|
-
action: decisionAction,
|
|
845
|
-
source: 'plain_text',
|
|
846
|
-
...(engineResult.targetRequestId ? { requestId: engineResult.targetRequestId } : {}),
|
|
847
|
-
};
|
|
848
|
-
|
|
849
|
-
const result = handleChannelDecision(conversationId, engineDecision);
|
|
850
|
-
|
|
851
|
-
if (result.applied) {
|
|
852
|
-
// Deliver the engine's reply text to the user
|
|
853
|
-
try {
|
|
854
|
-
await deliverChannelReply(replyCallbackUrl, {
|
|
855
|
-
chatId: conversationExternalId,
|
|
856
|
-
text: engineResult.replyText,
|
|
857
|
-
assistantId,
|
|
858
|
-
}, bearerToken);
|
|
859
|
-
} catch (err) {
|
|
860
|
-
log.error({ err, conversationId }, 'Failed to deliver approval decision reply');
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
return { handled: true, type: 'decision_applied' };
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
// Race condition: request was already resolved by expiry sweep or
|
|
867
|
-
// concurrent callback. Deliver a stale notice instead of the
|
|
868
|
-
// engine's optimistic reply.
|
|
869
|
-
try {
|
|
870
|
-
const staleText = await composeApprovalMessageGenerative({
|
|
871
|
-
scenario: 'approval_already_resolved',
|
|
872
|
-
channel: sourceChannel,
|
|
873
|
-
}, {}, approvalCopyGenerator);
|
|
874
|
-
await deliverChannelReply(replyCallbackUrl, {
|
|
875
|
-
chatId: conversationExternalId,
|
|
876
|
-
text: staleText,
|
|
877
|
-
assistantId,
|
|
878
|
-
}, bearerToken);
|
|
879
|
-
} catch (err) {
|
|
880
|
-
log.error({ err, conversationId }, 'Failed to deliver stale approval notice');
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
return { handled: true, type: 'stale_ignored' };
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
// Fallback: no conversational generator available or no content — use
|
|
887
|
-
// the legacy deterministic path as a safety net. This preserves backward
|
|
888
|
-
// compatibility when the generator is not injected.
|
|
889
|
-
if (content) {
|
|
890
|
-
const legacyDecision = parseApprovalDecision(content);
|
|
891
|
-
if (legacyDecision) {
|
|
892
|
-
if (legacyDecision.requestId) {
|
|
893
|
-
if (pending.length === 0 || !pending.some(p => p.requestId === legacyDecision.requestId)) {
|
|
894
|
-
return { handled: true, type: 'stale_ignored' };
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
-
const result = handleChannelDecision(conversationId, legacyDecision);
|
|
898
|
-
if (result.applied) {
|
|
899
|
-
return { handled: true, type: 'decision_applied' };
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
// Race condition: request was already resolved.
|
|
903
|
-
try {
|
|
904
|
-
const staleText = await composeApprovalMessageGenerative({
|
|
905
|
-
scenario: 'approval_already_resolved',
|
|
906
|
-
channel: sourceChannel,
|
|
907
|
-
}, {}, approvalCopyGenerator);
|
|
908
|
-
await deliverChannelReply(replyCallbackUrl, {
|
|
909
|
-
chatId: conversationExternalId,
|
|
910
|
-
text: staleText,
|
|
911
|
-
assistantId,
|
|
912
|
-
}, bearerToken);
|
|
913
|
-
} catch (err) {
|
|
914
|
-
log.error({ err, conversationId }, 'Failed to deliver stale approval notice (legacy path)');
|
|
915
|
-
}
|
|
916
|
-
return { handled: true, type: 'stale_ignored' };
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
// No decision could be extracted and no conversational engine is available —
|
|
921
|
-
// deliver a simple status reply rather than a reminder prompt.
|
|
922
|
-
try {
|
|
923
|
-
const statusText = await composeApprovalMessageGenerative({
|
|
924
|
-
scenario: 'reminder_prompt',
|
|
925
|
-
channel: sourceChannel,
|
|
926
|
-
toolName: pending.length > 0 ? pending[0].toolName : undefined,
|
|
927
|
-
}, {}, approvalCopyGenerator);
|
|
928
|
-
await deliverChannelReply(replyCallbackUrl, {
|
|
929
|
-
chatId: conversationExternalId,
|
|
930
|
-
text: statusText,
|
|
931
|
-
assistantId,
|
|
932
|
-
}, bearerToken);
|
|
933
|
-
} catch (err) {
|
|
934
|
-
log.error({ err, conversationId }, 'Failed to deliver approval status reply');
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
return { handled: true, type: 'assistant_turn' };
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
// ---------------------------------------------------------------------------
|
|
941
|
-
// Access request decision helper
|
|
942
|
-
// ---------------------------------------------------------------------------
|
|
943
|
-
|
|
944
|
-
/**
|
|
945
|
-
* Handle a guardian's decision on an `ingress_access_request` approval.
|
|
946
|
-
* Delegates to the access-request-decision module and orchestrates
|
|
947
|
-
* notification delivery.
|
|
948
|
-
*
|
|
949
|
-
* On approve: creates a verification session, delivers the code to the
|
|
950
|
-
* guardian, and notifies the requester to expect a code.
|
|
951
|
-
*
|
|
952
|
-
* On deny: marks the request as denied and notifies the requester.
|
|
953
|
-
*/
|
|
954
|
-
async function handleAccessRequestApproval(
|
|
955
|
-
approval: GuardianApprovalRequest,
|
|
956
|
-
action: 'approve' | 'deny',
|
|
957
|
-
decidedByExternalUserId: string,
|
|
958
|
-
replyCallbackUrl: string,
|
|
959
|
-
assistantId: string,
|
|
960
|
-
bearerToken?: string,
|
|
961
|
-
): Promise<ApprovalInterceptionResult> {
|
|
962
|
-
const decisionResult = handleAccessRequestDecision(
|
|
963
|
-
approval,
|
|
964
|
-
action,
|
|
965
|
-
decidedByExternalUserId,
|
|
966
|
-
);
|
|
967
|
-
|
|
968
|
-
if (decisionResult.type === 'stale' || decisionResult.type === 'idempotent') {
|
|
969
|
-
return { handled: true, type: 'stale_ignored' };
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
if (decisionResult.type === 'denied') {
|
|
973
|
-
await notifyRequesterOfDenial({
|
|
492
|
+
return handleGuardianTextEngineDecision({
|
|
493
|
+
conversationId,
|
|
494
|
+
conversationExternalId,
|
|
495
|
+
sourceChannel,
|
|
974
496
|
replyCallbackUrl,
|
|
975
|
-
|
|
497
|
+
content,
|
|
976
498
|
assistantId,
|
|
977
499
|
bearerToken,
|
|
500
|
+
approvalCopyGenerator,
|
|
501
|
+
approvalConversationGenerator,
|
|
502
|
+
pending,
|
|
503
|
+
allowedActions,
|
|
978
504
|
});
|
|
979
|
-
|
|
980
|
-
// Emit both guardian_decision and denied signals so all lifecycle
|
|
981
|
-
// observers are notified of the denial.
|
|
982
|
-
const deniedPayload = {
|
|
983
|
-
sourceChannel: approval.channel,
|
|
984
|
-
requesterExternalUserId: approval.requesterExternalUserId,
|
|
985
|
-
requesterChatId: approval.requesterChatId,
|
|
986
|
-
decidedByExternalUserId,
|
|
987
|
-
decision: 'denied' as const,
|
|
988
|
-
};
|
|
989
|
-
|
|
990
|
-
void emitNotificationSignal({
|
|
991
|
-
sourceEventName: 'ingress.trusted_contact.guardian_decision',
|
|
992
|
-
sourceChannel: approval.channel,
|
|
993
|
-
sourceSessionId: approval.conversationId,
|
|
994
|
-
assistantId,
|
|
995
|
-
attentionHints: {
|
|
996
|
-
requiresAction: false,
|
|
997
|
-
urgency: 'medium',
|
|
998
|
-
isAsyncBackground: false,
|
|
999
|
-
visibleInSourceNow: false,
|
|
1000
|
-
},
|
|
1001
|
-
contextPayload: deniedPayload,
|
|
1002
|
-
dedupeKey: `trusted-contact:guardian-decision:${approval.id}`,
|
|
1003
|
-
});
|
|
1004
|
-
|
|
1005
|
-
void emitNotificationSignal({
|
|
1006
|
-
sourceEventName: 'ingress.trusted_contact.denied',
|
|
1007
|
-
sourceChannel: approval.channel,
|
|
1008
|
-
sourceSessionId: approval.conversationId,
|
|
1009
|
-
assistantId,
|
|
1010
|
-
attentionHints: {
|
|
1011
|
-
requiresAction: false,
|
|
1012
|
-
urgency: 'low',
|
|
1013
|
-
isAsyncBackground: false,
|
|
1014
|
-
visibleInSourceNow: false,
|
|
1015
|
-
},
|
|
1016
|
-
contextPayload: deniedPayload,
|
|
1017
|
-
dedupeKey: `trusted-contact:denied:${approval.id}`,
|
|
1018
|
-
});
|
|
1019
|
-
|
|
1020
|
-
return { handled: true, type: 'guardian_decision_applied' };
|
|
1021
505
|
}
|
|
1022
506
|
|
|
1023
|
-
//
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
if (
|
|
1028
|
-
const
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
)
|
|
1041
|
-
|
|
507
|
+
// ── Natural language approval intent parser ──
|
|
508
|
+
// Covers a broad set of colloquial approval/rejection phrases, emoji, and
|
|
509
|
+
// timed-approval variants. Runs before the legacy parser to provide wider
|
|
510
|
+
// coverage for channels (like Slack) that rely on plain-text responses.
|
|
511
|
+
if (pending.length > 0 && content) {
|
|
512
|
+
const nlIntent = parseApprovalIntent(content);
|
|
513
|
+
if (nlIntent && nlIntent.confidence >= 0.9) {
|
|
514
|
+
const nlDecision: ApprovalDecisionResult = {
|
|
515
|
+
action:
|
|
516
|
+
nlIntent.decision === "approve"
|
|
517
|
+
? "approve_once"
|
|
518
|
+
: nlIntent.decision === "approve_10m"
|
|
519
|
+
? "approve_10m"
|
|
520
|
+
: "reject",
|
|
521
|
+
source: "plain_text",
|
|
522
|
+
};
|
|
523
|
+
const nlResult = handleChannelDecision(conversationId, nlDecision);
|
|
524
|
+
if (nlResult.applied) {
|
|
525
|
+
return { handled: true, type: "decision_applied" };
|
|
526
|
+
}
|
|
1042
527
|
}
|
|
1043
528
|
}
|
|
1044
529
|
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
// Let the requester know something went wrong without revealing details
|
|
1054
|
-
await notifyRequesterOfDeliveryFailure({
|
|
530
|
+
// ── Legacy deterministic fallback ──
|
|
531
|
+
// When no conversational engine is available, use the deterministic parser
|
|
532
|
+
// as a safety net for backward compatibility.
|
|
533
|
+
if (content) {
|
|
534
|
+
const legacyResult = await handleGuardianLegacyFallback({
|
|
535
|
+
conversationId,
|
|
536
|
+
conversationExternalId,
|
|
537
|
+
sourceChannel,
|
|
1055
538
|
replyCallbackUrl,
|
|
1056
|
-
|
|
539
|
+
content,
|
|
1057
540
|
assistantId,
|
|
1058
541
|
bearerToken,
|
|
542
|
+
approvalCopyGenerator,
|
|
543
|
+
pending,
|
|
1059
544
|
});
|
|
545
|
+
if (legacyResult) {
|
|
546
|
+
return legacyResult;
|
|
547
|
+
}
|
|
1060
548
|
}
|
|
1061
549
|
|
|
1062
|
-
//
|
|
1063
|
-
//
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
},
|
|
1080
|
-
contextPayload: {
|
|
1081
|
-
sourceChannel: approval.channel,
|
|
1082
|
-
requesterExternalUserId: approval.requesterExternalUserId,
|
|
1083
|
-
requesterChatId: approval.requesterChatId,
|
|
1084
|
-
decidedByExternalUserId,
|
|
1085
|
-
decision: 'approved',
|
|
1086
|
-
},
|
|
1087
|
-
dedupeKey: `trusted-contact:guardian-decision:${approval.id}`,
|
|
1088
|
-
});
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
// Emit verification_sent with visibleInSourceNow=true so the notification
|
|
1092
|
-
// pipeline suppresses delivery — the guardian already received the
|
|
1093
|
-
// verification code directly. Without this flag, the pipeline generates
|
|
1094
|
-
// a redundant LLM message like "Good news! Your request has been approved."
|
|
1095
|
-
if (decisionResult.verificationSessionId && codeDelivered) {
|
|
1096
|
-
void emitNotificationSignal({
|
|
1097
|
-
sourceEventName: 'ingress.trusted_contact.verification_sent',
|
|
1098
|
-
sourceChannel: approval.channel,
|
|
1099
|
-
sourceSessionId: approval.conversationId,
|
|
1100
|
-
assistantId,
|
|
1101
|
-
attentionHints: {
|
|
1102
|
-
requiresAction: false,
|
|
1103
|
-
urgency: 'low',
|
|
1104
|
-
isAsyncBackground: true,
|
|
1105
|
-
visibleInSourceNow: true,
|
|
1106
|
-
},
|
|
1107
|
-
contextPayload: {
|
|
1108
|
-
sourceChannel: approval.channel,
|
|
1109
|
-
requesterExternalUserId: approval.requesterExternalUserId,
|
|
1110
|
-
requesterChatId: approval.requesterChatId,
|
|
1111
|
-
verificationSessionId: decisionResult.verificationSessionId,
|
|
1112
|
-
},
|
|
1113
|
-
dedupeKey: `trusted-contact:verification-sent:${decisionResult.verificationSessionId}`,
|
|
1114
|
-
});
|
|
1115
|
-
}
|
|
550
|
+
// No decision could be extracted and no conversational engine is available —
|
|
551
|
+
// deliver a simple status reply rather than a reminder prompt.
|
|
552
|
+
await deliverStaleApprovalReply({
|
|
553
|
+
scenario: "reminder_prompt",
|
|
554
|
+
sourceChannel,
|
|
555
|
+
replyCallbackUrl,
|
|
556
|
+
chatId: conversationExternalId,
|
|
557
|
+
assistantId,
|
|
558
|
+
bearerToken,
|
|
559
|
+
approvalCopyGenerator,
|
|
560
|
+
logger: log,
|
|
561
|
+
errorLogMessage: "Failed to deliver approval status reply",
|
|
562
|
+
extraContext: {
|
|
563
|
+
toolName: pending.length > 0 ? pending[0].toolName : undefined,
|
|
564
|
+
},
|
|
565
|
+
errorLogContext: { conversationId },
|
|
566
|
+
});
|
|
1116
567
|
|
|
1117
|
-
return { handled: true, type:
|
|
568
|
+
return { handled: true, type: "assistant_turn" };
|
|
1118
569
|
}
|