@vellumai/assistant 0.11.2 → 0.11.3-staging.1
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-queue.test.ts +265 -1
- package/src/__tests__/conversation-retry-route.test.ts +3 -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-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-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-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 +216 -132
- 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/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 +296 -145
- 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 +85 -42
- package/src/daemon/conversation-process.ts +76 -28
- 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 +105 -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.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/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 +56 -8
- 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 +350 -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 +295 -42
- 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/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/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
|
|
|
@@ -1999,6 +2046,7 @@ export async function handleSendMessage(
|
|
|
1999
2046
|
requestId: uuidv7(),
|
|
2000
2047
|
metadata: greetingMeta,
|
|
2001
2048
|
clientMessageId,
|
|
2049
|
+
...(clientOs ? { requestClientOs: clientOs } : {}),
|
|
2002
2050
|
});
|
|
2003
2051
|
|
|
2004
2052
|
const conversationId = mapping.conversationId;
|
|
@@ -2037,34 +2085,37 @@ export async function handleSendMessage(
|
|
|
2037
2085
|
}
|
|
2038
2086
|
}
|
|
2039
2087
|
|
|
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
|
-
|
|
2088
|
+
scheduleCannedReplyRelease({
|
|
2089
|
+
conversation,
|
|
2090
|
+
origin: "canned_greeting",
|
|
2091
|
+
emit: () => {
|
|
2092
|
+
broadcastMessage({
|
|
2093
|
+
type: "user_message_echo",
|
|
2094
|
+
text: rawContent,
|
|
2095
|
+
conversationId,
|
|
2096
|
+
messageId: persisted.id,
|
|
2097
|
+
clientMessageId,
|
|
2098
|
+
});
|
|
2099
|
+
broadcastMessage({
|
|
2100
|
+
type: "assistant_text_delta",
|
|
2101
|
+
text: cannedGreeting,
|
|
2102
|
+
conversationId,
|
|
2103
|
+
});
|
|
2104
|
+
emitCannedMessageComplete(
|
|
2105
|
+
broadcastMessage,
|
|
2106
|
+
conversationId,
|
|
2107
|
+
persistedAssistant.id,
|
|
2108
|
+
);
|
|
2109
|
+
// Rows persisted before this deferred burst; advance the
|
|
2110
|
+
// snapshot↔stream anchor past the events just emitted so `/messages`
|
|
2111
|
+
// never returns these rows behind a stale anchor.
|
|
2112
|
+
recordConversationPersistedSeq(conversationId, getCurrentSeq());
|
|
2113
|
+
publishConversationMessagesChanged(conversationId, originClientId);
|
|
2114
|
+
},
|
|
2115
|
+
afterRelease: () => {
|
|
2116
|
+
conversation.warmPromptCache();
|
|
2117
|
+
},
|
|
2118
|
+
});
|
|
2068
2119
|
|
|
2069
2120
|
log.info(
|
|
2070
2121
|
{ conversationId, personalized: !!body.onboarding },
|
|
@@ -2329,6 +2380,7 @@ export async function handleSendMessage(
|
|
|
2329
2380
|
requestId: uuidv7(),
|
|
2330
2381
|
metadata: withClientMetadata(slashMeta, clientMetadata),
|
|
2331
2382
|
clientMessageId,
|
|
2383
|
+
...(clientOs ? { requestClientOs: clientOs } : {}),
|
|
2332
2384
|
});
|
|
2333
2385
|
if (persisted.deduplicated) {
|
|
2334
2386
|
return {
|
|
@@ -2372,33 +2424,35 @@ export async function handleSendMessage(
|
|
|
2372
2424
|
// starts processing.
|
|
2373
2425
|
const conversationId = mapping.conversationId;
|
|
2374
2426
|
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
|
-
|
|
2427
|
+
scheduleCannedReplyRelease({
|
|
2428
|
+
conversation,
|
|
2429
|
+
origin: "slash_command",
|
|
2430
|
+
emit: () => {
|
|
2431
|
+
broadcastMessage({
|
|
2432
|
+
type: "user_message_echo",
|
|
2433
|
+
text: rawContent,
|
|
2434
|
+
conversationId,
|
|
2435
|
+
messageId: persisted.id,
|
|
2436
|
+
clientMessageId,
|
|
2437
|
+
});
|
|
2438
|
+
if (modelInfoEvent) {
|
|
2439
|
+
broadcastMessage(modelInfoEvent);
|
|
2440
|
+
}
|
|
2441
|
+
broadcastMessage({
|
|
2442
|
+
type: "assistant_text_delta",
|
|
2443
|
+
text: message,
|
|
2444
|
+
conversationId,
|
|
2445
|
+
});
|
|
2446
|
+
emitCannedMessageComplete(
|
|
2447
|
+
broadcastMessage,
|
|
2448
|
+
conversationId,
|
|
2449
|
+
persistedAssistant.id,
|
|
2450
|
+
);
|
|
2451
|
+
// Same anchor advance as the canned-greeting path above.
|
|
2452
|
+
recordConversationPersistedSeq(conversationId, getCurrentSeq());
|
|
2453
|
+
publishConversationMessagesChanged(conversationId, originClientId);
|
|
2454
|
+
},
|
|
2455
|
+
});
|
|
2402
2456
|
|
|
2403
2457
|
cleanupDeferred = true;
|
|
2404
2458
|
return response;
|
|
@@ -2428,6 +2482,7 @@ export async function handleSendMessage(
|
|
|
2428
2482
|
requestId: uuidv7(),
|
|
2429
2483
|
metadata: withClientMetadata(slashMeta, clientMetadata),
|
|
2430
2484
|
clientMessageId,
|
|
2485
|
+
...(clientOs ? { requestClientOs: clientOs } : {}),
|
|
2431
2486
|
});
|
|
2432
2487
|
} catch (err) {
|
|
2433
2488
|
// The fire-and-forget compaction below owns clearing `processing`, but a
|
|
@@ -2522,6 +2577,7 @@ export async function handleSendMessage(
|
|
|
2522
2577
|
requestId: uuidv7(),
|
|
2523
2578
|
metadata: withClientMetadata(slashMeta, clientMetadata),
|
|
2524
2579
|
clientMessageId,
|
|
2580
|
+
...(clientOs ? { requestClientOs: clientOs } : {}),
|
|
2525
2581
|
});
|
|
2526
2582
|
if (persisted.deduplicated) {
|
|
2527
2583
|
return {
|
|
@@ -2591,6 +2647,7 @@ export async function handleSendMessage(
|
|
|
2591
2647
|
),
|
|
2592
2648
|
scripted: body.scripted,
|
|
2593
2649
|
clientMessageId,
|
|
2650
|
+
...(clientOs ? { requestClientOs: clientOs } : {}),
|
|
2594
2651
|
});
|
|
2595
2652
|
|
|
2596
2653
|
const messageId = persistResult.id;
|
|
@@ -3095,7 +3152,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
3095
3152
|
.string()
|
|
3096
3153
|
.optional()
|
|
3097
3154
|
.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.',
|
|
3155
|
+
'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
3156
|
),
|
|
3100
3157
|
visibleAppId: z
|
|
3101
3158
|
.string()
|