@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
|
@@ -116,6 +116,7 @@ import {
|
|
|
116
116
|
isConversationProcessing,
|
|
117
117
|
isHiddenMessageMetadata,
|
|
118
118
|
isProviderErrorMetadata,
|
|
119
|
+
isSuppressedQueuedMessage,
|
|
119
120
|
isSystemCardMetadata,
|
|
120
121
|
type MessageRow,
|
|
121
122
|
recordConversationPersistedSeq,
|
|
@@ -172,6 +173,7 @@ import {
|
|
|
172
173
|
emitCannedMessageComplete,
|
|
173
174
|
persistCannedAssistantCard,
|
|
174
175
|
} from "./canned-message-complete.js";
|
|
176
|
+
import { scheduleCannedReplyRelease } from "./canned-reply-release.js";
|
|
175
177
|
import { buildChannelMetadata } from "./channel-metadata.js";
|
|
176
178
|
import {
|
|
177
179
|
BadRequestError,
|
|
@@ -639,7 +641,7 @@ async function tryConsumeGuardianReply(params: {
|
|
|
639
641
|
attachments,
|
|
640
642
|
});
|
|
641
643
|
|
|
642
|
-
const cleanUserMessage = createUserMessage(content, attachments);
|
|
644
|
+
const cleanUserMessage = await createUserMessage(content, attachments);
|
|
643
645
|
const llmUserMessage = enrichMessageWithSourcePaths(
|
|
644
646
|
cleanUserMessage,
|
|
645
647
|
attachments,
|
|
@@ -691,6 +693,68 @@ async function tryConsumeGuardianReply(params: {
|
|
|
691
693
|
return { consumed: true, messageId };
|
|
692
694
|
}
|
|
693
695
|
|
|
696
|
+
/**
|
|
697
|
+
* Read the notification discriminators a client uses to keep daemon-injected
|
|
698
|
+
* rows out of the rendered transcript off a message's parsed metadata.
|
|
699
|
+
*
|
|
700
|
+
* One extraction shared by the persisted-history rows and the queued rows
|
|
701
|
+
* synthesized from the in-memory queue, so a row carries the same flags
|
|
702
|
+
* whichever side of the drain it is fetched from.
|
|
703
|
+
*/
|
|
704
|
+
function extractNotificationDiscriminators(
|
|
705
|
+
meta: Record<string, unknown>,
|
|
706
|
+
): Pick<
|
|
707
|
+
ConversationMessage,
|
|
708
|
+
"subagentNotification" | "acpNotification" | "backgroundEventNotification"
|
|
709
|
+
> {
|
|
710
|
+
const discriminators: Pick<
|
|
711
|
+
ConversationMessage,
|
|
712
|
+
"subagentNotification" | "acpNotification" | "backgroundEventNotification"
|
|
713
|
+
> = {};
|
|
714
|
+
|
|
715
|
+
// Every wake persists a `<background_event source="...">` trigger row
|
|
716
|
+
// (see `persistWakeTriggerMessage`) that the LLM reads. Flag any such
|
|
717
|
+
// row so clients hide it from the transcript like a subagent/ACP
|
|
718
|
+
// notification: the user-facing "Conversation Woke" card (or, for a
|
|
719
|
+
// backgrounded bash run, the inline terminal card) carries the status.
|
|
720
|
+
if (isBackgroundEventMetadata(meta)) {
|
|
721
|
+
discriminators.backgroundEventNotification = true;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
const subagent = meta.subagentNotification as
|
|
725
|
+
| Record<string, unknown>
|
|
726
|
+
| undefined;
|
|
727
|
+
if (
|
|
728
|
+
subagent &&
|
|
729
|
+
typeof subagent.subagentId === "string" &&
|
|
730
|
+
typeof subagent.label === "string"
|
|
731
|
+
) {
|
|
732
|
+
discriminators.subagentNotification = {
|
|
733
|
+
subagentId: subagent.subagentId,
|
|
734
|
+
label: subagent.label,
|
|
735
|
+
status:
|
|
736
|
+
typeof subagent.status === "string" ? subagent.status : "completed",
|
|
737
|
+
...(typeof subagent.error === "string" ? { error: subagent.error } : {}),
|
|
738
|
+
...(typeof subagent.conversationId === "string"
|
|
739
|
+
? { conversationId: subagent.conversationId }
|
|
740
|
+
: {}),
|
|
741
|
+
...(typeof subagent.objective === "string"
|
|
742
|
+
? { objective: subagent.objective }
|
|
743
|
+
: {}),
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
const acp = meta.acpNotification as Record<string, unknown> | undefined;
|
|
748
|
+
if (acp && typeof acp.acpSessionId === "string") {
|
|
749
|
+
discriminators.acpNotification = {
|
|
750
|
+
acpSessionId: acp.acpSessionId,
|
|
751
|
+
...(typeof acp.agent === "string" ? { agent: acp.agent } : {}),
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
return discriminators;
|
|
756
|
+
}
|
|
757
|
+
|
|
694
758
|
/**
|
|
695
759
|
* Render the live conversation's in-memory message queue into history rows.
|
|
696
760
|
*
|
|
@@ -713,12 +777,17 @@ function buildQueuedMessagePayloads(
|
|
|
713
777
|
return [];
|
|
714
778
|
}
|
|
715
779
|
|
|
716
|
-
//
|
|
717
|
-
// persisted row, and here the in-memory queue window: a latest-page
|
|
718
|
-
// while the item still awaits drain must not surface it as a queued
|
|
780
|
+
// Rows that never render as a user bubble are suppressed at every stage —
|
|
781
|
+
// echo, persisted row, and here the in-memory queue window: a latest-page
|
|
782
|
+
// fetch while the item still awaits drain must not surface it as a queued
|
|
783
|
+
// bubble. That covers hidden sends and the daemon's own injected
|
|
784
|
+
// notifications (a subagent's completion summary enqueued into a busy
|
|
785
|
+
// parent, an ACP run outcome, a wake trigger) — the user follows those
|
|
786
|
+
// through their inline cards, never as a queued message they could steer or
|
|
787
|
+
// cancel.
|
|
719
788
|
return conversation
|
|
720
789
|
.snapshotQueuedMessages()
|
|
721
|
-
.filter((item) => !
|
|
790
|
+
.filter((item) => !isSuppressedQueuedMessage(item.metadata))
|
|
722
791
|
.map((item, index) => {
|
|
723
792
|
const text = item.displayContent ?? item.content;
|
|
724
793
|
const attachments: RuntimeAttachmentMetadata[] = item.attachments.map(
|
|
@@ -755,15 +824,19 @@ function buildQueuedMessagePayloads(
|
|
|
755
824
|
...(item.clientMessageId
|
|
756
825
|
? { clientMessageId: item.clientMessageId }
|
|
757
826
|
: {}),
|
|
827
|
+
// The filter above already drops every daemon-injected notification,
|
|
828
|
+
// so these flags are redundant today. Carrying them keeps a queued row
|
|
829
|
+
// self-describing on the wire, matching its persisted counterpart.
|
|
830
|
+
...extractNotificationDiscriminators(item.metadata ?? {}),
|
|
758
831
|
queueStatus: "queued" as const,
|
|
759
832
|
queuePosition: index + 1,
|
|
760
833
|
};
|
|
761
834
|
});
|
|
762
835
|
}
|
|
763
836
|
|
|
764
|
-
export function handleListMessages({
|
|
837
|
+
export async function handleListMessages({
|
|
765
838
|
queryParams,
|
|
766
|
-
}: RouteHandlerArgs): Record<string, unknown
|
|
839
|
+
}: RouteHandlerArgs): Promise<Record<string, unknown>> {
|
|
767
840
|
const conversationId = queryParams?.conversationId;
|
|
768
841
|
const conversationKey = queryParams?.conversationKey;
|
|
769
842
|
|
|
@@ -920,23 +993,14 @@ export function handleListMessages({
|
|
|
920
993
|
// was queued or its persistence was delayed (long assistant generation),
|
|
921
994
|
// sentAt captures the actual event time. Falls back to createdAt.
|
|
922
995
|
let sentAt: number | undefined;
|
|
923
|
-
let
|
|
924
|
-
|
|
925
|
-
subagentId: string;
|
|
926
|
-
label: string;
|
|
927
|
-
status: string;
|
|
928
|
-
error?: string;
|
|
929
|
-
conversationId?: string;
|
|
930
|
-
}
|
|
931
|
-
| undefined;
|
|
932
|
-
let acpNotification: { acpSessionId: string; agent?: string } | undefined;
|
|
933
|
-
let backgroundEventNotification: boolean | undefined;
|
|
996
|
+
let notifications: ReturnType<typeof extractNotificationDiscriminators> =
|
|
997
|
+
{};
|
|
934
998
|
let backgroundToolCompletion: ConversationMessage["backgroundToolCompletion"];
|
|
935
999
|
let systemCard: boolean | undefined;
|
|
936
1000
|
let providerError: ConversationMessage["providerError"];
|
|
937
1001
|
if (msg.metadata) {
|
|
938
1002
|
try {
|
|
939
|
-
const meta = JSON.parse(msg.metadata)
|
|
1003
|
+
const meta = JSON.parse(msg.metadata) as Record<string, unknown>;
|
|
940
1004
|
if (typeof meta.sentAt === "number") {
|
|
941
1005
|
sentAt = meta.sentAt;
|
|
942
1006
|
}
|
|
@@ -958,14 +1022,7 @@ export function handleListMessages({
|
|
|
958
1022
|
: {}),
|
|
959
1023
|
};
|
|
960
1024
|
}
|
|
961
|
-
|
|
962
|
-
// (see `persistWakeTriggerMessage`) that the LLM reads. Flag any such
|
|
963
|
-
// row so clients hide it from the transcript like a subagent/ACP
|
|
964
|
-
// notification — the user-facing "Conversation Woke" card (or, for a
|
|
965
|
-
// backgrounded bash run, the inline terminal card) carries the status.
|
|
966
|
-
if (isBackgroundEventMetadata(meta)) {
|
|
967
|
-
backgroundEventNotification = true;
|
|
968
|
-
}
|
|
1025
|
+
notifications = extractNotificationDiscriminators(meta);
|
|
969
1026
|
// `persistWakeTriggerMessage` stamps the structured completion onto the
|
|
970
1027
|
// same wake row, letting the web rebuild a terminal inline card from
|
|
971
1028
|
// history after a restart (the in-memory completed ring does not survive).
|
|
@@ -975,32 +1032,6 @@ export function handleListMessages({
|
|
|
975
1032
|
if (completionParse.success) {
|
|
976
1033
|
backgroundToolCompletion = completionParse.data;
|
|
977
1034
|
}
|
|
978
|
-
if (meta.subagentNotification) {
|
|
979
|
-
const n = meta.subagentNotification;
|
|
980
|
-
if (typeof n.subagentId === "string" && typeof n.label === "string") {
|
|
981
|
-
subagentNotification = {
|
|
982
|
-
subagentId: n.subagentId,
|
|
983
|
-
label: n.label,
|
|
984
|
-
status: typeof n.status === "string" ? n.status : "completed",
|
|
985
|
-
...(typeof n.error === "string" ? { error: n.error } : {}),
|
|
986
|
-
...(typeof n.conversationId === "string"
|
|
987
|
-
? { conversationId: n.conversationId }
|
|
988
|
-
: {}),
|
|
989
|
-
...(typeof n.objective === "string"
|
|
990
|
-
? { objective: n.objective }
|
|
991
|
-
: {}),
|
|
992
|
-
};
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
if (meta.acpNotification) {
|
|
996
|
-
const n = meta.acpNotification;
|
|
997
|
-
if (typeof n.acpSessionId === "string") {
|
|
998
|
-
acpNotification = {
|
|
999
|
-
acpSessionId: n.acpSessionId,
|
|
1000
|
-
...(typeof n.agent === "string" ? { agent: n.agent } : {}),
|
|
1001
|
-
};
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
1035
|
} catch {
|
|
1005
1036
|
// Ignore malformed metadata
|
|
1006
1037
|
}
|
|
@@ -1025,9 +1056,9 @@ export function handleListMessages({
|
|
|
1025
1056
|
content,
|
|
1026
1057
|
createdAt: msg.createdAt,
|
|
1027
1058
|
sentAt,
|
|
1028
|
-
subagentNotification,
|
|
1029
|
-
acpNotification,
|
|
1030
|
-
backgroundEventNotification,
|
|
1059
|
+
subagentNotification: notifications.subagentNotification,
|
|
1060
|
+
acpNotification: notifications.acpNotification,
|
|
1061
|
+
backgroundEventNotification: notifications.backgroundEventNotification,
|
|
1031
1062
|
backgroundToolCompletion,
|
|
1032
1063
|
systemCard,
|
|
1033
1064
|
providerError,
|
|
@@ -1046,196 +1077,207 @@ export function handleListMessages({
|
|
|
1046
1077
|
);
|
|
1047
1078
|
const pendingQuestions = collectPendingQuestions(resolvedConversationId);
|
|
1048
1079
|
|
|
1049
|
-
const messages: RuntimeMessagePayload[] =
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1080
|
+
const messages: RuntimeMessagePayload[] = await Promise.all(
|
|
1081
|
+
parsed.map(async (m) => {
|
|
1082
|
+
const mergedMessageIds = m.id ? (mergedIdMap.get(m.id) ?? []) : [];
|
|
1083
|
+
|
|
1084
|
+
// Hydrate the row's attachments from the DB. A metadata-only query avoids
|
|
1085
|
+
// loading large base64 blobs for non-image attachments (documents, audio);
|
|
1086
|
+
// full data is fetched only for images so the client can generate
|
|
1087
|
+
// thumbnails for inline display on history restore. Merged messages
|
|
1088
|
+
// (consecutive assistant merge) are queried too so their attachments
|
|
1089
|
+
// aren't lost before DB compaction relinks them.
|
|
1090
|
+
let msgAttachments: RuntimeAttachmentMetadata[] = [];
|
|
1091
|
+
if (m.id) {
|
|
1092
|
+
const idsToQuery = [m.id, ...mergedMessageIds];
|
|
1093
|
+
const linked = idsToQuery.flatMap((id) =>
|
|
1094
|
+
getAttachmentMetadataForMessage(id),
|
|
1095
|
+
);
|
|
1096
|
+
if (linked.length > 0) {
|
|
1097
|
+
msgAttachments = await Promise.all(
|
|
1098
|
+
linked.map(async (a) => {
|
|
1099
|
+
// Hydrate image rows for inline thumbnails. Legacy HEIC can be
|
|
1100
|
+
// stored under application/octet-stream (empty File.type fallback),
|
|
1101
|
+
// so `.heic`/`.heif` rows are hydrated by filename too;
|
|
1102
|
+
// normalizeImageBase64 sniffs the bytes and rewrites only genuine
|
|
1103
|
+
// HEIF, which Chromium-based clients cannot decode. Filename and
|
|
1104
|
+
// sizeBytes keep describing the stored original, which
|
|
1105
|
+
// /attachments/:id/content serves verbatim for downloads.
|
|
1106
|
+
const isImage = a.mimeType.startsWith("image/");
|
|
1107
|
+
const isLegacyHeic =
|
|
1108
|
+
!isImage && isHeicFilename(a.originalFilename);
|
|
1109
|
+
const full =
|
|
1110
|
+
isImage || isLegacyHeic
|
|
1111
|
+
? getAttachmentById(a.id, { hydrateFileData: true })
|
|
1112
|
+
: null;
|
|
1113
|
+
const display = full?.dataBase64
|
|
1114
|
+
? await normalizeImageBase64(a.mimeType, full.dataBase64)
|
|
1115
|
+
: null;
|
|
1116
|
+
// Image rows carry data even when unconverted (thumbnails); a
|
|
1117
|
+
// non-image row only becomes renderable once conversion yields a
|
|
1118
|
+
// JPEG, so it stays metadata-only when conversion is unavailable.
|
|
1119
|
+
const useDisplay =
|
|
1120
|
+
display && (isImage || display.converted) ? display : null;
|
|
1121
|
+
return {
|
|
1122
|
+
id: a.id,
|
|
1123
|
+
filename: a.originalFilename,
|
|
1124
|
+
mimeType: useDisplay?.mimeType ?? a.mimeType,
|
|
1125
|
+
sizeBytes: a.sizeBytes,
|
|
1126
|
+
kind: useDisplay?.converted
|
|
1127
|
+
? classifyKind(useDisplay.mimeType)
|
|
1128
|
+
: a.kind,
|
|
1129
|
+
...(useDisplay ? { data: useDisplay.dataBase64 } : {}),
|
|
1130
|
+
...(a.thumbnailBase64
|
|
1131
|
+
? { thumbnailData: a.thumbnailBase64 }
|
|
1132
|
+
: {}),
|
|
1133
|
+
fileBacked: true,
|
|
1134
|
+
};
|
|
1135
|
+
}),
|
|
1136
|
+
);
|
|
1137
|
+
}
|
|
1100
1138
|
}
|
|
1101
|
-
}
|
|
1102
1139
|
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1140
|
+
// Align the hydrated rows with the file-block refs, then render. Rendering
|
|
1141
|
+
// after alignment lets renderHistoryContent inline each `attachment` block
|
|
1142
|
+
// during its single content walk, so `contentBlocks` comes back ready to
|
|
1143
|
+
// ship with no post-processing. The aligned reorder/rewrite keeps the
|
|
1144
|
+
// legacy `attachments` array and `contentOrder` positions consistent.
|
|
1145
|
+
const attachmentRefs = collectAttachmentRefs(m.content);
|
|
1146
|
+
const aligned = alignAttachments(attachmentRefs, msgAttachments);
|
|
1147
|
+
msgAttachments = aligned.attachments;
|
|
1148
|
+
const attachmentBlocks = attachmentRefs.map((_ref, refIdx) => {
|
|
1149
|
+
const att = aligned.refIndexToAttachment.get(refIdx);
|
|
1150
|
+
return att ? toAttachmentBlockRef(att) : null;
|
|
1151
|
+
});
|
|
1152
|
+
const rendered = renderHistoryContent(
|
|
1153
|
+
m.content,
|
|
1154
|
+
attachmentBlocks,
|
|
1155
|
+
m.id ?? undefined,
|
|
1156
|
+
);
|
|
1120
1157
|
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1158
|
+
const toolCalls = enrichToolCallsWithQuestion(
|
|
1159
|
+
enrichToolCallsWithConfirmation(rendered.toolCalls, {
|
|
1160
|
+
workspaceDir,
|
|
1161
|
+
pendingConfirmations,
|
|
1162
|
+
}),
|
|
1163
|
+
{ pendingQuestions },
|
|
1164
|
+
);
|
|
1128
1165
|
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1166
|
+
// Strip <no_response/> markers from assistant messages so web/API clients
|
|
1167
|
+
// never see the raw sentinel. Only assistant messages produce it; user
|
|
1168
|
+
// messages are untouched. The filter is applied consistently to the
|
|
1169
|
+
// segments, the contentOrder text refs, and the text blocks of
|
|
1170
|
+
// contentBlocks.
|
|
1171
|
+
let textSegments = rendered.textSegments;
|
|
1172
|
+
let contentOrder = rendered.contentOrder;
|
|
1173
|
+
let contentBlocks = rendered.contentBlocks;
|
|
1174
|
+
if (m.role === "assistant") {
|
|
1175
|
+
const keepIndices: number[] = [];
|
|
1176
|
+
const filteredSegments: string[] = [];
|
|
1177
|
+
for (let i = 0; i < rendered.textSegments.length; i++) {
|
|
1178
|
+
const cleaned = rendered.textSegments[i]
|
|
1179
|
+
.replace(NO_RESPONSE_INLINE_RE, "")
|
|
1180
|
+
.trim();
|
|
1181
|
+
if (cleaned.length > 0) {
|
|
1182
|
+
keepIndices.push(i);
|
|
1183
|
+
filteredSegments.push(cleaned);
|
|
1184
|
+
}
|
|
1147
1185
|
}
|
|
1186
|
+
const indexMap = new Map<number, number>();
|
|
1187
|
+
keepIndices.forEach((oldIdx, newIdx) => indexMap.set(oldIdx, newIdx));
|
|
1188
|
+
contentOrder = rendered.contentOrder
|
|
1189
|
+
.map((entry) => {
|
|
1190
|
+
const tm = entry.match(/^text:(\d+)$/);
|
|
1191
|
+
if (!tm) {
|
|
1192
|
+
return entry;
|
|
1193
|
+
}
|
|
1194
|
+
const newIdx = indexMap.get(Number(tm[1]));
|
|
1195
|
+
return newIdx !== undefined ? `text:${newIdx}` : undefined;
|
|
1196
|
+
})
|
|
1197
|
+
.filter((e): e is string => e !== undefined);
|
|
1198
|
+
textSegments = filteredSegments;
|
|
1199
|
+
contentBlocks = rendered.contentBlocks
|
|
1200
|
+
.map((block) =>
|
|
1201
|
+
block.type === "text"
|
|
1202
|
+
? {
|
|
1203
|
+
type: "text" as const,
|
|
1204
|
+
text: block.text.replace(NO_RESPONSE_INLINE_RE, "").trim(),
|
|
1205
|
+
}
|
|
1206
|
+
: block,
|
|
1207
|
+
)
|
|
1208
|
+
.filter((block) => block.type !== "text" || block.text.length > 0);
|
|
1148
1209
|
}
|
|
1149
|
-
const indexMap = new Map<number, number>();
|
|
1150
|
-
keepIndices.forEach((oldIdx, newIdx) => indexMap.set(oldIdx, newIdx));
|
|
1151
|
-
contentOrder = rendered.contentOrder
|
|
1152
|
-
.map((entry) => {
|
|
1153
|
-
const tm = entry.match(/^text:(\d+)$/);
|
|
1154
|
-
if (!tm) {
|
|
1155
|
-
return entry;
|
|
1156
|
-
}
|
|
1157
|
-
const newIdx = indexMap.get(Number(tm[1]));
|
|
1158
|
-
return newIdx !== undefined ? `text:${newIdx}` : undefined;
|
|
1159
|
-
})
|
|
1160
|
-
.filter((e): e is string => e !== undefined);
|
|
1161
|
-
textSegments = filteredSegments;
|
|
1162
|
-
contentBlocks = rendered.contentBlocks
|
|
1163
|
-
.map((block) =>
|
|
1164
|
-
block.type === "text"
|
|
1165
|
-
? {
|
|
1166
|
-
type: "text" as const,
|
|
1167
|
-
text: block.text.replace(NO_RESPONSE_INLINE_RE, "").trim(),
|
|
1168
|
-
}
|
|
1169
|
-
: block,
|
|
1170
|
-
)
|
|
1171
|
-
.filter((block) => block.type !== "text" || block.text.length > 0);
|
|
1172
|
-
}
|
|
1173
1210
|
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1211
|
+
// Ensure every hydrated attachment has a corresponding content block.
|
|
1212
|
+
// renderHistoryContent inlines attachment blocks only when it has
|
|
1213
|
+
// file-block refs with matching DB rows; directives (assistant-authored
|
|
1214
|
+
// <vellum-attachment/> tags) don't leave a file block after stripping,
|
|
1215
|
+
// so their attachments end up in the flat `attachments` array but not in
|
|
1216
|
+
// `contentBlocks`. Append any that are missing so the canonical
|
|
1217
|
+
// projection is complete.
|
|
1218
|
+
const existingAttachmentIds = new Set(
|
|
1219
|
+
contentBlocks
|
|
1220
|
+
.filter(
|
|
1221
|
+
(
|
|
1222
|
+
b,
|
|
1223
|
+
): b is Extract<ConversationContentBlock, { type: "attachment" }> =>
|
|
1224
|
+
b.type === "attachment",
|
|
1225
|
+
)
|
|
1226
|
+
.map((b) => b.attachment.id),
|
|
1227
|
+
);
|
|
1228
|
+
for (const att of msgAttachments) {
|
|
1229
|
+
if (!existingAttachmentIds.has(att.id)) {
|
|
1230
|
+
contentBlocks.push({
|
|
1231
|
+
type: "attachment",
|
|
1232
|
+
attachment: toAttachmentBlockRef(att),
|
|
1233
|
+
});
|
|
1234
|
+
}
|
|
1195
1235
|
}
|
|
1196
|
-
}
|
|
1197
1236
|
|
|
1198
|
-
|
|
1237
|
+
const alignedContentOrder = aligned.rewriteContentOrder(contentOrder);
|
|
1199
1238
|
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
? {
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
? {
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
+
// Use sentAt (actual event time) for the display timestamp when available,
|
|
1240
|
+
// falling back to createdAt (persistence time). Clients use this display
|
|
1241
|
+
// timestamp as their pagination cursor after memory-pressure trimming,
|
|
1242
|
+
// while server-side pagination filters on createdAt. The mismatch is
|
|
1243
|
+
// benign: it may return slightly extra data on a page boundary but never
|
|
1244
|
+
// loses messages.
|
|
1245
|
+
const displayTimestamp = m.sentAt ?? m.createdAt;
|
|
1246
|
+
return {
|
|
1247
|
+
id: m.id ?? "",
|
|
1248
|
+
...(mergedMessageIds.length > 0 ? { mergedMessageIds } : {}),
|
|
1249
|
+
...(m.clientMessageId ? { clientMessageId: m.clientMessageId } : {}),
|
|
1250
|
+
role: m.role,
|
|
1251
|
+
timestamp: new Date(displayTimestamp).toISOString(),
|
|
1252
|
+
attachments: msgAttachments,
|
|
1253
|
+
...(toolCalls.length > 0 ? { toolCalls } : {}),
|
|
1254
|
+
...(rendered.surfaces.length > 0
|
|
1255
|
+
? { surfaces: rendered.surfaces }
|
|
1256
|
+
: {}),
|
|
1257
|
+
...(textSegments.length > 0 ? { textSegments } : {}),
|
|
1258
|
+
...(rendered.thinkingSegments.length > 0
|
|
1259
|
+
? { thinkingSegments: rendered.thinkingSegments }
|
|
1260
|
+
: {}),
|
|
1261
|
+
...(alignedContentOrder.length > 0
|
|
1262
|
+
? { contentOrder: alignedContentOrder }
|
|
1263
|
+
: {}),
|
|
1264
|
+
contentBlocks,
|
|
1265
|
+
...(m.subagentNotification
|
|
1266
|
+
? { subagentNotification: m.subagentNotification }
|
|
1267
|
+
: {}),
|
|
1268
|
+
...(m.acpNotification ? { acpNotification: m.acpNotification } : {}),
|
|
1269
|
+
...(m.backgroundEventNotification
|
|
1270
|
+
? { backgroundEventNotification: true }
|
|
1271
|
+
: {}),
|
|
1272
|
+
...(m.backgroundToolCompletion
|
|
1273
|
+
? { backgroundToolCompletion: m.backgroundToolCompletion }
|
|
1274
|
+
: {}),
|
|
1275
|
+
...(m.systemCard ? { systemCard: true } : {}),
|
|
1276
|
+
...(m.providerError ? { providerError: m.providerError } : {}),
|
|
1277
|
+
...(m.slackMessage ? { slackMessage: m.slackMessage } : {}),
|
|
1278
|
+
};
|
|
1279
|
+
}),
|
|
1280
|
+
);
|
|
1239
1281
|
|
|
1240
1282
|
// Snapshot↔stream alignment token: the `seq` of the last event whose
|
|
1241
1283
|
// content is durably persisted for this conversation, read from the
|
|
@@ -1579,7 +1621,7 @@ export async function handleSendMessage(
|
|
|
1579
1621
|
typeof body.clientTimezone === "string"
|
|
1580
1622
|
? (canonicalizeTimeZone(body.clientTimezone) ?? undefined)
|
|
1581
1623
|
: undefined;
|
|
1582
|
-
// Client OS surface ("web" | "ios" | "macos" | "android"), reported
|
|
1624
|
+
// Client OS surface ("web" | "ios" | "macos" | "windows" | "android"), reported
|
|
1583
1625
|
// separately from the transport `interface`. Validated against the dedicated
|
|
1584
1626
|
// `ClientOs` value set (NOT the interface vocabulary) and only kept when it
|
|
1585
1627
|
// resolves — it drives the per-turn `client_os:` context line, never
|
|
@@ -1704,6 +1746,11 @@ export async function handleSendMessage(
|
|
|
1704
1746
|
mapping = getOrCreateConversation(resolvedConversationKey, {
|
|
1705
1747
|
conversationType: "standard",
|
|
1706
1748
|
title: onboardingTitle,
|
|
1749
|
+
// This route already resolved the channel the message arrived on, and
|
|
1750
|
+
// this is the seam that materializes the row, so the conversation is
|
|
1751
|
+
// attributed from the moment it exists rather than on its first
|
|
1752
|
+
// message.
|
|
1753
|
+
origin: sourceChannel,
|
|
1707
1754
|
});
|
|
1708
1755
|
}
|
|
1709
1756
|
|
|
@@ -1868,6 +1915,15 @@ export async function handleSendMessage(
|
|
|
1868
1915
|
conversation.setTrustContext({ trustClass: "guardian", sourceChannel });
|
|
1869
1916
|
}
|
|
1870
1917
|
|
|
1918
|
+
// The trust this request's turn runs under, captured here rather than read
|
|
1919
|
+
// back at the agent loop below. Every branch above has just written it and
|
|
1920
|
+
// nothing awaits in between, so this is the resolved sender. Between here
|
|
1921
|
+
// and the loop the conversation slot is writable by paths that do not own
|
|
1922
|
+
// this turn (channel ingress for another actor, live-voice hydration,
|
|
1923
|
+
// pointer elevation, the voice bridge), and the loop would otherwise
|
|
1924
|
+
// re-read it and run this turn as whoever wrote last.
|
|
1925
|
+
const turnTrustContext = conversation.trustContext;
|
|
1926
|
+
|
|
1871
1927
|
const isInteractive = isInteractiveInterface(sourceInterface);
|
|
1872
1928
|
// Translate the dev-bypass actor principal to the real guardian principal
|
|
1873
1929
|
// before the same-actor host-proxy gate so web/iOS turns match the macOS
|
|
@@ -1999,6 +2055,7 @@ export async function handleSendMessage(
|
|
|
1999
2055
|
requestId: uuidv7(),
|
|
2000
2056
|
metadata: greetingMeta,
|
|
2001
2057
|
clientMessageId,
|
|
2058
|
+
...(clientOs ? { requestClientOs: clientOs } : {}),
|
|
2002
2059
|
});
|
|
2003
2060
|
|
|
2004
2061
|
const conversationId = mapping.conversationId;
|
|
@@ -2037,34 +2094,37 @@ export async function handleSendMessage(
|
|
|
2037
2094
|
}
|
|
2038
2095
|
}
|
|
2039
2096
|
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2097
|
+
scheduleCannedReplyRelease({
|
|
2098
|
+
conversation,
|
|
2099
|
+
origin: "canned_greeting",
|
|
2100
|
+
emit: () => {
|
|
2101
|
+
broadcastMessage({
|
|
2102
|
+
type: "user_message_echo",
|
|
2103
|
+
text: rawContent,
|
|
2104
|
+
conversationId,
|
|
2105
|
+
messageId: persisted.id,
|
|
2106
|
+
clientMessageId,
|
|
2107
|
+
});
|
|
2108
|
+
broadcastMessage({
|
|
2109
|
+
type: "assistant_text_delta",
|
|
2110
|
+
text: cannedGreeting,
|
|
2111
|
+
conversationId,
|
|
2112
|
+
});
|
|
2113
|
+
emitCannedMessageComplete(
|
|
2114
|
+
broadcastMessage,
|
|
2115
|
+
conversationId,
|
|
2116
|
+
persistedAssistant.id,
|
|
2117
|
+
);
|
|
2118
|
+
// Rows persisted before this deferred burst; advance the
|
|
2119
|
+
// snapshot↔stream anchor past the events just emitted so `/messages`
|
|
2120
|
+
// never returns these rows behind a stale anchor.
|
|
2121
|
+
recordConversationPersistedSeq(conversationId, getCurrentSeq());
|
|
2122
|
+
publishConversationMessagesChanged(conversationId, originClientId);
|
|
2123
|
+
},
|
|
2124
|
+
afterRelease: () => {
|
|
2125
|
+
conversation.warmPromptCache();
|
|
2126
|
+
},
|
|
2127
|
+
});
|
|
2068
2128
|
|
|
2069
2129
|
log.info(
|
|
2070
2130
|
{ conversationId, personalized: !!body.onboarding },
|
|
@@ -2329,6 +2389,7 @@ export async function handleSendMessage(
|
|
|
2329
2389
|
requestId: uuidv7(),
|
|
2330
2390
|
metadata: withClientMetadata(slashMeta, clientMetadata),
|
|
2331
2391
|
clientMessageId,
|
|
2392
|
+
...(clientOs ? { requestClientOs: clientOs } : {}),
|
|
2332
2393
|
});
|
|
2333
2394
|
if (persisted.deduplicated) {
|
|
2334
2395
|
return {
|
|
@@ -2372,33 +2433,35 @@ export async function handleSendMessage(
|
|
|
2372
2433
|
// starts processing.
|
|
2373
2434
|
const conversationId = mapping.conversationId;
|
|
2374
2435
|
const message = slashResult.message;
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2436
|
+
scheduleCannedReplyRelease({
|
|
2437
|
+
conversation,
|
|
2438
|
+
origin: "slash_command",
|
|
2439
|
+
emit: () => {
|
|
2440
|
+
broadcastMessage({
|
|
2441
|
+
type: "user_message_echo",
|
|
2442
|
+
text: rawContent,
|
|
2443
|
+
conversationId,
|
|
2444
|
+
messageId: persisted.id,
|
|
2445
|
+
clientMessageId,
|
|
2446
|
+
});
|
|
2447
|
+
if (modelInfoEvent) {
|
|
2448
|
+
broadcastMessage(modelInfoEvent);
|
|
2449
|
+
}
|
|
2450
|
+
broadcastMessage({
|
|
2451
|
+
type: "assistant_text_delta",
|
|
2452
|
+
text: message,
|
|
2453
|
+
conversationId,
|
|
2454
|
+
});
|
|
2455
|
+
emitCannedMessageComplete(
|
|
2456
|
+
broadcastMessage,
|
|
2457
|
+
conversationId,
|
|
2458
|
+
persistedAssistant.id,
|
|
2459
|
+
);
|
|
2460
|
+
// Same anchor advance as the canned-greeting path above.
|
|
2461
|
+
recordConversationPersistedSeq(conversationId, getCurrentSeq());
|
|
2462
|
+
publishConversationMessagesChanged(conversationId, originClientId);
|
|
2463
|
+
},
|
|
2464
|
+
});
|
|
2402
2465
|
|
|
2403
2466
|
cleanupDeferred = true;
|
|
2404
2467
|
return response;
|
|
@@ -2428,6 +2491,7 @@ export async function handleSendMessage(
|
|
|
2428
2491
|
requestId: uuidv7(),
|
|
2429
2492
|
metadata: withClientMetadata(slashMeta, clientMetadata),
|
|
2430
2493
|
clientMessageId,
|
|
2494
|
+
...(clientOs ? { requestClientOs: clientOs } : {}),
|
|
2431
2495
|
});
|
|
2432
2496
|
} catch (err) {
|
|
2433
2497
|
// The fire-and-forget compaction below owns clearing `processing`, but a
|
|
@@ -2522,6 +2586,7 @@ export async function handleSendMessage(
|
|
|
2522
2586
|
requestId: uuidv7(),
|
|
2523
2587
|
metadata: withClientMetadata(slashMeta, clientMetadata),
|
|
2524
2588
|
clientMessageId,
|
|
2589
|
+
...(clientOs ? { requestClientOs: clientOs } : {}),
|
|
2525
2590
|
});
|
|
2526
2591
|
if (persisted.deduplicated) {
|
|
2527
2592
|
return {
|
|
@@ -2591,6 +2656,7 @@ export async function handleSendMessage(
|
|
|
2591
2656
|
),
|
|
2592
2657
|
scripted: body.scripted,
|
|
2593
2658
|
clientMessageId,
|
|
2659
|
+
...(clientOs ? { requestClientOs: clientOs } : {}),
|
|
2594
2660
|
});
|
|
2595
2661
|
|
|
2596
2662
|
const messageId = persistResult.id;
|
|
@@ -2634,6 +2700,7 @@ export async function handleSendMessage(
|
|
|
2634
2700
|
onEvent: broadcastMessage,
|
|
2635
2701
|
isInteractive,
|
|
2636
2702
|
isUserMessage: true,
|
|
2703
|
+
turnTrustContext,
|
|
2637
2704
|
...(body.hidden === true ? { isHiddenPrompt: true } : {}),
|
|
2638
2705
|
})
|
|
2639
2706
|
.catch((err) => {
|
|
@@ -3095,7 +3162,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
3095
3162
|
.string()
|
|
3096
3163
|
.optional()
|
|
3097
3164
|
.describe(
|
|
3098
|
-
'Client OS surface ("web" | "ios" | "macos" | "android"), reported separately from `interface`. Drives the per-turn `client_os` context only; does not affect transport/host-proxy capabilities.',
|
|
3165
|
+
'Client OS surface ("web" | "ios" | "macos" | "windows" | "android"), reported separately from `interface`. Drives the per-turn `client_os` context only; does not affect transport/host-proxy capabilities.',
|
|
3099
3166
|
),
|
|
3100
3167
|
visibleAppId: z
|
|
3101
3168
|
.string()
|