@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
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
import type { AssistantEvent } from "../api/index.js";
|
|
13
13
|
import type { Message, ProviderResponse } from "../providers/types.js";
|
|
14
14
|
import { stampAndBuffer } from "../runtime/assistant-stream-state.js";
|
|
15
|
+
import { createAbortReason } from "../util/abort-reasons.js";
|
|
15
16
|
import { setConfig } from "./helpers/set-config.js";
|
|
16
17
|
|
|
17
18
|
// ---------------------------------------------------------------------------
|
|
@@ -675,6 +676,62 @@ describe("Conversation message queue", () => {
|
|
|
675
676
|
expect(pendingRuns.length).toBe(3);
|
|
676
677
|
});
|
|
677
678
|
|
|
679
|
+
// `Conversation.clientOs` is a live field that only a transport-carrying
|
|
680
|
+
// message refreshes, so a transport-less drain (a surface action, a signal)
|
|
681
|
+
// persists the OS of an earlier send. Both rows keep that OS for telemetry;
|
|
682
|
+
// only the row that reported it claims the surface, which is what stops an
|
|
683
|
+
// attended Mac from suppressing the push for a button tapped on the phone.
|
|
684
|
+
test("[experimental] only a queued send that reported its own OS claims that surface", async () => {
|
|
685
|
+
capturedAddMessages.length = 0;
|
|
686
|
+
const conversation = makeConversation();
|
|
687
|
+
await conversation.loadFromDb();
|
|
688
|
+
|
|
689
|
+
const p1 = conversation.processMessage({
|
|
690
|
+
content: "msg-1",
|
|
691
|
+
attachments: [],
|
|
692
|
+
onEvent: () => {},
|
|
693
|
+
requestId: "req-1",
|
|
694
|
+
});
|
|
695
|
+
await waitForPendingRun(1);
|
|
696
|
+
|
|
697
|
+
conversation.enqueueMessage({
|
|
698
|
+
content: "from-the-mac",
|
|
699
|
+
onEvent: () => {},
|
|
700
|
+
requestId: "req-mac",
|
|
701
|
+
transport: { channelId: "vellum", interfaceId: "web", clientOs: "macos" },
|
|
702
|
+
});
|
|
703
|
+
// A surface action: no transport, so the drain leaves the conversation's
|
|
704
|
+
// `clientOs` on the macOS value the send above applied.
|
|
705
|
+
conversation.enqueueMessage({
|
|
706
|
+
content: "[User action on card surface: submit]",
|
|
707
|
+
onEvent: () => {},
|
|
708
|
+
requestId: "req-surface-action",
|
|
709
|
+
});
|
|
710
|
+
|
|
711
|
+
await resolveRun(0);
|
|
712
|
+
await p1;
|
|
713
|
+
await waitForPendingRun(2);
|
|
714
|
+
await resolveRun(1);
|
|
715
|
+
await waitForPendingRun(3);
|
|
716
|
+
|
|
717
|
+
const macRow = capturedAddMessages.find(
|
|
718
|
+
(m) => m.role === "user" && m.content.includes("from-the-mac"),
|
|
719
|
+
);
|
|
720
|
+
expect(macRow).toBeDefined();
|
|
721
|
+
expect(macRow!.metadata?.client).toEqual({ os: "macos" });
|
|
722
|
+
expect(macRow!.metadata?.clientOsFromRequest).toBe(true);
|
|
723
|
+
|
|
724
|
+
const surfaceActionRow = capturedAddMessages.find(
|
|
725
|
+
(m) => m.role === "user" && m.content.includes("User action on card"),
|
|
726
|
+
);
|
|
727
|
+
expect(surfaceActionRow).toBeDefined();
|
|
728
|
+
expect(surfaceActionRow!.metadata?.client).toEqual({ os: "macos" });
|
|
729
|
+
expect(surfaceActionRow!.metadata?.clientOsFromRequest).toBeUndefined();
|
|
730
|
+
|
|
731
|
+
await resolveRun(2);
|
|
732
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
733
|
+
});
|
|
734
|
+
|
|
678
735
|
test("[experimental] queued passthrough siblings viewing different apps do NOT batch", async () => {
|
|
679
736
|
// A batched turn applies only the head's `visibleAppId`, which drives the
|
|
680
737
|
// `visible_app:` context line. Coalescing messages sent while different
|
|
@@ -826,7 +883,87 @@ describe("Conversation message queue", () => {
|
|
|
826
883
|
await new Promise((r) => setTimeout(r, 10));
|
|
827
884
|
});
|
|
828
885
|
|
|
829
|
-
test("
|
|
886
|
+
test("subagent notifications are never acked with message_queued and don't shift visible positions", async () => {
|
|
887
|
+
const conversation = makeConversation();
|
|
888
|
+
await conversation.loadFromDb();
|
|
889
|
+
|
|
890
|
+
const notificationEvents: AssistantEvent[] = [];
|
|
891
|
+
const visibleEvents: AssistantEvent[] = [];
|
|
892
|
+
|
|
893
|
+
const p1 = conversation.processMessage({
|
|
894
|
+
content: "msg-1",
|
|
895
|
+
attachments: [],
|
|
896
|
+
requestId: "req-1",
|
|
897
|
+
});
|
|
898
|
+
await waitForPendingRun(1);
|
|
899
|
+
|
|
900
|
+
// A subagent's completion summary injected into a busy parent is daemon
|
|
901
|
+
// scaffolding: the user follows that run through its inline card, so the
|
|
902
|
+
// row gets no queued ack and no queue-drawer bubble.
|
|
903
|
+
const notification = conversation.enqueueMessage({
|
|
904
|
+
content: '[Subagent "hermes-local-review" — important] review finished',
|
|
905
|
+
onEvent: (e) => notificationEvents.push(e),
|
|
906
|
+
requestId: "req-subagent",
|
|
907
|
+
metadata: {
|
|
908
|
+
subagentNotification: {
|
|
909
|
+
subagentId: "sub-1",
|
|
910
|
+
label: "hermes-local-review",
|
|
911
|
+
status: "completed",
|
|
912
|
+
conversationId: "conv-sub-1",
|
|
913
|
+
objective: "review the diff",
|
|
914
|
+
},
|
|
915
|
+
},
|
|
916
|
+
});
|
|
917
|
+
expect(notification.queued).toBe(true);
|
|
918
|
+
expect(
|
|
919
|
+
notificationEvents.filter((e) => e.type === "message_queued"),
|
|
920
|
+
).toEqual([]);
|
|
921
|
+
|
|
922
|
+
// The user's own send queued behind it is position 1: the notification
|
|
923
|
+
// does not consume a visible slot, matching the cold-load snapshot.
|
|
924
|
+
const visible = conversation.enqueueMessage({
|
|
925
|
+
content: "visible-msg",
|
|
926
|
+
onEvent: (e) => visibleEvents.push(e),
|
|
927
|
+
requestId: "req-visible",
|
|
928
|
+
});
|
|
929
|
+
expect(visible.queued).toBe(true);
|
|
930
|
+
expect(conversation.getQueueDepth()).toBe(2);
|
|
931
|
+
expect(
|
|
932
|
+
visibleEvents.find((e) => e.type === "message_queued"),
|
|
933
|
+
).toMatchObject({
|
|
934
|
+
requestId: "req-visible",
|
|
935
|
+
position: 1,
|
|
936
|
+
});
|
|
937
|
+
|
|
938
|
+
// Suppressing the ack changes only what clients are told: the row is
|
|
939
|
+
// still queued, still drains, and still wakes the parent on the notification
|
|
940
|
+
// text (delivery is asserted end-to-end in "drained subagent-notification
|
|
941
|
+
// message persists and wakes the agent but emits no user_message_echo").
|
|
942
|
+
await resolveRun(0);
|
|
943
|
+
await p1;
|
|
944
|
+
await waitForPendingRun(2);
|
|
945
|
+
await waitForCondition(() => conversation.getQueueDepth() === 0);
|
|
946
|
+
expect(
|
|
947
|
+
capturedAddMessages.some((m) =>
|
|
948
|
+
m.content.includes("hermes-local-review"),
|
|
949
|
+
),
|
|
950
|
+
).toBe(true);
|
|
951
|
+
|
|
952
|
+
for (let i = 1; i < pendingRuns.length; i++) {
|
|
953
|
+
await resolveRun(i);
|
|
954
|
+
}
|
|
955
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
956
|
+
|
|
957
|
+
// Queue events stay paired: an enqueue that was never acked is never
|
|
958
|
+
// dequeued either, so the client counter can't retire an entry it never
|
|
959
|
+
// took. The visible send keeps both halves.
|
|
960
|
+
expect(
|
|
961
|
+
notificationEvents.filter((e) => e.type === "message_dequeued"),
|
|
962
|
+
).toEqual([]);
|
|
963
|
+
expect(visibleEvents.some((e) => e.type === "message_dequeued")).toBe(true);
|
|
964
|
+
});
|
|
965
|
+
|
|
966
|
+
test("abort() clears the queue and closes out each queued message", async () => {
|
|
830
967
|
const conversation = makeConversation();
|
|
831
968
|
await conversation.loadFromDb();
|
|
832
969
|
|
|
@@ -873,6 +1010,17 @@ describe("Conversation message queue", () => {
|
|
|
873
1010
|
conversationId: "conv-1",
|
|
874
1011
|
});
|
|
875
1012
|
|
|
1013
|
+
// Each discarded row also gets its own terminal event. `generation_cancelled`
|
|
1014
|
+
// closes out the turn they were waiting on; only `message_queued_deleted`
|
|
1015
|
+
// closes out the queued rows themselves, and without it clients keep the
|
|
1016
|
+
// pending indicator up forever, since no `message_dequeued` is coming.
|
|
1017
|
+
expect(
|
|
1018
|
+
events2.find((e) => e.type === "message_queued_deleted"),
|
|
1019
|
+
).toMatchObject({ conversationId: "conv-1", requestId: "req-2" });
|
|
1020
|
+
expect(
|
|
1021
|
+
events3.find((e) => e.type === "message_queued_deleted"),
|
|
1022
|
+
).toMatchObject({ conversationId: "conv-1", requestId: "req-3" });
|
|
1023
|
+
|
|
876
1024
|
// abort() must NOT emit conversation_error or generic error for queued discards.
|
|
877
1025
|
const err2 = events2.find((e) => e.type === "error");
|
|
878
1026
|
expect(err2).toBeUndefined();
|
|
@@ -897,6 +1045,122 @@ describe("Conversation message queue", () => {
|
|
|
897
1045
|
await new Promise((r) => setTimeout(r, 10));
|
|
898
1046
|
});
|
|
899
1047
|
|
|
1048
|
+
test("a user interrupt keeps the queue and the stopped turn's drain sends it", async () => {
|
|
1049
|
+
// GIVEN a turn in flight with a message queued behind it
|
|
1050
|
+
const conversation = makeConversation();
|
|
1051
|
+
await conversation.loadFromDb();
|
|
1052
|
+
|
|
1053
|
+
const events2: AssistantEvent[] = [];
|
|
1054
|
+
conversation.processMessage({
|
|
1055
|
+
content: "msg-1",
|
|
1056
|
+
attachments: [],
|
|
1057
|
+
requestId: "req-1",
|
|
1058
|
+
});
|
|
1059
|
+
await waitForPendingRun(1);
|
|
1060
|
+
|
|
1061
|
+
conversation.enqueueMessage({
|
|
1062
|
+
content: "msg-2",
|
|
1063
|
+
onEvent: (e) => events2.push(e),
|
|
1064
|
+
requestId: "req-2",
|
|
1065
|
+
});
|
|
1066
|
+
expect(conversation.getQueueDepth()).toBe(1);
|
|
1067
|
+
|
|
1068
|
+
// WHEN the user hits Stop
|
|
1069
|
+
conversation.abort(
|
|
1070
|
+
createAbortReason("user_cancel", "conversation-queue.test", "conv-1"),
|
|
1071
|
+
);
|
|
1072
|
+
|
|
1073
|
+
// THEN the queued message survives the abort. Stop ends the turn the user
|
|
1074
|
+
// is watching, not the message they queued behind it, and a discard here
|
|
1075
|
+
// reaches no client: it emits no per-row terminal event.
|
|
1076
|
+
expect(conversation.getQueueDepth()).toBe(1);
|
|
1077
|
+
expect(
|
|
1078
|
+
events2.find((e) => e.type === "generation_cancelled"),
|
|
1079
|
+
).toBeUndefined();
|
|
1080
|
+
expect(
|
|
1081
|
+
events2.find((e) => e.type === "message_queued_deleted"),
|
|
1082
|
+
).toBeUndefined();
|
|
1083
|
+
|
|
1084
|
+
// AND once the stopped turn unwinds, its `finally` drains the queue, so the
|
|
1085
|
+
// message is sent instead of needing to be retyped.
|
|
1086
|
+
await resolveRun(0);
|
|
1087
|
+
await waitForPendingRun(2);
|
|
1088
|
+
expect(events2.find((e) => e.type === "message_dequeued")).toMatchObject({
|
|
1089
|
+
conversationId: "conv-1",
|
|
1090
|
+
requestId: "req-2",
|
|
1091
|
+
});
|
|
1092
|
+
expect(conversation.getQueueDepth()).toBe(0);
|
|
1093
|
+
expect(
|
|
1094
|
+
JSON.stringify(
|
|
1095
|
+
pendingRuns[1].messages[pendingRuns[1].messages.length - 1],
|
|
1096
|
+
),
|
|
1097
|
+
).toContain("msg-2");
|
|
1098
|
+
|
|
1099
|
+
await resolveRun(1);
|
|
1100
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
1101
|
+
});
|
|
1102
|
+
|
|
1103
|
+
test("a user interrupt mid-tool repairs the abandoned tool_use before the queued message runs", async () => {
|
|
1104
|
+
// GIVEN a turn whose history ends with an unanswered tool_use, the shape a
|
|
1105
|
+
// Stop mid-tool-call leaves behind and which providers reject outright
|
|
1106
|
+
const conversation = makeConversation();
|
|
1107
|
+
await conversation.loadFromDb();
|
|
1108
|
+
|
|
1109
|
+
const events2: AssistantEvent[] = [];
|
|
1110
|
+
conversation.processMessage({
|
|
1111
|
+
content: "msg-1",
|
|
1112
|
+
attachments: [],
|
|
1113
|
+
requestId: "req-1",
|
|
1114
|
+
});
|
|
1115
|
+
await waitForPendingRun(1);
|
|
1116
|
+
|
|
1117
|
+
conversation.enqueueMessage({
|
|
1118
|
+
content: "msg-2",
|
|
1119
|
+
onEvent: (e) => events2.push(e),
|
|
1120
|
+
requestId: "req-2",
|
|
1121
|
+
});
|
|
1122
|
+
|
|
1123
|
+
// WHEN the user interrupts and the stopped turn unwinds with the tool call
|
|
1124
|
+
// still unanswered, then drains the queue
|
|
1125
|
+
conversation.abort(
|
|
1126
|
+
createAbortReason("user_cancel", "conversation-queue.test", "conv-1"),
|
|
1127
|
+
);
|
|
1128
|
+
const interrupted = pendingRuns[0];
|
|
1129
|
+
await interrupted.onEvent({ type: "llm_call_started" });
|
|
1130
|
+
interrupted.resolve([
|
|
1131
|
+
...interrupted.messages,
|
|
1132
|
+
{
|
|
1133
|
+
role: "assistant",
|
|
1134
|
+
content: [
|
|
1135
|
+
{
|
|
1136
|
+
type: "tool_use",
|
|
1137
|
+
id: "toolu-interrupted",
|
|
1138
|
+
name: "bash",
|
|
1139
|
+
input: {},
|
|
1140
|
+
},
|
|
1141
|
+
],
|
|
1142
|
+
},
|
|
1143
|
+
]);
|
|
1144
|
+
await waitForPendingRun(2);
|
|
1145
|
+
|
|
1146
|
+
// THEN the drained turn opens with a synthetic result for the abandoned
|
|
1147
|
+
// call rather than a dangling tool_use.
|
|
1148
|
+
const repaired = pendingRuns[1].messages.find(
|
|
1149
|
+
(m) =>
|
|
1150
|
+
m.role === "user" &&
|
|
1151
|
+
m.content.some(
|
|
1152
|
+
(block) =>
|
|
1153
|
+
block.type === "tool_result" &&
|
|
1154
|
+
block.tool_use_id === "toolu-interrupted",
|
|
1155
|
+
),
|
|
1156
|
+
);
|
|
1157
|
+
expect(repaired).toBeDefined();
|
|
1158
|
+
expect(conversation.pendingInterruptRepair).toBe(false);
|
|
1159
|
+
|
|
1160
|
+
await resolveRun(1);
|
|
1161
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
1162
|
+
});
|
|
1163
|
+
|
|
900
1164
|
test("conversation-scoped errors emit both conversation_error and generic error", async () => {
|
|
901
1165
|
const conversation = makeConversation();
|
|
902
1166
|
await conversation.loadFromDb();
|
|
@@ -24,6 +24,7 @@ import { z } from "zod";
|
|
|
24
24
|
import {
|
|
25
25
|
isBackgroundEventMetadata,
|
|
26
26
|
isEchoSuppressedUserMessage,
|
|
27
|
+
isHiddenMessageMetadata,
|
|
27
28
|
} from "../persistence/conversation-types.js";
|
|
28
29
|
|
|
29
30
|
mock.module("../config/env.js", () => ({
|
|
@@ -73,7 +74,7 @@ const getConversationMock = mock((id: string) =>
|
|
|
73
74
|
mock.module("../persistence/conversation-crud.js", () => ({
|
|
74
75
|
addMessage: async () => ({ id: "unused", deduplicated: false }),
|
|
75
76
|
archiveConversation: () => true,
|
|
76
|
-
|
|
77
|
+
batchSetConversationPlacement: () => {},
|
|
77
78
|
countConversationsByScheduleJobId: () => 0,
|
|
78
79
|
deleteConversation: () => ({ segmentIds: [], deletedSummaryIds: [] }),
|
|
79
80
|
extractImageSourcePaths: () => undefined,
|
|
@@ -81,6 +82,7 @@ mock.module("../persistence/conversation-crud.js", () => ({
|
|
|
81
82
|
getConversation: getConversationMock,
|
|
82
83
|
isBackgroundEventMetadata,
|
|
83
84
|
isEchoSuppressedUserMessage,
|
|
85
|
+
isHiddenMessageMetadata,
|
|
84
86
|
provenanceFromTrustContext: () => ({ provenanceTrustClass: "unknown" }),
|
|
85
87
|
setConversationSurfaced: () => null,
|
|
86
88
|
unarchiveConversation: () => true,
|
|
@@ -175,8 +175,12 @@ describe("getOrCreateConversation ephemeral flag", () => {
|
|
|
175
175
|
|
|
176
176
|
await getOrCreateConversation("real-conversation-id");
|
|
177
177
|
|
|
178
|
+
// No trust context on this call, so no origin is asserted: the row is
|
|
179
|
+
// left unattributed for the first inbound message to claim, rather than
|
|
180
|
+
// being guessed as native.
|
|
178
181
|
expect(mockEnsureConversationExists).toHaveBeenCalledWith(
|
|
179
182
|
"real-conversation-id",
|
|
183
|
+
undefined,
|
|
180
184
|
);
|
|
181
185
|
});
|
|
182
186
|
});
|
|
@@ -304,7 +304,7 @@ describe("attachment orphan cleanup", () => {
|
|
|
304
304
|
"Here is a file",
|
|
305
305
|
);
|
|
306
306
|
|
|
307
|
-
const stored = uploadAttachment("chart.png", "image/png", "iVBOR");
|
|
307
|
+
const stored = await uploadAttachment("chart.png", "image/png", "iVBOR");
|
|
308
308
|
linkAttachmentToMessage(assistantMsg.id, stored.id, 0);
|
|
309
309
|
|
|
310
310
|
// Verify attachment is linked
|
|
@@ -331,7 +331,7 @@ describe("attachment orphan cleanup", () => {
|
|
|
331
331
|
await addMessage(conv.id, "user", "question");
|
|
332
332
|
const msg2 = await addMessage(conv.id, "assistant", "second");
|
|
333
333
|
|
|
334
|
-
const shared = uploadAttachment("shared.png", "image/png", "AAAA");
|
|
334
|
+
const shared = await uploadAttachment("shared.png", "image/png", "AAAA");
|
|
335
335
|
linkAttachmentToMessage(msg1.id, shared.id, 0);
|
|
336
336
|
linkAttachmentToMessage(msg2.id, shared.id, 0);
|
|
337
337
|
|
|
@@ -353,7 +353,11 @@ describe("attachment orphan cleanup", () => {
|
|
|
353
353
|
test("clearAll removes all attachments", async () => {
|
|
354
354
|
const conv = createConversation("test");
|
|
355
355
|
const msg = await addMessage(conv.id, "assistant", "file");
|
|
356
|
-
const stored = uploadAttachment(
|
|
356
|
+
const stored = await uploadAttachment(
|
|
357
|
+
"doc.pdf",
|
|
358
|
+
"application/pdf",
|
|
359
|
+
"JVBER",
|
|
360
|
+
);
|
|
357
361
|
linkAttachmentToMessage(msg.id, stored.id, 0);
|
|
358
362
|
|
|
359
363
|
await clearAll();
|
|
@@ -441,11 +445,11 @@ describe("attachment orphan cleanup", () => {
|
|
|
441
445
|
);
|
|
442
446
|
|
|
443
447
|
// An attachment linked to the assistant message (should be cleaned up)
|
|
444
|
-
const linked = uploadAttachment("chart.png", "image/png", "iVBOR");
|
|
448
|
+
const linked = await uploadAttachment("chart.png", "image/png", "iVBOR");
|
|
445
449
|
linkAttachmentToMessage(assistantMsg.id, linked.id, 0);
|
|
446
450
|
|
|
447
451
|
// A freshly uploaded attachment not linked to any message (should survive)
|
|
448
|
-
uploadAttachment("pending.png", "image/png", "AAAA");
|
|
452
|
+
await uploadAttachment("pending.png", "image/png", "AAAA");
|
|
449
453
|
|
|
450
454
|
deleteLastExchange(conv.id);
|
|
451
455
|
|
|
@@ -543,7 +547,7 @@ describe("attachment reuse across conversation lifecycles", () => {
|
|
|
543
547
|
test("attachment uploaded in conversation A is retrievable by ID without any conversation reference", async () => {
|
|
544
548
|
const convA = createConversation("Conversation A");
|
|
545
549
|
const msgA = await addMessage(convA.id, "assistant", "Here is a file");
|
|
546
|
-
const stored = uploadAttachment(
|
|
550
|
+
const stored = await uploadAttachment(
|
|
547
551
|
"report.pdf",
|
|
548
552
|
"application/pdf",
|
|
549
553
|
"JVBERA==",
|
|
@@ -570,7 +574,11 @@ describe("attachment reuse across conversation lifecycles", () => {
|
|
|
570
574
|
const msgB = await addMessage(convB.id, "assistant", "Reused file");
|
|
571
575
|
|
|
572
576
|
// Upload once, link to both conversations
|
|
573
|
-
const stored = uploadAttachment(
|
|
577
|
+
const stored = await uploadAttachment(
|
|
578
|
+
"shared.png",
|
|
579
|
+
"image/png",
|
|
580
|
+
"iVBORw0K",
|
|
581
|
+
);
|
|
574
582
|
linkAttachmentToMessage(msgA.id, stored.id, 0);
|
|
575
583
|
linkAttachmentToMessage(msgB.id, stored.id, 0);
|
|
576
584
|
|
|
@@ -595,7 +603,7 @@ describe("attachment reuse across conversation lifecycles", () => {
|
|
|
595
603
|
await addMessage(convB.id, "user", "Show me the chart");
|
|
596
604
|
const msgB = await addMessage(convB.id, "assistant", "Reused");
|
|
597
605
|
|
|
598
|
-
const stored = uploadAttachment("chart.png", "image/png", "AAAA");
|
|
606
|
+
const stored = await uploadAttachment("chart.png", "image/png", "AAAA");
|
|
599
607
|
linkAttachmentToMessage(msgA.id, stored.id, 0);
|
|
600
608
|
linkAttachmentToMessage(msgB.id, stored.id, 0);
|
|
601
609
|
const linkedB = getAttachmentsForMessage(msgB.id);
|
|
@@ -621,8 +629,16 @@ describe("attachment reuse across conversation lifecycles", () => {
|
|
|
621
629
|
await addMessage(convA.id, "user", "upload in A");
|
|
622
630
|
await addMessage(convB.id, "user", "upload in B");
|
|
623
631
|
|
|
624
|
-
const first = uploadAttachment(
|
|
625
|
-
|
|
632
|
+
const first = await uploadAttachment(
|
|
633
|
+
"photo.png",
|
|
634
|
+
"image/png",
|
|
635
|
+
"DEDUPCROSS",
|
|
636
|
+
);
|
|
637
|
+
const second = await uploadAttachment(
|
|
638
|
+
"photo.png",
|
|
639
|
+
"image/png",
|
|
640
|
+
"DEDUPCROSS",
|
|
641
|
+
);
|
|
626
642
|
|
|
627
643
|
expect(second.id).not.toBe(first.id);
|
|
628
644
|
});
|
|
@@ -53,7 +53,7 @@ const getConversationMock = mock((id: string) =>
|
|
|
53
53
|
mock.module("../persistence/conversation-crud.js", () => ({
|
|
54
54
|
addMessage: addMessageMock,
|
|
55
55
|
archiveConversation: () => true,
|
|
56
|
-
|
|
56
|
+
batchSetConversationPlacement: () => {},
|
|
57
57
|
countConversationsByScheduleJobId: () => 0,
|
|
58
58
|
deleteConversation: () => ({ segmentIds: [], deletedSummaryIds: [] }),
|
|
59
59
|
extractImageSourcePaths: () => undefined,
|
|
@@ -9,12 +9,23 @@ mock.module("../runtime/assistant-event-hub.js", () => ({
|
|
|
9
9
|
broadcastMessage: (msg: AssistantEvent) => broadcastedMessages.push(msg),
|
|
10
10
|
}));
|
|
11
11
|
|
|
12
|
+
// These surfaces are shown live and asserted through their client messages, so
|
|
13
|
+
// history holds nothing. Stand in an empty store: the completion path reads
|
|
14
|
+
// persisted `ui_surface` blocks, and this file's DB carries no schema, so the
|
|
15
|
+
// real read would throw and be indistinguishable from a persistence failure.
|
|
16
|
+
const realCrud = await import("../persistence/conversation-crud.js");
|
|
17
|
+
mock.module("../persistence/conversation-crud.js", () => ({
|
|
18
|
+
...realCrud,
|
|
19
|
+
getMessages: () => [],
|
|
20
|
+
}));
|
|
21
|
+
|
|
12
22
|
const { createSurfaceMutex, handleSurfaceAction, surfaceProxyResolver } =
|
|
13
23
|
await import("../daemon/conversation-surfaces.js");
|
|
14
24
|
|
|
15
|
-
import type {
|
|
25
|
+
import type { Conversation } from "../daemon/conversation.js";
|
|
16
26
|
import type { SurfaceType, UiSurfaceShow } from "../daemon/message-protocol.js";
|
|
17
27
|
import type { UserMessageAttachment } from "../daemon/message-types/shared.js";
|
|
28
|
+
import { asConversation } from "./helpers/mock-conversation.js";
|
|
18
29
|
|
|
19
30
|
interface ProcessMessageCall {
|
|
20
31
|
content: string;
|
|
@@ -25,13 +36,11 @@ interface ProcessMessageCall {
|
|
|
25
36
|
sourceActorPrincipalId?: string;
|
|
26
37
|
}
|
|
27
38
|
|
|
28
|
-
function makeContext(
|
|
29
|
-
sent: AssistantEvent[] = [],
|
|
30
|
-
): SurfaceConversationContext & {
|
|
39
|
+
function makeContext(sent: AssistantEvent[] = []): Conversation & {
|
|
31
40
|
processMessageCalls: ProcessMessageCall[];
|
|
32
41
|
} {
|
|
33
42
|
const processMessageCalls: ProcessMessageCall[] = [];
|
|
34
|
-
return {
|
|
43
|
+
return asConversation({
|
|
35
44
|
conversationId: "conv-1",
|
|
36
45
|
sendToClient: (msg: AssistantEvent) => sent.push(msg),
|
|
37
46
|
pendingSurfaceActions: new Map<string, { surfaceType: SurfaceType }>(),
|
|
@@ -60,7 +69,7 @@ function makeContext(
|
|
|
60
69
|
},
|
|
61
70
|
withSurface: createSurfaceMutex(),
|
|
62
71
|
processMessageCalls,
|
|
63
|
-
};
|
|
72
|
+
});
|
|
64
73
|
}
|
|
65
74
|
|
|
66
75
|
describe("surface action delivery to assistant", () => {
|
|
@@ -29,7 +29,8 @@ const {
|
|
|
29
29
|
surfaceProxyResolver,
|
|
30
30
|
} = await import("../daemon/conversation-surfaces.js");
|
|
31
31
|
|
|
32
|
-
import type {
|
|
32
|
+
import type { Conversation } from "../daemon/conversation.js";
|
|
33
|
+
import type { ProcessMessageOptions } from "../daemon/conversation-process.js";
|
|
33
34
|
import type { SurfaceType, UiSurfaceShow } from "../daemon/message-protocol.js";
|
|
34
35
|
import {
|
|
35
36
|
getMemorySqlite,
|
|
@@ -61,7 +62,7 @@ interface ProcessMessageCall {
|
|
|
61
62
|
function makeContext(
|
|
62
63
|
conversationId: string,
|
|
63
64
|
sent: AssistantEvent[] = [],
|
|
64
|
-
):
|
|
65
|
+
): Conversation & {
|
|
65
66
|
processMessageCalls: ProcessMessageCall[];
|
|
66
67
|
} {
|
|
67
68
|
const processMessageCalls: ProcessMessageCall[] = [];
|
|
@@ -81,7 +82,7 @@ function makeContext(
|
|
|
81
82
|
isProcessing: () => false,
|
|
82
83
|
enqueueMessage: () => ({ queued: false, requestId: "req-1" }),
|
|
83
84
|
getQueueDepth: () => 0,
|
|
84
|
-
processMessage: async (options) => {
|
|
85
|
+
processMessage: async (options: ProcessMessageOptions) => {
|
|
85
86
|
processMessageCalls.push({
|
|
86
87
|
content: options.content,
|
|
87
88
|
activeSurfaceId: options.activeSurfaceId,
|
|
@@ -90,7 +91,7 @@ function makeContext(
|
|
|
90
91
|
},
|
|
91
92
|
withSurface: createSurfaceMutex(),
|
|
92
93
|
processMessageCalls,
|
|
93
|
-
} as
|
|
94
|
+
} as unknown as Conversation & {
|
|
94
95
|
processMessageCalls: ProcessMessageCall[];
|
|
95
96
|
};
|
|
96
97
|
}
|
|
@@ -102,7 +103,7 @@ function resetTables(): void {
|
|
|
102
103
|
|
|
103
104
|
/** Render a choice surface tagged (or not) with an activation_moment. */
|
|
104
105
|
async function showTaggedChoice(
|
|
105
|
-
ctx:
|
|
106
|
+
ctx: Conversation,
|
|
106
107
|
sent: AssistantEvent[],
|
|
107
108
|
activationMoment?: string,
|
|
108
109
|
): Promise<string> {
|
|
@@ -9,11 +9,13 @@
|
|
|
9
9
|
|
|
10
10
|
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
11
11
|
|
|
12
|
+
import { asConversation } from "./helpers/mock-conversation.js";
|
|
13
|
+
|
|
12
14
|
const sentMessages: unknown[] = [];
|
|
13
15
|
let mockHasClient = true;
|
|
14
16
|
// Default principal id used for both ctx.trustContext and clients in the
|
|
15
17
|
// existing single-user tests. Tests that exercise cross-user behaviour
|
|
16
|
-
// override this on individual clients and on the
|
|
18
|
+
// override this on individual clients and on the Conversation.
|
|
17
19
|
const DEFAULT_PRINCIPAL = "user-1";
|
|
18
20
|
type MockClient = {
|
|
19
21
|
clientId: string;
|
|
@@ -47,22 +49,21 @@ mock.module("../runtime/pending-interactions.js", () => ({
|
|
|
47
49
|
removeByConversation: () => {},
|
|
48
50
|
}));
|
|
49
51
|
|
|
50
|
-
const { surfaceProxyResolver } =
|
|
52
|
+
const { createSurfaceMutex, surfaceProxyResolver } =
|
|
51
53
|
await import("../daemon/conversation-surfaces.js");
|
|
52
54
|
const {
|
|
53
55
|
HostAppControlProxy,
|
|
54
56
|
_resetActiveAppControlSession,
|
|
55
57
|
_setActiveAppControlSession,
|
|
56
58
|
} = await import("../daemon/host-app-control-proxy.js");
|
|
57
|
-
type
|
|
58
|
-
import("../daemon/conversation-surfaces.js").SurfaceConversationContext;
|
|
59
|
+
type Conversation = import("../daemon/conversation.js").Conversation;
|
|
59
60
|
|
|
60
61
|
// ---------------------------------------------------------------------------
|
|
61
62
|
// Test helpers
|
|
62
63
|
// ---------------------------------------------------------------------------
|
|
63
64
|
|
|
64
65
|
/**
|
|
65
|
-
* Build a minimal
|
|
66
|
+
* Build a minimal Conversation with an optional
|
|
66
67
|
* hostAppControlProxy. Only the fields required by the app-control routing
|
|
67
68
|
* path are populated.
|
|
68
69
|
*/
|
|
@@ -74,8 +75,8 @@ function buildMockContext(
|
|
|
74
75
|
) => void,
|
|
75
76
|
trustGuardianPrincipalId: string | null = DEFAULT_PRINCIPAL,
|
|
76
77
|
actorPrincipalId: string | null = trustGuardianPrincipalId,
|
|
77
|
-
):
|
|
78
|
-
return {
|
|
78
|
+
): Conversation {
|
|
79
|
+
return asConversation({
|
|
79
80
|
conversationId,
|
|
80
81
|
trustContext:
|
|
81
82
|
trustGuardianPrincipalId != null
|
|
@@ -87,13 +88,13 @@ function buildMockContext(
|
|
|
87
88
|
: undefined,
|
|
88
89
|
authContext:
|
|
89
90
|
actorPrincipalId != null
|
|
90
|
-
? ({ actorPrincipalId } as
|
|
91
|
+
? ({ actorPrincipalId } as Conversation["authContext"])
|
|
91
92
|
: undefined,
|
|
92
93
|
currentTurnAuthContext:
|
|
93
94
|
actorPrincipalId != null
|
|
94
95
|
? ({
|
|
95
96
|
actorPrincipalId,
|
|
96
|
-
} as
|
|
97
|
+
} as Conversation["currentTurnAuthContext"])
|
|
97
98
|
: undefined,
|
|
98
99
|
sendToClient: () => {},
|
|
99
100
|
pendingSurfaceActions: new Map(),
|
|
@@ -109,8 +110,8 @@ function buildMockContext(
|
|
|
109
110
|
enqueueMessage: () => ({ queued: false, requestId: "r1" }),
|
|
110
111
|
getQueueDepth: () => 0,
|
|
111
112
|
processMessage: async () => "",
|
|
112
|
-
withSurface:
|
|
113
|
-
};
|
|
113
|
+
withSurface: createSurfaceMutex(),
|
|
114
|
+
});
|
|
114
115
|
}
|
|
115
116
|
|
|
116
117
|
// ---------------------------------------------------------------------------
|
|
@@ -2,13 +2,17 @@ import { describe, expect, test } from "bun:test";
|
|
|
2
2
|
|
|
3
3
|
import type { AssistantEvent } from "../api/index.js";
|
|
4
4
|
import { DynamicPagePreviewSchema } from "../api/surfaces.js";
|
|
5
|
+
import type { Conversation } from "../daemon/conversation.js";
|
|
5
6
|
import {
|
|
6
7
|
buildAppOpenPreview,
|
|
7
8
|
createSurfaceMutex,
|
|
8
|
-
type SurfaceConversationContext,
|
|
9
9
|
surfaceProxyResolver,
|
|
10
10
|
} from "../daemon/conversation-surfaces.js";
|
|
11
11
|
import type { SurfaceType } from "../daemon/message-protocol.js";
|
|
12
|
+
import {
|
|
13
|
+
asConversation,
|
|
14
|
+
mockChannelCapabilities,
|
|
15
|
+
} from "./helpers/mock-conversation.js";
|
|
12
16
|
|
|
13
17
|
interface ContextOptions {
|
|
14
18
|
hasNoClient?: boolean;
|
|
@@ -18,11 +22,13 @@ interface ContextOptions {
|
|
|
18
22
|
function makeContext(
|
|
19
23
|
sent: AssistantEvent[] = [],
|
|
20
24
|
options: ContextOptions = {},
|
|
21
|
-
):
|
|
22
|
-
return {
|
|
25
|
+
): Conversation {
|
|
26
|
+
return asConversation({
|
|
23
27
|
conversationId: "session-1",
|
|
24
28
|
hasNoClient: options.hasNoClient,
|
|
25
|
-
channelCapabilities:
|
|
29
|
+
channelCapabilities:
|
|
30
|
+
options.channelCapabilities &&
|
|
31
|
+
mockChannelCapabilities(options.channelCapabilities),
|
|
26
32
|
sendToClient: (msg) => sent.push(msg),
|
|
27
33
|
pendingSurfaceActions: new Map<string, { surfaceType: SurfaceType }>(),
|
|
28
34
|
lastSurfaceAction: new Map<
|
|
@@ -39,7 +45,7 @@ function makeContext(
|
|
|
39
45
|
getQueueDepth: () => 0,
|
|
40
46
|
processMessage: async () => "ok",
|
|
41
47
|
withSurface: createSurfaceMutex(),
|
|
42
|
-
};
|
|
48
|
+
});
|
|
43
49
|
}
|
|
44
50
|
|
|
45
51
|
describe("app_open render-capability gate", () => {
|