@vellumai/assistant 0.9.0 → 0.10.0-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +18 -34
- package/bun.lock +7 -8
- package/docs/activation-funnel-telemetry.md +28 -22
- package/docs/architecture/security.md +29 -28
- package/docs/stt-provider-onboarding.md +3 -5
- package/docs/workflows-testing.md +13 -44
- package/docs/workflows.md +3 -5
- package/node_modules/@vellumai/ces-client/src/__tests__/ces-client.test.ts +47 -0
- package/node_modules/@vellumai/ces-client/src/rpc-client.ts +28 -5
- package/node_modules/@vellumai/environments/src/seeds.ts +2 -5
- package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +97 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +10 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +32 -6
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +119 -0
- package/node_modules/@vellumai/gateway-client/src/types.ts +15 -84
- package/openapi.yaml +976 -63
- package/package.json +2 -1
- package/scripts/sync-llm-catalog.ts +6 -15
- package/scripts/sync-web-search-catalog.ts +3 -11
- package/src/__tests__/access-request-card-view.test.ts +98 -0
- package/src/__tests__/access-request-seed-content-blocks.test.ts +2 -4
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +72 -32
- package/src/__tests__/agent-loop-compaction-strip.test.ts +241 -0
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +16 -13
- package/src/__tests__/agent-loop-output-hooks.test.ts +69 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +25 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -3
- package/src/__tests__/app-compiler.test.ts +15 -1
- package/src/__tests__/app-dir-path-guard.test.ts +0 -1
- package/src/__tests__/assistant-feature-flag-guard.test.ts +1 -4
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +0 -2
- package/src/__tests__/auth-fallback-events-store.test.ts +6 -14
- package/src/__tests__/avatar-identity-sync.test.ts +2 -27
- package/src/__tests__/btw-routes.test.ts +6 -8
- package/src/__tests__/call-pointer-messages.test.ts +28 -0
- package/src/__tests__/cancel-clears-processing.test.ts +89 -0
- package/src/__tests__/channel-approval-routes.test.ts +0 -4
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +5 -15
- package/src/__tests__/checker.test.ts +0 -3
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +3 -4
- package/src/__tests__/compactor-image-manifest-trust.test.ts +21 -1
- package/src/__tests__/compactor-summary-call-truncation.test.ts +223 -0
- package/src/__tests__/config-loader-backfill.test.ts +268 -27
- package/src/__tests__/config-schema.test.ts +35 -0
- package/src/__tests__/config-watcher.test.ts +0 -18
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -2
- package/src/__tests__/contact-store-user-file.test.ts +0 -6
- package/src/__tests__/contacts-tools.test.ts +29 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +22 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop.test.ts +58 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
- package/src/__tests__/conversation-lifecycle.test.ts +7 -9
- package/src/__tests__/conversation-load-history-repair.test.ts +101 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +15 -12
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -3
- package/src/__tests__/conversation-title-service.test.ts +62 -0
- package/src/__tests__/credential-broker.test.ts +449 -1
- package/src/__tests__/credential-execution-shell-lockdown.test.ts +18 -11
- package/src/__tests__/credential-execution-tools.test.ts +0 -1
- package/src/__tests__/credential-prompt-route.test.ts +4 -4
- package/src/__tests__/credential-routes.test.ts +360 -0
- package/src/__tests__/credential-security-invariants.test.ts +4 -13
- package/src/__tests__/disk-pressure-policy.test.ts +12 -0
- package/src/__tests__/disk-usage.test.ts +65 -0
- package/src/__tests__/dynamic-page-surface.test.ts +152 -1
- package/src/__tests__/fixtures/credential-security-fixtures.ts +2 -33
- package/src/__tests__/gateway-flag-listener.test.ts +110 -1
- package/src/__tests__/gateway-only-guard.test.ts +3 -7
- package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
- package/src/__tests__/guardian-card-withdrawal.test.ts +403 -0
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +5 -3
- package/src/__tests__/guardian-grant-minting.test.ts +3 -35
- package/src/__tests__/guardian-routing-invariants.test.ts +64 -26
- package/src/__tests__/guardian-routing-state.test.ts +0 -1
- package/src/__tests__/headless-browser-mode.test.ts +10 -0
- package/src/__tests__/headless-browser-navigate.test.ts +8 -3
- package/src/__tests__/helpers/create-guardian-binding.ts +0 -1
- package/src/__tests__/host-browser-proxy.test.ts +87 -0
- package/src/__tests__/identity-routes.test.ts +0 -189
- package/src/__tests__/inbound-invite-redemption.test.ts +4 -4
- package/src/__tests__/injector-v3-suppression.test.ts +27 -20
- package/src/__tests__/internal-telemetry-routes.test.ts +6 -14
- package/src/__tests__/invite-redemption-service.test.ts +4 -7
- package/src/__tests__/llm-callsite-catalog.test.ts +5 -6
- package/src/__tests__/llm-catalog-parity.test.ts +30 -23
- package/src/__tests__/llm-resolver.test.ts +70 -24
- package/src/__tests__/llm-schema.test.ts +1 -0
- package/src/__tests__/managed-profile-guard.test.ts +163 -4
- package/src/__tests__/mcp-health-check.test.ts +6 -7
- package/src/__tests__/media-stream-server-integration.test.ts +317 -13
- package/src/__tests__/oauth-provider-seed-logos.test.ts +4 -6
- package/src/__tests__/onboarding-persona-write.test.ts +1 -1
- package/src/__tests__/path-policy.test.ts +34 -0
- package/src/__tests__/persona-resolver.test.ts +49 -14
- package/src/__tests__/plugin-api-model-profiles.test.ts +178 -0
- package/src/__tests__/plugin-api-provider.test.ts +24 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +6 -3
- package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +214 -0
- package/src/__tests__/provider-send-message-override-profile.test.ts +76 -0
- package/src/__tests__/reaction-persistence.test.ts +150 -29
- package/src/__tests__/registry.test.ts +2 -7
- package/src/__tests__/relay-server.test.ts +285 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +1 -10
- package/src/__tests__/schedule-routes.test.ts +0 -30
- package/src/__tests__/schedule-tools.test.ts +2 -18
- package/src/__tests__/scheduler-reuse-conversation.test.ts +8 -5
- package/src/__tests__/skill-execute-input.test.ts +51 -1
- package/src/__tests__/skill-runtime-path.test.ts +2 -3
- package/src/__tests__/skills.test.ts +51 -0
- package/src/__tests__/slack-notification-approval-card.test.ts +176 -0
- package/src/__tests__/slack-reaction-canonical-approval.test.ts +285 -0
- package/src/__tests__/subagent-tools.test.ts +266 -0
- package/src/__tests__/surface-completion-nudge-hook.test.ts +367 -0
- package/src/__tests__/task-progress-nudge-hook.test.ts +1 -1
- package/src/__tests__/title-generate-hook.test.ts +100 -3
- package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +1 -29
- package/src/__tests__/token-manager.test.ts +519 -0
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +1 -1
- package/src/__tests__/tool-audit-listener.test.ts +7 -7
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +6 -3
- package/src/__tests__/tool-executor.test.ts +0 -79
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +4 -2
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +220 -3
- package/src/__tests__/trusted-contact-multichannel.test.ts +3 -3
- package/src/__tests__/trusted-contact-verification.test.ts +8 -10
- package/src/__tests__/twilio-routes.test.ts +81 -1
- package/src/__tests__/voice-invite-redemption.test.ts +2 -3
- package/src/__tests__/weak-open-model.test.ts +30 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +6 -25
- package/src/__tests__/workspace-greetings.test.ts +152 -0
- package/src/__tests__/workspace-migration-105-enable-memory-v3-live-for-new-workspaces.test.ts +149 -0
- package/src/__tests__/workspace-migration-108-drop-balanced-economy-profile.test.ts +285 -0
- package/src/__tests__/workspace-migration-add-send-diagnostics.test.ts +1 -1
- package/src/__tests__/workspace-migration-drop-collect-usage-data.test.ts +118 -0
- package/src/__tests__/workspace-migration-drop-send-diagnostics.test.ts +118 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +0 -4
- package/src/agent/loop.ts +49 -29
- package/src/api/README.md +6 -6
- package/src/api/events/tool-result.ts +6 -0
- package/src/api/events/workflow-completed.ts +53 -0
- package/src/api/events/workflow-leaf-finished.ts +38 -0
- package/src/api/events/workflow-leaf-started.ts +35 -0
- package/src/api/events/workflow-progress.ts +32 -0
- package/src/api/events/workflow-started.ts +31 -0
- package/src/api/index.ts +40 -0
- package/src/api/responses/conversation-message.ts +28 -4
- package/src/api/responses/home.ts +26 -4
- package/src/api/responses/workflow-journal.ts +53 -0
- package/src/approvals/guardian-card-withdrawal.ts +145 -0
- package/src/approvals/guardian-decision-primitive.ts +26 -3
- package/src/approvals/guardian-request-resolvers.ts +183 -80
- package/src/calls/__tests__/channel-admission-reader.test.ts +132 -0
- package/src/calls/__tests__/relay-setup-router.test.ts +350 -0
- package/src/calls/call-pointer-messages.ts +10 -4
- package/src/calls/channel-admission-reader.ts +104 -0
- package/src/calls/guardian-dispatch.ts +17 -45
- package/src/calls/media-stream-server.ts +84 -2
- package/src/calls/relay-access-wait.ts +1 -1
- package/src/calls/relay-server.ts +66 -0
- package/src/calls/relay-setup-router.ts +82 -1
- package/src/calls/twilio-routes.ts +17 -8
- package/src/calls/voice-session-bridge.ts +2 -2
- package/src/cli/commands/clients.ts +3 -0
- package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2-compare-render.test.ts +1 -1
- package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2.test.ts +8 -7
- package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v3.test.ts +5 -4
- package/src/cli/commands/memory/index.ts +30 -0
- package/src/cli/commands/{memory-v2-compare-render.ts → memory/memory-v2-compare-render.ts} +1 -1
- package/src/cli/commands/{memory-v2.ts → memory/memory-v2.ts} +6 -15
- package/src/cli/commands/{memory-v3.ts → memory/memory-v3.ts} +97 -11
- package/src/cli/commands/oauth/status.test.ts +36 -0
- package/src/cli/commands/oauth/status.ts +23 -3
- package/src/cli/commands/plugins.ts +197 -4
- package/src/cli/lib/__tests__/diff-plugin.test.ts +443 -0
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
- package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +443 -0
- package/src/cli/lib/__tests__/plugin-surfaces.test.ts +111 -0
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +295 -2
- package/src/cli/lib/diff-plugin.ts +346 -0
- package/src/cli/lib/inspect-plugin.ts +12 -1
- package/src/cli/lib/install-from-github.ts +105 -17
- package/src/cli/lib/merge-plugin-tree.ts +328 -0
- package/src/cli/lib/plugin-fingerprint.ts +14 -0
- package/src/cli/lib/plugin-surfaces.ts +104 -0
- package/src/cli/lib/upgrade-plugin.ts +298 -10
- package/src/cli/program.ts +2 -6
- package/src/config/__tests__/sync-gated-profiles.test.ts +368 -0
- package/src/config/assistant-feature-flags.ts +22 -7
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +0 -1
- package/src/config/bundled-skills/messaging/SKILL.md +6 -4
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +9 -8
- package/src/config/bundled-skills/subagent/SKILL.md +4 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +4 -0
- package/src/config/bundled-skills/workflows/SKILL.md +14 -8
- package/src/config/bundled-tool-registry.ts +2 -7
- package/src/config/call-site-defaults.ts +15 -2
- package/src/config/feature-flag-registry.json +46 -31
- package/src/config/inference-profile-validation.ts +26 -0
- package/src/config/llm-resolver.ts +3 -0
- package/src/config/loader.ts +4 -0
- package/src/config/memory-v3-gate.ts +11 -0
- package/src/config/profile-order.ts +28 -0
- package/src/config/schema.ts +8 -6
- package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
- package/src/config/schemas/call-site-catalog.ts +7 -0
- package/src/config/schemas/channels.ts +11 -0
- package/src/config/schemas/elevenlabs.ts +0 -1
- package/src/config/schemas/llm.ts +31 -0
- package/src/config/schemas/memory-lifecycle.ts +3 -7
- package/src/config/schemas/memory-v3.ts +6 -0
- package/src/config/schemas/platform.ts +0 -8
- package/src/config/schemas/services.ts +18 -0
- package/src/config/seed-inference-profiles.ts +109 -44
- package/src/config/skills.ts +21 -0
- package/src/config/sync-gated-profiles.ts +220 -0
- package/src/contacts/contact-store.ts +89 -106
- package/src/contacts/contacts-write.ts +5 -22
- package/src/contacts/types.ts +0 -1
- package/src/context/compactor.ts +88 -54
- package/src/context/strip-injections.ts +58 -10
- package/src/context/token-estimator.ts +1 -1
- package/src/credential-execution/process-manager.ts +55 -14
- package/src/credential-execution/prompted-credential.ts +2 -3
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -2
- package/src/daemon/config-watcher.ts +0 -4
- package/src/daemon/conversation-agent-loop-handlers.ts +2 -0
- package/src/daemon/conversation-agent-loop.ts +114 -22
- package/src/daemon/conversation-history.ts +1 -1
- package/src/daemon/conversation-lifecycle.ts +3 -5
- package/src/daemon/conversation-process.ts +13 -5
- package/src/daemon/conversation-runtime-assembly.ts +13 -15
- package/src/daemon/conversation-slash.ts +2 -23
- package/src/daemon/conversation-surfaces.ts +26 -0
- package/src/daemon/conversation-tool-setup.ts +27 -14
- package/src/daemon/conversation.ts +66 -14
- package/src/daemon/disk-pressure-policy.ts +5 -3
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +0 -1
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -1
- package/src/daemon/handlers/config-a2a.ts +0 -2
- package/src/daemon/handlers/config-channels.ts +15 -16
- package/src/daemon/handlers/config-slack-channel.ts +22 -3
- package/src/daemon/handlers/conversations.ts +107 -0
- package/src/daemon/host-browser-proxy.ts +41 -0
- package/src/daemon/lifecycle.ts +55 -27
- package/src/daemon/message-provenance.ts +2 -0
- package/src/daemon/message-types/contacts.ts +0 -1
- package/src/daemon/message-types/conversations.ts +3 -3
- package/src/daemon/message-types/sync.ts +0 -1
- package/src/daemon/message-types/web-activity.ts +7 -1
- package/src/daemon/message-types/workflows.ts +83 -1
- package/src/daemon/orphan-reaper.test.ts +0 -19
- package/src/daemon/orphan-reaper.ts +2 -24
- package/src/daemon/server.ts +0 -10
- package/src/daemon/tool-setup-types.ts +4 -0
- package/src/daemon/trust-context.ts +1 -1
- package/src/events/tool-audit-listener.ts +2 -2
- package/src/home/feed-source-enrichment.test.ts +151 -0
- package/src/home/feed-source-enrichment.ts +176 -0
- package/src/home/relationship-state.ts +2 -4
- package/src/instrument.ts +18 -6
- package/src/ipc/__tests__/binary-result-ipc.test.ts +81 -0
- package/src/ipc/__tests__/clients-list-ipc.test.ts +20 -0
- package/src/ipc/assistant-server.ts +37 -4
- package/src/ipc/gateway-flag-listener.ts +18 -2
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +5 -16
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +7 -11
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +37 -7
- package/src/memory/__tests__/memory-retrospective-job.test.ts +229 -401
- package/src/memory/__tests__/onboarding-events-store.test.ts +7 -7
- package/src/memory/auth-fallback-events-store.ts +2 -2
- package/src/memory/auto-analysis-enqueue.ts +3 -5
- package/src/memory/bookmark-crud.ts +1 -2
- package/src/memory/canonical-guardian-store.ts +39 -1
- package/src/memory/conversation-crud.ts +9 -4
- package/src/memory/conversation-key-store.ts +17 -2
- package/src/memory/conversation-title-service.ts +64 -7
- package/src/memory/db-init.ts +17 -17
- package/src/memory/embedding-backend.ts +38 -1
- package/src/memory/embedding-billing-breaker.ts +96 -0
- package/src/memory/jobs-store.ts +25 -13
- package/src/memory/jobs-worker.ts +54 -1
- package/src/memory/lifecycle-events-store.ts +2 -2
- package/src/memory/memory-retrospective-constants.ts +4 -4
- package/src/memory/memory-retrospective-enqueue.ts +31 -6
- package/src/memory/memory-retrospective-job.ts +28 -227
- package/src/memory/migrations/129-contact-channels-access-fields.ts +18 -9
- package/src/memory/migrations/131-drop-legacy-member-guardian-tables.ts +14 -2
- package/src/memory/migrations/289-contact-channels-unique-ext-user.ts +10 -0
- package/src/memory/migrations/291-contact-channels-renormalize-addresses.ts +72 -0
- package/src/memory/migrations/292-schedule-default-no-reuse-conversation.test.ts +67 -0
- package/src/memory/migrations/292-schedule-default-no-reuse-conversation.ts +25 -0
- package/src/memory/migrations/293-workflow-journal-leaf-tokens.ts +32 -0
- package/src/memory/migrations/294-drop-external-user-id.ts +31 -0
- package/src/memory/migrations/295-drop-approval-prompt-ts-tracker.ts +20 -0
- package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.test.ts +110 -0
- package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.ts +68 -0
- package/src/memory/migrations/__tests__/131-drop-legacy-member-guardian-tables.test.ts +154 -0
- package/src/memory/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +31 -0
- package/src/memory/migrations/__tests__/291-contact-channels-renormalize-addresses.test.ts +341 -0
- package/src/memory/migrations/__tests__/run-migrations.test.ts +52 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/run-migrations.ts +41 -0
- package/src/memory/migrations/validate-migration-state.ts +1 -1
- package/src/memory/onboarding-events-store.ts +3 -3
- package/src/memory/schema/contacts.ts +0 -5
- package/src/memory/skill-loaded-events-store.test.ts +7 -15
- package/src/memory/skill-loaded-events-store.ts +2 -2
- package/src/memory/tool-executed-events-store.test.ts +7 -7
- package/src/memory/turn-trace-store.test.ts +736 -0
- package/src/memory/turn-trace-store.ts +364 -0
- package/src/memory/v2/__tests__/consolidation-job.test.ts +8 -0
- package/src/memory/v2/__tests__/skill-content.test.ts +30 -0
- package/src/memory/v2/consolidation-job.ts +2 -2
- package/src/memory/v2/skill-content.ts +25 -7
- package/src/memory/v2/skill-store.ts +7 -1
- package/src/memory/v3-eval/__tests__/eval-packets.test.ts +248 -0
- package/src/memory/v3-eval/eval-packets.ts +546 -0
- package/src/messaging/providers/slack/adapter.ts +1 -1
- package/src/messaging/providers/slack/api.ts +31 -0
- package/src/messaging/providers/slack/send.test.ts +114 -2
- package/src/messaging/providers/slack/send.ts +30 -7
- package/src/messaging/providers/slack/withdraw.test.ts +200 -0
- package/src/messaging/providers/slack/withdraw.ts +161 -0
- package/src/notifications/AGENTS.md +2 -0
- package/src/notifications/access-request-copy.ts +72 -59
- package/src/notifications/adapters/shared.ts +29 -0
- package/src/notifications/adapters/slack.ts +58 -103
- package/src/notifications/adapters/telegram.ts +2 -20
- package/src/notifications/approval-card-data.ts +333 -0
- package/src/notifications/broadcaster.ts +16 -3
- package/src/notifications/canonical-delivery-recorder.ts +139 -0
- package/src/notifications/copy-composer.ts +3 -3
- package/src/notifications/decision-engine.ts +4 -2
- package/src/notifications/destination-resolver.ts +4 -6
- package/src/notifications/guardian-question-mode.ts +10 -0
- package/src/notifications/home-feed-side-effect.ts +7 -16
- package/src/notifications/notification-utils.ts +19 -20
- package/src/notifications/signal.ts +79 -43
- package/src/notifications/types.ts +98 -121
- package/src/oauth/AGENTS.md +5 -24
- package/src/permissions/checker.test.ts +51 -0
- package/src/permissions/checker.ts +185 -26
- package/src/permissions/ipc-risk-types.ts +24 -0
- package/src/permissions/question-prompter.test.ts +27 -0
- package/src/permissions/question-prompter.ts +4 -0
- package/src/platform/client.test.ts +119 -0
- package/src/platform/client.ts +66 -0
- package/src/platform/consent-cache.test.ts +267 -0
- package/src/platform/consent-cache.ts +174 -0
- package/src/plugin-api/constants.ts +1 -1
- package/src/plugin-api/index.ts +33 -1
- package/src/plugin-api/model-profiles.ts +33 -0
- package/src/plugin-api/types.ts +50 -2
- package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +56 -0
- package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +43 -0
- package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +137 -0
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +153 -0
- package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +138 -0
- package/src/plugins/defaults/advisor/__tests__/transcript.test.ts +147 -0
- package/src/plugins/defaults/advisor/advisor-gate.ts +29 -0
- package/src/plugins/defaults/advisor/advisor-state-store.ts +94 -0
- package/src/plugins/defaults/advisor/config.ts +21 -0
- package/src/plugins/defaults/advisor/consult.ts +93 -0
- package/src/plugins/defaults/advisor/hooks/post-model-call.ts +34 -0
- package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +30 -0
- package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +19 -0
- package/src/plugins/defaults/advisor/package.json +14 -0
- package/src/plugins/defaults/advisor/steering.ts +67 -0
- package/src/plugins/defaults/advisor/tools/advisor.ts +65 -0
- package/src/plugins/defaults/advisor/transcript.ts +76 -0
- package/src/plugins/defaults/index.ts +60 -0
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +22 -9
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +2 -2
- package/src/plugins/defaults/memory-retrieval/tail-reinjection-strip.ts +64 -0
- package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +29 -21
- package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +129 -9
- package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +31 -4
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +77 -2
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +7 -10
- package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +144 -11
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +32 -20
- package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +56 -3
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +23 -2
- package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +276 -0
- package/src/plugins/defaults/surface-completion-nudge/hooks/stop.ts +22 -0
- package/src/plugins/defaults/surface-completion-nudge/nudge-state-store.ts +46 -0
- package/src/plugins/defaults/surface-completion-nudge/package.json +14 -0
- package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +3 -13
- package/src/plugins/defaults/title-generate/hooks/stop.ts +56 -21
- package/src/prompts/persona-resolver.ts +14 -4
- package/src/prompts/templates/system-sections.ts +7 -2
- package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +1 -0
- package/src/providers/__tests__/retry-callsite.test.ts +176 -0
- package/src/providers/atlascloud/client.ts +85 -0
- package/src/providers/fetch-provider-catalog.ts +85 -0
- package/src/providers/inference/adapter-factory.ts +3 -0
- package/src/providers/model-catalog.ts +58 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +33 -0
- package/src/providers/openai/chat-completions-provider.ts +7 -0
- package/src/providers/openai/responses-provider.ts +10 -0
- package/src/providers/provider-send-message.ts +11 -3
- package/src/providers/retry.ts +53 -12
- package/src/providers/search-provider-catalog.ts +10 -0
- package/src/providers/weak-open-model.ts +22 -0
- package/src/runtime/AGENTS.md +0 -1
- package/src/runtime/__tests__/agent-wake.test.ts +181 -0
- package/src/runtime/__tests__/client-health.test.ts +44 -0
- package/src/runtime/access-request-helper.ts +21 -53
- package/src/runtime/actor-trust-resolver.ts +59 -63
- package/src/runtime/agent-wake.ts +52 -0
- package/src/runtime/assistant-event-hub.ts +18 -4
- package/src/runtime/auth/__tests__/route-policy.test.ts +12 -0
- package/src/runtime/auth/require-bound-guardian.ts +1 -4
- package/src/runtime/btw-sidechain.ts +3 -6
- package/src/runtime/capabilities.test.ts +120 -0
- package/src/runtime/capabilities.ts +197 -0
- package/src/runtime/channel-approval-types.ts +22 -45
- package/src/runtime/channel-invite-transports/telegram.ts +4 -4
- package/src/runtime/channel-retry-sweep.ts +1 -0
- package/src/runtime/channel-verification-service.ts +3 -3
- package/src/runtime/client-health.ts +26 -0
- package/src/runtime/confirmation-request-guardian-bridge.ts +38 -29
- package/src/runtime/effective-capabilities.test.ts +128 -0
- package/src/runtime/effective-capabilities.ts +84 -0
- package/src/runtime/guardian-reply-router.ts +106 -21
- package/src/runtime/invite-redemption-service.ts +9 -25
- package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +123 -0
- package/src/runtime/migrations/vbundle-builder.ts +49 -20
- package/src/runtime/pending-interactions.ts +15 -0
- package/src/runtime/routes/__tests__/client-routes.test.ts +13 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +67 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +240 -1
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +2 -2
- package/src/runtime/routes/assets/vellum-design-system.css +1959 -0
- package/src/runtime/routes/browser-tabs-routes.ts +9 -0
- package/src/runtime/routes/btw-routes.ts +1 -27
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +17 -8
- package/src/runtime/routes/client-routes.ts +10 -0
- package/src/runtime/routes/contact-routes.ts +31 -8
- package/src/runtime/routes/conversation-compaction-routes.ts +1 -1
- package/src/runtime/routes/conversation-management-routes.ts +80 -1
- package/src/runtime/routes/conversation-query-routes.ts +68 -22
- package/src/runtime/routes/conversation-routes.ts +39 -14
- package/src/runtime/routes/credential-routes.ts +40 -16
- package/src/runtime/routes/empty-state-greeting-cache.ts +1 -2
- package/src/runtime/routes/events-routes.ts +1 -3
- package/src/runtime/routes/guardian-approval-interception.ts +14 -73
- package/src/runtime/routes/guardian-approval-prompt.ts +22 -4
- package/src/runtime/routes/home-feed-routes.ts +8 -3
- package/src/runtime/routes/identity-routes.ts +1 -296
- package/src/runtime/routes/inbound-message-handler.ts +214 -228
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +89 -7
- package/src/runtime/routes/inbound-stages/admission-policy.test.ts +154 -0
- package/src/runtime/routes/inbound-stages/admission-policy.ts +140 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +3 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +11 -6
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -2
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +1 -2
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +7 -7
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +47 -28
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +358 -0
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +8 -0
- package/src/runtime/routes/integrations/slack/channel.ts +36 -0
- package/src/runtime/routes/internal-telemetry-routes.ts +1 -1
- package/src/runtime/routes/mcp-auth-routes.ts +233 -41
- package/src/runtime/routes/memory-eval-routes.ts +87 -0
- package/src/runtime/routes/notification-routes.ts +122 -133
- package/src/runtime/routes/platform-routes.ts +2 -2
- package/src/runtime/routes/plugins-routes.ts +202 -3
- package/src/runtime/routes/schedule-routes.ts +0 -22
- package/src/runtime/routes/secret-routes.ts +10 -0
- package/src/runtime/routes/surface-action-routes.ts +2 -1
- package/src/runtime/routes/tool-call-question-enrichment.test.ts +146 -0
- package/src/runtime/routes/tool-call-question-enrichment.ts +66 -0
- package/src/runtime/routes/workflow-routes.test.ts +229 -44
- package/src/runtime/routes/workflow-routes.ts +131 -29
- package/src/runtime/routes/workspace-greetings.ts +55 -0
- package/src/runtime/sync/resource-sync-events.ts +1 -11
- package/src/runtime/tool-grant-request-helper.ts +18 -16
- package/src/runtime/trust-context-resolver.ts +8 -5
- package/src/schedule/inference-profile.ts +2 -14
- package/src/schedule/schedule-store.ts +1 -1
- package/src/schedule/scheduler-types.ts +5 -1
- package/src/security/__tests__/provider-key-env-fallback.test.ts +6 -0
- package/src/security/secret-patterns.ts +3 -0
- package/src/subagent/manager.ts +17 -4
- package/src/subagent/types.ts +6 -0
- package/src/telemetry/trace-collection-policy.test.ts +28 -0
- package/src/telemetry/trace-collection-policy.ts +30 -0
- package/src/telemetry/types.ts +89 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +586 -36
- package/src/telemetry/usage-telemetry-reporter.ts +148 -41
- package/src/tools/AGENTS.md +3 -3
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +31 -0
- package/src/tools/browser/browser-execution.ts +30 -19
- package/src/tools/document/document-tool.ts +2 -3
- package/src/tools/executor.ts +5 -3
- package/src/tools/host-terminal/host-shell.ts +5 -4
- package/src/tools/memory/register.ts +2 -2
- package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +360 -0
- package/src/tools/network/__tests__/web-search.test.ts +143 -0
- package/src/tools/network/web-fetch.ts +372 -1
- package/src/tools/network/web-search-error.ts +1 -1
- package/src/tools/network/web-search.ts +213 -10
- package/src/tools/permission-checker.ts +4 -3
- package/src/tools/registry.ts +20 -0
- package/src/tools/schedule/create.ts +7 -12
- package/src/tools/schedule/update.ts +4 -11
- package/src/tools/shared/filesystem/path-policy.ts +39 -13
- package/src/tools/side-effects.ts +2 -17
- package/src/tools/skills/execute.ts +33 -0
- package/src/tools/subagent/spawn.ts +61 -12
- package/src/tools/terminal/shell.ts +10 -4
- package/src/tools/tool-approval-handler.ts +18 -13
- package/src/tools/tool-manifest.ts +0 -2
- package/src/tools/types.ts +9 -0
- package/src/tools/ui-surface/definitions.ts +64 -3
- package/src/tools/verification-control-plane-policy.ts +3 -1
- package/src/tools/workflows/run-workflow.test.ts +8 -18
- package/src/tools/workflows/run-workflow.ts +1 -0
- package/src/util/disk-usage.ts +78 -23
- package/src/util/platform.ts +10 -3
- package/src/watcher/telemetry.ts +2 -2
- package/src/workflows/capabilities.ts +2 -3
- package/src/workflows/engine.test.ts +175 -1
- package/src/workflows/engine.ts +82 -0
- package/src/workflows/journal-store.test.ts +70 -0
- package/src/workflows/journal-store.ts +18 -3
- package/src/workflows/run-manager.test.ts +171 -28
- package/src/workflows/run-manager.ts +66 -24
- package/src/workspace/migrations/105-enable-memory-v3-live-for-new-workspaces.ts +63 -0
- package/src/workspace/migrations/106-drop-collect-usage-data.ts +47 -0
- package/src/workspace/migrations/107-drop-send-diagnostics.ts +47 -0
- package/src/workspace/migrations/108-drop-balanced-economy-profile.ts +129 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/__tests__/app-control-no-global-cgevent.test.ts +0 -98
- package/src/__tests__/credential-security-e2e.test.ts +0 -362
- package/src/__tests__/credential-vault-unit.test.ts +0 -1528
- package/src/__tests__/credential-vault.test.ts +0 -1706
- package/src/__tests__/identity-intro-cache.test.ts +0 -315
- package/src/__tests__/secret-onetime-send.test.ts +0 -182
- package/src/cli/commands/__tests__/task.test.ts +0 -914
- package/src/cli/commands/task.ts +0 -771
- package/src/config/bundled-skills/personal-page/SKILL.md +0 -57
- package/src/config/bundled-skills/personal-page/TOOLS.json +0 -27
- package/src/config/bundled-skills/personal-page/tools/app-refresh.ts +0 -17
- package/src/config/preloaded-apps/personal-page/src/components/About.tsx +0 -22
- package/src/config/preloaded-apps/personal-page/src/components/App.tsx +0 -16
- package/src/config/preloaded-apps/personal-page/src/components/Features.tsx +0 -77
- package/src/config/preloaded-apps/personal-page/src/components/Hero.tsx +0 -57
- package/src/config/preloaded-apps/personal-page/src/components/Pending.tsx +0 -28
- package/src/config/preloaded-apps/personal-page/src/components/animations.tsx +0 -234
- package/src/config/preloaded-apps/personal-page/src/components/icons.tsx +0 -48
- package/src/config/preloaded-apps/personal-page/src/components/media.ts +0 -16
- package/src/config/preloaded-apps/personal-page/src/index.html +0 -20
- package/src/config/preloaded-apps/personal-page/src/main.tsx +0 -7
- package/src/config/preloaded-apps/personal-page/src/profile-data.ts +0 -82
- package/src/config/preloaded-apps/personal-page/src/styles.css +0 -759
- package/src/memory/__tests__/preloaded-apps.test.ts +0 -85
- package/src/memory/preloaded-apps.ts +0 -116
- package/src/notifications/tool-approval-copy.ts +0 -142
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +0 -78
- package/src/runtime/routes/identity-intro-cache.ts +0 -172
- package/src/tools/credentials/vault.ts +0 -712
|
@@ -5,6 +5,11 @@
|
|
|
5
5
|
* invite token redemption.
|
|
6
6
|
*/
|
|
7
7
|
import type { SourceMetadata } from "@vellumai/gateway-client";
|
|
8
|
+
import {
|
|
9
|
+
ADMISSION_POLICY_DEFAULT,
|
|
10
|
+
type AdmissionPolicy,
|
|
11
|
+
isAdmissionPolicy,
|
|
12
|
+
} from "@vellumai/gateway-client";
|
|
8
13
|
|
|
9
14
|
import {
|
|
10
15
|
attachmentsToContentBlocks,
|
|
@@ -17,6 +22,7 @@ import {
|
|
|
17
22
|
isChannelId,
|
|
18
23
|
parseInterfaceId,
|
|
19
24
|
} from "../../channels/types.js";
|
|
25
|
+
import { isAssistantFeatureFlagEnabled } from "../../config/assistant-feature-flags.js";
|
|
20
26
|
import { getConfig } from "../../config/loader.js";
|
|
21
27
|
import {
|
|
22
28
|
createApprovalConversationGenerator,
|
|
@@ -53,7 +59,6 @@ import {
|
|
|
53
59
|
import {
|
|
54
60
|
clearPayload,
|
|
55
61
|
findMessageBySourceId,
|
|
56
|
-
linkMessage,
|
|
57
62
|
recordInbound,
|
|
58
63
|
} from "../../memory/delivery-crud.js";
|
|
59
64
|
import { markProcessed } from "../../memory/delivery-status.js";
|
|
@@ -78,28 +83,45 @@ import {
|
|
|
78
83
|
type SlackMessageMetadata,
|
|
79
84
|
writeSlackMetadata,
|
|
80
85
|
} from "../../messaging/providers/slack/message-metadata.js";
|
|
86
|
+
import { MESSAGE_PREVIEW_MAX_LENGTH } from "../../notifications/notification-utils.js";
|
|
81
87
|
import type { ContentBlock } from "../../providers/types.js";
|
|
82
88
|
import { wrapUntrustedContent } from "../../security/untrusted-content.js";
|
|
83
89
|
import { canonicalizeInboundIdentity } from "../../util/canonicalize-identity.js";
|
|
84
90
|
import { getLogger } from "../../util/logger.js";
|
|
91
|
+
import { truncate } from "../../util/truncate.js";
|
|
92
|
+
import { notifyGuardianOfAccessRequest } from "../access-request-helper.js";
|
|
85
93
|
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
|
|
86
94
|
import { deliverChannelReply } from "../gateway-client.js";
|
|
87
95
|
import { resolveTrustContext } from "../trust-context-resolver.js";
|
|
88
96
|
import { canonicalChannelAssistantId } from "./channel-route-shared.js";
|
|
89
97
|
import { BadRequestError } from "./errors.js";
|
|
90
98
|
import { handleApprovalInterception } from "./guardian-approval-interception.js";
|
|
91
|
-
import {
|
|
99
|
+
import {
|
|
100
|
+
channelStatusToMemberStatus,
|
|
101
|
+
enforceIngressAcl,
|
|
102
|
+
} from "./inbound-stages/acl-enforcement.js";
|
|
103
|
+
import { enforceAdmissionPolicy } from "./inbound-stages/admission-policy.js";
|
|
92
104
|
import { processChannelMessageInBackground } from "./inbound-stages/background-dispatch.js";
|
|
93
105
|
import { handleBootstrapIntercept } from "./inbound-stages/bootstrap-intercept.js";
|
|
94
106
|
import { handleEditIntercept } from "./inbound-stages/edit-intercept.js";
|
|
95
107
|
import { handleEscalationIntercept } from "./inbound-stages/escalation-intercept.js";
|
|
96
108
|
import { handleGuardianActivationIntercept } from "./inbound-stages/guardian-activation-intercept.js";
|
|
97
109
|
import { handleGuardianReplyIntercept } from "./inbound-stages/guardian-reply-intercept.js";
|
|
110
|
+
import {
|
|
111
|
+
handleSlackReactionIntercept,
|
|
112
|
+
isSlackReactionEvent,
|
|
113
|
+
} from "./inbound-stages/reaction-intercept.js";
|
|
98
114
|
import { runSecretIngressCheck } from "./inbound-stages/secret-ingress-check.js";
|
|
99
115
|
import { tryTranscribeAudioAttachments } from "./inbound-stages/transcribe-audio.js";
|
|
100
116
|
import type { RouteHandlerArgs } from "./types.js";
|
|
101
117
|
|
|
102
118
|
const log = getLogger("runtime-http");
|
|
119
|
+
|
|
120
|
+
// Gates the per-channel admission floor stage. When off, the floor is never
|
|
121
|
+
// enforced and inbound falls back to ACL-only behavior (the gateway also skips
|
|
122
|
+
// attaching a floor when off, so the ACL sees the default permissive policy).
|
|
123
|
+
const CHANNEL_TRUST_FLOORS_FLAG = "channel-trust-floors" as const;
|
|
124
|
+
|
|
103
125
|
const DISK_PRESSURE_REMOTE_BLOCK_REPLY =
|
|
104
126
|
"Storage is critically low, so remote messages are ignored until the guardian frees enough space. Please try again later.";
|
|
105
127
|
|
|
@@ -383,6 +405,57 @@ export async function handleChannelInbound({
|
|
|
383
405
|
});
|
|
384
406
|
if (guardianActivationResponse) return guardianActivationResponse;
|
|
385
407
|
|
|
408
|
+
// ── Slack reaction handling ──
|
|
409
|
+
// Reactions are passive channel signals — not messages, and not access
|
|
410
|
+
// attempts. Dispatch them to a dedicated interceptor BEFORE the message
|
|
411
|
+
// pipeline (ACL, admission floor, disk-pressure, conversation binding) so a
|
|
412
|
+
// 👍 never triggers a verification handshake or an access-request
|
|
413
|
+
// notification, and a stranger's reaction creates no conversation/binding.
|
|
414
|
+
// The interceptor drops strangers, records known contacts' reactions as
|
|
415
|
+
// transcript signals, and routes a guardian's reaction on an approval card
|
|
416
|
+
// through the canonical guardian decision pipeline. Reactions never drive an
|
|
417
|
+
// agent turn.
|
|
418
|
+
if (isSlackReactionEvent(body)) {
|
|
419
|
+
return handleSlackReactionIntercept({
|
|
420
|
+
callbackData: body.callbackData!,
|
|
421
|
+
sourceChannel,
|
|
422
|
+
sourceInterface,
|
|
423
|
+
conversationExternalId,
|
|
424
|
+
externalMessageId,
|
|
425
|
+
canonicalAssistantId,
|
|
426
|
+
rawSenderId,
|
|
427
|
+
canonicalSenderId,
|
|
428
|
+
actorDisplayName: body.actorDisplayName,
|
|
429
|
+
actorUsername: body.actorUsername,
|
|
430
|
+
replyCallbackUrl: body.replyCallbackUrl,
|
|
431
|
+
sourceMetadata: body.sourceMetadata,
|
|
432
|
+
slackChannelName,
|
|
433
|
+
approvalConversationGenerator,
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// ── Admission policy pre-computation ──
|
|
438
|
+
// Resolve the effective policy before ACL so it can skip its hard-deny
|
|
439
|
+
// paths for permissive policies (`strangers`, `any_contact`). The same
|
|
440
|
+
// value is reused by the floor stage below, which is gated on
|
|
441
|
+
// `channel-trust-floors`.
|
|
442
|
+
const channelTrustFloorsEnabled = isAssistantFeatureFlagEnabled(
|
|
443
|
+
CHANNEL_TRUST_FLOORS_FLAG,
|
|
444
|
+
getConfig(),
|
|
445
|
+
);
|
|
446
|
+
const admissionPolicyFromGateway = isAdmissionPolicy(
|
|
447
|
+
sourceMetadata?.admissionPolicy,
|
|
448
|
+
)
|
|
449
|
+
? (sourceMetadata!.admissionPolicy as AdmissionPolicy)
|
|
450
|
+
: ADMISSION_POLICY_DEFAULT;
|
|
451
|
+
// Pass `undefined` to the ACL when the feature is off so it takes none of
|
|
452
|
+
// its policy-aware bypasses (the floor stage is skipped too). This keeps the
|
|
453
|
+
// flag-off path on the pre-feature ACL behavior and prevents a bypass from
|
|
454
|
+
// routing to a disabled floor stage and admitting unconditionally.
|
|
455
|
+
const effectiveAdmissionPolicyForAcl = channelTrustFloorsEnabled
|
|
456
|
+
? admissionPolicyFromGateway
|
|
457
|
+
: undefined;
|
|
458
|
+
|
|
386
459
|
// ── Ingress ACL enforcement ──
|
|
387
460
|
const aclResult = await enforceIngressAcl({
|
|
388
461
|
canonicalSenderId,
|
|
@@ -398,6 +471,7 @@ export async function handleChannelInbound({
|
|
|
398
471
|
replyCallbackUrl: body.replyCallbackUrl,
|
|
399
472
|
assistantId,
|
|
400
473
|
externalMessageId,
|
|
474
|
+
effectiveAdmissionPolicy: effectiveAdmissionPolicyForAcl,
|
|
401
475
|
});
|
|
402
476
|
if (aclResult.earlyResponse) return aclResult.earlyResponse;
|
|
403
477
|
const { resolvedMember } = aclResult;
|
|
@@ -657,6 +731,144 @@ export async function handleChannelInbound({
|
|
|
657
731
|
slackActorTimezone,
|
|
658
732
|
);
|
|
659
733
|
|
|
734
|
+
// ── Admission policy floor ──
|
|
735
|
+
// Sits between trust resolution and the agent loop. The gateway attaches
|
|
736
|
+
// the per-channel-type floor (`sourceMetadata.admissionPolicy`); the
|
|
737
|
+
// runtime evaluates `trustClass ≥ floor`. Denials reuse the same
|
|
738
|
+
// canned-reply / guardian-notify side effects as `not_a_member` (no
|
|
739
|
+
// re-verification challenge — §8.2). The gateway kill switch already
|
|
740
|
+
// dropped `no_one` upstream, but the stage handles it defensively.
|
|
741
|
+
//
|
|
742
|
+
// Internal channels (`vellum`, `platform`, `a2a`) short-circuit admit
|
|
743
|
+
// inside `enforceAdmissionPolicy` — defense in depth alongside the
|
|
744
|
+
// gateway's exempt-channel skip and the PUT-handler's 403.
|
|
745
|
+
//
|
|
746
|
+
// Bootstrap deep-link: when ACL flagged a validated pending_bootstrap
|
|
747
|
+
// session, skip the floor entirely. The bootstrap intercept stage below
|
|
748
|
+
// handles identity binding and emits its own reply; the sender has not
|
|
749
|
+
// yet acquired a trust class and should not be denied here.
|
|
750
|
+
// Gated by `channel-trust-floors`: when off, skip the floor entirely (admit)
|
|
751
|
+
// so inbound falls back to ACL-only behavior. The gateway also omits the
|
|
752
|
+
// floor when off, so the ACL above already saw the default permissive policy.
|
|
753
|
+
const admissionResult =
|
|
754
|
+
!channelTrustFloorsEnabled || aclResult.isValidatedBootstrap
|
|
755
|
+
? ({ admitted: true } as const)
|
|
756
|
+
: enforceAdmissionPolicy({
|
|
757
|
+
sourceChannel,
|
|
758
|
+
trustClass: trustCtx.trustClass,
|
|
759
|
+
memberStatus: resolvedMember?.channel.status,
|
|
760
|
+
policy: admissionPolicyFromGateway,
|
|
761
|
+
});
|
|
762
|
+
if (!admissionResult.admitted) {
|
|
763
|
+
log.info(
|
|
764
|
+
{
|
|
765
|
+
sourceChannel,
|
|
766
|
+
conversationExternalId,
|
|
767
|
+
eventId: result.eventId,
|
|
768
|
+
trustClass: trustCtx.trustClass,
|
|
769
|
+
reason: admissionResult.reason,
|
|
770
|
+
effectivePolicy: admissionResult.effectivePolicy,
|
|
771
|
+
shouldChallenge: admissionResult.shouldChallenge,
|
|
772
|
+
},
|
|
773
|
+
"Inbound admission policy floor denied",
|
|
774
|
+
);
|
|
775
|
+
|
|
776
|
+
// §8.2 + webhook idempotency: skip guardian-notify + reply side
|
|
777
|
+
// effects on duplicate deliveries (matches the disk-pressure branch
|
|
778
|
+
// below at line ~810). Without this guard, a webhook retry of the
|
|
779
|
+
// same duplicated event that hit the floor re-fires the access
|
|
780
|
+
// request notification and the canned denial reply — visible to the
|
|
781
|
+
// guardian/sender without a re-evaluation.
|
|
782
|
+
if (result.duplicate) {
|
|
783
|
+
return {
|
|
784
|
+
accepted: true,
|
|
785
|
+
duplicate: result.duplicate,
|
|
786
|
+
eventId: result.eventId,
|
|
787
|
+
denied: true,
|
|
788
|
+
reason: admissionResult.reason,
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
// Notify the guardian about the access attempt — same surface as
|
|
793
|
+
// `acl-enforcement.ts:267-449` for `not_a_member`, so denials are
|
|
794
|
+
// visible in the same UI. previousMemberStatus is only meaningful when
|
|
795
|
+
// a member record exists; we pass it through when available so the
|
|
796
|
+
// guardian sees "previously pending" etc.
|
|
797
|
+
let guardianNotified = false;
|
|
798
|
+
try {
|
|
799
|
+
const accessResult = notifyGuardianOfAccessRequest({
|
|
800
|
+
canonicalAssistantId,
|
|
801
|
+
sourceChannel,
|
|
802
|
+
conversationExternalId,
|
|
803
|
+
actorExternalId: canonicalSenderId ?? rawSenderId,
|
|
804
|
+
actorDisplayName: body.actorDisplayName,
|
|
805
|
+
actorUsername: body.actorUsername,
|
|
806
|
+
...(resolvedMember
|
|
807
|
+
? {
|
|
808
|
+
previousMemberStatus: channelStatusToMemberStatus(
|
|
809
|
+
resolvedMember.channel.status,
|
|
810
|
+
),
|
|
811
|
+
}
|
|
812
|
+
: {}),
|
|
813
|
+
messagePreview: truncate(trimmedContent, MESSAGE_PREVIEW_MAX_LENGTH),
|
|
814
|
+
...(typeof sourceMetadata?.isStranger === "boolean"
|
|
815
|
+
? { isStranger: sourceMetadata.isStranger }
|
|
816
|
+
: {}),
|
|
817
|
+
...(typeof sourceMetadata?.isRestricted === "boolean"
|
|
818
|
+
? { isRestricted: sourceMetadata.isRestricted }
|
|
819
|
+
: {}),
|
|
820
|
+
...(typeof sourceMetadata?.messageId === "string"
|
|
821
|
+
? { messageTs: sourceMetadata.messageId }
|
|
822
|
+
: {}),
|
|
823
|
+
});
|
|
824
|
+
guardianNotified = accessResult.notified;
|
|
825
|
+
} catch (err) {
|
|
826
|
+
log.error(
|
|
827
|
+
{ err, sourceChannel, conversationExternalId },
|
|
828
|
+
"Failed to notify guardian of access request (admission policy)",
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
// Canned reply mirrors the not_a_member surface. §8.2: no upgrade
|
|
833
|
+
// challenge text for `trusted_contacts` / `guardian_only` denials —
|
|
834
|
+
// sender gets the standard "ask the guardian" copy.
|
|
835
|
+
const replyText = guardianNotified
|
|
836
|
+
? "Hmm looks like you don't have access to talk to me. I'll let your guardian know you tried."
|
|
837
|
+
: "Sorry, you haven't been approved to message this assistant.";
|
|
838
|
+
let replyDelivered = false;
|
|
839
|
+
if (replyCallbackUrl) {
|
|
840
|
+
const replyPayload: Parameters<typeof deliverChannelReply>[1] = {
|
|
841
|
+
chatId: conversationExternalId,
|
|
842
|
+
text: replyText,
|
|
843
|
+
assistantId: canonicalAssistantId,
|
|
844
|
+
};
|
|
845
|
+
if (sourceChannel === "slack" && (canonicalSenderId ?? rawSenderId)) {
|
|
846
|
+
replyPayload.ephemeral = true;
|
|
847
|
+
replyPayload.user = (canonicalSenderId ?? rawSenderId)!;
|
|
848
|
+
}
|
|
849
|
+
try {
|
|
850
|
+
await deliverChannelReply(replyCallbackUrl, replyPayload);
|
|
851
|
+
replyDelivered = true;
|
|
852
|
+
} catch (err) {
|
|
853
|
+
log.error(
|
|
854
|
+
{ err, conversationExternalId },
|
|
855
|
+
"Failed to deliver admission policy denial reply",
|
|
856
|
+
);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
if (!result.duplicate) markProcessed(result.eventId);
|
|
861
|
+
|
|
862
|
+
return {
|
|
863
|
+
accepted: true,
|
|
864
|
+
duplicate: result.duplicate,
|
|
865
|
+
eventId: result.eventId,
|
|
866
|
+
denied: true,
|
|
867
|
+
reason: admissionResult.reason,
|
|
868
|
+
...(!replyDelivered && { replyText }),
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
|
|
660
872
|
const diskPressureDecision = classifyDiskPressureTurnPolicy(
|
|
661
873
|
getDiskPressureStatus(),
|
|
662
874
|
{
|
|
@@ -717,121 +929,6 @@ export async function handleChannelInbound({
|
|
|
717
929
|
};
|
|
718
930
|
}
|
|
719
931
|
|
|
720
|
-
// ── Slack reaction handling ──
|
|
721
|
-
// Reactions arrive as regular `SlackInboundEvent`s with `callbackData`
|
|
722
|
-
// prefixed `reaction:` (added) or `reaction_removed:` (removed).
|
|
723
|
-
//
|
|
724
|
-
// Two paths from here:
|
|
725
|
-
// 1. Guardian approval-by-reaction. A `reaction:` (added) event from
|
|
726
|
-
// the guardian on an active approval prompt is consumed by
|
|
727
|
-
// `handleApprovalInterception` to apply the decision. In that case
|
|
728
|
-
// we do NOT persist the reaction as a transcript line — resolved
|
|
729
|
-
// guardian approval reactions have no transcript representation.
|
|
730
|
-
// 2. All other reactions (non-guardian, no pending approval, stale,
|
|
731
|
-
// and any `reaction_removed:` event regardless of actor) fall
|
|
732
|
-
// through to `persistSlackReactionAsMessage` so Slack transcript
|
|
733
|
-
// rendering can surface them inline. Reactions never trigger an
|
|
734
|
-
// agent response, so we short-circuit before escalation and
|
|
735
|
-
// agent-loop dispatch in both cases.
|
|
736
|
-
if (isSlackReactionEvent(body)) {
|
|
737
|
-
// Approval interception runs only for reactions (added) — `reaction_removed`
|
|
738
|
-
// never expresses an approval intent, so un-reacting is left as a pure
|
|
739
|
-
// transcript signal. Gated by the same `replyCallbackUrl && !duplicate`
|
|
740
|
-
// preconditions used by the standard approval interception call below.
|
|
741
|
-
const isReactionAdded = body.callbackData?.startsWith("reaction:") === true;
|
|
742
|
-
if (isReactionAdded && replyCallbackUrl && !result.duplicate) {
|
|
743
|
-
const trustCtxForReaction: TrustContext = attachSlackRequesterTimezone(
|
|
744
|
-
resolveTrustContext({
|
|
745
|
-
assistantId: canonicalAssistantId,
|
|
746
|
-
sourceChannel,
|
|
747
|
-
conversationExternalId,
|
|
748
|
-
actorExternalId: rawSenderId,
|
|
749
|
-
actorUsername: body.actorUsername,
|
|
750
|
-
actorDisplayName: body.actorDisplayName,
|
|
751
|
-
}),
|
|
752
|
-
slackActorTimezone,
|
|
753
|
-
);
|
|
754
|
-
|
|
755
|
-
const approvalMessageTs =
|
|
756
|
-
typeof sourceMetadata?.messageId === "string"
|
|
757
|
-
? sourceMetadata.messageId
|
|
758
|
-
: undefined;
|
|
759
|
-
|
|
760
|
-
const reactionApprovalResult = await handleApprovalInterception({
|
|
761
|
-
conversationId: result.conversationId,
|
|
762
|
-
callbackData: body.callbackData,
|
|
763
|
-
content: trimmedContent,
|
|
764
|
-
conversationExternalId,
|
|
765
|
-
sourceChannel,
|
|
766
|
-
actorExternalId: canonicalSenderId ?? rawSenderId,
|
|
767
|
-
replyCallbackUrl,
|
|
768
|
-
trustCtx: trustCtxForReaction,
|
|
769
|
-
assistantId: canonicalAssistantId,
|
|
770
|
-
approvalCopyGenerator,
|
|
771
|
-
approvalConversationGenerator,
|
|
772
|
-
approvalMessageTs,
|
|
773
|
-
});
|
|
774
|
-
|
|
775
|
-
// A real guardian decision was applied — short-circuit and skip the
|
|
776
|
-
// reaction-persistence path so we do not double-record it as a
|
|
777
|
-
// transcript line. All other interception outcomes (stale_ignored,
|
|
778
|
-
// non-guardian, no pending approval) fall through to persistence.
|
|
779
|
-
if (reactionApprovalResult.type === "guardian_decision_applied") {
|
|
780
|
-
return {
|
|
781
|
-
accepted: true,
|
|
782
|
-
duplicate: false,
|
|
783
|
-
eventId: result.eventId,
|
|
784
|
-
approval: reactionApprovalResult.type,
|
|
785
|
-
};
|
|
786
|
-
}
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
const reactedMessageTs =
|
|
790
|
-
typeof sourceMetadata?.messageId === "string"
|
|
791
|
-
? sourceMetadata.messageId
|
|
792
|
-
: undefined;
|
|
793
|
-
if (!reactedMessageTs) {
|
|
794
|
-
log.debug(
|
|
795
|
-
{ conversationId: result.conversationId, eventId: result.eventId },
|
|
796
|
-
"Skipping reaction persistence: missing sourceMetadata.messageId",
|
|
797
|
-
);
|
|
798
|
-
return {
|
|
799
|
-
accepted: result.accepted,
|
|
800
|
-
duplicate: result.duplicate,
|
|
801
|
-
eventId: result.eventId,
|
|
802
|
-
};
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
const threadTs =
|
|
806
|
-
typeof sourceMetadata?.threadId === "string"
|
|
807
|
-
? sourceMetadata.threadId
|
|
808
|
-
: undefined;
|
|
809
|
-
|
|
810
|
-
try {
|
|
811
|
-
await persistSlackReactionAsMessage({
|
|
812
|
-
conversationId: result.conversationId,
|
|
813
|
-
conversationExternalId,
|
|
814
|
-
eventId: result.eventId,
|
|
815
|
-
callbackData: body.callbackData!,
|
|
816
|
-
actorDisplayName: body.actorDisplayName,
|
|
817
|
-
threadTs,
|
|
818
|
-
reactedMessageTs,
|
|
819
|
-
duplicate: result.duplicate,
|
|
820
|
-
});
|
|
821
|
-
} catch (err) {
|
|
822
|
-
log.error(
|
|
823
|
-
{ err, conversationId: result.conversationId, eventId: result.eventId },
|
|
824
|
-
"Failed to persist Slack reaction event",
|
|
825
|
-
);
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
return {
|
|
829
|
-
accepted: result.accepted,
|
|
830
|
-
duplicate: result.duplicate,
|
|
831
|
-
eventId: result.eventId,
|
|
832
|
-
};
|
|
833
|
-
}
|
|
834
|
-
|
|
835
932
|
// ── Ingress escalation ──
|
|
836
933
|
const escalationResponse = handleEscalationIntercept({
|
|
837
934
|
resolvedMember,
|
|
@@ -1294,117 +1391,6 @@ export async function handleChannelInbound({
|
|
|
1294
1391
|
};
|
|
1295
1392
|
}
|
|
1296
1393
|
|
|
1297
|
-
/**
|
|
1298
|
-
* Detect a Slack reaction event by inspecting the inbound payload's
|
|
1299
|
-
* `callbackData` prefix. The gateway encodes reactions as a unified
|
|
1300
|
-
* `SlackInboundEvent` with `callbackData` of the form
|
|
1301
|
-
* `reaction:<emoji>` (added) or `reaction_removed:<emoji>` (removed) —
|
|
1302
|
-
* see `gateway/src/slack/normalize.ts`. This helper centralizes that
|
|
1303
|
-
* convention so the daemon can route reactions to a dedicated persistence
|
|
1304
|
-
* branch instead of the agent-response pipeline.
|
|
1305
|
-
*/
|
|
1306
|
-
export function isSlackReactionEvent(body: {
|
|
1307
|
-
sourceChannel?: string;
|
|
1308
|
-
callbackData?: string;
|
|
1309
|
-
}): boolean {
|
|
1310
|
-
if (body.sourceChannel !== "slack") return false;
|
|
1311
|
-
const cb = body.callbackData;
|
|
1312
|
-
if (typeof cb !== "string") return false;
|
|
1313
|
-
return cb.startsWith("reaction:") || cb.startsWith("reaction_removed:");
|
|
1314
|
-
}
|
|
1315
|
-
|
|
1316
|
-
/**
|
|
1317
|
-
* Parse a reaction `callbackData` string into its op (added/removed) and
|
|
1318
|
-
* emoji name. Returns `null` when the input is not a reaction prefix or
|
|
1319
|
-
* when the emoji portion is empty.
|
|
1320
|
-
*/
|
|
1321
|
-
export function parseSlackReactionCallbackData(
|
|
1322
|
-
callbackData: string,
|
|
1323
|
-
): { op: "added" | "removed"; emoji: string } | null {
|
|
1324
|
-
let op: "added" | "removed";
|
|
1325
|
-
let emoji: string;
|
|
1326
|
-
if (callbackData.startsWith("reaction_removed:")) {
|
|
1327
|
-
op = "removed";
|
|
1328
|
-
emoji = callbackData.slice("reaction_removed:".length);
|
|
1329
|
-
} else if (callbackData.startsWith("reaction:")) {
|
|
1330
|
-
op = "added";
|
|
1331
|
-
emoji = callbackData.slice("reaction:".length);
|
|
1332
|
-
} else {
|
|
1333
|
-
return null;
|
|
1334
|
-
}
|
|
1335
|
-
if (emoji.length === 0) return null;
|
|
1336
|
-
return { op, emoji };
|
|
1337
|
-
}
|
|
1338
|
-
|
|
1339
|
-
/**
|
|
1340
|
-
* Persist a Slack reaction event as a `messages` row with `slackMeta`
|
|
1341
|
-
* envelope so the renderer can surface it inline in the chronological
|
|
1342
|
-
* transcript. Reactions do not trigger an agent response — the row is
|
|
1343
|
-
* written and the inbound event is linked, but the agent loop is not
|
|
1344
|
-
* dispatched.
|
|
1345
|
-
*
|
|
1346
|
-
* The caller is expected to have run `recordInbound` already so that
|
|
1347
|
-
* deduplication and conversation resolution have happened. Duplicate
|
|
1348
|
-
* inbound events are skipped here to keep persistence idempotent.
|
|
1349
|
-
*/
|
|
1350
|
-
async function persistSlackReactionAsMessage(params: {
|
|
1351
|
-
conversationId: string;
|
|
1352
|
-
conversationExternalId: string;
|
|
1353
|
-
eventId: string;
|
|
1354
|
-
callbackData: string;
|
|
1355
|
-
actorDisplayName?: string;
|
|
1356
|
-
threadTs?: string;
|
|
1357
|
-
reactedMessageTs: string;
|
|
1358
|
-
duplicate: boolean;
|
|
1359
|
-
}): Promise<void> {
|
|
1360
|
-
if (params.duplicate) return;
|
|
1361
|
-
|
|
1362
|
-
const parsed = parseSlackReactionCallbackData(params.callbackData);
|
|
1363
|
-
if (!parsed) {
|
|
1364
|
-
log.debug(
|
|
1365
|
-
{
|
|
1366
|
-
conversationId: params.conversationId,
|
|
1367
|
-
callbackData: params.callbackData,
|
|
1368
|
-
},
|
|
1369
|
-
"Skipping reaction persistence: unparseable callbackData",
|
|
1370
|
-
);
|
|
1371
|
-
return;
|
|
1372
|
-
}
|
|
1373
|
-
|
|
1374
|
-
const slackMeta: SlackMessageMetadata = {
|
|
1375
|
-
source: "slack",
|
|
1376
|
-
channelId: params.conversationExternalId,
|
|
1377
|
-
channelTs: params.reactedMessageTs,
|
|
1378
|
-
eventKind: "reaction",
|
|
1379
|
-
...(params.threadTs ? { threadTs: params.threadTs } : {}),
|
|
1380
|
-
...(params.actorDisplayName
|
|
1381
|
-
? { displayName: params.actorDisplayName }
|
|
1382
|
-
: {}),
|
|
1383
|
-
reaction: {
|
|
1384
|
-
emoji: parsed.emoji,
|
|
1385
|
-
targetChannelTs: params.reactedMessageTs,
|
|
1386
|
-
op: parsed.op,
|
|
1387
|
-
...(params.actorDisplayName
|
|
1388
|
-
? { actorDisplayName: params.actorDisplayName }
|
|
1389
|
-
: {}),
|
|
1390
|
-
},
|
|
1391
|
-
};
|
|
1392
|
-
|
|
1393
|
-
// Sentinel content — Slack transcript renderers read `slackMeta` to format
|
|
1394
|
-
// the reaction line; the literal text is never displayed to the model.
|
|
1395
|
-
const persisted = await addMessage(
|
|
1396
|
-
params.conversationId,
|
|
1397
|
-
"user",
|
|
1398
|
-
"[reaction]",
|
|
1399
|
-
{
|
|
1400
|
-
metadata: { slackMeta: writeSlackMetadata(slackMeta) },
|
|
1401
|
-
skipIndexing: true,
|
|
1402
|
-
},
|
|
1403
|
-
);
|
|
1404
|
-
linkMessage(params.eventId, persisted.id);
|
|
1405
|
-
markProcessed(params.eventId);
|
|
1406
|
-
}
|
|
1407
|
-
|
|
1408
1394
|
/**
|
|
1409
1395
|
* Threshold of stored Slack-tagged messages below which a conversation is
|
|
1410
1396
|
* considered "cold" and eligible for one-shot backfill. The number is
|