@vellumai/assistant 0.11.2 → 0.11.3-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 +58 -3
- package/docs/trusted-contact-access.md +9 -5
- package/docs/vellum-doctor.md +195 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/ces-client/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/src/rpc-client.ts +19 -2
- package/node_modules/@vellumai/environments/package.json +2 -1
- package/node_modules/@vellumai/environments/src/__tests__/cloud-assistant-hub-url.test.ts +38 -0
- package/node_modules/@vellumai/environments/src/__tests__/install-layout.test.ts +98 -0
- package/node_modules/@vellumai/environments/src/__tests__/package-boundary.test.ts +5 -5
- package/node_modules/@vellumai/environments/src/index.ts +17 -6
- package/node_modules/@vellumai/environments/src/install-layout.ts +49 -0
- package/node_modules/@vellumai/environments/src/seeds.ts +29 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +4 -0
- package/node_modules/@vellumai/gateway-client/src/verification-session-contract.ts +91 -6
- package/node_modules/@vellumai/ipc-server-utils/src/endpoint.test.ts +36 -0
- package/node_modules/@vellumai/ipc-server-utils/src/endpoint.ts +142 -0
- package/node_modules/@vellumai/ipc-server-utils/src/index.ts +2 -0
- package/node_modules/@vellumai/ipc-server-utils/src/listen-options.ts +3 -0
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +15 -1
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +17 -2
- package/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
- package/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +16 -2
- package/openapi.yaml +589 -30
- package/package.json +1 -1
- package/src/__tests__/agent-image-optimize.test.ts +4 -4
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +113 -66
- package/src/__tests__/agent-loop-override-profile.test.ts +38 -48
- package/src/__tests__/agent-loop-subagent-billing-headers.test.ts +166 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
- package/src/__tests__/answered-question-persistence.test.ts +240 -0
- package/src/__tests__/anthropic-provider.test.ts +165 -30
- package/src/__tests__/app-control-flow.test.ts +9 -8
- package/src/__tests__/assistant-event-hub.test.ts +48 -0
- package/src/__tests__/attachments-store-heic-normalize.test.ts +16 -12
- package/src/__tests__/attachments-store.test.ts +130 -68
- package/src/__tests__/attachments.test.ts +36 -36
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
- package/src/__tests__/call-start-guardian-guard.test.ts +18 -4
- package/src/__tests__/canned-reply-release.test.ts +86 -0
- package/src/__tests__/channel-guardian.test.ts +59 -29
- package/src/__tests__/channel-readiness-telegram-remote.test.ts +154 -0
- package/src/__tests__/channel-setup-panel-ack.test.ts +6 -5
- package/src/__tests__/client-os-metadata-persistence.test.ts +103 -4
- package/src/__tests__/compactor-image-manifest-trust.test.ts +1 -1
- package/src/__tests__/consult-deadline.test.ts +65 -0
- package/src/__tests__/conversation-agent-loop.test.ts +438 -2
- package/src/__tests__/conversation-disk-view-integration.test.ts +5 -1
- package/src/__tests__/conversation-disk-view.test.ts +4 -4
- package/src/__tests__/conversation-error.test.ts +22 -3
- package/src/__tests__/conversation-fork-crud.test.ts +5 -1
- package/src/__tests__/conversation-fork-referential.test.ts +352 -0
- package/src/__tests__/conversation-fork-retrospective.test.ts +5 -1
- package/src/__tests__/conversation-group-tools.test.ts +32 -2
- package/src/__tests__/conversation-inference-profile-route.test.ts +27 -1
- package/src/__tests__/conversation-initial-prompt.test.ts +51 -22
- package/src/__tests__/conversation-key-store-bootstrap-cleanup.test.ts +119 -0
- package/src/__tests__/conversation-key-store-origin.test.ts +105 -0
- package/src/__tests__/conversation-list-recency-ordering.test.ts +104 -0
- package/src/__tests__/conversation-origin-at-creation.test.ts +153 -0
- package/src/__tests__/conversation-origin-channel-filter.test.ts +95 -0
- package/src/__tests__/conversation-placement-promotion.test.ts +172 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +123 -0
- package/src/__tests__/conversation-queue.test.ts +433 -1
- package/src/__tests__/conversation-retry-route.test.ts +3 -1
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +64 -1
- package/src/__tests__/conversation-store-ephemeral.test.ts +4 -0
- package/src/__tests__/conversation-store.test.ts +26 -10
- package/src/__tests__/conversation-summarize-route.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +15 -6
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -5
- package/src/__tests__/conversation-surfaces-app-control.test.ts +12 -11
- package/src/__tests__/conversation-surfaces-app-open.test.ts +11 -5
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +5 -4
- package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +967 -0
- package/src/__tests__/conversation-surfaces-persisted-info.test.ts +312 -0
- package/src/__tests__/conversation-surfaces-queued-emit.test.ts +6 -5
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -8
- package/src/__tests__/conversation-surfaces-standalone.test.ts +21 -11
- package/src/__tests__/conversation-surfaces-state-update.test.ts +7 -11
- package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -6
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +11 -6
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +9 -6
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +70 -7
- package/src/__tests__/conversation-wait-for-idle.test.ts +6 -11
- package/src/__tests__/credential-prompt-route.test.ts +57 -7
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/cu-unified-flow.test.ts +89 -28
- package/src/__tests__/custom-group-listing-visibility.test.ts +1 -1
- package/src/__tests__/db-schedule-syntax-migration.test.ts +4 -1
- package/src/__tests__/discord-access-request-privacy.test.ts +366 -0
- package/src/__tests__/discord-requester-notice-privacy.test.ts +87 -0
- package/src/__tests__/disk-pressure-guard.test.ts +55 -55
- package/src/__tests__/disk-pressure-routes.test.ts +10 -10
- package/src/__tests__/disk-pressure-tools.test.ts +2 -2
- package/src/__tests__/disk-usage.test.ts +35 -20
- package/src/__tests__/document-sync-tags.test.ts +379 -0
- package/src/__tests__/document-update-default-surface.test.ts +28 -0
- package/src/__tests__/dynamic-skill-background-guard.test.ts +2 -2
- package/src/__tests__/emit-signal-routing-intent.test.ts +3 -4
- package/src/__tests__/ensure-conversation-exists.test.ts +8 -5
- package/src/__tests__/events-dev-bypass-actor.test.ts +183 -1
- package/src/__tests__/evict-conversations-for-reload.test.ts +90 -0
- package/src/__tests__/file-list-tool.test.ts +12 -10
- package/src/__tests__/file-ops-service.test.ts +151 -44
- package/src/__tests__/file-read-container-boundary.test.ts +137 -0
- package/src/__tests__/file-read-tool.test.ts +21 -9
- package/src/__tests__/file-url-path-guard.test.ts +83 -0
- package/src/__tests__/filesystem-tools.test.ts +82 -66
- package/src/__tests__/guardian-outbound-http.test.ts +8 -8
- package/src/__tests__/helpers/gateway-verification-sessions-stub.ts +14 -1
- package/src/__tests__/helpers/hub-clients.ts +42 -0
- package/src/__tests__/helpers/mock-conversation.ts +46 -0
- package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +61 -57
- package/src/__tests__/history-repair.test.ts +112 -12
- package/src/__tests__/host-bash-proxy.test.ts +10 -5
- package/src/__tests__/host-bash-routes.test.ts +67 -0
- package/src/__tests__/host-browser-proxy.test.ts +2 -2
- package/src/__tests__/host-cu-proxy.test.ts +3 -7
- package/src/__tests__/host-file-proxy.test.ts +3 -7
- package/src/__tests__/host-file-read-tool.test.ts +5 -1
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +6 -4
- package/src/__tests__/http-conversation-lineage.test.ts +2 -5
- package/src/__tests__/http-user-message-parity.test.ts +44 -0
- package/src/__tests__/identity-routes.test.ts +13 -13
- package/src/__tests__/image-conversion.test.ts +29 -26
- package/src/__tests__/image-source-path-reinject.test.ts +2 -2
- package/src/__tests__/inference-profile-session-handler.test.ts +95 -0
- package/src/__tests__/inference-profile-session-ipc.test.ts +25 -0
- package/src/__tests__/introduction-card-resolver.test.ts +6 -1
- package/src/__tests__/list-messages-attachments.test.ts +56 -32
- package/src/__tests__/list-messages-background-tool-completion.test.ts +4 -4
- package/src/__tests__/list-messages-client-message-id.test.ts +2 -2
- package/src/__tests__/list-messages-hidden-metadata.test.ts +16 -16
- package/src/__tests__/list-messages-page-latest.test.ts +61 -61
- package/src/__tests__/list-messages-provider-error.test.ts +6 -6
- package/src/__tests__/list-messages-queued.test.ts +49 -6
- package/src/__tests__/list-messages-system-card.test.ts +4 -4
- package/src/__tests__/list-messages-tool-merge.test.ts +9 -9
- package/src/__tests__/llm-resolver-override-or-default.test.ts +141 -0
- package/src/__tests__/llm-usage-store.test.ts +55 -0
- package/src/__tests__/manual-token-reconciliation.test.ts +45 -0
- package/src/__tests__/mcp-tool-annotations-risk.test.ts +133 -0
- package/src/__tests__/media-stream-server-integration.test.ts +36 -0
- package/src/__tests__/migration-export-http.test.ts +1 -1
- package/src/__tests__/migration-import-commit-http.test.ts +1 -1
- package/src/__tests__/migration-import-preflight-http.test.ts +1 -1
- package/src/__tests__/migration-validate-http.test.ts +1 -1
- package/src/__tests__/mtime-cache.test.ts +65 -3
- package/src/__tests__/notification-platform-adapter.test.ts +104 -0
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +1 -1
- package/src/__tests__/oauth-provider-profiles.test.ts +4 -2
- package/src/__tests__/oauth-provider-seed-logos.test.ts +65 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +17 -0
- package/src/__tests__/oauth-providers-routes.test.ts +1 -0
- package/src/__tests__/openai-responses-prompt-cache.test.ts +5 -2
- package/src/__tests__/path-policy.test.ts +164 -1
- package/src/__tests__/persist-media-references.test.ts +2 -2
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +5 -5
- package/src/__tests__/persist-unsendable-image.test.ts +23 -23
- package/src/__tests__/persona-resolver.test.ts +154 -0
- package/src/__tests__/plugin-api-webhook-url.test.ts +170 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +6 -0
- package/src/__tests__/processing-flag-persist-failure.test.ts +15 -10
- package/src/__tests__/profile-availability-incomplete.test.ts +113 -0
- package/src/__tests__/profiler-routes.test.ts +13 -13
- package/src/__tests__/prompt-cache-cross-turn-stability.test.ts +593 -0
- package/src/__tests__/proxy-approval-callback.test.ts +3 -3
- package/src/__tests__/queued-message-cancel-and-steer.test.ts +189 -0
- package/src/__tests__/queued-message-steer-actor-scoping.test.ts +164 -0
- package/src/__tests__/resolve-trust-class.test.ts +20 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +1 -1
- package/src/__tests__/run-due-schedules.test.ts +174 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +15 -7
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +166 -0
- package/src/__tests__/schedule-routes.test.ts +730 -8
- package/src/__tests__/schedule-store.test.ts +540 -0
- package/src/__tests__/schedule-tools.test.ts +103 -0
- package/src/__tests__/scheduler-wake.test.ts +5 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +29 -1
- package/src/__tests__/secure-keys.test.ts +91 -0
- package/src/__tests__/server-history-render.test.ts +97 -7
- package/src/__tests__/size-guard.test.ts +8 -8
- package/src/__tests__/skill-docs-sync-guard.test.ts +3 -2
- package/src/__tests__/skill-tool-factory.test.ts +247 -0
- package/src/__tests__/skills-install-staging.test.ts +15 -6
- package/src/__tests__/slack-edit-ordering-characterization.test.ts +103 -0
- package/src/__tests__/slack-inbound-verification.test.ts +4 -1
- package/src/__tests__/slack-mention-binding-invariance.test.ts +103 -0
- package/src/__tests__/slack-mention-provider-leak-audit.test.ts +135 -0
- package/src/__tests__/starter-task-flow.test.ts +5 -4
- package/src/__tests__/steer-on-enqueue-question.test.ts +3 -2
- package/src/__tests__/stt-language-catalog-parity.test.ts +38 -0
- package/src/__tests__/subagent-allowlist-validation.test.ts +26 -4
- package/src/__tests__/subagent-cron-run-attribution.test.ts +301 -0
- package/src/__tests__/subagent-disposal.test.ts +10 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +10 -0
- package/src/__tests__/subagent-fork-prompt-role.test.ts +85 -11
- package/src/__tests__/subagent-fork-spawn.test.ts +15 -7
- package/src/__tests__/subagent-manager-notify.test.ts +148 -0
- package/src/__tests__/subagent-notify-parent.test.ts +1 -1
- package/src/__tests__/subagent-persistence.test.ts +141 -0
- package/src/__tests__/subagent-role-registry.test.ts +172 -63
- package/src/__tests__/subagent-role-resolution.test.ts +88 -0
- package/src/__tests__/subagent-spawn-and-await.test.ts +48 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +111 -10
- package/src/__tests__/subagent-terminal-message.test.ts +88 -1
- package/src/__tests__/subagent-tool-gate-mode.test.ts +225 -10
- package/src/__tests__/subagent-tools.test.ts +1901 -108
- package/src/__tests__/surface-completion-compaction-boundary.test.ts +124 -0
- package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +298 -0
- package/src/__tests__/system-prompt.test.ts +82 -7
- package/src/__tests__/tool-grant-request-escalation.test.ts +40 -1
- package/src/__tests__/tool-result-spool.test.ts +74 -18
- package/src/__tests__/tool-side-effects-documents.test.ts +174 -0
- package/src/__tests__/tool-side-effects-hook-failures.test.ts +129 -0
- package/src/__tests__/tools-audio-read.test.ts +10 -10
- package/src/__tests__/tools-get-route.test.ts +85 -12
- package/src/__tests__/tools-list-cli.test.ts +171 -0
- package/src/__tests__/top-level-renderer.test.ts +54 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +68 -1
- package/src/__tests__/trusted-contact-multichannel.test.ts +4 -1
- package/src/__tests__/turn-tail-chain.test.ts +135 -0
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +6 -4
- package/src/__tests__/ui-visual-surface.test.ts +5 -4
- package/src/__tests__/ui-work-result-surface.test.ts +5 -4
- package/src/__tests__/unified-turn-context-visible-app.test.ts +7 -8
- package/src/__tests__/usage-routes.test.ts +62 -0
- package/src/__tests__/verification-outbound-delivery.test.ts +176 -0
- package/src/__tests__/visible-app-context.test.ts +20 -4
- package/src/__tests__/web-search-history.test.ts +96 -0
- package/src/__tests__/workspace-migration-139-clear-renamed-cost-profile-label.test.ts +6 -6
- package/src/__tests__/workspace-migration-140-repair-seed-pinned-memory-v3-live.test.ts +330 -0
- package/src/acp/failure-error.ts +3 -5
- package/src/agent/attachments.ts +26 -24
- package/src/agent/history-repair/history-repair.ts +27 -26
- package/src/agent/image-optimize.ts +6 -6
- package/src/agent/loop.ts +40 -22
- package/src/agent/message-types.ts +3 -3
- package/src/api/constants/document-tools.ts +55 -0
- package/src/api/events/question-answered.ts +53 -0
- package/src/api/events/tool-result.ts +7 -0
- package/src/api/index.ts +13 -0
- package/src/api/responses/conversation-message.ts +11 -0
- package/src/api/surfaces-oauth-connect.test.ts +96 -0
- package/src/api/surfaces.ts +36 -8
- package/src/approvals/guardian-channel-delivery.ts +83 -0
- package/src/approvals/guardian-expiry-notifier.ts +13 -11
- package/src/approvals/guardian-request-resolvers.ts +222 -135
- package/src/calls/__tests__/voice-session-bridge.test.ts +50 -0
- package/src/calls/media-stream-server.ts +9 -1
- package/src/calls/voice-session-bridge.ts +38 -0
- package/src/channels/__tests__/gateway-verification-sessions.test.ts +3 -3
- package/src/channels/config.ts +7 -2
- package/src/channels/gateway-verification-sessions.ts +7 -2
- package/src/channels/types.ts +7 -1
- package/src/cli/commands/__tests__/cache.test.ts +7 -4
- package/src/cli/commands/__tests__/cli-test-harness.ts +82 -0
- package/src/cli/commands/__tests__/conversations-wake.test.ts +51 -6
- package/src/cli/commands/__tests__/inference-models.test.ts +14 -0
- package/src/cli/commands/__tests__/inference-profiles.test.ts +44 -1
- package/src/cli/commands/__tests__/inference-providers.test.ts +7 -0
- package/src/cli/commands/__tests__/plugins.test.ts +692 -0
- package/src/cli/commands/__tests__/schedules.test.ts +136 -37
- package/src/cli/commands/conversations.ts +7 -3
- package/src/cli/commands/credentials.help.ts +7 -0
- package/src/cli/commands/inference-profiles.ts +9 -3
- package/src/cli/commands/inference.help.ts +16 -2
- package/src/cli/commands/mcp.help.ts +4 -2
- package/src/cli/commands/memory/memory-retrospective.ts +18 -0
- package/src/cli/commands/notifications.ts +3 -6
- package/src/cli/commands/oauth/connect-surface-guidance.test.ts +16 -0
- package/src/cli/commands/oauth/connect-surface-guidance.ts +25 -7
- package/src/cli/commands/oauth/connect.test.ts +26 -1
- package/src/cli/commands/oauth/connect.ts +4 -1
- package/src/cli/commands/oauth/index.help.ts +3 -1
- package/src/cli/commands/oauth/providers.ts +3 -0
- package/src/cli/commands/plugins.help.ts +25 -2
- package/src/cli/commands/plugins.ts +289 -10
- package/src/cli/commands/schedules.help.ts +14 -12
- package/src/cli/commands/schedules.ts +19 -5
- package/src/cli/commands/tools.help.ts +4 -2
- package/src/cli/commands/tools.ts +38 -0
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +1 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +79 -0
- package/src/cli/lib/__tests__/install-from-platform.test.ts +47 -1
- package/src/cli/lib/__tests__/plugin-surfaces.test.ts +86 -7
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +122 -0
- package/src/cli/lib/install-from-github.ts +61 -0
- package/src/cli/lib/install-from-platform.ts +13 -2
- package/src/cli/lib/plugin-surfaces.ts +124 -4
- package/src/cli/lib/upgrade-plugin.ts +18 -0
- package/src/cli.ts +1 -1
- package/src/config/__tests__/deployment-context-defaults.test.ts +73 -0
- package/src/config/__tests__/memory-retrospective-schema.test.ts +40 -0
- package/src/config/__tests__/plugin-updates-schema.test.ts +43 -0
- package/src/config/__tests__/profile-tool-support.test.ts +131 -0
- package/src/config/bundled-skills/AGENTS.md +1 -1
- package/src/config/bundled-skills/app-builder/SKILL.md +1 -1
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +3 -3
- package/src/config/bundled-skills/schedule/SKILL.md +5 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +1 -0
- package/src/config/bundled-skills/subagent/SKILL.md +53 -22
- package/src/config/bundled-skills/subagent/TOOLS.json +14 -13
- package/src/config/bundled-skills/visualize/SKILL.md +1 -1
- package/src/config/default-profile-catalog.ts +6 -2
- package/src/config/feature-flag-registry.json +25 -17
- package/src/config/llm-resolver.ts +45 -15
- package/src/config/loader.ts +70 -1
- package/src/config/profile-tool-support.ts +110 -0
- package/src/config/sanitize-for-transfer.ts +11 -0
- package/src/config/schema.ts +4 -0
- package/src/config/schemas/__tests__/stt.test.ts +20 -5
- package/src/config/schemas/channels.ts +13 -0
- package/src/config/schemas/memory-retrospective.ts +25 -0
- package/src/config/schemas/plugin-updates.ts +55 -0
- package/src/config/schemas/services.ts +8 -4
- package/src/config/schemas/stt.ts +17 -5
- package/src/config/schemas/timeouts.ts +1 -1
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +16 -0
- package/src/contacts/guardian-delivery-reader.ts +29 -2
- package/src/context/compactor.ts +4 -4
- package/src/context/post-turn-tool-result-truncation.ts +32 -16
- package/src/context/strip-injections.ts +42 -0
- package/src/context/tool-result-spool.ts +32 -18
- package/src/credential-execution/ces-runtime.ts +3 -0
- package/src/credential-execution/client.ts +22 -1
- package/src/credential-execution/process-manager.test.ts +99 -0
- package/src/credential-execution/process-manager.ts +62 -16
- package/src/daemon/__tests__/abort-null-controller.test.ts +141 -5
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +8 -12
- package/src/daemon/__tests__/install-assistant-command.test.ts +234 -0
- package/src/daemon/__tests__/turn-tail-assistant-reply-notify.test.ts +2 -4
- package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +20 -29
- package/src/daemon/channel-ui-capability.ts +4 -4
- package/src/daemon/conversation-agent-loop-handlers.ts +117 -61
- package/src/daemon/conversation-agent-loop.ts +318 -148
- package/src/daemon/conversation-attachments.ts +1 -1
- package/src/daemon/conversation-error.ts +8 -1
- package/src/daemon/conversation-initial-prompt.ts +16 -38
- package/src/daemon/conversation-lifecycle.ts +154 -32
- package/src/daemon/conversation-messaging.ts +106 -43
- package/src/daemon/conversation-process.ts +131 -33
- package/src/daemon/conversation-queue-manager.ts +10 -0
- package/src/daemon/conversation-runtime-assembly.ts +9 -4
- package/src/daemon/conversation-store.ts +52 -3
- package/src/daemon/conversation-surface-state.ts +9 -0
- package/src/daemon/conversation-surfaces.ts +403 -210
- package/src/daemon/conversation-tool-setup.ts +56 -7
- package/src/daemon/conversation-turn-finalize.ts +134 -89
- package/src/daemon/conversation.ts +111 -27
- package/src/daemon/disk-pressure-guard-lifecycle.ts +2 -2
- package/src/daemon/disk-pressure-guard.ts +3 -3
- package/src/daemon/doordash-steps.ts +5 -5
- package/src/daemon/external-plugins-bootstrap.ts +7 -1
- package/src/daemon/handlers/config-channels.ts +48 -5
- package/src/daemon/handlers/conversation-history.ts +1 -1
- package/src/daemon/handlers/conversations.ts +62 -17
- package/src/daemon/handlers/shared.ts +12 -0
- package/src/daemon/handlers/skills.ts +11 -1
- package/src/daemon/identity-helpers.ts +38 -10
- package/src/daemon/install-assistant-command.ts +322 -0
- package/src/daemon/lifecycle.ts +14 -3
- package/src/daemon/message-types/conversations.ts +6 -7
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/persist-media-references.ts +23 -14
- package/src/daemon/process-message.ts +6 -6
- package/src/daemon/tool-setup-types.ts +19 -122
- package/src/daemon/tool-side-effects.ts +17 -94
- package/src/daemon/trust-context-types.ts +39 -0
- package/src/daemon/trust-context.ts +14 -6
- package/src/daemon/turn-tail-chain.ts +73 -0
- package/src/daemon/web-search-history.ts +47 -33
- package/src/heartbeat/heartbeat-service.ts +6 -6
- package/src/ipc/__tests__/socket-path.test.ts +21 -0
- package/src/ipc/assistant-server.ts +17 -10
- package/src/ipc/cli-client.ts +10 -1
- package/src/ipc/routes/__tests__/documents-sync-ipc-routes.test.ts +56 -0
- package/src/ipc/routes/documents-sync-ipc-routes.ts +42 -0
- package/src/ipc/socket-cleanup.ts +9 -7
- package/src/ipc/socket-path.ts +4 -96
- package/src/live-voice/__tests__/live-voice-archive.test.ts +16 -16
- package/src/live-voice/__tests__/live-voice-attach-image.test.ts +209 -0
- package/src/live-voice/__tests__/live-voice-connection.test.ts +20 -0
- package/src/live-voice/__tests__/live-voice-integration.test.ts +7 -5
- package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +265 -0
- package/src/live-voice/__tests__/live-voice-stt.test.ts +6 -1
- package/src/live-voice/__tests__/live-voice-vad.test.ts +35 -15
- package/src/live-voice/__tests__/protocol.test.ts +52 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +3 -0
- package/src/live-voice/live-voice-archive.ts +13 -13
- package/src/live-voice/live-voice-connection.ts +7 -1
- package/src/live-voice/live-voice-photo.ts +169 -0
- package/src/live-voice/live-voice-session.ts +108 -4
- package/src/live-voice/protocol.ts +89 -1
- package/src/mcp/client.ts +10 -0
- package/src/messaging/providers/__tests__/callback-routing.test.ts +5 -1
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +66 -4
- package/src/messaging/providers/callback-routing.ts +1 -0
- package/src/messaging/providers/discord/api.ts +312 -0
- package/src/messaging/providers/discord/dm-delivery.test.ts +204 -0
- package/src/messaging/providers/discord/render.test.ts +204 -0
- package/src/messaging/providers/discord/render.ts +195 -0
- package/src/messaging/providers/discord/send.test.ts +179 -0
- package/src/messaging/providers/discord/send.ts +212 -0
- package/src/messaging/providers/discord/transport.ts +81 -0
- package/src/messaging/providers/index.ts +3 -1
- package/src/messaging/providers/retry-policy.test.ts +247 -0
- package/src/messaging/providers/retry-policy.ts +206 -0
- package/src/messaging/providers/slack/mention-source.test.ts +285 -0
- package/src/messaging/providers/slack/mention-source.ts +287 -0
- package/src/messaging/providers/telegram-bot/api.ts +47 -130
- package/src/messaging/providers/whatsapp/api.ts +47 -136
- package/src/monitoring/__tests__/db-integrity-sample.test.ts +4 -1
- package/src/monitoring/__tests__/plugin-auto-update.test.ts +332 -0
- package/src/monitoring/db-integrity-sample.ts +6 -1
- package/src/monitoring/plugin-auto-update.ts +359 -0
- package/src/monitoring/resource-sampler.ts +21 -5
- package/src/monitoring/worker.ts +13 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +375 -2
- package/src/notifications/__tests__/broadcaster.test.ts +37 -1
- package/src/notifications/__tests__/copy-composer.test.ts +165 -0
- package/src/notifications/__tests__/emit-signal-pipeline-failure.test.ts +205 -0
- package/src/notifications/__tests__/notification-utils.test.ts +249 -0
- package/src/notifications/adapters/platform.ts +31 -2
- package/src/notifications/assistant-reply-producer.ts +79 -32
- package/src/notifications/broadcaster.ts +30 -10
- package/src/notifications/copy-composer.ts +69 -0
- package/src/notifications/emit-signal.ts +82 -15
- package/src/notifications/events-store.ts +10 -2
- package/src/notifications/home-feed-side-effect.ts +6 -3
- package/src/notifications/notification-utils.ts +173 -5
- package/src/notifications/signal.ts +12 -0
- package/src/oauth/AGENTS.md +4 -2
- package/src/oauth/byo-connection.ts +6 -1
- package/src/oauth/credential-token-resolver.ts +3 -10
- package/src/oauth/manual-token-connection.ts +29 -64
- package/src/oauth/manual-token-providers.ts +62 -0
- package/src/oauth/provider-serializer.ts +13 -0
- package/src/oauth/seed-providers.ts +62 -11
- package/src/onboarding/onboarding-events-store.ts +91 -1
- package/src/permissions/question-prompter.test.ts +4 -0
- package/src/permissions/question-prompter.ts +21 -4
- package/src/persistence/__tests__/conversation-lineage.test.ts +248 -0
- package/src/persistence/attachments-store.ts +15 -15
- package/src/persistence/conversation-attention-store.ts +30 -10
- package/src/persistence/conversation-bootstrap.ts +17 -0
- package/src/persistence/conversation-crud.ts +363 -97
- package/src/persistence/conversation-group-migration.ts +1 -1
- package/src/persistence/conversation-key-store.ts +38 -10
- package/src/persistence/conversation-lineage.ts +226 -0
- package/src/persistence/conversation-plugin-facade.ts +28 -3
- package/src/persistence/conversation-queries.ts +207 -33
- package/src/persistence/conversation-types.ts +107 -1
- package/src/persistence/jobs-store.ts +32 -8
- package/src/persistence/llm-usage-store.ts +22 -0
- package/src/persistence/migrations/361-normalize-managed-connection-rows.test.ts +168 -0
- package/src/persistence/migrations/361-normalize-managed-connection-rows.ts +76 -0
- package/src/persistence/migrations/362-add-conversation-subagent-kind.test.ts +187 -0
- package/src/persistence/migrations/362-add-conversation-subagent-kind.ts +93 -0
- package/src/persistence/migrations/363-backfill-schedule-inference-profile.test.ts +229 -0
- package/src/persistence/migrations/363-backfill-schedule-inference-profile.ts +127 -0
- package/src/persistence/migrations/364-add-schedule-source-key.test.ts +120 -0
- package/src/persistence/migrations/364-add-schedule-source-key.ts +43 -0
- package/src/persistence/migrations/365-add-conversation-fork-strategy.ts +27 -0
- package/src/persistence/schema/conversations.ts +32 -0
- package/src/persistence/schema/infrastructure.ts +3 -0
- package/src/persistence/steps.ts +30 -0
- package/src/persistence/subagent-store.ts +148 -6
- package/src/platform/managed-speech.test.ts +20 -0
- package/src/platform/managed-speech.ts +9 -0
- package/src/plugin-api/index.ts +8 -0
- package/src/plugin-api/webhook-url.ts +151 -0
- package/src/plugins/__tests__/installed-plugin-dirs.test.ts +82 -0
- package/src/plugins/__tests__/source-fingerprint.test.ts +5 -1
- package/src/plugins/collect-source-versions.ts +4 -27
- package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +5 -5
- package/src/plugins/defaults/exploration-drift/package.json +1 -1
- package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +4 -2
- package/src/plugins/defaults/image-recovery/recover.ts +67 -57
- package/src/plugins/defaults/index.ts +1 -1
- package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +64 -18
- package/src/plugins/defaults/memory/__tests__/jobs-worker-outcome-contract.test.ts +242 -0
- package/src/plugins/defaults/memory/__tests__/jobs-worker-retrospective-sweep.test.ts +24 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +48 -3
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +511 -19
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +39 -3
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +493 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +5 -4
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +5 -1
- package/src/plugins/defaults/memory/job-handlers.ts +87 -5
- package/src/plugins/defaults/memory/jobs-worker.ts +60 -6
- package/src/plugins/defaults/memory/memory-retrospective-constants.ts +11 -0
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +29 -0
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +342 -60
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +23 -3
- package/src/plugins/defaults/memory/substrate/consolidation-lock.ts +9 -4
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +7 -0
- package/src/plugins/defaults/memory/v1/graph/injection.ts +1 -1
- package/src/plugins/defaults/memory/v2/router.ts +8 -0
- package/src/plugins/defaults/turn-context/unified-turn-context.ts +1 -2
- package/src/plugins/external-plugin-loader.ts +17 -8
- package/src/plugins/installed-plugin-dirs.ts +101 -0
- package/src/plugins/mtime-cache.ts +34 -22
- package/src/plugins/types.ts +69 -8
- package/src/prompts/persona-resolver.ts +6 -2
- package/src/prompts/system-prompt.ts +72 -17
- package/src/providers/__tests__/inference.test.ts +40 -0
- package/src/providers/__tests__/preflight-resolved-config.test.ts +58 -1
- package/src/providers/__tests__/retry-callsite.test.ts +67 -0
- package/src/providers/__tests__/vellum-connection-routing.test.ts +42 -11
- package/src/providers/anthropic/client.ts +112 -95
- package/src/providers/connection-resolution.ts +35 -1
- package/src/providers/gemini/client.ts +5 -5
- package/src/providers/inference/adapter-factory.ts +16 -10
- package/src/providers/inference/auth.ts +16 -0
- package/src/providers/inference/connection-availability.ts +164 -12
- package/src/providers/inference/connections.ts +25 -1
- package/src/providers/media-resolve.ts +21 -11
- package/src/providers/model-catalog.ts +15 -0
- package/src/providers/openai/chat-completions-provider.ts +4 -4
- package/src/providers/openai/responses-provider.ts +12 -25
- package/src/providers/registry.ts +9 -4
- package/src/providers/retry.ts +25 -0
- package/src/providers/server-tool-pairing.ts +134 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +187 -6
- package/src/providers/speech-to-text/deepgram.ts +1 -0
- package/src/providers/speech-to-text/resolve.ts +80 -10
- package/src/providers/speech-to-text/vellum-managed.ts +7 -1
- package/src/providers/speech-to-text/vellum-speech-relay-connection.ts +3 -1
- package/src/providers/types.ts +26 -6
- package/src/providers/vellum-model-routing.ts +6 -7
- package/src/runtime/AGENTS.md +2 -0
- package/src/runtime/__tests__/agent-wake.test.ts +16 -16
- package/src/runtime/__tests__/background-job-runner.test.ts +0 -144
- package/src/runtime/__tests__/desktop-presence.test.ts +162 -0
- package/src/runtime/agent-wake.ts +63 -24
- package/src/runtime/assistant-event-hub.ts +87 -12
- package/src/runtime/auth/__tests__/guard-tests.test.ts +2 -0
- package/src/runtime/auth/__tests__/scopes.test.ts +20 -0
- package/src/runtime/auth/same-actor.ts +56 -8
- package/src/runtime/auth/scopes.ts +12 -0
- package/src/runtime/auth/types.ts +2 -0
- package/src/runtime/background-job-runner.ts +5 -27
- package/src/runtime/channel-readiness-service.ts +59 -3
- package/src/runtime/channel-readiness-types.ts +18 -0
- package/src/runtime/desktop-presence.ts +69 -0
- package/src/runtime/http-server.ts +12 -0
- package/src/runtime/local-actor-identity.ts +11 -9
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/client-routes.test.ts +186 -14
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +547 -1
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +162 -7
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +14 -10
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +340 -3
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +28 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +173 -1
- package/src/runtime/routes/__tests__/question-routes.test.ts +64 -0
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +20 -0
- package/src/runtime/routes/__tests__/skill-history-route.test.ts +116 -0
- package/src/runtime/routes/__tests__/wake-conversation-routes.test.ts +60 -2
- package/src/runtime/routes/archive-utils.ts +16 -12
- package/src/runtime/routes/attachment-routes.ts +13 -6
- package/src/runtime/routes/canned-reply-release.ts +54 -0
- package/src/runtime/routes/channel-verification-routes.ts +2 -27
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +5 -0
- package/src/runtime/routes/client-routes.ts +114 -2
- package/src/runtime/routes/conversation-cli-routes.ts +10 -12
- package/src/runtime/routes/conversation-list-routes.ts +59 -10
- package/src/runtime/routes/conversation-management-routes.ts +47 -18
- package/src/runtime/routes/conversation-query-routes.ts +32 -53
- package/src/runtime/routes/conversation-routes.ts +360 -293
- package/src/runtime/routes/credential-prompt-routes.ts +23 -2
- package/src/runtime/routes/debug-routes.ts +4 -1
- package/src/runtime/routes/default-provider-routes.ts +7 -11
- package/src/runtime/routes/documents-routes.ts +44 -1
- package/src/runtime/routes/events-routes.ts +28 -1
- package/src/runtime/routes/host-app-control-routes.ts +2 -0
- package/src/runtime/routes/host-bash-routes.ts +2 -0
- package/src/runtime/routes/host-browser-routes.ts +2 -0
- package/src/runtime/routes/host-cu-routes.ts +2 -0
- package/src/runtime/routes/host-file-routes.ts +2 -0
- package/src/runtime/routes/host-transfer-routes.ts +4 -0
- package/src/runtime/routes/identity-routes.ts +6 -6
- package/src/runtime/routes/inbound-message-handler.ts +5 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +7 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +14 -0
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -2
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +14 -11
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -17
- package/src/runtime/routes/inference-profile-availability-guard.ts +171 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +26 -2
- package/src/runtime/routes/inference-profile-session-routes.ts +2 -1
- package/src/runtime/routes/inference-profiles-routes.ts +152 -73
- package/src/runtime/routes/inference-provider-connection-routes.ts +0 -16
- package/src/runtime/routes/llm-call-sites-routes.ts +13 -0
- package/src/runtime/routes/log-export-routes.ts +1 -1
- package/src/runtime/routes/notification-routes.ts +0 -14
- package/src/runtime/routes/oauth-providers.ts +1 -0
- package/src/runtime/routes/plugins-routes.ts +106 -1
- package/src/runtime/routes/profiler-routes.ts +4 -2
- package/src/runtime/routes/question-routes.ts +28 -10
- package/src/runtime/routes/retrospective-routes.ts +9 -3
- package/src/runtime/routes/schedule-routes.ts +210 -12
- package/src/runtime/routes/secret-routes.ts +40 -23
- package/src/runtime/routes/settings-routes.ts +41 -13
- package/src/runtime/routes/skills-routes.ts +79 -0
- package/src/runtime/routes/ui-snapshot-routes.ts +1 -0
- package/src/runtime/routes/wake-conversation-routes.ts +23 -0
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
- package/src/runtime/services/conversation-serializer.ts +24 -9
- package/src/runtime/sync/documents-sidecar-publish.test.ts +101 -0
- package/src/runtime/sync/resource-sync-events.ts +79 -1
- package/src/runtime/sync/worker-daemon-notify.test.ts +34 -0
- package/src/runtime/sync/worker-daemon-notify.ts +44 -6
- package/src/runtime/verification-outbound-actions.ts +250 -222
- package/src/runtime/verification-templates.ts +41 -30
- package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +614 -0
- package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1066 -0
- package/src/schedule/inference-profile.ts +64 -3
- package/src/schedule/plugin-schedule-declarations.ts +518 -0
- package/src/schedule/plugin-schedule-reconciler.ts +605 -0
- package/src/schedule/plugin-schedules-gate.ts +23 -0
- package/src/schedule/schedule-store.ts +520 -26
- package/src/schedule/scheduler.ts +38 -0
- package/src/security/credential-backend.ts +51 -4
- package/src/security/encrypted-store.ts +64 -42
- package/src/security/secure-keys.ts +55 -7
- package/src/skills/catalog-install.ts +20 -7
- package/src/skills/inline-command-runner.ts +2 -7
- package/src/skills/skill-history.test.ts +269 -0
- package/src/skills/skill-history.ts +250 -0
- package/src/skills/skillssh-registry.ts +1 -1
- package/src/stt/daemon-batch-transcriber.ts +8 -6
- package/src/subagent/__tests__/consult-prompt.test.ts +25 -0
- package/src/subagent/consult-prompt.ts +3 -1
- package/src/subagent/consult-transcript.ts +1 -1
- package/src/subagent/manager.ts +304 -44
- package/src/subagent/progress-events.ts +35 -0
- package/src/subagent/role-resolution.ts +88 -0
- package/src/subagent/types.ts +302 -67
- package/src/subagent/validate-allowlists.ts +3 -4
- package/src/telegram/__tests__/webhook-health.test.ts +73 -1
- package/src/telegram/webhook-health.ts +101 -3
- package/src/telemetry/__tests__/telemetry-event-fixtures.ts +2 -0
- package/src/telemetry/activation-funnel.ts +6 -1
- package/src/telemetry/live-voice-funnel.ts +75 -0
- package/src/telemetry/telemetry-event-sources.ts +6 -0
- package/src/telemetry/telemetry-wire-source.json +1 -1
- package/src/telemetry/telemetry-wire.generated.ts +2 -0
- package/src/telemetry/types.ts +23 -4
- package/src/telemetry/usage-telemetry-reporter.test.ts +4 -0
- package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +1 -1
- package/src/tools/ask-question/ask-question-tool.test.ts +118 -3
- package/src/tools/ask-question/ask-question-tool.ts +56 -2
- package/src/tools/browser/browser-execution.ts +1 -1
- package/src/tools/calls/call-start.ts +8 -5
- package/src/tools/conversation-groups/move_to_group.ts +10 -12
- package/src/tools/document/document-tool.ts +11 -4
- package/src/tools/execution-timeout.ts +9 -2
- package/src/tools/executor.ts +7 -6
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +7 -13
- package/src/tools/filesystem/search.ts +23 -21
- package/src/tools/filesystem/write.ts +4 -1
- package/src/tools/host-filesystem/edit.ts +7 -2
- package/src/tools/host-filesystem/read.ts +21 -8
- package/src/tools/host-filesystem/write.ts +10 -2
- package/src/tools/host-terminal/host-shell.ts +2 -2
- package/src/tools/mcp/mcp-tool-factory.ts +25 -1
- package/src/tools/permission-checker.ts +8 -3
- package/src/tools/schedule/delete.ts +13 -1
- package/src/tools/schedule/list.ts +14 -3
- package/src/tools/schedule/update.ts +56 -33
- package/src/tools/shared/filesystem/audio-read.ts +6 -4
- package/src/tools/shared/filesystem/file-ops-service.ts +176 -116
- package/src/tools/shared/filesystem/image-read.ts +12 -12
- package/src/tools/shared/filesystem/path-policy.ts +70 -5
- package/src/tools/shared/filesystem/size-guard.ts +6 -6
- package/src/tools/shared/input-misuse.ts +72 -0
- package/src/tools/skills/scaffold-managed.ts +82 -0
- package/src/tools/skills/skill-tool-factory.ts +14 -1
- package/src/tools/subagent/consult-deadline.ts +12 -7
- package/src/tools/subagent/message.ts +3 -1
- package/src/tools/subagent/read.ts +66 -4
- package/src/tools/subagent/spawn.ts +500 -78
- package/src/tools/tool-approval-handler.ts +45 -4
- package/src/tools/types.ts +22 -3
- package/src/tools/ui-surface/surface-shape-docs.ts +1 -1
- package/src/tools/ui-surface/visual-validation.ts +2 -0
- package/src/usage/__tests__/subagent-attribution.test.ts +109 -0
- package/src/usage/subagent-attribution.ts +108 -0
- package/src/util/__tests__/sqlite-retry.test.ts +112 -0
- package/src/util/abort-reasons.ts +16 -0
- package/src/util/ansi.ts +44 -0
- package/src/util/disk-usage.ts +17 -13
- package/src/util/image-conversion.ts +20 -13
- package/src/util/schedule-source-key.ts +23 -0
- package/src/util/worker-process.ts +7 -1
- package/src/workspace/git-service.ts +33 -9
- package/src/workspace/migrations/140-repair-seed-pinned-memory-v3-live.ts +260 -0
- package/src/workspace/migrations/141-stt-english-default-to-multilingual.ts +111 -0
- package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +126 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/workspace/top-level-renderer.ts +15 -2
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -357
- package/src/daemon/install-symlink.ts +0 -207
- package/src/notifications/deferred-emit.ts +0 -147
|
@@ -4,15 +4,15 @@ import {
|
|
|
4
4
|
type MessageAttachmentInput,
|
|
5
5
|
} from "./attachments.js";
|
|
6
6
|
|
|
7
|
-
export function createUserMessage(
|
|
7
|
+
export async function createUserMessage(
|
|
8
8
|
text: string,
|
|
9
9
|
attachments: MessageAttachmentInput[] = [],
|
|
10
|
-
): Message {
|
|
10
|
+
): Promise<Message> {
|
|
11
11
|
const content = [] as Message["content"];
|
|
12
12
|
if (text.trim().length > 0) {
|
|
13
13
|
content.push({ type: "text", text });
|
|
14
14
|
}
|
|
15
|
-
content.push(...attachmentsToContentBlocks(attachments));
|
|
15
|
+
content.push(...(await attachmentsToContentBlocks(attachments)));
|
|
16
16
|
return { role: "user", content };
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The document tools that mutate the stored document set, and what each one
|
|
3
|
+
* leaves behind. This is the single declaration both the daemon and the web
|
|
4
|
+
* client derive their tool sets from, so a new mutating document tool is added
|
|
5
|
+
* here once and every consumer picks it up.
|
|
6
|
+
*
|
|
7
|
+
* Tool names are the ones the runner sees. Calls arriving through the bundled
|
|
8
|
+
* `document-editor` skill reach the daemon already unwrapped to the inner tool
|
|
9
|
+
* name, and the web client unwraps the `skill_execute` envelope itself.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export interface DocumentMutationTool {
|
|
13
|
+
/** The executed tool name. */
|
|
14
|
+
readonly name: string;
|
|
15
|
+
/**
|
|
16
|
+
* Whether the document is still openable once the tool has run. A deleted
|
|
17
|
+
* document has nothing to open, so it cannot anchor a link back to itself.
|
|
18
|
+
*/
|
|
19
|
+
readonly reopenable: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Whether the tool writes into an already-created document, as opposed to
|
|
22
|
+
* the create that opened it.
|
|
23
|
+
*/
|
|
24
|
+
readonly edit: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const DOCUMENT_MUTATION_TOOLS: readonly DocumentMutationTool[] = [
|
|
28
|
+
{ name: "document_create", reopenable: true, edit: false },
|
|
29
|
+
{ name: "document_update", reopenable: true, edit: true },
|
|
30
|
+
{ name: "document_replace_text", reopenable: true, edit: true },
|
|
31
|
+
{ name: "document_delete", reopenable: false, edit: false },
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Every tool that changes the document list. The daemon hooks these to publish
|
|
36
|
+
* a documents-changed broadcast, because they carry no list-level change signal
|
|
37
|
+
* of their own and client asset lists would otherwise keep serving a cached
|
|
38
|
+
* list after an edit and a deleted document would linger as a ghost row.
|
|
39
|
+
*/
|
|
40
|
+
export const DOCUMENT_MUTATION_TOOL_NAMES: readonly string[] =
|
|
41
|
+
DOCUMENT_MUTATION_TOOLS.map((tool) => tool.name);
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The mutating tools that leave the document openable. The web transcript
|
|
45
|
+
* anchors its changed-document chips on these, so a delete never produces a
|
|
46
|
+
* chip pointing at a document that is gone.
|
|
47
|
+
*/
|
|
48
|
+
export const REOPENABLE_DOCUMENT_MUTATION_TOOL_NAMES: readonly string[] =
|
|
49
|
+
DOCUMENT_MUTATION_TOOLS.filter((tool) => tool.reopenable).map(
|
|
50
|
+
(tool) => tool.name,
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
/** The mutating tools that write into an already-created document. */
|
|
54
|
+
export const DOCUMENT_EDIT_TOOL_NAMES: readonly string[] =
|
|
55
|
+
DOCUMENT_MUTATION_TOOLS.filter((tool) => tool.edit).map((tool) => tool.name);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable record of an `ask_question` prompt the user has answered.
|
|
3
|
+
*
|
|
4
|
+
* The pending counterpart (`question_request` / `PendingToolQuestion`) is live
|
|
5
|
+
* registry state: it exists only while the prompt is outstanding and vanishes
|
|
6
|
+
* the moment the interaction resolves. This record is the opposite. It is
|
|
7
|
+
* produced by the `ask_question` executor once the prompt settles, rides the
|
|
8
|
+
* `tool_result` event, and is persisted on the tool_use block, so the answered
|
|
9
|
+
* question and the user's choice stay readable in the transcript across
|
|
10
|
+
* conversation switches, reloads, and history reopens.
|
|
11
|
+
*
|
|
12
|
+
* `questions` mirrors the `question_request` event's `questions[]` (same
|
|
13
|
+
* daemon-assigned `q1`, `q2`, ... ids) so the answered card renders from the
|
|
14
|
+
* same shape the interactive card did. `responses` is ordered to match, one
|
|
15
|
+
* entry per question.
|
|
16
|
+
*
|
|
17
|
+
* Only user-driven outcomes are recorded: a completed batch, or a card the
|
|
18
|
+
* user closed without answering (every question `skipped`). A prompt that
|
|
19
|
+
* timed out or was aborted produced no user decision, so it carries no record
|
|
20
|
+
* and the tool's own error result stands on its own.
|
|
21
|
+
*
|
|
22
|
+
* Canonical wire-contract source. Daemon code imports the type directly from
|
|
23
|
+
* this file; external consumers import via `@vellumai/assistant-api`.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { z } from "zod";
|
|
27
|
+
|
|
28
|
+
import { QuestionEntrySchema } from "./question-request.js";
|
|
29
|
+
|
|
30
|
+
export const AnsweredQuestionResponseSchema = z.object({
|
|
31
|
+
/** Daemon-assigned question id (`q1`, `q2`, ...) this answer belongs to. */
|
|
32
|
+
questionId: z.string(),
|
|
33
|
+
decision: z.enum(["option", "free_text", "skipped"]),
|
|
34
|
+
/** Chosen option id. Present only when `decision` is `"option"`. */
|
|
35
|
+
optionId: z.string().optional(),
|
|
36
|
+
/** The user's typed answer. Present only when `decision` is `"free_text"`. */
|
|
37
|
+
text: z.string().optional(),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export type AnsweredQuestionResponse = z.infer<
|
|
41
|
+
typeof AnsweredQuestionResponseSchema
|
|
42
|
+
>;
|
|
43
|
+
|
|
44
|
+
export const AnsweredQuestionSchema = z.object({
|
|
45
|
+
/** The resolved interaction's request id, matching the `question_request` that raised it. */
|
|
46
|
+
requestId: z.string(),
|
|
47
|
+
questions: z.array(QuestionEntrySchema),
|
|
48
|
+
responses: z.array(AnsweredQuestionResponseSchema),
|
|
49
|
+
/** `"completed"` when the user submitted a batch, `"closed"` when they dismissed the card. */
|
|
50
|
+
overall: z.enum(["completed", "closed"]),
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
export type AnsweredQuestion = z.infer<typeof AnsweredQuestionSchema>;
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
ConfirmationDiffSchema,
|
|
35
35
|
DirectoryScopeOptionSchema,
|
|
36
36
|
} from "./confirmation-request.js";
|
|
37
|
+
import { AnsweredQuestionSchema } from "./question-answered.js";
|
|
37
38
|
|
|
38
39
|
export const RiskScopeOptionSchema = z.object({
|
|
39
40
|
pattern: z.string(),
|
|
@@ -131,6 +132,12 @@ export const ToolResultEventSchema = z.object({
|
|
|
131
132
|
approvalReason: z.string().optional(),
|
|
132
133
|
riskThreshold: z.string().optional(),
|
|
133
134
|
activityMetadata: ToolActivityMetadataSchema.optional(),
|
|
135
|
+
/**
|
|
136
|
+
* Set only by `ask_question`: the questions asked and the answers the user
|
|
137
|
+
* gave. Carried here so the answered card renders the instant the prompt
|
|
138
|
+
* resolves, from the same record the daemon persists on the tool_use block.
|
|
139
|
+
*/
|
|
140
|
+
answeredQuestion: AnsweredQuestionSchema.optional(),
|
|
134
141
|
/**
|
|
135
142
|
* Stable, machine-readable classification for an error result (only set when
|
|
136
143
|
* `isError`). Lets a client branch on a known failure — e.g.
|
package/src/api/index.ts
CHANGED
|
@@ -137,6 +137,13 @@ export {
|
|
|
137
137
|
CALL_SITE_COMPACTION_AGENT,
|
|
138
138
|
CALL_SITE_SYNTHETIC_AGENT_ERROR_MESSAGE,
|
|
139
139
|
} from "./constants/call-sites.js";
|
|
140
|
+
export {
|
|
141
|
+
DOCUMENT_EDIT_TOOL_NAMES,
|
|
142
|
+
DOCUMENT_MUTATION_TOOL_NAMES,
|
|
143
|
+
DOCUMENT_MUTATION_TOOLS,
|
|
144
|
+
type DocumentMutationTool,
|
|
145
|
+
REOPENABLE_DOCUMENT_MUTATION_TOOL_NAMES,
|
|
146
|
+
} from "./constants/document-tools.js";
|
|
140
147
|
export {
|
|
141
148
|
SSE_REPLAY_RING_AGE_LIMIT_MS,
|
|
142
149
|
SSE_REPLAY_RING_COUNT_LIMIT,
|
|
@@ -493,6 +500,12 @@ export {
|
|
|
493
500
|
type PlatformDisconnectedEvent,
|
|
494
501
|
PlatformDisconnectedEventSchema,
|
|
495
502
|
} from "./events/platform-disconnected.js";
|
|
503
|
+
export {
|
|
504
|
+
type AnsweredQuestion,
|
|
505
|
+
type AnsweredQuestionResponse,
|
|
506
|
+
AnsweredQuestionResponseSchema,
|
|
507
|
+
AnsweredQuestionSchema,
|
|
508
|
+
} from "./events/question-answered.js";
|
|
496
509
|
export {
|
|
497
510
|
type QuestionEntry,
|
|
498
511
|
QuestionEntrySchema,
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
DirectoryScopeOptionSchema,
|
|
30
30
|
ScopeOptionSchema,
|
|
31
31
|
} from "../events/confirmation-request.js";
|
|
32
|
+
import { AnsweredQuestionSchema } from "../events/question-answered.js";
|
|
32
33
|
import { QuestionEntrySchema } from "../events/question-request.js";
|
|
33
34
|
import { ToolActivityMetadataSchema } from "../events/tool-result.js";
|
|
34
35
|
|
|
@@ -242,6 +243,16 @@ export const ConversationMessageToolCallSchema = z.object({
|
|
|
242
243
|
* render time). Lets a cold reconnect restore the inline question card.
|
|
243
244
|
*/
|
|
244
245
|
pendingQuestion: PendingToolQuestionSchema.optional(),
|
|
246
|
+
/**
|
|
247
|
+
* The answered counterpart to `pendingQuestion`: the questions an
|
|
248
|
+
* `ask_question` call asked and the answers the user gave. Persisted on the
|
|
249
|
+
* tool_use block rather than stamped from the live registry, so it survives a
|
|
250
|
+
* conversation switch, a reload, and a history reopen. A tool call carries at
|
|
251
|
+
* most one of the two: the pending prompt while it is outstanding, the
|
|
252
|
+
* answered record once it settles. Absent on history rows written before the
|
|
253
|
+
* daemon recorded it.
|
|
254
|
+
*/
|
|
255
|
+
answeredQuestion: AnsweredQuestionSchema.optional(),
|
|
245
256
|
});
|
|
246
257
|
export type ConversationMessageToolCall = z.infer<
|
|
247
258
|
typeof ConversationMessageToolCallSchema
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
type OAuthConnectSurfaceData,
|
|
5
|
+
OAuthConnectSurfaceDataSchema,
|
|
6
|
+
} from "./surfaces.js";
|
|
7
|
+
|
|
8
|
+
describe("OAuthConnectSurfaceDataSchema requestedScopes", () => {
|
|
9
|
+
test("parses a valid scopes array and preserves order", () => {
|
|
10
|
+
const parsed = OAuthConnectSurfaceDataSchema.parse({
|
|
11
|
+
providerKey: "google",
|
|
12
|
+
requestedScopes: [
|
|
13
|
+
"https://www.googleapis.com/auth/tasks",
|
|
14
|
+
"https://www.googleapis.com/auth/calendar",
|
|
15
|
+
"openid",
|
|
16
|
+
],
|
|
17
|
+
});
|
|
18
|
+
expect(parsed.requestedScopes).toEqual([
|
|
19
|
+
"https://www.googleapis.com/auth/tasks",
|
|
20
|
+
"https://www.googleapis.com/auth/calendar",
|
|
21
|
+
"openid",
|
|
22
|
+
]);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("absent requestedScopes parses to undefined", () => {
|
|
26
|
+
const parsed = OAuthConnectSurfaceDataSchema.parse({
|
|
27
|
+
providerKey: "google",
|
|
28
|
+
});
|
|
29
|
+
expect(parsed.requestedScopes).toBeUndefined();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("an empty array collapses to undefined", () => {
|
|
33
|
+
const parsed = OAuthConnectSurfaceDataSchema.parse({
|
|
34
|
+
providerKey: "google",
|
|
35
|
+
requestedScopes: [],
|
|
36
|
+
});
|
|
37
|
+
expect(parsed.requestedScopes).toBeUndefined();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("non-array values collapse to undefined instead of rejecting", () => {
|
|
41
|
+
for (const value of [
|
|
42
|
+
"https://www.googleapis.com/auth/tasks, openid",
|
|
43
|
+
42,
|
|
44
|
+
true,
|
|
45
|
+
{ scope: "openid" },
|
|
46
|
+
null,
|
|
47
|
+
]) {
|
|
48
|
+
const parsed = OAuthConnectSurfaceDataSchema.parse({
|
|
49
|
+
providerKey: "google",
|
|
50
|
+
requestedScopes: value,
|
|
51
|
+
});
|
|
52
|
+
expect(parsed.requestedScopes).toBeUndefined();
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("an array of blanks collapses to undefined", () => {
|
|
57
|
+
const parsed = OAuthConnectSurfaceDataSchema.parse({
|
|
58
|
+
providerKey: "google",
|
|
59
|
+
requestedScopes: ["", " ", "\t"],
|
|
60
|
+
});
|
|
61
|
+
expect(parsed.requestedScopes).toBeUndefined();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("entries are trimmed and blank or non-string junk is dropped", () => {
|
|
65
|
+
const parsed = OAuthConnectSurfaceDataSchema.parse({
|
|
66
|
+
providerKey: "google",
|
|
67
|
+
requestedScopes: [
|
|
68
|
+
" https://www.googleapis.com/auth/tasks ",
|
|
69
|
+
"",
|
|
70
|
+
null,
|
|
71
|
+
{ nope: true },
|
|
72
|
+
"openid",
|
|
73
|
+
],
|
|
74
|
+
});
|
|
75
|
+
expect(parsed.requestedScopes).toEqual([
|
|
76
|
+
"https://www.googleapis.com/auth/tasks",
|
|
77
|
+
"openid",
|
|
78
|
+
]);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("a bare string is not split on commas (scopes are opaque URIs)", () => {
|
|
82
|
+
const parsed = OAuthConnectSurfaceDataSchema.parse({
|
|
83
|
+
providerKey: "google",
|
|
84
|
+
requestedScopes: "a,b,c",
|
|
85
|
+
});
|
|
86
|
+
expect(parsed.requestedScopes).toBeUndefined();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("legacy payload { providerKey: 'google' } still parses (skew guard)", () => {
|
|
90
|
+
const parsed: OAuthConnectSurfaceData = OAuthConnectSurfaceDataSchema.parse(
|
|
91
|
+
{ providerKey: "google" },
|
|
92
|
+
);
|
|
93
|
+
expect(parsed.providerKey).toBe("google");
|
|
94
|
+
expect(parsed.requestedScopes).toBeUndefined();
|
|
95
|
+
});
|
|
96
|
+
});
|
package/src/api/surfaces.ts
CHANGED
|
@@ -120,6 +120,21 @@ export const CardSurfaceDataSchema = z.object({
|
|
|
120
120
|
});
|
|
121
121
|
export type CardSurfaceData = z.infer<typeof CardSurfaceDataSchema>;
|
|
122
122
|
|
|
123
|
+
/**
|
|
124
|
+
* Stringify+trim entries, drop blanks and non-scalars, and collapse an
|
|
125
|
+
* empty result to `undefined` so a schema treats it as "field absent".
|
|
126
|
+
*/
|
|
127
|
+
function cleanedStringEntries(items: unknown[]): string[] | undefined {
|
|
128
|
+
const cleaned = items
|
|
129
|
+
.map((item) =>
|
|
130
|
+
typeof item === "string" || typeof item === "number"
|
|
131
|
+
? String(item).trim()
|
|
132
|
+
: "",
|
|
133
|
+
)
|
|
134
|
+
.filter((item) => item.length > 0);
|
|
135
|
+
return cleaned.length > 0 ? cleaned : undefined;
|
|
136
|
+
}
|
|
137
|
+
|
|
123
138
|
/**
|
|
124
139
|
* Accepted MIME-type / extension patterns for a `file_upload` surface.
|
|
125
140
|
*
|
|
@@ -137,14 +152,7 @@ const FileUploadAcceptedTypesSchema = z.preprocess((value) => {
|
|
|
137
152
|
: Array.isArray(value)
|
|
138
153
|
? value
|
|
139
154
|
: [];
|
|
140
|
-
|
|
141
|
-
.map((item) =>
|
|
142
|
-
typeof item === "string" || typeof item === "number"
|
|
143
|
-
? String(item).trim()
|
|
144
|
-
: "",
|
|
145
|
-
)
|
|
146
|
-
.filter((item) => item.length > 0);
|
|
147
|
-
return cleaned.length > 0 ? cleaned : undefined;
|
|
155
|
+
return cleanedStringEntries(items);
|
|
148
156
|
}, z.array(z.string()).optional());
|
|
149
157
|
|
|
150
158
|
export const FileUploadSurfaceDataSchema = z.object({
|
|
@@ -238,6 +246,19 @@ export const ChoiceSurfaceDataSchema = z.object({
|
|
|
238
246
|
});
|
|
239
247
|
export type ChoiceSurfaceData = z.infer<typeof ChoiceSurfaceDataSchema>;
|
|
240
248
|
|
|
249
|
+
/**
|
|
250
|
+
* Requested OAuth scopes for an `oauth_connect` surface.
|
|
251
|
+
*
|
|
252
|
+
* Unlike `FileUploadAcceptedTypesSchema`, a bare string is NOT split on
|
|
253
|
+
* commas: OAuth scopes are opaque URIs, so only arrays are accepted.
|
|
254
|
+
* Entries are stringified and trimmed, blanks are dropped, and an empty
|
|
255
|
+
* result or any non-array value collapses to `undefined` (use defaults).
|
|
256
|
+
*/
|
|
257
|
+
const RequestedScopesSchema = z.preprocess(
|
|
258
|
+
(value) => (Array.isArray(value) ? cleanedStringEntries(value) : undefined),
|
|
259
|
+
z.array(z.string()).optional(),
|
|
260
|
+
);
|
|
261
|
+
|
|
241
262
|
export const OAuthConnectSurfaceDataSchema = z.object({
|
|
242
263
|
/** OAuth provider key from the managed provider catalog, e.g. "google". */
|
|
243
264
|
providerKey: z
|
|
@@ -246,6 +267,13 @@ export const OAuthConnectSurfaceDataSchema = z.object({
|
|
|
246
267
|
z.string(),
|
|
247
268
|
)
|
|
248
269
|
.catch(""),
|
|
270
|
+
/**
|
|
271
|
+
* Optional OAuth scopes to request for the managed connection. A full
|
|
272
|
+
* replacement set: when present, the platform uses exactly these scopes
|
|
273
|
+
* instead of its defaults (it does not merge). Omit to use the platform's
|
|
274
|
+
* default scopes for the provider.
|
|
275
|
+
*/
|
|
276
|
+
requestedScopes: RequestedScopesSchema,
|
|
249
277
|
/** Optional display label. The client falls back to the provider catalog. */
|
|
250
278
|
displayName: tolerantString(),
|
|
251
279
|
/** Optional helper text. The client falls back to the provider catalog. */
|
|
@@ -15,6 +15,11 @@
|
|
|
15
15
|
* guardian decided off-channel (desktop), or the expiry sweep fired on a timer
|
|
16
16
|
* with no originating request in hand. Returns null for channels that have no
|
|
17
17
|
* deliverable route (e.g. email, the in-app vellum surface).
|
|
18
|
+
*
|
|
19
|
+
* Discord carries `dm=1`, which tells its transport that the `chatId` it is
|
|
20
|
+
* handed names a person to open a DM with rather than a channel to post in.
|
|
21
|
+
* Pair it with {@link resolveRequesterDeliveryTarget}, which supplies that
|
|
22
|
+
* person.
|
|
18
23
|
*/
|
|
19
24
|
export function resolveDeliverCallbackUrlForChannel(
|
|
20
25
|
channel: string,
|
|
@@ -24,7 +29,85 @@ export function resolveDeliverCallbackUrlForChannel(
|
|
|
24
29
|
case "whatsapp":
|
|
25
30
|
case "slack":
|
|
26
31
|
return `/deliver/${channel}`;
|
|
32
|
+
case "discord":
|
|
33
|
+
return "/deliver/discord?dm=1";
|
|
27
34
|
default:
|
|
28
35
|
return null;
|
|
29
36
|
}
|
|
30
37
|
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Whether a message posted back in-band on this channel can be kept to one
|
|
41
|
+
* reader.
|
|
42
|
+
*
|
|
43
|
+
* Slack can, with `chat.postEphemeral`. Discord cannot: it has no ephemeral
|
|
44
|
+
* message outside an interaction response, so anything posted into the room a
|
|
45
|
+
* guardian replied in, or the room a request came from, is readable by every
|
|
46
|
+
* member of the server. That applies to a decision notice and to a
|
|
47
|
+
* verification code alike, which is why the callers treat an in-band reply
|
|
48
|
+
* context as unusable for Discord and fall through to the DM route instead.
|
|
49
|
+
*
|
|
50
|
+
* Telegram and WhatsApp are trivially true: their conversation already has one
|
|
51
|
+
* reader.
|
|
52
|
+
*/
|
|
53
|
+
export function channelCanAddressOneReaderInBand(channel: string): boolean {
|
|
54
|
+
return channel !== "discord";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Whether a notice can be addressed to one person by their user id rather than
|
|
59
|
+
* to the conversation the request arrived in.
|
|
60
|
+
*
|
|
61
|
+
* Slack opens a 1:1 DM when a `U…` id is posted as the channel. Discord
|
|
62
|
+
* resolves a user snowflake to a DM channel on its `dm`-marked route. This is
|
|
63
|
+
* an OUTBOUND question only: it says a message can be put in front of one
|
|
64
|
+
* person, and nothing about whether they can answer it.
|
|
65
|
+
*/
|
|
66
|
+
export function channelDeliversToUserId(channel: string): boolean {
|
|
67
|
+
return channel === "slack" || channel === "discord";
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Whether a verification code can be sent straight to the requester, rather
|
|
72
|
+
* than handed to the guardian to relay out of band.
|
|
73
|
+
*
|
|
74
|
+
* Deliberately NOT the same set as {@link channelDeliversToUserId}, though it
|
|
75
|
+
* looks like it. That one asks whether a message reaches one person; this asks
|
|
76
|
+
* whether a code handshake can COMPLETE there, which additionally needs the
|
|
77
|
+
* reply to be heard. The copy this gates says "reply with it here", so a
|
|
78
|
+
* channel that can send into a DM but not receive from one would strand the
|
|
79
|
+
* requester holding a code they can never spend.
|
|
80
|
+
*
|
|
81
|
+
* Discord qualifies on both halves: its `dm`-marked route reaches the person,
|
|
82
|
+
* and `gateway/src/discord/admit.ts` admits DMs so the reply is heard.
|
|
83
|
+
*/
|
|
84
|
+
export function channelCanCompleteCodeHandshakeInDm(channel: string): boolean {
|
|
85
|
+
return channel === "slack" || channel === "discord";
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Resolve who a requester notice is addressed to on the callback-less route.
|
|
90
|
+
*
|
|
91
|
+
* A request's `requesterChatId` is wherever the request came from, and where
|
|
92
|
+
* the channel has a private route to a user id that room is one other people
|
|
93
|
+
* can read. "Your request was denied" posted into a community channel is worse
|
|
94
|
+
* than not sending it, so those channels address the requester's own user id
|
|
95
|
+
* instead and let their transport turn it into a DM.
|
|
96
|
+
*
|
|
97
|
+
* Telegram and WhatsApp fall through to the chat id because theirs already is
|
|
98
|
+
* the private one-to-one conversation. So does a request with no actor
|
|
99
|
+
* identity: there is nobody to open a DM with, and on the channels that need
|
|
100
|
+
* one the transport reports that as a delivery failure rather than posting to
|
|
101
|
+
* the room.
|
|
102
|
+
*/
|
|
103
|
+
export function resolveRequesterDeliveryTarget(params: {
|
|
104
|
+
channel: string;
|
|
105
|
+
requesterChatId: string;
|
|
106
|
+
requesterExternalUserId: string;
|
|
107
|
+
}): string {
|
|
108
|
+
const { channel, requesterChatId, requesterExternalUserId } = params;
|
|
109
|
+
if (channelDeliversToUserId(channel) && requesterExternalUserId) {
|
|
110
|
+
return requesterExternalUserId;
|
|
111
|
+
}
|
|
112
|
+
return requesterChatId;
|
|
113
|
+
}
|
|
@@ -28,7 +28,10 @@ import { deliverChannelReply } from "../runtime/gateway-client.js";
|
|
|
28
28
|
import { introductionMode } from "../runtime/introduction-policy.js";
|
|
29
29
|
import * as pendingInteractions from "../runtime/pending-interactions.js";
|
|
30
30
|
import { getLogger } from "../util/logger.js";
|
|
31
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
resolveDeliverCallbackUrlForChannel,
|
|
33
|
+
resolveRequesterDeliveryTarget,
|
|
34
|
+
} from "./guardian-channel-delivery.js";
|
|
32
35
|
|
|
33
36
|
const log = getLogger("guardian-expiry-notifier");
|
|
34
37
|
|
|
@@ -108,9 +111,10 @@ function releaseExpiredInteraction(request: GuardianRequestWire): void {
|
|
|
108
111
|
*
|
|
109
112
|
* The sweep is timer-driven and holds no inbound reply callback URL, so this
|
|
110
113
|
* mirrors the resolvers' off-channel (desktop) delivery path: post to the
|
|
111
|
-
* callback-less `/deliver/<channel>` route. On Slack the notice is
|
|
112
|
-
* the requester's DM via their user id rather than the channel id,
|
|
113
|
-
* never posted into a shared channel
|
|
114
|
+
* callback-less `/deliver/<channel>` route. On Slack and Discord the notice is
|
|
115
|
+
* routed to the requester's DM via their user id rather than the channel id,
|
|
116
|
+
* so it is never posted into a shared channel (see
|
|
117
|
+
* `resolveRequesterDeliveryTarget`). No-ops on channels without a deliverable
|
|
114
118
|
* route (e.g. email, the in-app vellum surface) or when the requester chat is
|
|
115
119
|
* unknown. Best-effort: a delivery failure is logged, never thrown.
|
|
116
120
|
*/
|
|
@@ -128,13 +132,11 @@ async function notifyRequesterOfExpiry(
|
|
|
128
132
|
return;
|
|
129
133
|
}
|
|
130
134
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
? requesterExternalUserId
|
|
137
|
-
: requesterChatId;
|
|
135
|
+
const targetChatId = resolveRequesterDeliveryTarget({
|
|
136
|
+
channel,
|
|
137
|
+
requesterChatId,
|
|
138
|
+
requesterExternalUserId,
|
|
139
|
+
});
|
|
138
140
|
|
|
139
141
|
try {
|
|
140
142
|
await deliverChannelReply(deliverUrl, {
|