@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
|
@@ -50,6 +50,20 @@ const CredentialPromptParams = z.object({
|
|
|
50
50
|
// Response type (shared with CLI consumer)
|
|
51
51
|
// ---------------------------------------------------------------------------
|
|
52
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Appended to every terminal success message.
|
|
55
|
+
*
|
|
56
|
+
* The prompt blocks until the user answers, so by the time a caller reads the
|
|
57
|
+
* result the secure input is already gone from the UI. A bare `ok: true` reads
|
|
58
|
+
* as "the prompt opened successfully", which leads a model to follow up with
|
|
59
|
+
* "the prompt is open, paste your value there" — pointing the user at a surface
|
|
60
|
+
* that has already closed. The user, having just submitted, re-answers a prompt
|
|
61
|
+
* that never reappears, and the flow loops. State the close explicitly so the
|
|
62
|
+
* only available reading is the correct one.
|
|
63
|
+
*/
|
|
64
|
+
const PROMPT_CLOSED_NOTICE =
|
|
65
|
+
"The secure prompt has closed — do not ask the user to enter this value again.";
|
|
66
|
+
|
|
53
67
|
export type CredentialPromptResult = {
|
|
54
68
|
ok: boolean;
|
|
55
69
|
/**
|
|
@@ -204,19 +218,26 @@ async function handleCredentialPrompt({ body = {} }: RouteHandlerArgs) {
|
|
|
204
218
|
ok: true,
|
|
205
219
|
service: validated.service,
|
|
206
220
|
field: validated.field,
|
|
207
|
-
message: `One-time credential provided for ${validated.service}/${validated.field}. The value was not saved and will be consumed by the next operation
|
|
221
|
+
message: `One-time credential provided for ${validated.service}/${validated.field}. The value was not saved and will be consumed by the next operation. ${PROMPT_CLOSED_NOTICE}`,
|
|
208
222
|
};
|
|
209
223
|
}
|
|
210
224
|
|
|
225
|
+
// A Slack channel token is routed through the channel config rather than the
|
|
226
|
+
// vault, so its connection status is what describes the outcome; every other
|
|
227
|
+
// credential reports the vault write.
|
|
211
228
|
const slackStatus = persisted.slackChannel
|
|
212
229
|
? formatSlackChannelStatus(persisted.slackChannel).trim()
|
|
213
230
|
: "";
|
|
231
|
+
const outcomeSummary =
|
|
232
|
+
slackStatus.length > 0
|
|
233
|
+
? slackStatus
|
|
234
|
+
: `Credential received from the user and stored as ${validated.service}/${validated.field}.`;
|
|
214
235
|
|
|
215
236
|
return {
|
|
216
237
|
ok: true,
|
|
217
238
|
service: validated.service,
|
|
218
239
|
field: validated.field,
|
|
219
|
-
message:
|
|
240
|
+
message: `${outcomeSummary} ${PROMPT_CLOSED_NOTICE}`,
|
|
220
241
|
};
|
|
221
242
|
}
|
|
222
243
|
|
|
@@ -50,7 +50,10 @@ function getDebugInfo() {
|
|
|
50
50
|
// Debug view counts every standard conversation, archived or not, so the
|
|
51
51
|
// diagnostics report doesn't undercount after the route-level default
|
|
52
52
|
// moved to "active".
|
|
53
|
-
const conversationCount = countConversations(
|
|
53
|
+
const conversationCount = countConversations({
|
|
54
|
+
conversationType: "standard",
|
|
55
|
+
archiveStatus: "all",
|
|
56
|
+
});
|
|
54
57
|
const memoryItemCount = getMemoryItemCount();
|
|
55
58
|
const dbSizeBytes = getDatabaseSizeBytes();
|
|
56
59
|
|
|
@@ -25,22 +25,18 @@ import {
|
|
|
25
25
|
DEFAULT_PROVIDER_CHOICES,
|
|
26
26
|
DefaultProviderSchema,
|
|
27
27
|
} from "../../config/schemas/llm.js";
|
|
28
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
computeConnectionAvailability,
|
|
30
|
+
CONNECTION_AVAILABILITY_STATUSES,
|
|
31
|
+
} from "../../providers/inference/connection-availability.js";
|
|
29
32
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
30
33
|
import { BadRequestError } from "./errors.js";
|
|
31
34
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
32
35
|
|
|
33
36
|
const availabilitySchema = z.object({
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"missing_connection",
|
|
38
|
-
"missing_credential",
|
|
39
|
-
"provider_mismatch",
|
|
40
|
-
"unsupported_auth",
|
|
41
|
-
"vellum_unauthenticated",
|
|
42
|
-
"unknown",
|
|
43
|
-
]),
|
|
37
|
+
// `missing_default` is this route's own verdict (no default provider is
|
|
38
|
+
// configured at all), so it extends the shared set rather than living in it.
|
|
39
|
+
status: z.enum([...CONNECTION_AVAILABILITY_STATUSES, "missing_default"]),
|
|
44
40
|
/** Present on every non-`ok` status: names the broken thing and the fix. */
|
|
45
41
|
message: z.string().optional(),
|
|
46
42
|
});
|
|
@@ -16,12 +16,17 @@ import {
|
|
|
16
16
|
getDocumentById,
|
|
17
17
|
getDocumentByWorkspacePath,
|
|
18
18
|
getDocumentsForConversation,
|
|
19
|
+
isDocumentAssociatedWithConversation,
|
|
19
20
|
refreshDocumentContentFromFile,
|
|
20
21
|
saveDocument,
|
|
21
22
|
} from "../../documents/document-store.js";
|
|
22
23
|
import { rawAll } from "../../persistence/raw-query.js";
|
|
23
24
|
import { getLogger } from "../../util/logger.js";
|
|
24
25
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
26
|
+
import {
|
|
27
|
+
getOriginClientId,
|
|
28
|
+
publishDocumentsChanged,
|
|
29
|
+
} from "../sync/resource-sync-events.js";
|
|
25
30
|
import { renderMarkdownToPDF } from "./document-pdf-renderer.js";
|
|
26
31
|
import {
|
|
27
32
|
BadRequestError,
|
|
@@ -159,6 +164,12 @@ function loadDocumentPayload(surfaceId: string): Record<string, unknown> {
|
|
|
159
164
|
* content has drifted from the bytes on disk (the file was edited outside the
|
|
160
165
|
* editor), the row is refreshed from the file before it is returned. Writes go
|
|
161
166
|
* the other way — the document store writes through to the file.
|
|
167
|
+
*
|
|
168
|
+
* The publishes here carry no origin client id on purpose. The only caller,
|
|
169
|
+
* `viewer-store.loadWorkspaceFileDocument`, opens the file and never
|
|
170
|
+
* invalidates its own document queries, so the client that creates the row is
|
|
171
|
+
* the one that most needs to hear about it: suppressing its own echo would
|
|
172
|
+
* leave its assets pill and Library without the document it just opened.
|
|
162
173
|
*/
|
|
163
174
|
function handleDocumentForWorkspaceFile({
|
|
164
175
|
body,
|
|
@@ -194,8 +205,13 @@ function handleDocumentForWorkspaceFile({
|
|
|
194
205
|
if (existing) {
|
|
195
206
|
// Opening the file from another conversation grants that conversation
|
|
196
207
|
// access, the same association the link route writes.
|
|
208
|
+
const alreadyLinked = isDocumentAssociatedWithConversation(
|
|
209
|
+
existing.surfaceId,
|
|
210
|
+
conversationId,
|
|
211
|
+
);
|
|
197
212
|
addDocumentConversation(existing.surfaceId, conversationId);
|
|
198
213
|
|
|
214
|
+
let refreshed = false;
|
|
199
215
|
if (existing.content !== fileText) {
|
|
200
216
|
const refresh = refreshDocumentContentFromFile(
|
|
201
217
|
existing.surfaceId,
|
|
@@ -204,11 +220,18 @@ function handleDocumentForWorkspaceFile({
|
|
|
204
220
|
if (!refresh.success) {
|
|
205
221
|
throw new InternalError(refresh.error);
|
|
206
222
|
}
|
|
223
|
+
refreshed = true;
|
|
207
224
|
log.info(
|
|
208
225
|
{ surfaceId: existing.surfaceId, workspacePath: relativePath },
|
|
209
226
|
"Refreshed file-backed document from disk",
|
|
210
227
|
);
|
|
211
228
|
}
|
|
229
|
+
|
|
230
|
+
// Reopening an unchanged, already-linked file writes nothing, so it must
|
|
231
|
+
// not invalidate every client's document list on each open.
|
|
232
|
+
if (!alreadyLinked || refreshed) {
|
|
233
|
+
publishDocumentsChanged();
|
|
234
|
+
}
|
|
212
235
|
return loadDocumentPayload(existing.surfaceId);
|
|
213
236
|
}
|
|
214
237
|
|
|
@@ -227,7 +250,14 @@ function handleDocumentForWorkspaceFile({
|
|
|
227
250
|
if (!raced) {
|
|
228
251
|
throw new InternalError(created.error);
|
|
229
252
|
}
|
|
253
|
+
const racedAlreadyLinked = isDocumentAssociatedWithConversation(
|
|
254
|
+
raced.surfaceId,
|
|
255
|
+
conversationId,
|
|
256
|
+
);
|
|
230
257
|
addDocumentConversation(raced.surfaceId, conversationId);
|
|
258
|
+
if (!racedAlreadyLinked) {
|
|
259
|
+
publishDocumentsChanged();
|
|
260
|
+
}
|
|
231
261
|
return loadDocumentPayload(raced.surfaceId);
|
|
232
262
|
}
|
|
233
263
|
|
|
@@ -235,6 +265,7 @@ function handleDocumentForWorkspaceFile({
|
|
|
235
265
|
{ surfaceId, workspacePath: relativePath, conversationId },
|
|
236
266
|
"Bound workspace file to a new document",
|
|
237
267
|
);
|
|
268
|
+
publishDocumentsChanged();
|
|
238
269
|
return loadDocumentPayload(surfaceId);
|
|
239
270
|
}
|
|
240
271
|
|
|
@@ -325,7 +356,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
325
356
|
success: z.literal(true),
|
|
326
357
|
surfaceId: z.string(),
|
|
327
358
|
}),
|
|
328
|
-
handler: ({ body }) => {
|
|
359
|
+
handler: ({ body, headers }) => {
|
|
329
360
|
const { surfaceId, conversationId, title, content, wordCount } = (body ??
|
|
330
361
|
{}) as {
|
|
331
362
|
surfaceId?: string;
|
|
@@ -362,6 +393,12 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
362
393
|
if (!result.success) {
|
|
363
394
|
throw new InternalError(result.error);
|
|
364
395
|
}
|
|
396
|
+
// Every save moves `updated_at`, which both document lists order by and
|
|
397
|
+
// the Library renders next to the word count, so a content-only save
|
|
398
|
+
// changes what the list surfaces show. The publish coalesces, which
|
|
399
|
+
// bounds the web editor's per-keystroke autosave to one broadcast per
|
|
400
|
+
// second, and the saving client suppresses its own echo by origin id.
|
|
401
|
+
publishDocumentsChanged(getOriginClientId(headers));
|
|
365
402
|
return result;
|
|
366
403
|
},
|
|
367
404
|
},
|
|
@@ -426,6 +463,12 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
426
463
|
{ surfaceId: pathParams!.id, conversationId },
|
|
427
464
|
"Linked document to conversation",
|
|
428
465
|
);
|
|
466
|
+
// No origin client id: the only caller, `document-viewer-page`, links the
|
|
467
|
+
// document and then navigates to the conversation whose assets pill must
|
|
468
|
+
// now list it, without invalidating anything itself. Suppressing its own
|
|
469
|
+
// echo would land it on a conversation whose pill is missing the document
|
|
470
|
+
// it just linked.
|
|
471
|
+
publishDocumentsChanged();
|
|
429
472
|
return { success: true as const };
|
|
430
473
|
},
|
|
431
474
|
},
|
|
@@ -42,7 +42,10 @@ import type { ReplaySubscriber } from "../assistant-stream-state.js";
|
|
|
42
42
|
import { getReplayWindow } from "../assistant-stream-state.js";
|
|
43
43
|
import { ACTOR_PRINCIPALS, GATEWAY_PRINCIPALS } from "../auth/route-policy.js";
|
|
44
44
|
import { DEFAULT_HEARTBEAT_INTERVAL_MS } from "../client-health.js";
|
|
45
|
-
import {
|
|
45
|
+
import {
|
|
46
|
+
resolveActorPrincipalIdForLocalGuardian,
|
|
47
|
+
resolveActorPrincipalIdForLocalGuardianSync,
|
|
48
|
+
} from "../local-actor-identity.js";
|
|
46
49
|
import {
|
|
47
50
|
BadRequestError,
|
|
48
51
|
NotFoundError,
|
|
@@ -452,6 +455,30 @@ export function handleSubscribeAssistantEvents(
|
|
|
452
455
|
throw err;
|
|
453
456
|
}
|
|
454
457
|
|
|
458
|
+
// Self-heal for dev-bypass connections: the sync resolution above reads
|
|
459
|
+
// only the guardian-delivery cache, which can be cold at connect time.
|
|
460
|
+
// Without this, the subscription would carry no principal for its whole
|
|
461
|
+
// lifetime and every host-proxy result would 403. Fire-and-forget so the
|
|
462
|
+
// stream is not delayed; keyed by connectionId so a reconnect race cannot
|
|
463
|
+
// patch the subscription that replaced this one.
|
|
464
|
+
if (
|
|
465
|
+
clientId &&
|
|
466
|
+
interfaceId &&
|
|
467
|
+
actorPrincipalId == null &&
|
|
468
|
+
rawActorPrincipalId?.trim() === "dev-bypass"
|
|
469
|
+
) {
|
|
470
|
+
void resolveActorPrincipalIdForLocalGuardian("dev-bypass")
|
|
471
|
+
.then((resolved) => {
|
|
472
|
+
if (resolved) {
|
|
473
|
+
hub.fillClientActorPrincipalId(sub.connectionId, resolved);
|
|
474
|
+
}
|
|
475
|
+
})
|
|
476
|
+
.catch(() => {
|
|
477
|
+
// Best-effort: an unreachable gateway leaves the record unhealed;
|
|
478
|
+
// the next reconnect retries.
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
|
|
455
482
|
const stream = new ReadableStream<Uint8Array>(
|
|
456
483
|
{
|
|
457
484
|
start(controller) {
|
|
@@ -19,6 +19,7 @@ import type {
|
|
|
19
19
|
HostAppControlResultPayload,
|
|
20
20
|
HostAppControlState,
|
|
21
21
|
} from "../../daemon/message-types/host-app-control.js";
|
|
22
|
+
import { assistantEventHub } from "../assistant-event-hub.js";
|
|
22
23
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
23
24
|
import {
|
|
24
25
|
enforceSameActorOrThrow,
|
|
@@ -118,6 +119,7 @@ async function handleHostAppControlResult({ body, headers }: RouteHandlerArgs) {
|
|
|
118
119
|
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
119
120
|
targetClientId: peeked.targetClientId,
|
|
120
121
|
op: "host_app_control",
|
|
122
|
+
hubForMissingTarget: assistantEventHub,
|
|
121
123
|
});
|
|
122
124
|
}
|
|
123
125
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
|
|
9
9
|
import { HostBashProxy } from "../../daemon/host-bash-proxy.js";
|
|
10
|
+
import { assistantEventHub } from "../assistant-event-hub.js";
|
|
10
11
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
11
12
|
import {
|
|
12
13
|
enforceSameActorOrThrow,
|
|
@@ -99,6 +100,7 @@ async function handleHostBashResult({ body, headers }: RouteHandlerArgs) {
|
|
|
99
100
|
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
100
101
|
targetClientId,
|
|
101
102
|
op: "host_bash",
|
|
103
|
+
hubForMissingTarget: assistantEventHub,
|
|
102
104
|
});
|
|
103
105
|
}
|
|
104
106
|
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
publishCdpEvent,
|
|
12
12
|
} from "../../browser-session/events.js";
|
|
13
13
|
import { clearPinnedTabByTabId } from "../../tools/browser/pinned-tabs.js";
|
|
14
|
+
import { assistantEventHub } from "../assistant-event-hub.js";
|
|
14
15
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
15
16
|
import {
|
|
16
17
|
enforceSameActorOrThrow,
|
|
@@ -137,6 +138,7 @@ export async function resolveHostBrowserResultByRequestId(
|
|
|
137
138
|
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
138
139
|
targetClientId: peeked.targetClientId,
|
|
139
140
|
op: "host_browser",
|
|
141
|
+
hubForMissingTarget: assistantEventHub,
|
|
140
142
|
});
|
|
141
143
|
} catch (err) {
|
|
142
144
|
// enforceSameActorOrThrow throws ForbiddenError on rejection.
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
|
|
9
9
|
import { findConversation } from "../../daemon/conversation-registry.js";
|
|
10
|
+
import { assistantEventHub } from "../assistant-event-hub.js";
|
|
10
11
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
11
12
|
import {
|
|
12
13
|
enforceSameActorOrThrow,
|
|
@@ -107,6 +108,7 @@ async function handleHostCuResult({ body, headers }: RouteHandlerArgs) {
|
|
|
107
108
|
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
108
109
|
targetClientId: peeked.targetClientId,
|
|
109
110
|
op: "host_cu",
|
|
111
|
+
hubForMissingTarget: assistantEventHub,
|
|
110
112
|
});
|
|
111
113
|
}
|
|
112
114
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
|
|
9
9
|
import { HostFileProxy } from "../../daemon/host-file-proxy.js";
|
|
10
|
+
import { assistantEventHub } from "../assistant-event-hub.js";
|
|
10
11
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
11
12
|
import {
|
|
12
13
|
enforceSameActorOrThrow,
|
|
@@ -97,6 +98,7 @@ async function handleHostFileResult({ body, headers }: RouteHandlerArgs) {
|
|
|
97
98
|
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
98
99
|
targetClientId: peeked.targetClientId,
|
|
99
100
|
op: "host_file",
|
|
101
|
+
hubForMissingTarget: assistantEventHub,
|
|
100
102
|
});
|
|
101
103
|
}
|
|
102
104
|
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
|
|
10
10
|
import { HostTransferProxy } from "../../daemon/host-transfer-proxy.js";
|
|
11
|
+
import { assistantEventHub } from "../assistant-event-hub.js";
|
|
11
12
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
12
13
|
import {
|
|
13
14
|
enforceSameActorOrThrow,
|
|
@@ -83,6 +84,7 @@ async function handleTransferContentGet({
|
|
|
83
84
|
match.proxy.getTargetActorPrincipalIdForTransfer(transferId),
|
|
84
85
|
targetClientId,
|
|
85
86
|
op: "host_transfer",
|
|
87
|
+
hubForMissingTarget: assistantEventHub,
|
|
86
88
|
});
|
|
87
89
|
}
|
|
88
90
|
|
|
@@ -168,6 +170,7 @@ async function handleTransferContentPut({
|
|
|
168
170
|
match.proxy.getTargetActorPrincipalIdForTransfer(transferId),
|
|
169
171
|
targetClientId,
|
|
170
172
|
op: "host_transfer",
|
|
173
|
+
hubForMissingTarget: assistantEventHub,
|
|
171
174
|
});
|
|
172
175
|
}
|
|
173
176
|
|
|
@@ -240,6 +243,7 @@ async function handleTransferResult({ body, headers }: RouteHandlerArgs) {
|
|
|
240
243
|
targetActorPrincipalId: peeked.targetActorPrincipalId,
|
|
241
244
|
targetClientId: peeked.targetClientId,
|
|
242
245
|
op: "host_transfer",
|
|
246
|
+
hubForMissingTarget: assistantEventHub,
|
|
243
247
|
});
|
|
244
248
|
}
|
|
245
249
|
|
|
@@ -230,15 +230,15 @@ export function handleHealth(): Response {
|
|
|
230
230
|
}
|
|
231
231
|
|
|
232
232
|
/** Disk usage for the health payload; null when it can't be measured. */
|
|
233
|
-
function sampleDiskUsageInfo(): ReturnType<typeof getDiskUsageInfo> {
|
|
233
|
+
async function sampleDiskUsageInfo(): ReturnType<typeof getDiskUsageInfo> {
|
|
234
234
|
try {
|
|
235
|
-
return getDiskUsageInfo();
|
|
235
|
+
return await getDiskUsageInfo();
|
|
236
236
|
} catch {
|
|
237
237
|
return null;
|
|
238
238
|
}
|
|
239
239
|
}
|
|
240
240
|
|
|
241
|
-
function getDetailedHealth() {
|
|
241
|
+
async function getDetailedHealth() {
|
|
242
242
|
let profiler: ReturnType<typeof getProfilerRuntimeStatus> | undefined;
|
|
243
243
|
try {
|
|
244
244
|
profiler = getProfilerRuntimeStatus();
|
|
@@ -260,7 +260,7 @@ function getDetailedHealth() {
|
|
|
260
260
|
status: "healthy",
|
|
261
261
|
timestamp: new Date().toISOString(),
|
|
262
262
|
version: APP_VERSION,
|
|
263
|
-
disk: sampleDiskUsageInfo(),
|
|
263
|
+
disk: await sampleDiskUsageInfo(),
|
|
264
264
|
memory: getMemoryInfo(),
|
|
265
265
|
cpu: getCpuInfo(),
|
|
266
266
|
migrations: {
|
|
@@ -280,8 +280,8 @@ function getDetailedHealth() {
|
|
|
280
280
|
};
|
|
281
281
|
}
|
|
282
282
|
|
|
283
|
-
export function handleDetailedHealth(): Response {
|
|
284
|
-
return Response.json(getDetailedHealth());
|
|
283
|
+
export async function handleDetailedHealth(): Promise<Response> {
|
|
284
|
+
return Response.json(await getDetailedHealth());
|
|
285
285
|
}
|
|
286
286
|
|
|
287
287
|
type UnreadyDbMigrationReadiness = Extract<
|
|
@@ -1816,7 +1816,7 @@ async function persistBackfilledSlackMessage(params: {
|
|
|
1816
1816
|
);
|
|
1817
1817
|
continue;
|
|
1818
1818
|
}
|
|
1819
|
-
attachInlineAttachmentToMessage(
|
|
1819
|
+
await attachInlineAttachmentToMessage(
|
|
1820
1820
|
persisted.id,
|
|
1821
1821
|
i,
|
|
1822
1822
|
downloaded.filename,
|
|
@@ -1863,21 +1863,21 @@ async function persistBackfilledSlackMessage(params: {
|
|
|
1863
1863
|
updateMessageContent(
|
|
1864
1864
|
persisted.id,
|
|
1865
1865
|
JSON.stringify(
|
|
1866
|
-
buildBackfilledSlackContentBlocks(rawText, hydratedAttachments),
|
|
1866
|
+
await buildBackfilledSlackContentBlocks(rawText, hydratedAttachments),
|
|
1867
1867
|
),
|
|
1868
1868
|
);
|
|
1869
1869
|
}
|
|
1870
1870
|
}
|
|
1871
1871
|
|
|
1872
|
-
function buildBackfilledSlackContentBlocks(
|
|
1872
|
+
async function buildBackfilledSlackContentBlocks(
|
|
1873
1873
|
text: string,
|
|
1874
1874
|
attachments: MessageAttachmentInput[],
|
|
1875
|
-
): ContentBlock[] {
|
|
1875
|
+
): Promise<ContentBlock[]> {
|
|
1876
1876
|
const blocks: ContentBlock[] = [];
|
|
1877
1877
|
if (text.trim().length > 0) {
|
|
1878
1878
|
blocks.push({ type: "text", text });
|
|
1879
1879
|
}
|
|
1880
|
-
blocks.push(...attachmentsToContentBlocks(attachments));
|
|
1880
|
+
blocks.push(...(await attachmentsToContentBlocks(attachments)));
|
|
1881
1881
|
return blocks;
|
|
1882
1882
|
}
|
|
1883
1883
|
|
|
@@ -980,7 +980,12 @@ async function initiateVerificationChallenge(params: {
|
|
|
980
980
|
try {
|
|
981
981
|
[existingChallenge, existingSession] = await Promise.all([
|
|
982
982
|
getPendingSession(sourceChannel),
|
|
983
|
-
|
|
983
|
+
// Scoped to this sender. Reading the channel's latest and comparing
|
|
984
|
+
// its `expectedExternalUserId` misses their session whenever somebody
|
|
985
|
+
// else started more recently.
|
|
986
|
+
findActiveSession(sourceChannel, {
|
|
987
|
+
expectedExternalUserId: senderUserId,
|
|
988
|
+
}),
|
|
984
989
|
]);
|
|
985
990
|
} catch (err) {
|
|
986
991
|
log.warn(
|
|
@@ -992,8 +997,7 @@ async function initiateVerificationChallenge(params: {
|
|
|
992
997
|
const senderHasPending =
|
|
993
998
|
(existingChallenge &&
|
|
994
999
|
existingChallenge.expectedExternalUserId === senderUserId) ||
|
|
995
|
-
|
|
996
|
-
existingSession.expectedExternalUserId === senderUserId);
|
|
1000
|
+
existingSession != null;
|
|
997
1001
|
if (senderHasPending) {
|
|
998
1002
|
log.debug(
|
|
999
1003
|
{
|
|
@@ -386,6 +386,20 @@ export function processChannelMessageInBackground(
|
|
|
386
386
|
// Telegram typing heartbeat
|
|
387
387
|
// ---------------------------------------------------------------------------
|
|
388
388
|
|
|
389
|
+
/**
|
|
390
|
+
* How often the typing status is re-sent while a turn runs.
|
|
391
|
+
*
|
|
392
|
+
* `sendChatAction` sets a status that expires on its own after a few seconds,
|
|
393
|
+
* and the Bot API offers no stop/start pair to hold one open, so showing
|
|
394
|
+
* typing across a multi-second turn means re-sending on a timer. The interval
|
|
395
|
+
* has to stay under that expiry or the indicator blinks off between beats;
|
|
396
|
+
* anyone changing it should check the current window first.
|
|
397
|
+
*
|
|
398
|
+
* No explicit stop is needed on the delivery path: Telegram clears the status
|
|
399
|
+
* as soon as the bot sends a message.
|
|
400
|
+
*
|
|
401
|
+
* https://core.telegram.org/bots/api#sendchataction
|
|
402
|
+
*/
|
|
389
403
|
const TELEGRAM_TYPING_INTERVAL_MS = 4_000;
|
|
390
404
|
|
|
391
405
|
function shouldEmitTelegramTyping(
|
|
@@ -26,7 +26,7 @@ import { sendTelegramReply } from "../../../messaging/providers/telegram-bot/sen
|
|
|
26
26
|
import { getLogger } from "../../../util/logger.js";
|
|
27
27
|
import { RESEND_COOLDOWN_MS } from "../../verification-outbound-actions.js";
|
|
28
28
|
import {
|
|
29
|
-
|
|
29
|
+
composeVerificationText,
|
|
30
30
|
GUARDIAN_VERIFY_TEMPLATE_KEYS,
|
|
31
31
|
} from "../../verification-templates.js";
|
|
32
32
|
|
|
@@ -194,7 +194,7 @@ export async function handleBootstrapIntercept(
|
|
|
194
194
|
const newSession: CreateOutboundSessionResult = minted;
|
|
195
195
|
|
|
196
196
|
// Compose and send the verification prompt via Telegram
|
|
197
|
-
const telegramBody =
|
|
197
|
+
const telegramBody = composeVerificationText(
|
|
198
198
|
GUARDIAN_VERIFY_TEMPLATE_KEYS.TELEGRAM_CHALLENGE_REQUEST,
|
|
199
199
|
{
|
|
200
200
|
code: newSession.secret,
|
|
@@ -122,8 +122,9 @@ describe("handleGuardianActivationIntercept", () => {
|
|
|
122
122
|
identityBindingStatus: "bound",
|
|
123
123
|
destinationAddress: "chat-123",
|
|
124
124
|
verificationPurpose: "guardian",
|
|
125
|
-
// No session was read
|
|
126
|
-
|
|
125
|
+
// No session was read for this sender, so the create is a
|
|
126
|
+
// sender-scoped create-if-absent.
|
|
127
|
+
ifNoneActiveForExternalUserId: "user-42",
|
|
127
128
|
});
|
|
128
129
|
|
|
129
130
|
// Verify deliverChannelReply was called with the welcome/verify message
|
|
@@ -243,7 +244,11 @@ describe("handleGuardianActivationIntercept", () => {
|
|
|
243
244
|
expect(emitNotificationSignalCalls).toHaveLength(0);
|
|
244
245
|
});
|
|
245
246
|
|
|
246
|
-
test("
|
|
247
|
+
test("someone else verifying does not turn this sender away", async () => {
|
|
248
|
+
// The read is scoped to the sender, so another person's live session is
|
|
249
|
+
// invisible here and this activation proceeds as a first one. Without the
|
|
250
|
+
// scope it would return the stranger's session and this sender would be
|
|
251
|
+
// told a verification is "already in progress" that is not theirs.
|
|
247
252
|
gatewaySessions.state.activeSession = {
|
|
248
253
|
id: "existing-sess",
|
|
249
254
|
channel: "telegram",
|
|
@@ -254,16 +259,14 @@ describe("handleGuardianActivationIntercept", () => {
|
|
|
254
259
|
|
|
255
260
|
const result = await handleGuardianActivationIntercept(makeParams());
|
|
256
261
|
|
|
257
|
-
|
|
258
|
-
expect(result).not.toBeNull();
|
|
259
|
-
const body = result!;
|
|
260
|
-
expect(body).toEqual({ accepted: true, guardianActivation: true });
|
|
262
|
+
expect(result).toEqual({ accepted: true, guardianActivation: true });
|
|
261
263
|
expect(gatewaySessions.calls.create).toHaveLength(1);
|
|
262
|
-
//
|
|
263
|
-
//
|
|
264
|
+
// Carrying the guard is what keeps the stranger's code alive: the mint
|
|
265
|
+
// supersedes by bound identity, and this sender is not that identity.
|
|
264
266
|
expect(
|
|
265
|
-
(gatewaySessions.calls.create[0] as Record<string, unknown>)
|
|
266
|
-
|
|
267
|
+
(gatewaySessions.calls.create[0] as Record<string, unknown>)
|
|
268
|
+
.ifNoneActiveForExternalUserId,
|
|
269
|
+
).toBe("user-42");
|
|
267
270
|
expect(emitNotificationSignalCalls).toHaveLength(1);
|
|
268
271
|
});
|
|
269
272
|
|
|
@@ -133,7 +133,11 @@ export async function handleGuardianActivationIntercept(
|
|
|
133
133
|
// normal pipeline handle the message.
|
|
134
134
|
let existingSession: VerificationSessionWire | null;
|
|
135
135
|
try {
|
|
136
|
-
|
|
136
|
+
// This sender's own session. The channel may carry others, and what the
|
|
137
|
+
// guard below needs to know is whether THIS activation is a duplicate.
|
|
138
|
+
existingSession = await findActiveSession(sourceChannel, {
|
|
139
|
+
expectedExternalUserId: rawSenderId,
|
|
140
|
+
});
|
|
137
141
|
} catch (err) {
|
|
138
142
|
log.warn(
|
|
139
143
|
{ err, sourceChannel },
|
|
@@ -158,25 +162,18 @@ export async function handleGuardianActivationIntercept(
|
|
|
158
162
|
return { accepted: true, guardianActivationPending: true };
|
|
159
163
|
};
|
|
160
164
|
|
|
165
|
+
// The read is scoped to this sender, so anything it returned is this
|
|
166
|
+
// sender's own activation already in flight.
|
|
161
167
|
if (existingSession) {
|
|
162
|
-
|
|
163
|
-
// user triggered the session, let this sender proceed (they'll supersede
|
|
164
|
-
// the stale session via createOutboundSession's revocation logic).
|
|
165
|
-
const sessionOwner =
|
|
166
|
-
existingSession.expectedExternalUserId ?? existingSession.expectedChatId;
|
|
167
|
-
if (
|
|
168
|
-
sessionOwner === rawSenderId ||
|
|
169
|
-
sessionOwner === conversationExternalId
|
|
170
|
-
) {
|
|
171
|
-
return respondActivationPending();
|
|
172
|
-
}
|
|
168
|
+
return respondActivationPending();
|
|
173
169
|
}
|
|
174
170
|
|
|
175
171
|
// ── Create verification session ──
|
|
176
|
-
//
|
|
177
|
-
//
|
|
178
|
-
// between conflicts here instead of revoking that
|
|
179
|
-
//
|
|
172
|
+
// The read above saw no session for this sender, so the sender-scoped
|
|
173
|
+
// create-if-absent makes the mint atomic: a concurrent activation from the
|
|
174
|
+
// same sender that minted in between conflicts here instead of revoking that
|
|
175
|
+
// first code. Scoped to the sender rather than the channel, because another
|
|
176
|
+
// person verifying at the same time is ordinary and must not block this.
|
|
180
177
|
let sessionResult: Awaited<
|
|
181
178
|
ReturnType<typeof createOutboundSessionConditional>
|
|
182
179
|
>;
|
|
@@ -188,7 +185,7 @@ export async function handleGuardianActivationIntercept(
|
|
|
188
185
|
identityBindingStatus: "bound",
|
|
189
186
|
destinationAddress: conversationExternalId,
|
|
190
187
|
verificationPurpose: "guardian",
|
|
191
|
-
|
|
188
|
+
ifNoneActiveForExternalUserId: rawSenderId,
|
|
192
189
|
});
|
|
193
190
|
} catch (err) {
|
|
194
191
|
log.warn(
|