@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
|
@@ -55,6 +55,87 @@ function shouldUseEphemeral(sourceChannel: string, chatId: string): boolean {
|
|
|
55
55
|
return sourceChannel === "slack" && chatId.startsWith("C");
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Deliver the verification code straight to the requester's Slack DM so the
|
|
60
|
+
* guardian is never an out-of-band courier for the secret.
|
|
61
|
+
*
|
|
62
|
+
* Slack is the only channel with a guaranteed private path to the requester:
|
|
63
|
+
* posting to their user ID (`U…`) opens a 1:1 DM. The `threadTs` query param is
|
|
64
|
+
* dropped because it points at the guardian's channel thread and would raise
|
|
65
|
+
* `thread_not_found` in the DM. The code is sent as a durable (non-ephemeral)
|
|
66
|
+
* message the requester can refer back to when verifying.
|
|
67
|
+
*
|
|
68
|
+
* The verification session is identity-bound to the requester, so delivering
|
|
69
|
+
* the code to them directly does not widen who can consume it — it only removes
|
|
70
|
+
* the guardian relay step.
|
|
71
|
+
*
|
|
72
|
+
* Returns whether the code was delivered.
|
|
73
|
+
*/
|
|
74
|
+
async function deliverVerificationCodeToSlackRequester(params: {
|
|
75
|
+
replyCallbackUrl: string;
|
|
76
|
+
requesterExternalUserId: string;
|
|
77
|
+
verificationCode: string;
|
|
78
|
+
assistantId: string;
|
|
79
|
+
}): Promise<boolean> {
|
|
80
|
+
let callbackUrl = params.replyCallbackUrl;
|
|
81
|
+
try {
|
|
82
|
+
const url = new URL(params.replyCallbackUrl);
|
|
83
|
+
url.searchParams.delete("threadTs");
|
|
84
|
+
callbackUrl = url.toString();
|
|
85
|
+
} catch {
|
|
86
|
+
// Relative path (e.g. the desktop "/deliver/slack" target) — use as-is;
|
|
87
|
+
// it carries no threadTs to strip.
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
await deliverChannelReply(callbackUrl, {
|
|
92
|
+
chatId: params.requesterExternalUserId,
|
|
93
|
+
text:
|
|
94
|
+
"Great news — your access request was approved! " +
|
|
95
|
+
`Your verification code is: \`${params.verificationCode}\`. ` +
|
|
96
|
+
"Reply with it here to complete verification. The code expires in 10 minutes.",
|
|
97
|
+
assistantId: params.assistantId,
|
|
98
|
+
});
|
|
99
|
+
return true;
|
|
100
|
+
} catch (err) {
|
|
101
|
+
log.error(
|
|
102
|
+
{ err, requesterExternalUserId: params.requesterExternalUserId },
|
|
103
|
+
"Failed to auto-deliver verification code to Slack requester",
|
|
104
|
+
);
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Build a requester-facing channel notice (approval/denial/courier text).
|
|
111
|
+
*
|
|
112
|
+
* Posts to the originating chat. On a Slack shared channel it goes out as an
|
|
113
|
+
* ephemeral message visible only to the requester — and because
|
|
114
|
+
* `chat.postEphemeral` needs a channel ID, `chatId` stays the channel
|
|
115
|
+
* (`requesterChatId`), never the requester's `U…` user ID.
|
|
116
|
+
*/
|
|
117
|
+
function buildRequesterChannelNotice(params: {
|
|
118
|
+
channel: string;
|
|
119
|
+
requesterChatId: string;
|
|
120
|
+
requesterExternalUserId: string;
|
|
121
|
+
text: string;
|
|
122
|
+
assistantId: string;
|
|
123
|
+
}): Parameters<typeof deliverChannelReply>[1] {
|
|
124
|
+
const payload: Parameters<typeof deliverChannelReply>[1] = {
|
|
125
|
+
chatId: params.requesterChatId,
|
|
126
|
+
text: params.text,
|
|
127
|
+
assistantId: params.assistantId,
|
|
128
|
+
};
|
|
129
|
+
if (
|
|
130
|
+
shouldUseEphemeral(params.channel, params.requesterChatId) &&
|
|
131
|
+
params.requesterExternalUserId
|
|
132
|
+
) {
|
|
133
|
+
payload.ephemeral = true;
|
|
134
|
+
payload.user = params.requesterExternalUserId;
|
|
135
|
+
}
|
|
136
|
+
return payload;
|
|
137
|
+
}
|
|
138
|
+
|
|
58
139
|
// ---------------------------------------------------------------------------
|
|
59
140
|
// Types
|
|
60
141
|
// ---------------------------------------------------------------------------
|
|
@@ -363,8 +444,6 @@ const accessRequestResolver: GuardianRequestResolver = {
|
|
|
363
444
|
const requesterExternalUserId = request.requesterExternalUserId ?? "";
|
|
364
445
|
const requesterChatId =
|
|
365
446
|
request.requesterChatId ?? request.requesterExternalUserId ?? "";
|
|
366
|
-
const requesterLabel =
|
|
367
|
-
requesterExternalUserId || requesterChatId || "the requester";
|
|
368
447
|
const decidedByExternalUserId = ctx.actor.actorExternalUserId ?? "";
|
|
369
448
|
const assistantId = DAEMON_INTERNAL_ASSISTANT_ID;
|
|
370
449
|
const desktopDeliverUrl = resolveDeliverCallbackUrlForChannel(channel);
|
|
@@ -373,16 +452,23 @@ const accessRequestResolver: GuardianRequestResolver = {
|
|
|
373
452
|
const requesterContactResult = requesterExternalUserId
|
|
374
453
|
? findContactChannel({
|
|
375
454
|
channelType: channel,
|
|
376
|
-
|
|
455
|
+
address: requesterExternalUserId,
|
|
377
456
|
})
|
|
378
457
|
: null;
|
|
379
458
|
const requesterDisplayName =
|
|
380
459
|
requesterContactResult?.contact.displayName ?? null;
|
|
381
460
|
|
|
461
|
+
// Guardian-facing label prefers the contact display name over the raw ID.
|
|
462
|
+
const requesterLabel =
|
|
463
|
+
requesterDisplayName ||
|
|
464
|
+
requesterExternalUserId ||
|
|
465
|
+
requesterChatId ||
|
|
466
|
+
"the requester";
|
|
467
|
+
|
|
382
468
|
const decidedByContactResult = decidedByExternalUserId
|
|
383
469
|
? findContactChannel({
|
|
384
470
|
channelType: channel,
|
|
385
|
-
|
|
471
|
+
address: decidedByExternalUserId,
|
|
386
472
|
})
|
|
387
473
|
: null;
|
|
388
474
|
const decidedByDisplayName =
|
|
@@ -397,22 +483,15 @@ const accessRequestResolver: GuardianRequestResolver = {
|
|
|
397
483
|
// Deliver denial notification and lifecycle signals when channel context is available
|
|
398
484
|
if (channelDeliveryContext) {
|
|
399
485
|
try {
|
|
400
|
-
const denialPayload: Parameters<typeof deliverChannelReply>[1] = {
|
|
401
|
-
chatId: requesterChatId,
|
|
402
|
-
text: "Your access request has been denied.",
|
|
403
|
-
assistantId,
|
|
404
|
-
};
|
|
405
|
-
// On Slack shared channels, deliver as ephemeral so only the requester sees the denial
|
|
406
|
-
if (
|
|
407
|
-
shouldUseEphemeral(channel, requesterChatId) &&
|
|
408
|
-
requesterExternalUserId
|
|
409
|
-
) {
|
|
410
|
-
denialPayload.ephemeral = true;
|
|
411
|
-
denialPayload.user = requesterExternalUserId;
|
|
412
|
-
}
|
|
413
486
|
await deliverChannelReply(
|
|
414
487
|
channelDeliveryContext.replyCallbackUrl,
|
|
415
|
-
|
|
488
|
+
buildRequesterChannelNotice({
|
|
489
|
+
channel,
|
|
490
|
+
requesterChatId,
|
|
491
|
+
requesterExternalUserId,
|
|
492
|
+
text: "Your access request has been denied.",
|
|
493
|
+
assistantId,
|
|
494
|
+
}),
|
|
416
495
|
);
|
|
417
496
|
} catch (err) {
|
|
418
497
|
log.error(
|
|
@@ -563,7 +642,7 @@ const accessRequestResolver: GuardianRequestResolver = {
|
|
|
563
642
|
|
|
564
643
|
// Deliver verification code to guardian
|
|
565
644
|
const codeText =
|
|
566
|
-
`You approved access for ${
|
|
645
|
+
`You approved access for ${requesterLabel}. ` +
|
|
567
646
|
`Give them this verification code: \`${session.secret}\`. ` +
|
|
568
647
|
`The code expires in 10 minutes.`;
|
|
569
648
|
try {
|
|
@@ -629,12 +708,8 @@ const accessRequestResolver: GuardianRequestResolver = {
|
|
|
629
708
|
}
|
|
630
709
|
}
|
|
631
710
|
|
|
632
|
-
//
|
|
633
|
-
//
|
|
634
|
-
const requesterTargetChatId =
|
|
635
|
-
channel === "slack" && requesterExternalUserId
|
|
636
|
-
? requesterExternalUserId
|
|
637
|
-
: requesterChatId;
|
|
711
|
+
// Strip threadTs from the requester reply URL — it belongs to the
|
|
712
|
+
// guardian's channel thread and would cause thread_not_found in a DM.
|
|
638
713
|
let requesterCallbackUrl = channelDeliveryContext.replyCallbackUrl;
|
|
639
714
|
if (channel === "slack" && requesterExternalUserId) {
|
|
640
715
|
try {
|
|
@@ -647,47 +722,58 @@ const accessRequestResolver: GuardianRequestResolver = {
|
|
|
647
722
|
}
|
|
648
723
|
|
|
649
724
|
if (codeDelivered) {
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
}
|
|
666
|
-
await deliverChannelReply(requesterCallbackUrl, approvalPayload);
|
|
725
|
+
// On Slack, deliver the code straight to the requester's DM so the
|
|
726
|
+
// guardian doesn't have to relay it. Other channels (and a failed Slack
|
|
727
|
+
// delivery) fall back to the courier notice — there is no guaranteed
|
|
728
|
+
// private path to the requester elsewhere (e.g. group chats).
|
|
729
|
+
const requesterCodeDelivered =
|
|
730
|
+
channel === "slack" && requesterExternalUserId
|
|
731
|
+
? await deliverVerificationCodeToSlackRequester({
|
|
732
|
+
replyCallbackUrl: channelDeliveryContext.replyCallbackUrl,
|
|
733
|
+
requesterExternalUserId,
|
|
734
|
+
verificationCode: session.secret,
|
|
735
|
+
assistantId,
|
|
736
|
+
})
|
|
737
|
+
: false;
|
|
738
|
+
|
|
739
|
+
if (requesterCodeDelivered) {
|
|
667
740
|
requesterNotified = true;
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
741
|
+
} else {
|
|
742
|
+
try {
|
|
743
|
+
await deliverChannelReply(
|
|
744
|
+
requesterCallbackUrl,
|
|
745
|
+
buildRequesterChannelNotice({
|
|
746
|
+
channel,
|
|
747
|
+
requesterChatId,
|
|
748
|
+
requesterExternalUserId,
|
|
749
|
+
text:
|
|
750
|
+
"Your access request has been approved! " +
|
|
751
|
+
"Please enter the 6-digit verification code you receive from the guardian.",
|
|
752
|
+
assistantId,
|
|
753
|
+
}),
|
|
754
|
+
);
|
|
755
|
+
requesterNotified = true;
|
|
756
|
+
} catch (err) {
|
|
757
|
+
log.error(
|
|
758
|
+
{ err, requesterChatId },
|
|
759
|
+
"Failed to notify requester of access request approval",
|
|
760
|
+
);
|
|
761
|
+
}
|
|
673
762
|
}
|
|
674
763
|
} else {
|
|
675
764
|
try {
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
failurePayload.user = requesterExternalUserId;
|
|
689
|
-
}
|
|
690
|
-
await deliverChannelReply(requesterCallbackUrl, failurePayload);
|
|
765
|
+
await deliverChannelReply(
|
|
766
|
+
requesterCallbackUrl,
|
|
767
|
+
buildRequesterChannelNotice({
|
|
768
|
+
channel,
|
|
769
|
+
requesterChatId,
|
|
770
|
+
requesterExternalUserId,
|
|
771
|
+
text:
|
|
772
|
+
"Your access request was approved, but we were unable to " +
|
|
773
|
+
"deliver the verification code. Please try again later.",
|
|
774
|
+
assistantId,
|
|
775
|
+
}),
|
|
776
|
+
);
|
|
691
777
|
} catch (err) {
|
|
692
778
|
log.error(
|
|
693
779
|
{ err, requesterChatId },
|
|
@@ -721,26 +807,43 @@ const accessRequestResolver: GuardianRequestResolver = {
|
|
|
721
807
|
});
|
|
722
808
|
}
|
|
723
809
|
} else if (desktopDeliverUrl && requesterChatId) {
|
|
724
|
-
//
|
|
725
|
-
//
|
|
726
|
-
|
|
810
|
+
// Guardian decided off-channel (e.g. desktop) but the requester is on a
|
|
811
|
+
// deliverable channel. On Slack, DM the code directly (parity with the
|
|
812
|
+
// on-channel path); otherwise fall back to the courier notice.
|
|
813
|
+
const requesterCodeDelivered =
|
|
727
814
|
channel === "slack" && requesterExternalUserId
|
|
728
|
-
?
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
});
|
|
815
|
+
? await deliverVerificationCodeToSlackRequester({
|
|
816
|
+
replyCallbackUrl: desktopDeliverUrl,
|
|
817
|
+
requesterExternalUserId,
|
|
818
|
+
verificationCode: session.secret,
|
|
819
|
+
assistantId,
|
|
820
|
+
})
|
|
821
|
+
: false;
|
|
822
|
+
|
|
823
|
+
if (requesterCodeDelivered) {
|
|
738
824
|
requesterNotified = true;
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
825
|
+
} else {
|
|
826
|
+
// For Slack, route to DM via requesterExternalUserId (user ID) instead
|
|
827
|
+
// of requesterChatId (channel ID) to avoid posting in public channels.
|
|
828
|
+
const targetChatId =
|
|
829
|
+
channel === "slack" && requesterExternalUserId
|
|
830
|
+
? requesterExternalUserId
|
|
831
|
+
: requesterChatId;
|
|
832
|
+
try {
|
|
833
|
+
await deliverChannelReply(desktopDeliverUrl, {
|
|
834
|
+
chatId: targetChatId,
|
|
835
|
+
text:
|
|
836
|
+
"Your access request has been approved! " +
|
|
837
|
+
"Please enter the 6-digit verification code you receive from the guardian.",
|
|
838
|
+
assistantId,
|
|
839
|
+
});
|
|
840
|
+
requesterNotified = true;
|
|
841
|
+
} catch (err) {
|
|
842
|
+
log.error(
|
|
843
|
+
{ err, requesterChatId },
|
|
844
|
+
"Failed to notify requester of access request approval (desktop decision path)",
|
|
845
|
+
);
|
|
846
|
+
}
|
|
744
847
|
}
|
|
745
848
|
}
|
|
746
849
|
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the gateway-backed channel admission policy reader.
|
|
3
|
+
*
|
|
4
|
+
* The reader fails open (returns null = admit) so a gateway IPC failure can
|
|
5
|
+
* never block a live call. These tests pin that contract plus the TTL cache.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
9
|
+
|
|
10
|
+
// ── Controllable IPC mock ────────────────────────────────────────────────────
|
|
11
|
+
|
|
12
|
+
type IpcHandler = (params?: Record<string, unknown>) => unknown;
|
|
13
|
+
|
|
14
|
+
const ipcHandlers = new Map<string, IpcHandler>();
|
|
15
|
+
const ipcCallLog: Array<{
|
|
16
|
+
method: string;
|
|
17
|
+
params?: Record<string, unknown>;
|
|
18
|
+
timeoutMs?: number;
|
|
19
|
+
}> = [];
|
|
20
|
+
|
|
21
|
+
mock.module("../../ipc/gateway-client.js", () => ({
|
|
22
|
+
ipcCall: async (
|
|
23
|
+
method: string,
|
|
24
|
+
params?: Record<string, unknown>,
|
|
25
|
+
timeoutMs?: number,
|
|
26
|
+
) => {
|
|
27
|
+
ipcCallLog.push({ method, params, timeoutMs });
|
|
28
|
+
const handler = ipcHandlers.get(method);
|
|
29
|
+
return handler ? handler(params) : undefined;
|
|
30
|
+
},
|
|
31
|
+
ipcCallPersistent: async () => undefined,
|
|
32
|
+
resetPersistentClient: () => {},
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
import {
|
|
36
|
+
_clearCacheForTesting,
|
|
37
|
+
getChannelAdmissionPolicy,
|
|
38
|
+
} from "../channel-admission-reader.js";
|
|
39
|
+
|
|
40
|
+
const METHOD = "get_channel_admission_policy";
|
|
41
|
+
|
|
42
|
+
function countCalls(method: string): number {
|
|
43
|
+
return ipcCallLog.filter((c) => c.method === method).length;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
describe("getChannelAdmissionPolicy", () => {
|
|
47
|
+
beforeEach(() => {
|
|
48
|
+
_clearCacheForTesting();
|
|
49
|
+
ipcHandlers.clear();
|
|
50
|
+
ipcCallLog.length = 0;
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("returns the gateway-resolved policy and caches it within the TTL", async () => {
|
|
54
|
+
ipcHandlers.set(METHOD, () => ({ policy: "guardian_only" }));
|
|
55
|
+
|
|
56
|
+
expect(await getChannelAdmissionPolicy("telegram")).toBe("guardian_only");
|
|
57
|
+
// Second call within TTL is served from cache — no extra IPC round-trip.
|
|
58
|
+
expect(await getChannelAdmissionPolicy("telegram")).toBe("guardian_only");
|
|
59
|
+
expect(countCalls(METHOD)).toBe(1);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("bounds the IPC read with a short timeout so it fails open promptly", async () => {
|
|
63
|
+
ipcHandlers.set(METHOD, () => ({ policy: "guardian_only" }));
|
|
64
|
+
|
|
65
|
+
await getChannelAdmissionPolicy("telegram");
|
|
66
|
+
|
|
67
|
+
const call = ipcCallLog.find((c) => c.method === METHOD);
|
|
68
|
+
expect(call?.timeoutMs).toBe(1_000);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("returns null when IPC transport fails (undefined)", async () => {
|
|
72
|
+
ipcHandlers.set(METHOD, () => undefined);
|
|
73
|
+
expect(await getChannelAdmissionPolicy("telegram")).toBeNull();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("returns null when the gateway explicitly resolves no policy", async () => {
|
|
77
|
+
ipcHandlers.set(METHOD, () => ({ policy: null }));
|
|
78
|
+
expect(await getChannelAdmissionPolicy("telegram")).toBeNull();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("returns null when the IPC call throws", async () => {
|
|
82
|
+
ipcHandlers.set(METHOD, () => {
|
|
83
|
+
throw new Error("socket exploded");
|
|
84
|
+
});
|
|
85
|
+
expect(await getChannelAdmissionPolicy("telegram")).toBeNull();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("returns null for an invalid policy string", async () => {
|
|
89
|
+
ipcHandlers.set(METHOD, () => ({ policy: "definitely-not-a-policy" }));
|
|
90
|
+
expect(await getChannelAdmissionPolicy("telegram")).toBeNull();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("caches the explicit no-enforcement (null) answer within the TTL", async () => {
|
|
94
|
+
// The gateway successfully said "no enforcement" — a real, cacheable answer.
|
|
95
|
+
ipcHandlers.set(METHOD, () => ({ policy: null }));
|
|
96
|
+
expect(await getChannelAdmissionPolicy("telegram")).toBeNull();
|
|
97
|
+
expect(await getChannelAdmissionPolicy("telegram")).toBeNull();
|
|
98
|
+
expect(countCalls(METHOD)).toBe(1);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("does NOT cache a transport failure (undefined) — re-consults the gateway", async () => {
|
|
102
|
+
// First setup: gateway hiccup → fail open to null, NOT cached.
|
|
103
|
+
ipcHandlers.set(METHOD, () => undefined);
|
|
104
|
+
expect(await getChannelAdmissionPolicy("telegram")).toBeNull();
|
|
105
|
+
|
|
106
|
+
// Gateway recovers with a restrictive policy: the next setup must re-attempt
|
|
107
|
+
// the IPC (not serve a stale fail-open null) and honor the now-recovered floor.
|
|
108
|
+
ipcHandlers.set(METHOD, () => ({ policy: "guardian_only" }));
|
|
109
|
+
expect(await getChannelAdmissionPolicy("telegram")).toBe("guardian_only");
|
|
110
|
+
expect(countCalls(METHOD)).toBe(2);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test("does NOT cache a thrown IPC error — re-consults the gateway", async () => {
|
|
114
|
+
ipcHandlers.set(METHOD, () => {
|
|
115
|
+
throw new Error("socket exploded");
|
|
116
|
+
});
|
|
117
|
+
expect(await getChannelAdmissionPolicy("telegram")).toBeNull();
|
|
118
|
+
|
|
119
|
+
ipcHandlers.set(METHOD, () => ({ policy: "no_one" }));
|
|
120
|
+
expect(await getChannelAdmissionPolicy("telegram")).toBe("no_one");
|
|
121
|
+
expect(countCalls(METHOD)).toBe(2);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test("does NOT cache a malformed shape — re-consults the gateway", async () => {
|
|
125
|
+
ipcHandlers.set(METHOD, () => ({ policy: "definitely-not-a-policy" }));
|
|
126
|
+
expect(await getChannelAdmissionPolicy("telegram")).toBeNull();
|
|
127
|
+
|
|
128
|
+
ipcHandlers.set(METHOD, () => ({ policy: "guardian_only" }));
|
|
129
|
+
expect(await getChannelAdmissionPolicy("telegram")).toBe("guardian_only");
|
|
130
|
+
expect(countCalls(METHOD)).toBe(2);
|
|
131
|
+
});
|
|
132
|
+
});
|