@vellumai/assistant 0.11.2 → 0.11.3-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +58 -3
- package/docs/trusted-contact-access.md +9 -5
- package/docs/vellum-doctor.md +195 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/ces-client/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/src/rpc-client.ts +19 -2
- package/node_modules/@vellumai/environments/package.json +2 -1
- package/node_modules/@vellumai/environments/src/__tests__/cloud-assistant-hub-url.test.ts +38 -0
- package/node_modules/@vellumai/environments/src/__tests__/install-layout.test.ts +98 -0
- package/node_modules/@vellumai/environments/src/__tests__/package-boundary.test.ts +5 -5
- package/node_modules/@vellumai/environments/src/index.ts +17 -6
- package/node_modules/@vellumai/environments/src/install-layout.ts +49 -0
- package/node_modules/@vellumai/environments/src/seeds.ts +29 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +4 -0
- package/node_modules/@vellumai/gateway-client/src/verification-session-contract.ts +91 -6
- package/node_modules/@vellumai/ipc-server-utils/src/endpoint.test.ts +36 -0
- package/node_modules/@vellumai/ipc-server-utils/src/endpoint.ts +142 -0
- package/node_modules/@vellumai/ipc-server-utils/src/index.ts +2 -0
- package/node_modules/@vellumai/ipc-server-utils/src/listen-options.ts +3 -0
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +15 -1
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +17 -2
- package/node_modules/@vellumai/service-contracts/src/channels.ts +39 -0
- package/node_modules/@vellumai/service-contracts/src/ingress.ts +10 -0
- package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +6 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +16 -2
- package/openapi.yaml +589 -30
- package/package.json +1 -1
- package/src/__tests__/agent-image-optimize.test.ts +4 -4
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +113 -66
- package/src/__tests__/agent-loop-override-profile.test.ts +38 -48
- package/src/__tests__/agent-loop-subagent-billing-headers.test.ts +166 -0
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
- package/src/__tests__/answered-question-persistence.test.ts +240 -0
- package/src/__tests__/anthropic-provider.test.ts +165 -30
- package/src/__tests__/app-control-flow.test.ts +9 -8
- package/src/__tests__/assistant-event-hub.test.ts +48 -0
- package/src/__tests__/attachments-store-heic-normalize.test.ts +16 -12
- package/src/__tests__/attachments-store.test.ts +130 -68
- package/src/__tests__/attachments.test.ts +36 -36
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
- package/src/__tests__/call-start-guardian-guard.test.ts +18 -4
- package/src/__tests__/canned-reply-release.test.ts +86 -0
- package/src/__tests__/channel-guardian.test.ts +59 -29
- package/src/__tests__/channel-readiness-telegram-remote.test.ts +154 -0
- package/src/__tests__/channel-setup-panel-ack.test.ts +6 -5
- package/src/__tests__/client-os-metadata-persistence.test.ts +103 -4
- package/src/__tests__/compactor-image-manifest-trust.test.ts +1 -1
- package/src/__tests__/consult-deadline.test.ts +65 -0
- package/src/__tests__/conversation-agent-loop.test.ts +438 -2
- package/src/__tests__/conversation-disk-view-integration.test.ts +5 -1
- package/src/__tests__/conversation-disk-view.test.ts +4 -4
- package/src/__tests__/conversation-error.test.ts +22 -3
- package/src/__tests__/conversation-fork-crud.test.ts +5 -1
- package/src/__tests__/conversation-fork-referential.test.ts +352 -0
- package/src/__tests__/conversation-fork-retrospective.test.ts +5 -1
- package/src/__tests__/conversation-group-tools.test.ts +32 -2
- package/src/__tests__/conversation-inference-profile-route.test.ts +27 -1
- package/src/__tests__/conversation-initial-prompt.test.ts +51 -22
- package/src/__tests__/conversation-key-store-bootstrap-cleanup.test.ts +119 -0
- package/src/__tests__/conversation-key-store-origin.test.ts +105 -0
- package/src/__tests__/conversation-list-recency-ordering.test.ts +104 -0
- package/src/__tests__/conversation-origin-at-creation.test.ts +153 -0
- package/src/__tests__/conversation-origin-channel-filter.test.ts +95 -0
- package/src/__tests__/conversation-placement-promotion.test.ts +172 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +123 -0
- package/src/__tests__/conversation-queue.test.ts +433 -1
- package/src/__tests__/conversation-retry-route.test.ts +3 -1
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +64 -1
- package/src/__tests__/conversation-store-ephemeral.test.ts +4 -0
- package/src/__tests__/conversation-store.test.ts +26 -10
- package/src/__tests__/conversation-summarize-route.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +15 -6
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -5
- package/src/__tests__/conversation-surfaces-app-control.test.ts +12 -11
- package/src/__tests__/conversation-surfaces-app-open.test.ts +11 -5
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +5 -4
- package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +967 -0
- package/src/__tests__/conversation-surfaces-persisted-info.test.ts +312 -0
- package/src/__tests__/conversation-surfaces-queued-emit.test.ts +6 -5
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -8
- package/src/__tests__/conversation-surfaces-standalone.test.ts +21 -11
- package/src/__tests__/conversation-surfaces-state-update.test.ts +7 -11
- package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -6
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +11 -6
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +9 -6
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +70 -7
- package/src/__tests__/conversation-wait-for-idle.test.ts +6 -11
- package/src/__tests__/credential-prompt-route.test.ts +57 -7
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/cu-unified-flow.test.ts +89 -28
- package/src/__tests__/custom-group-listing-visibility.test.ts +1 -1
- package/src/__tests__/db-schedule-syntax-migration.test.ts +4 -1
- package/src/__tests__/discord-access-request-privacy.test.ts +366 -0
- package/src/__tests__/discord-requester-notice-privacy.test.ts +87 -0
- package/src/__tests__/disk-pressure-guard.test.ts +55 -55
- package/src/__tests__/disk-pressure-routes.test.ts +10 -10
- package/src/__tests__/disk-pressure-tools.test.ts +2 -2
- package/src/__tests__/disk-usage.test.ts +35 -20
- package/src/__tests__/document-sync-tags.test.ts +379 -0
- package/src/__tests__/document-update-default-surface.test.ts +28 -0
- package/src/__tests__/dynamic-skill-background-guard.test.ts +2 -2
- package/src/__tests__/emit-signal-routing-intent.test.ts +3 -4
- package/src/__tests__/ensure-conversation-exists.test.ts +8 -5
- package/src/__tests__/events-dev-bypass-actor.test.ts +183 -1
- package/src/__tests__/evict-conversations-for-reload.test.ts +90 -0
- package/src/__tests__/file-list-tool.test.ts +12 -10
- package/src/__tests__/file-ops-service.test.ts +151 -44
- package/src/__tests__/file-read-container-boundary.test.ts +137 -0
- package/src/__tests__/file-read-tool.test.ts +21 -9
- package/src/__tests__/file-url-path-guard.test.ts +83 -0
- package/src/__tests__/filesystem-tools.test.ts +82 -66
- package/src/__tests__/guardian-outbound-http.test.ts +8 -8
- package/src/__tests__/helpers/gateway-verification-sessions-stub.ts +14 -1
- package/src/__tests__/helpers/hub-clients.ts +42 -0
- package/src/__tests__/helpers/mock-conversation.ts +46 -0
- package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +61 -57
- package/src/__tests__/history-repair.test.ts +112 -12
- package/src/__tests__/host-bash-proxy.test.ts +10 -5
- package/src/__tests__/host-bash-routes.test.ts +67 -0
- package/src/__tests__/host-browser-proxy.test.ts +2 -2
- package/src/__tests__/host-cu-proxy.test.ts +3 -7
- package/src/__tests__/host-file-proxy.test.ts +3 -7
- package/src/__tests__/host-file-read-tool.test.ts +5 -1
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +6 -4
- package/src/__tests__/http-conversation-lineage.test.ts +2 -5
- package/src/__tests__/http-user-message-parity.test.ts +44 -0
- package/src/__tests__/identity-routes.test.ts +13 -13
- package/src/__tests__/image-conversion.test.ts +29 -26
- package/src/__tests__/image-source-path-reinject.test.ts +2 -2
- package/src/__tests__/inference-profile-session-handler.test.ts +95 -0
- package/src/__tests__/inference-profile-session-ipc.test.ts +25 -0
- package/src/__tests__/introduction-card-resolver.test.ts +6 -1
- package/src/__tests__/list-messages-attachments.test.ts +56 -32
- package/src/__tests__/list-messages-background-tool-completion.test.ts +4 -4
- package/src/__tests__/list-messages-client-message-id.test.ts +2 -2
- package/src/__tests__/list-messages-hidden-metadata.test.ts +16 -16
- package/src/__tests__/list-messages-page-latest.test.ts +61 -61
- package/src/__tests__/list-messages-provider-error.test.ts +6 -6
- package/src/__tests__/list-messages-queued.test.ts +49 -6
- package/src/__tests__/list-messages-system-card.test.ts +4 -4
- package/src/__tests__/list-messages-tool-merge.test.ts +9 -9
- package/src/__tests__/llm-resolver-override-or-default.test.ts +141 -0
- package/src/__tests__/llm-usage-store.test.ts +55 -0
- package/src/__tests__/manual-token-reconciliation.test.ts +45 -0
- package/src/__tests__/mcp-tool-annotations-risk.test.ts +133 -0
- package/src/__tests__/media-stream-server-integration.test.ts +36 -0
- package/src/__tests__/migration-export-http.test.ts +1 -1
- package/src/__tests__/migration-import-commit-http.test.ts +1 -1
- package/src/__tests__/migration-import-preflight-http.test.ts +1 -1
- package/src/__tests__/migration-validate-http.test.ts +1 -1
- package/src/__tests__/mtime-cache.test.ts +65 -3
- package/src/__tests__/notification-platform-adapter.test.ts +104 -0
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +1 -1
- package/src/__tests__/oauth-provider-profiles.test.ts +4 -2
- package/src/__tests__/oauth-provider-seed-logos.test.ts +65 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +17 -0
- package/src/__tests__/oauth-providers-routes.test.ts +1 -0
- package/src/__tests__/openai-responses-prompt-cache.test.ts +5 -2
- package/src/__tests__/path-policy.test.ts +164 -1
- package/src/__tests__/persist-media-references.test.ts +2 -2
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +5 -5
- package/src/__tests__/persist-unsendable-image.test.ts +23 -23
- package/src/__tests__/persona-resolver.test.ts +154 -0
- package/src/__tests__/plugin-api-webhook-url.test.ts +170 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +6 -0
- package/src/__tests__/processing-flag-persist-failure.test.ts +15 -10
- package/src/__tests__/profile-availability-incomplete.test.ts +113 -0
- package/src/__tests__/profiler-routes.test.ts +13 -13
- package/src/__tests__/prompt-cache-cross-turn-stability.test.ts +593 -0
- package/src/__tests__/proxy-approval-callback.test.ts +3 -3
- package/src/__tests__/queued-message-cancel-and-steer.test.ts +189 -0
- package/src/__tests__/queued-message-steer-actor-scoping.test.ts +164 -0
- package/src/__tests__/resolve-trust-class.test.ts +20 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +1 -1
- package/src/__tests__/run-due-schedules.test.ts +174 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +15 -7
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +166 -0
- package/src/__tests__/schedule-routes.test.ts +730 -8
- package/src/__tests__/schedule-store.test.ts +540 -0
- package/src/__tests__/schedule-tools.test.ts +103 -0
- package/src/__tests__/scheduler-wake.test.ts +5 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +29 -1
- package/src/__tests__/secure-keys.test.ts +91 -0
- package/src/__tests__/server-history-render.test.ts +97 -7
- package/src/__tests__/size-guard.test.ts +8 -8
- package/src/__tests__/skill-docs-sync-guard.test.ts +3 -2
- package/src/__tests__/skill-tool-factory.test.ts +247 -0
- package/src/__tests__/skills-install-staging.test.ts +15 -6
- package/src/__tests__/slack-edit-ordering-characterization.test.ts +103 -0
- package/src/__tests__/slack-inbound-verification.test.ts +4 -1
- package/src/__tests__/slack-mention-binding-invariance.test.ts +103 -0
- package/src/__tests__/slack-mention-provider-leak-audit.test.ts +135 -0
- package/src/__tests__/starter-task-flow.test.ts +5 -4
- package/src/__tests__/steer-on-enqueue-question.test.ts +3 -2
- package/src/__tests__/stt-language-catalog-parity.test.ts +38 -0
- package/src/__tests__/subagent-allowlist-validation.test.ts +26 -4
- package/src/__tests__/subagent-cron-run-attribution.test.ts +301 -0
- package/src/__tests__/subagent-disposal.test.ts +10 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +10 -0
- package/src/__tests__/subagent-fork-prompt-role.test.ts +85 -11
- package/src/__tests__/subagent-fork-spawn.test.ts +15 -7
- package/src/__tests__/subagent-manager-notify.test.ts +148 -0
- package/src/__tests__/subagent-notify-parent.test.ts +1 -1
- package/src/__tests__/subagent-persistence.test.ts +141 -0
- package/src/__tests__/subagent-role-registry.test.ts +172 -63
- package/src/__tests__/subagent-role-resolution.test.ts +88 -0
- package/src/__tests__/subagent-spawn-and-await.test.ts +48 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +111 -10
- package/src/__tests__/subagent-terminal-message.test.ts +88 -1
- package/src/__tests__/subagent-tool-gate-mode.test.ts +225 -10
- package/src/__tests__/subagent-tools.test.ts +1901 -108
- package/src/__tests__/surface-completion-compaction-boundary.test.ts +124 -0
- package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +298 -0
- package/src/__tests__/system-prompt.test.ts +82 -7
- package/src/__tests__/tool-grant-request-escalation.test.ts +40 -1
- package/src/__tests__/tool-result-spool.test.ts +74 -18
- package/src/__tests__/tool-side-effects-documents.test.ts +174 -0
- package/src/__tests__/tool-side-effects-hook-failures.test.ts +129 -0
- package/src/__tests__/tools-audio-read.test.ts +10 -10
- package/src/__tests__/tools-get-route.test.ts +85 -12
- package/src/__tests__/tools-list-cli.test.ts +171 -0
- package/src/__tests__/top-level-renderer.test.ts +54 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +68 -1
- package/src/__tests__/trusted-contact-multichannel.test.ts +4 -1
- package/src/__tests__/turn-tail-chain.test.ts +135 -0
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +6 -4
- package/src/__tests__/ui-visual-surface.test.ts +5 -4
- package/src/__tests__/ui-work-result-surface.test.ts +5 -4
- package/src/__tests__/unified-turn-context-visible-app.test.ts +7 -8
- package/src/__tests__/usage-routes.test.ts +62 -0
- package/src/__tests__/verification-outbound-delivery.test.ts +176 -0
- package/src/__tests__/visible-app-context.test.ts +20 -4
- package/src/__tests__/web-search-history.test.ts +96 -0
- package/src/__tests__/workspace-migration-139-clear-renamed-cost-profile-label.test.ts +6 -6
- package/src/__tests__/workspace-migration-140-repair-seed-pinned-memory-v3-live.test.ts +330 -0
- package/src/acp/failure-error.ts +3 -5
- package/src/agent/attachments.ts +26 -24
- package/src/agent/history-repair/history-repair.ts +27 -26
- package/src/agent/image-optimize.ts +6 -6
- package/src/agent/loop.ts +40 -22
- package/src/agent/message-types.ts +3 -3
- package/src/api/constants/document-tools.ts +55 -0
- package/src/api/events/question-answered.ts +53 -0
- package/src/api/events/tool-result.ts +7 -0
- package/src/api/index.ts +13 -0
- package/src/api/responses/conversation-message.ts +11 -0
- package/src/api/surfaces-oauth-connect.test.ts +96 -0
- package/src/api/surfaces.ts +36 -8
- package/src/approvals/guardian-channel-delivery.ts +83 -0
- package/src/approvals/guardian-expiry-notifier.ts +13 -11
- package/src/approvals/guardian-request-resolvers.ts +222 -135
- package/src/calls/__tests__/voice-session-bridge.test.ts +50 -0
- package/src/calls/media-stream-server.ts +9 -1
- package/src/calls/voice-session-bridge.ts +38 -0
- package/src/channels/__tests__/gateway-verification-sessions.test.ts +3 -3
- package/src/channels/config.ts +7 -2
- package/src/channels/gateway-verification-sessions.ts +7 -2
- package/src/channels/types.ts +7 -1
- package/src/cli/commands/__tests__/cache.test.ts +7 -4
- package/src/cli/commands/__tests__/cli-test-harness.ts +82 -0
- package/src/cli/commands/__tests__/conversations-wake.test.ts +51 -6
- package/src/cli/commands/__tests__/inference-models.test.ts +14 -0
- package/src/cli/commands/__tests__/inference-profiles.test.ts +44 -1
- package/src/cli/commands/__tests__/inference-providers.test.ts +7 -0
- package/src/cli/commands/__tests__/plugins.test.ts +692 -0
- package/src/cli/commands/__tests__/schedules.test.ts +136 -37
- package/src/cli/commands/conversations.ts +7 -3
- package/src/cli/commands/credentials.help.ts +7 -0
- package/src/cli/commands/inference-profiles.ts +9 -3
- package/src/cli/commands/inference.help.ts +16 -2
- package/src/cli/commands/mcp.help.ts +4 -2
- package/src/cli/commands/memory/memory-retrospective.ts +18 -0
- package/src/cli/commands/notifications.ts +3 -6
- package/src/cli/commands/oauth/connect-surface-guidance.test.ts +16 -0
- package/src/cli/commands/oauth/connect-surface-guidance.ts +25 -7
- package/src/cli/commands/oauth/connect.test.ts +26 -1
- package/src/cli/commands/oauth/connect.ts +4 -1
- package/src/cli/commands/oauth/index.help.ts +3 -1
- package/src/cli/commands/oauth/providers.ts +3 -0
- package/src/cli/commands/plugins.help.ts +25 -2
- package/src/cli/commands/plugins.ts +289 -10
- package/src/cli/commands/schedules.help.ts +14 -12
- package/src/cli/commands/schedules.ts +19 -5
- package/src/cli/commands/tools.help.ts +4 -2
- package/src/cli/commands/tools.ts +38 -0
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +1 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +79 -0
- package/src/cli/lib/__tests__/install-from-platform.test.ts +47 -1
- package/src/cli/lib/__tests__/plugin-surfaces.test.ts +86 -7
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +122 -0
- package/src/cli/lib/install-from-github.ts +61 -0
- package/src/cli/lib/install-from-platform.ts +13 -2
- package/src/cli/lib/plugin-surfaces.ts +124 -4
- package/src/cli/lib/upgrade-plugin.ts +18 -0
- package/src/cli.ts +1 -1
- package/src/config/__tests__/deployment-context-defaults.test.ts +73 -0
- package/src/config/__tests__/memory-retrospective-schema.test.ts +40 -0
- package/src/config/__tests__/plugin-updates-schema.test.ts +43 -0
- package/src/config/__tests__/profile-tool-support.test.ts +131 -0
- package/src/config/bundled-skills/AGENTS.md +1 -1
- package/src/config/bundled-skills/app-builder/SKILL.md +1 -1
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +3 -3
- package/src/config/bundled-skills/schedule/SKILL.md +5 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +1 -0
- package/src/config/bundled-skills/subagent/SKILL.md +53 -22
- package/src/config/bundled-skills/subagent/TOOLS.json +14 -13
- package/src/config/bundled-skills/visualize/SKILL.md +1 -1
- package/src/config/default-profile-catalog.ts +6 -2
- package/src/config/feature-flag-registry.json +25 -17
- package/src/config/llm-resolver.ts +45 -15
- package/src/config/loader.ts +70 -1
- package/src/config/profile-tool-support.ts +110 -0
- package/src/config/sanitize-for-transfer.ts +11 -0
- package/src/config/schema.ts +4 -0
- package/src/config/schemas/__tests__/stt.test.ts +20 -5
- package/src/config/schemas/channels.ts +13 -0
- package/src/config/schemas/memory-retrospective.ts +25 -0
- package/src/config/schemas/plugin-updates.ts +55 -0
- package/src/config/schemas/services.ts +8 -4
- package/src/config/schemas/stt.ts +17 -5
- package/src/config/schemas/timeouts.ts +1 -1
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +16 -0
- package/src/contacts/guardian-delivery-reader.ts +29 -2
- package/src/context/compactor.ts +4 -4
- package/src/context/post-turn-tool-result-truncation.ts +32 -16
- package/src/context/strip-injections.ts +42 -0
- package/src/context/tool-result-spool.ts +32 -18
- package/src/credential-execution/ces-runtime.ts +3 -0
- package/src/credential-execution/client.ts +22 -1
- package/src/credential-execution/process-manager.test.ts +99 -0
- package/src/credential-execution/process-manager.ts +62 -16
- package/src/daemon/__tests__/abort-null-controller.test.ts +141 -5
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +8 -12
- package/src/daemon/__tests__/install-assistant-command.test.ts +234 -0
- package/src/daemon/__tests__/turn-tail-assistant-reply-notify.test.ts +2 -4
- package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +20 -29
- package/src/daemon/channel-ui-capability.ts +4 -4
- package/src/daemon/conversation-agent-loop-handlers.ts +117 -61
- package/src/daemon/conversation-agent-loop.ts +318 -148
- package/src/daemon/conversation-attachments.ts +1 -1
- package/src/daemon/conversation-error.ts +8 -1
- package/src/daemon/conversation-initial-prompt.ts +16 -38
- package/src/daemon/conversation-lifecycle.ts +154 -32
- package/src/daemon/conversation-messaging.ts +106 -43
- package/src/daemon/conversation-process.ts +131 -33
- package/src/daemon/conversation-queue-manager.ts +10 -0
- package/src/daemon/conversation-runtime-assembly.ts +9 -4
- package/src/daemon/conversation-store.ts +52 -3
- package/src/daemon/conversation-surface-state.ts +9 -0
- package/src/daemon/conversation-surfaces.ts +403 -210
- package/src/daemon/conversation-tool-setup.ts +56 -7
- package/src/daemon/conversation-turn-finalize.ts +134 -89
- package/src/daemon/conversation.ts +111 -27
- package/src/daemon/disk-pressure-guard-lifecycle.ts +2 -2
- package/src/daemon/disk-pressure-guard.ts +3 -3
- package/src/daemon/doordash-steps.ts +5 -5
- package/src/daemon/external-plugins-bootstrap.ts +7 -1
- package/src/daemon/handlers/config-channels.ts +48 -5
- package/src/daemon/handlers/conversation-history.ts +1 -1
- package/src/daemon/handlers/conversations.ts +62 -17
- package/src/daemon/handlers/shared.ts +12 -0
- package/src/daemon/handlers/skills.ts +11 -1
- package/src/daemon/identity-helpers.ts +38 -10
- package/src/daemon/install-assistant-command.ts +322 -0
- package/src/daemon/lifecycle.ts +14 -3
- package/src/daemon/message-types/conversations.ts +6 -7
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/persist-media-references.ts +23 -14
- package/src/daemon/process-message.ts +6 -6
- package/src/daemon/tool-setup-types.ts +19 -122
- package/src/daemon/tool-side-effects.ts +17 -94
- package/src/daemon/trust-context-types.ts +39 -0
- package/src/daemon/trust-context.ts +14 -6
- package/src/daemon/turn-tail-chain.ts +73 -0
- package/src/daemon/web-search-history.ts +47 -33
- package/src/heartbeat/heartbeat-service.ts +6 -6
- package/src/ipc/__tests__/socket-path.test.ts +21 -0
- package/src/ipc/assistant-server.ts +17 -10
- package/src/ipc/cli-client.ts +10 -1
- package/src/ipc/routes/__tests__/documents-sync-ipc-routes.test.ts +56 -0
- package/src/ipc/routes/documents-sync-ipc-routes.ts +42 -0
- package/src/ipc/socket-cleanup.ts +9 -7
- package/src/ipc/socket-path.ts +4 -96
- package/src/live-voice/__tests__/live-voice-archive.test.ts +16 -16
- package/src/live-voice/__tests__/live-voice-attach-image.test.ts +209 -0
- package/src/live-voice/__tests__/live-voice-connection.test.ts +20 -0
- package/src/live-voice/__tests__/live-voice-integration.test.ts +7 -5
- package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +265 -0
- package/src/live-voice/__tests__/live-voice-stt.test.ts +6 -1
- package/src/live-voice/__tests__/live-voice-vad.test.ts +35 -15
- package/src/live-voice/__tests__/protocol.test.ts +52 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +3 -0
- package/src/live-voice/live-voice-archive.ts +13 -13
- package/src/live-voice/live-voice-connection.ts +7 -1
- package/src/live-voice/live-voice-photo.ts +169 -0
- package/src/live-voice/live-voice-session.ts +108 -4
- package/src/live-voice/protocol.ts +89 -1
- package/src/mcp/client.ts +10 -0
- package/src/messaging/providers/__tests__/callback-routing.test.ts +5 -1
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +66 -4
- package/src/messaging/providers/callback-routing.ts +1 -0
- package/src/messaging/providers/discord/api.ts +312 -0
- package/src/messaging/providers/discord/dm-delivery.test.ts +204 -0
- package/src/messaging/providers/discord/render.test.ts +204 -0
- package/src/messaging/providers/discord/render.ts +195 -0
- package/src/messaging/providers/discord/send.test.ts +179 -0
- package/src/messaging/providers/discord/send.ts +212 -0
- package/src/messaging/providers/discord/transport.ts +81 -0
- package/src/messaging/providers/index.ts +3 -1
- package/src/messaging/providers/retry-policy.test.ts +247 -0
- package/src/messaging/providers/retry-policy.ts +206 -0
- package/src/messaging/providers/slack/mention-source.test.ts +285 -0
- package/src/messaging/providers/slack/mention-source.ts +287 -0
- package/src/messaging/providers/telegram-bot/api.ts +47 -130
- package/src/messaging/providers/whatsapp/api.ts +47 -136
- package/src/monitoring/__tests__/db-integrity-sample.test.ts +4 -1
- package/src/monitoring/__tests__/plugin-auto-update.test.ts +332 -0
- package/src/monitoring/db-integrity-sample.ts +6 -1
- package/src/monitoring/plugin-auto-update.ts +359 -0
- package/src/monitoring/resource-sampler.ts +21 -5
- package/src/monitoring/worker.ts +13 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +375 -2
- package/src/notifications/__tests__/broadcaster.test.ts +37 -1
- package/src/notifications/__tests__/copy-composer.test.ts +165 -0
- package/src/notifications/__tests__/emit-signal-pipeline-failure.test.ts +205 -0
- package/src/notifications/__tests__/notification-utils.test.ts +249 -0
- package/src/notifications/adapters/platform.ts +31 -2
- package/src/notifications/assistant-reply-producer.ts +79 -32
- package/src/notifications/broadcaster.ts +30 -10
- package/src/notifications/copy-composer.ts +69 -0
- package/src/notifications/emit-signal.ts +82 -15
- package/src/notifications/events-store.ts +10 -2
- package/src/notifications/home-feed-side-effect.ts +6 -3
- package/src/notifications/notification-utils.ts +173 -5
- package/src/notifications/signal.ts +12 -0
- package/src/oauth/AGENTS.md +4 -2
- package/src/oauth/byo-connection.ts +6 -1
- package/src/oauth/credential-token-resolver.ts +3 -10
- package/src/oauth/manual-token-connection.ts +29 -64
- package/src/oauth/manual-token-providers.ts +62 -0
- package/src/oauth/provider-serializer.ts +13 -0
- package/src/oauth/seed-providers.ts +62 -11
- package/src/onboarding/onboarding-events-store.ts +91 -1
- package/src/permissions/question-prompter.test.ts +4 -0
- package/src/permissions/question-prompter.ts +21 -4
- package/src/persistence/__tests__/conversation-lineage.test.ts +248 -0
- package/src/persistence/attachments-store.ts +15 -15
- package/src/persistence/conversation-attention-store.ts +30 -10
- package/src/persistence/conversation-bootstrap.ts +17 -0
- package/src/persistence/conversation-crud.ts +363 -97
- package/src/persistence/conversation-group-migration.ts +1 -1
- package/src/persistence/conversation-key-store.ts +38 -10
- package/src/persistence/conversation-lineage.ts +226 -0
- package/src/persistence/conversation-plugin-facade.ts +28 -3
- package/src/persistence/conversation-queries.ts +207 -33
- package/src/persistence/conversation-types.ts +107 -1
- package/src/persistence/jobs-store.ts +32 -8
- package/src/persistence/llm-usage-store.ts +22 -0
- package/src/persistence/migrations/361-normalize-managed-connection-rows.test.ts +168 -0
- package/src/persistence/migrations/361-normalize-managed-connection-rows.ts +76 -0
- package/src/persistence/migrations/362-add-conversation-subagent-kind.test.ts +187 -0
- package/src/persistence/migrations/362-add-conversation-subagent-kind.ts +93 -0
- package/src/persistence/migrations/363-backfill-schedule-inference-profile.test.ts +229 -0
- package/src/persistence/migrations/363-backfill-schedule-inference-profile.ts +127 -0
- package/src/persistence/migrations/364-add-schedule-source-key.test.ts +120 -0
- package/src/persistence/migrations/364-add-schedule-source-key.ts +43 -0
- package/src/persistence/migrations/365-add-conversation-fork-strategy.ts +27 -0
- package/src/persistence/schema/conversations.ts +32 -0
- package/src/persistence/schema/infrastructure.ts +3 -0
- package/src/persistence/steps.ts +30 -0
- package/src/persistence/subagent-store.ts +148 -6
- package/src/platform/managed-speech.test.ts +20 -0
- package/src/platform/managed-speech.ts +9 -0
- package/src/plugin-api/index.ts +8 -0
- package/src/plugin-api/webhook-url.ts +151 -0
- package/src/plugins/__tests__/installed-plugin-dirs.test.ts +82 -0
- package/src/plugins/__tests__/source-fingerprint.test.ts +5 -1
- package/src/plugins/collect-source-versions.ts +4 -27
- package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +5 -5
- package/src/plugins/defaults/exploration-drift/package.json +1 -1
- package/src/plugins/defaults/image-recovery/hooks/post-model-call.ts +4 -2
- package/src/plugins/defaults/image-recovery/recover.ts +67 -57
- package/src/plugins/defaults/index.ts +1 -1
- package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +64 -18
- package/src/plugins/defaults/memory/__tests__/jobs-worker-outcome-contract.test.ts +242 -0
- package/src/plugins/defaults/memory/__tests__/jobs-worker-retrospective-sweep.test.ts +24 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +48 -3
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +511 -19
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +39 -3
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +493 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +5 -4
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +5 -1
- package/src/plugins/defaults/memory/job-handlers.ts +87 -5
- package/src/plugins/defaults/memory/jobs-worker.ts +60 -6
- package/src/plugins/defaults/memory/memory-retrospective-constants.ts +11 -0
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +29 -0
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +342 -60
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +23 -3
- package/src/plugins/defaults/memory/substrate/consolidation-lock.ts +9 -4
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +7 -0
- package/src/plugins/defaults/memory/v1/graph/injection.ts +1 -1
- package/src/plugins/defaults/memory/v2/router.ts +8 -0
- package/src/plugins/defaults/turn-context/unified-turn-context.ts +1 -2
- package/src/plugins/external-plugin-loader.ts +17 -8
- package/src/plugins/installed-plugin-dirs.ts +101 -0
- package/src/plugins/mtime-cache.ts +34 -22
- package/src/plugins/types.ts +69 -8
- package/src/prompts/persona-resolver.ts +6 -2
- package/src/prompts/system-prompt.ts +72 -17
- package/src/providers/__tests__/inference.test.ts +40 -0
- package/src/providers/__tests__/preflight-resolved-config.test.ts +58 -1
- package/src/providers/__tests__/retry-callsite.test.ts +67 -0
- package/src/providers/__tests__/vellum-connection-routing.test.ts +42 -11
- package/src/providers/anthropic/client.ts +112 -95
- package/src/providers/connection-resolution.ts +35 -1
- package/src/providers/gemini/client.ts +5 -5
- package/src/providers/inference/adapter-factory.ts +16 -10
- package/src/providers/inference/auth.ts +16 -0
- package/src/providers/inference/connection-availability.ts +164 -12
- package/src/providers/inference/connections.ts +25 -1
- package/src/providers/media-resolve.ts +21 -11
- package/src/providers/model-catalog.ts +15 -0
- package/src/providers/openai/chat-completions-provider.ts +4 -4
- package/src/providers/openai/responses-provider.ts +12 -25
- package/src/providers/registry.ts +9 -4
- package/src/providers/retry.ts +25 -0
- package/src/providers/server-tool-pairing.ts +134 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +187 -6
- package/src/providers/speech-to-text/deepgram.ts +1 -0
- package/src/providers/speech-to-text/resolve.ts +80 -10
- package/src/providers/speech-to-text/vellum-managed.ts +7 -1
- package/src/providers/speech-to-text/vellum-speech-relay-connection.ts +3 -1
- package/src/providers/types.ts +26 -6
- package/src/providers/vellum-model-routing.ts +6 -7
- package/src/runtime/AGENTS.md +2 -0
- package/src/runtime/__tests__/agent-wake.test.ts +16 -16
- package/src/runtime/__tests__/background-job-runner.test.ts +0 -144
- package/src/runtime/__tests__/desktop-presence.test.ts +162 -0
- package/src/runtime/agent-wake.ts +63 -24
- package/src/runtime/assistant-event-hub.ts +87 -12
- package/src/runtime/auth/__tests__/guard-tests.test.ts +2 -0
- package/src/runtime/auth/__tests__/scopes.test.ts +20 -0
- package/src/runtime/auth/same-actor.ts +56 -8
- package/src/runtime/auth/scopes.ts +12 -0
- package/src/runtime/auth/types.ts +2 -0
- package/src/runtime/background-job-runner.ts +5 -27
- package/src/runtime/channel-readiness-service.ts +59 -3
- package/src/runtime/channel-readiness-types.ts +18 -0
- package/src/runtime/desktop-presence.ts +69 -0
- package/src/runtime/http-server.ts +12 -0
- package/src/runtime/local-actor-identity.ts +11 -9
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/client-routes.test.ts +186 -14
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +547 -1
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +162 -7
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +14 -10
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +340 -3
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +28 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +173 -1
- package/src/runtime/routes/__tests__/question-routes.test.ts +64 -0
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +20 -0
- package/src/runtime/routes/__tests__/skill-history-route.test.ts +116 -0
- package/src/runtime/routes/__tests__/wake-conversation-routes.test.ts +60 -2
- package/src/runtime/routes/archive-utils.ts +16 -12
- package/src/runtime/routes/attachment-routes.ts +13 -6
- package/src/runtime/routes/canned-reply-release.ts +54 -0
- package/src/runtime/routes/channel-verification-routes.ts +2 -27
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +5 -0
- package/src/runtime/routes/client-routes.ts +114 -2
- package/src/runtime/routes/conversation-cli-routes.ts +10 -12
- package/src/runtime/routes/conversation-list-routes.ts +59 -10
- package/src/runtime/routes/conversation-management-routes.ts +47 -18
- package/src/runtime/routes/conversation-query-routes.ts +32 -53
- package/src/runtime/routes/conversation-routes.ts +360 -293
- package/src/runtime/routes/credential-prompt-routes.ts +23 -2
- package/src/runtime/routes/debug-routes.ts +4 -1
- package/src/runtime/routes/default-provider-routes.ts +7 -11
- package/src/runtime/routes/documents-routes.ts +44 -1
- package/src/runtime/routes/events-routes.ts +28 -1
- package/src/runtime/routes/host-app-control-routes.ts +2 -0
- package/src/runtime/routes/host-bash-routes.ts +2 -0
- package/src/runtime/routes/host-browser-routes.ts +2 -0
- package/src/runtime/routes/host-cu-routes.ts +2 -0
- package/src/runtime/routes/host-file-routes.ts +2 -0
- package/src/runtime/routes/host-transfer-routes.ts +4 -0
- package/src/runtime/routes/identity-routes.ts +6 -6
- package/src/runtime/routes/inbound-message-handler.ts +5 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +7 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +14 -0
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -2
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +14 -11
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -17
- package/src/runtime/routes/inference-profile-availability-guard.ts +171 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +26 -2
- package/src/runtime/routes/inference-profile-session-routes.ts +2 -1
- package/src/runtime/routes/inference-profiles-routes.ts +152 -73
- package/src/runtime/routes/inference-provider-connection-routes.ts +0 -16
- package/src/runtime/routes/llm-call-sites-routes.ts +13 -0
- package/src/runtime/routes/log-export-routes.ts +1 -1
- package/src/runtime/routes/notification-routes.ts +0 -14
- package/src/runtime/routes/oauth-providers.ts +1 -0
- package/src/runtime/routes/plugins-routes.ts +106 -1
- package/src/runtime/routes/profiler-routes.ts +4 -2
- package/src/runtime/routes/question-routes.ts +28 -10
- package/src/runtime/routes/retrospective-routes.ts +9 -3
- package/src/runtime/routes/schedule-routes.ts +210 -12
- package/src/runtime/routes/secret-routes.ts +40 -23
- package/src/runtime/routes/settings-routes.ts +41 -13
- package/src/runtime/routes/skills-routes.ts +79 -0
- package/src/runtime/routes/ui-snapshot-routes.ts +1 -0
- package/src/runtime/routes/wake-conversation-routes.ts +23 -0
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +1 -0
- package/src/runtime/services/conversation-serializer.ts +24 -9
- package/src/runtime/sync/documents-sidecar-publish.test.ts +101 -0
- package/src/runtime/sync/resource-sync-events.ts +79 -1
- package/src/runtime/sync/worker-daemon-notify.test.ts +34 -0
- package/src/runtime/sync/worker-daemon-notify.ts +44 -6
- package/src/runtime/verification-outbound-actions.ts +250 -222
- package/src/runtime/verification-templates.ts +41 -30
- package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +614 -0
- package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1066 -0
- package/src/schedule/inference-profile.ts +64 -3
- package/src/schedule/plugin-schedule-declarations.ts +518 -0
- package/src/schedule/plugin-schedule-reconciler.ts +605 -0
- package/src/schedule/plugin-schedules-gate.ts +23 -0
- package/src/schedule/schedule-store.ts +520 -26
- package/src/schedule/scheduler.ts +38 -0
- package/src/security/credential-backend.ts +51 -4
- package/src/security/encrypted-store.ts +64 -42
- package/src/security/secure-keys.ts +55 -7
- package/src/skills/catalog-install.ts +20 -7
- package/src/skills/inline-command-runner.ts +2 -7
- package/src/skills/skill-history.test.ts +269 -0
- package/src/skills/skill-history.ts +250 -0
- package/src/skills/skillssh-registry.ts +1 -1
- package/src/stt/daemon-batch-transcriber.ts +8 -6
- package/src/subagent/__tests__/consult-prompt.test.ts +25 -0
- package/src/subagent/consult-prompt.ts +3 -1
- package/src/subagent/consult-transcript.ts +1 -1
- package/src/subagent/manager.ts +304 -44
- package/src/subagent/progress-events.ts +35 -0
- package/src/subagent/role-resolution.ts +88 -0
- package/src/subagent/types.ts +302 -67
- package/src/subagent/validate-allowlists.ts +3 -4
- package/src/telegram/__tests__/webhook-health.test.ts +73 -1
- package/src/telegram/webhook-health.ts +101 -3
- package/src/telemetry/__tests__/telemetry-event-fixtures.ts +2 -0
- package/src/telemetry/activation-funnel.ts +6 -1
- package/src/telemetry/live-voice-funnel.ts +75 -0
- package/src/telemetry/telemetry-event-sources.ts +6 -0
- package/src/telemetry/telemetry-wire-source.json +1 -1
- package/src/telemetry/telemetry-wire.generated.ts +2 -0
- package/src/telemetry/types.ts +23 -4
- package/src/telemetry/usage-telemetry-reporter.test.ts +4 -0
- package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +1 -1
- package/src/tools/ask-question/ask-question-tool.test.ts +118 -3
- package/src/tools/ask-question/ask-question-tool.ts +56 -2
- package/src/tools/browser/browser-execution.ts +1 -1
- package/src/tools/calls/call-start.ts +8 -5
- package/src/tools/conversation-groups/move_to_group.ts +10 -12
- package/src/tools/document/document-tool.ts +11 -4
- package/src/tools/execution-timeout.ts +9 -2
- package/src/tools/executor.ts +7 -6
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +7 -13
- package/src/tools/filesystem/search.ts +23 -21
- package/src/tools/filesystem/write.ts +4 -1
- package/src/tools/host-filesystem/edit.ts +7 -2
- package/src/tools/host-filesystem/read.ts +21 -8
- package/src/tools/host-filesystem/write.ts +10 -2
- package/src/tools/host-terminal/host-shell.ts +2 -2
- package/src/tools/mcp/mcp-tool-factory.ts +25 -1
- package/src/tools/permission-checker.ts +8 -3
- package/src/tools/schedule/delete.ts +13 -1
- package/src/tools/schedule/list.ts +14 -3
- package/src/tools/schedule/update.ts +56 -33
- package/src/tools/shared/filesystem/audio-read.ts +6 -4
- package/src/tools/shared/filesystem/file-ops-service.ts +176 -116
- package/src/tools/shared/filesystem/image-read.ts +12 -12
- package/src/tools/shared/filesystem/path-policy.ts +70 -5
- package/src/tools/shared/filesystem/size-guard.ts +6 -6
- package/src/tools/shared/input-misuse.ts +72 -0
- package/src/tools/skills/scaffold-managed.ts +82 -0
- package/src/tools/skills/skill-tool-factory.ts +14 -1
- package/src/tools/subagent/consult-deadline.ts +12 -7
- package/src/tools/subagent/message.ts +3 -1
- package/src/tools/subagent/read.ts +66 -4
- package/src/tools/subagent/spawn.ts +500 -78
- package/src/tools/tool-approval-handler.ts +45 -4
- package/src/tools/types.ts +22 -3
- package/src/tools/ui-surface/surface-shape-docs.ts +1 -1
- package/src/tools/ui-surface/visual-validation.ts +2 -0
- package/src/usage/__tests__/subagent-attribution.test.ts +109 -0
- package/src/usage/subagent-attribution.ts +108 -0
- package/src/util/__tests__/sqlite-retry.test.ts +112 -0
- package/src/util/abort-reasons.ts +16 -0
- package/src/util/ansi.ts +44 -0
- package/src/util/disk-usage.ts +17 -13
- package/src/util/image-conversion.ts +20 -13
- package/src/util/schedule-source-key.ts +23 -0
- package/src/util/worker-process.ts +7 -1
- package/src/workspace/git-service.ts +33 -9
- package/src/workspace/migrations/140-repair-seed-pinned-memory-v3-live.ts +260 -0
- package/src/workspace/migrations/141-stt-english-default-to-multilingual.ts +111 -0
- package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +126 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/workspace/top-level-renderer.ts +15 -2
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -357
- package/src/daemon/install-symlink.ts +0 -207
- package/src/notifications/deferred-emit.ts +0 -147
|
@@ -100,8 +100,8 @@ describe("HEIC upload normalization wiring", () => {
|
|
|
100
100
|
await initializeDb();
|
|
101
101
|
}, 30_000);
|
|
102
102
|
|
|
103
|
-
test("uploadAttachmentFromBytes stores a JPEG master for HEIC", () => {
|
|
104
|
-
const stored = uploadAttachmentFromBytes(
|
|
103
|
+
test("uploadAttachmentFromBytes stores a JPEG master for HEIC", async () => {
|
|
104
|
+
const stored = await uploadAttachmentFromBytes(
|
|
105
105
|
"IMG_5487.HEIC",
|
|
106
106
|
"image/heic",
|
|
107
107
|
HEIC_BYTES,
|
|
@@ -115,8 +115,8 @@ describe("HEIC upload normalization wiring", () => {
|
|
|
115
115
|
expect(readFileSync(stagedPath!).equals(FAKE_JPEG)).toBe(true);
|
|
116
116
|
});
|
|
117
117
|
|
|
118
|
-
test("uploadAttachmentFromBytes leaves non-HEIC uploads verbatim", () => {
|
|
119
|
-
const stored = uploadAttachmentFromBytes(
|
|
118
|
+
test("uploadAttachmentFromBytes leaves non-HEIC uploads verbatim", async () => {
|
|
119
|
+
const stored = await uploadAttachmentFromBytes(
|
|
120
120
|
"photo.png",
|
|
121
121
|
"image/png",
|
|
122
122
|
HEIC_BYTES,
|
|
@@ -127,8 +127,8 @@ describe("HEIC upload normalization wiring", () => {
|
|
|
127
127
|
expect(stored.sizeBytes).toBe(HEIC_BYTES.length);
|
|
128
128
|
});
|
|
129
129
|
|
|
130
|
-
test("uploadAttachment (base64) stores a JPEG master for HEIC", () => {
|
|
131
|
-
const stored = uploadAttachment("IMG_1.heic", "image/heic", HEIC_B64);
|
|
130
|
+
test("uploadAttachment (base64) stores a JPEG master for HEIC", async () => {
|
|
131
|
+
const stored = await uploadAttachment("IMG_1.heic", "image/heic", HEIC_B64);
|
|
132
132
|
|
|
133
133
|
expect(stored.originalFilename).toBe("IMG_1.jpg");
|
|
134
134
|
expect(stored.mimeType).toBe("image/jpeg");
|
|
@@ -137,16 +137,20 @@ describe("HEIC upload normalization wiring", () => {
|
|
|
137
137
|
expect(row?.dataBase64).toBe(FAKE_JPEG_B64);
|
|
138
138
|
});
|
|
139
139
|
|
|
140
|
-
test("uploadAttachment (base64) leaves non-HEIC uploads verbatim", () => {
|
|
141
|
-
const stored = uploadAttachment("photo.png", "image/png", HEIC_B64);
|
|
140
|
+
test("uploadAttachment (base64) leaves non-HEIC uploads verbatim", async () => {
|
|
141
|
+
const stored = await uploadAttachment("photo.png", "image/png", HEIC_B64);
|
|
142
142
|
|
|
143
143
|
expect(stored.originalFilename).toBe("photo.png");
|
|
144
144
|
expect(stored.mimeType).toBe("image/png");
|
|
145
145
|
expect(stored.sizeBytes).toBe(HEIC_BYTES.length);
|
|
146
146
|
});
|
|
147
147
|
|
|
148
|
-
test("uploadAttachment (base64) propagates a MIME-only sniff correction", () => {
|
|
149
|
-
const stored = uploadAttachment(
|
|
148
|
+
test("uploadAttachment (base64) propagates a MIME-only sniff correction", async () => {
|
|
149
|
+
const stored = await uploadAttachment(
|
|
150
|
+
"photo.png",
|
|
151
|
+
"image/mislabeled",
|
|
152
|
+
HEIC_B64,
|
|
153
|
+
);
|
|
150
154
|
|
|
151
155
|
// Corrected MIME is stored; filename and payload stay verbatim.
|
|
152
156
|
expect(stored.originalFilename).toBe("photo.png");
|
|
@@ -163,7 +167,7 @@ describe("HEIC upload normalization wiring", () => {
|
|
|
163
167
|
JSON.stringify([{ type: "text", text: "photos" }]),
|
|
164
168
|
);
|
|
165
169
|
|
|
166
|
-
const normalized = attachInlineAttachmentToMessage(
|
|
170
|
+
const normalized = await attachInlineAttachmentToMessage(
|
|
167
171
|
msg.id,
|
|
168
172
|
0,
|
|
169
173
|
"IMG_2.HEIC",
|
|
@@ -176,7 +180,7 @@ describe("HEIC upload normalization wiring", () => {
|
|
|
176
180
|
|
|
177
181
|
// Assistant-outbound attachments are stored verbatim: no normalizeImage
|
|
178
182
|
// flag, no rewrite, even for HEIC content.
|
|
179
|
-
const verbatim = attachInlineAttachmentToMessage(
|
|
183
|
+
const verbatim = await attachInlineAttachmentToMessage(
|
|
180
184
|
msg.id,
|
|
181
185
|
1,
|
|
182
186
|
"IMG_3.HEIC",
|
|
@@ -65,8 +65,8 @@ function getLegacyConversationDirPath(
|
|
|
65
65
|
describe("uploadAttachment", () => {
|
|
66
66
|
beforeEach(resetTables);
|
|
67
67
|
|
|
68
|
-
test("stores attachment and returns metadata", () => {
|
|
69
|
-
const stored = uploadAttachment("chart.png", "image/png", "iVBORw0K");
|
|
68
|
+
test("stores attachment and returns metadata", async () => {
|
|
69
|
+
const stored = await uploadAttachment("chart.png", "image/png", "iVBORw0K");
|
|
70
70
|
|
|
71
71
|
expect(stored.id).toBeDefined();
|
|
72
72
|
expect(stored.originalFilename).toBe("chart.png");
|
|
@@ -76,16 +76,20 @@ describe("uploadAttachment", () => {
|
|
|
76
76
|
expect(stored.createdAt).toBeGreaterThan(0);
|
|
77
77
|
});
|
|
78
78
|
|
|
79
|
-
test("keeps uploads staged until linked", () => {
|
|
80
|
-
const stored = uploadAttachment(
|
|
79
|
+
test("keeps uploads staged until linked", async () => {
|
|
80
|
+
const stored = await uploadAttachment(
|
|
81
|
+
"small.txt",
|
|
82
|
+
"text/plain",
|
|
83
|
+
"aGVsbG8=",
|
|
84
|
+
);
|
|
81
85
|
const filePath = getFilePathForAttachment(stored.id);
|
|
82
86
|
|
|
83
87
|
expect(filePath).toBeNull();
|
|
84
88
|
expect(getAttachmentContent(stored.id)?.toString()).toBe("hello");
|
|
85
89
|
});
|
|
86
90
|
|
|
87
|
-
test("stores base64 in the DB row until linked", () => {
|
|
88
|
-
const stored = uploadAttachment("test.txt", "text/plain", "dGVzdA==");
|
|
91
|
+
test("stores base64 in the DB row until linked", async () => {
|
|
92
|
+
const stored = await uploadAttachment("test.txt", "text/plain", "dGVzdA==");
|
|
89
93
|
|
|
90
94
|
// Staged uploads keep the payload inline until they are attached to a message.
|
|
91
95
|
const rawRow = rawGet<{ data_base64: string }>(
|
|
@@ -100,35 +104,43 @@ describe("uploadAttachment", () => {
|
|
|
100
104
|
expect(row!.dataBase64).toBe("dGVzdA==");
|
|
101
105
|
});
|
|
102
106
|
|
|
103
|
-
test("classifies image MIME as image kind", () => {
|
|
104
|
-
const stored = uploadAttachment("pic.jpg", "image/jpeg", "AAAA");
|
|
107
|
+
test("classifies image MIME as image kind", async () => {
|
|
108
|
+
const stored = await uploadAttachment("pic.jpg", "image/jpeg", "AAAA");
|
|
105
109
|
expect(stored.kind).toBe("image");
|
|
106
110
|
});
|
|
107
111
|
|
|
108
|
-
test("classifies non-image MIME as document kind", () => {
|
|
109
|
-
const stored = uploadAttachment(
|
|
112
|
+
test("classifies non-image MIME as document kind", async () => {
|
|
113
|
+
const stored = await uploadAttachment(
|
|
114
|
+
"doc.pdf",
|
|
115
|
+
"application/pdf",
|
|
116
|
+
"JVBER",
|
|
117
|
+
);
|
|
110
118
|
expect(stored.kind).toBe("document");
|
|
111
119
|
});
|
|
112
120
|
|
|
113
|
-
test("generates unique IDs for each upload", () => {
|
|
114
|
-
const a = uploadAttachment("a.txt", "text/plain", "AA==");
|
|
115
|
-
const b = uploadAttachment("b.txt", "text/plain", "QQ==");
|
|
121
|
+
test("generates unique IDs for each upload", async () => {
|
|
122
|
+
const a = await uploadAttachment("a.txt", "text/plain", "AA==");
|
|
123
|
+
const b = await uploadAttachment("b.txt", "text/plain", "QQ==");
|
|
116
124
|
expect(a.id).not.toBe(b.id);
|
|
117
125
|
});
|
|
118
126
|
|
|
119
|
-
test("computes sizeBytes from base64 correctly", () => {
|
|
127
|
+
test("computes sizeBytes from base64 correctly", async () => {
|
|
120
128
|
// "hello" = "aGVsbG8=" (8 chars, 1 pad -> 5 bytes)
|
|
121
|
-
const stored = uploadAttachment(
|
|
129
|
+
const stored = await uploadAttachment(
|
|
130
|
+
"hello.txt",
|
|
131
|
+
"text/plain",
|
|
132
|
+
"aGVsbG8=",
|
|
133
|
+
);
|
|
122
134
|
expect(stored.sizeBytes).toBe(5);
|
|
123
135
|
});
|
|
124
136
|
|
|
125
|
-
test("does not deduplicate identical uploads before linking", () => {
|
|
126
|
-
const first = uploadAttachment(
|
|
137
|
+
test("does not deduplicate identical uploads before linking", async () => {
|
|
138
|
+
const first = await uploadAttachment(
|
|
127
139
|
"photo.png",
|
|
128
140
|
"image/png",
|
|
129
141
|
"iVBORw0KGgoAAAANSUh",
|
|
130
142
|
);
|
|
131
|
-
const second = uploadAttachment(
|
|
143
|
+
const second = await uploadAttachment(
|
|
132
144
|
"photo.png",
|
|
133
145
|
"image/png",
|
|
134
146
|
"iVBORw0KGgoAAAANSUh",
|
|
@@ -136,13 +148,13 @@ describe("uploadAttachment", () => {
|
|
|
136
148
|
expect(second.id).not.toBe(first.id);
|
|
137
149
|
});
|
|
138
150
|
|
|
139
|
-
test("does not deduplicate identical content when filenames differ", () => {
|
|
140
|
-
const first = uploadAttachment(
|
|
151
|
+
test("does not deduplicate identical content when filenames differ", async () => {
|
|
152
|
+
const first = await uploadAttachment(
|
|
141
153
|
"original.png",
|
|
142
154
|
"image/png",
|
|
143
155
|
"DUPECONTENT123",
|
|
144
156
|
);
|
|
145
|
-
const second = uploadAttachment(
|
|
157
|
+
const second = await uploadAttachment(
|
|
146
158
|
"renamed.png",
|
|
147
159
|
"image/png",
|
|
148
160
|
"DUPECONTENT123",
|
|
@@ -150,45 +162,47 @@ describe("uploadAttachment", () => {
|
|
|
150
162
|
expect(second.id).not.toBe(first.id);
|
|
151
163
|
});
|
|
152
164
|
|
|
153
|
-
test("does not deduplicate different content", () => {
|
|
154
|
-
const first = uploadAttachment("a.txt", "text/plain", "CONTENTA");
|
|
155
|
-
const second = uploadAttachment("b.txt", "text/plain", "CONTENTB");
|
|
165
|
+
test("does not deduplicate different content", async () => {
|
|
166
|
+
const first = await uploadAttachment("a.txt", "text/plain", "CONTENTA");
|
|
167
|
+
const second = await uploadAttachment("b.txt", "text/plain", "CONTENTB");
|
|
156
168
|
expect(second.id).not.toBe(first.id);
|
|
157
169
|
});
|
|
158
170
|
|
|
159
|
-
test("rejects payloads exceeding MAX_UPLOAD_BYTES", () => {
|
|
171
|
+
test("rejects payloads exceeding MAX_UPLOAD_BYTES", async () => {
|
|
160
172
|
// Build a base64 string that decodes to just over the limit.
|
|
161
173
|
// 4 base64 chars -> 3 bytes, so we need ceil((MAX_UPLOAD_BYTES+1)/3)*4 chars.
|
|
162
174
|
const oversizedLength = Math.ceil((MAX_UPLOAD_BYTES + 1) / 3) * 4;
|
|
163
175
|
const oversizedData = "A".repeat(oversizedLength);
|
|
164
176
|
|
|
165
|
-
expect(
|
|
177
|
+
await expect(
|
|
166
178
|
uploadAttachment("huge.bin", "application/octet-stream", oversizedData),
|
|
167
|
-
).toThrow(AttachmentUploadError);
|
|
179
|
+
).rejects.toThrow(AttachmentUploadError);
|
|
168
180
|
});
|
|
169
181
|
|
|
170
|
-
test("rejects invalid base64 data", () => {
|
|
171
|
-
expect(
|
|
182
|
+
test("rejects invalid base64 data", async () => {
|
|
183
|
+
await expect(
|
|
172
184
|
uploadAttachment("bad.txt", "text/plain", "!!!not-base64!!!"),
|
|
173
|
-
).toThrow(AttachmentUploadError);
|
|
185
|
+
).rejects.toThrow(AttachmentUploadError);
|
|
174
186
|
});
|
|
175
187
|
|
|
176
|
-
test("accepts base64 with non-standard padding/length", () => {
|
|
188
|
+
test("accepts base64 with non-standard padding/length", async () => {
|
|
177
189
|
// Lenient on length -- only character set is validated
|
|
178
|
-
expect(
|
|
190
|
+
await expect(
|
|
191
|
+
uploadAttachment("ok.txt", "text/plain", "AAA"),
|
|
192
|
+
).resolves.toBeDefined();
|
|
179
193
|
});
|
|
180
194
|
|
|
181
195
|
// Inserting the 100 MB payload into SQLite can take several seconds on
|
|
182
196
|
// slow CI runners, so this test needs more than the default 5s timeout.
|
|
183
|
-
test("accepts payload exactly at MAX_UPLOAD_BYTES", () => {
|
|
197
|
+
test("accepts payload exactly at MAX_UPLOAD_BYTES", async () => {
|
|
184
198
|
// MAX_UPLOAD_BYTES (100 MB) is divisible by 3, so (MAX/3)*4 base64 chars
|
|
185
199
|
// decodes to exactly MAX bytes with no padding.
|
|
186
200
|
const exactLength = (MAX_UPLOAD_BYTES / 3) * 4;
|
|
187
201
|
const exactData = "A".repeat(exactLength);
|
|
188
202
|
|
|
189
|
-
expect(
|
|
203
|
+
await expect(
|
|
190
204
|
uploadAttachment("exact.bin", "application/octet-stream", exactData),
|
|
191
|
-
).
|
|
205
|
+
).resolves.toBeDefined();
|
|
192
206
|
}, 30_000);
|
|
193
207
|
});
|
|
194
208
|
|
|
@@ -199,8 +213,12 @@ describe("uploadAttachment", () => {
|
|
|
199
213
|
describe("getAttachmentContent", () => {
|
|
200
214
|
beforeEach(resetTables);
|
|
201
215
|
|
|
202
|
-
test("returns staged content before the attachment is linked", () => {
|
|
203
|
-
const stored = uploadAttachment(
|
|
216
|
+
test("returns staged content before the attachment is linked", async () => {
|
|
217
|
+
const stored = await uploadAttachment(
|
|
218
|
+
"hello.txt",
|
|
219
|
+
"text/plain",
|
|
220
|
+
"aGVsbG8=",
|
|
221
|
+
);
|
|
204
222
|
const content = getAttachmentContent(stored.id);
|
|
205
223
|
|
|
206
224
|
expect(content).not.toBeNull();
|
|
@@ -215,7 +233,7 @@ describe("getAttachmentContent", () => {
|
|
|
215
233
|
test("returns null when a materialized on-disk file is missing (ENOENT)", async () => {
|
|
216
234
|
const conv = createConversation();
|
|
217
235
|
const msg = await addMessage(conv.id, "assistant", "File");
|
|
218
|
-
const stored = uploadAttachment("test.txt", "text/plain", "dGVzdA==");
|
|
236
|
+
const stored = await uploadAttachment("test.txt", "text/plain", "dGVzdA==");
|
|
219
237
|
linkAttachmentToMessage(msg.id, stored.id, 0);
|
|
220
238
|
const filePath = getFilePathForAttachment(stored.id);
|
|
221
239
|
|
|
@@ -259,8 +277,8 @@ describe("isValidBase64", () => {
|
|
|
259
277
|
describe("deleteAttachment", () => {
|
|
260
278
|
beforeEach(resetTables);
|
|
261
279
|
|
|
262
|
-
test("deletes existing attachment and returns deleted", () => {
|
|
263
|
-
const stored = uploadAttachment("file.txt", "text/plain", "dGVzdA==");
|
|
280
|
+
test("deletes existing attachment and returns deleted", async () => {
|
|
281
|
+
const stored = await uploadAttachment("file.txt", "text/plain", "dGVzdA==");
|
|
264
282
|
const result = deleteAttachment(stored.id);
|
|
265
283
|
expect(result).toBe("deleted");
|
|
266
284
|
|
|
@@ -271,7 +289,11 @@ describe("deleteAttachment", () => {
|
|
|
271
289
|
test("cleans up on-disk file when deleting", async () => {
|
|
272
290
|
const conv = createConversation();
|
|
273
291
|
const msg = await addMessage(conv.id, "assistant", "cleanup");
|
|
274
|
-
const stored = uploadAttachment(
|
|
292
|
+
const stored = await uploadAttachment(
|
|
293
|
+
"cleanup.txt",
|
|
294
|
+
"text/plain",
|
|
295
|
+
"dGVzdA==",
|
|
296
|
+
);
|
|
275
297
|
linkAttachmentToMessage(msg.id, stored.id, 0);
|
|
276
298
|
const filePath = getFilePathForAttachment(stored.id);
|
|
277
299
|
expect(existsSync(filePath!)).toBe(true);
|
|
@@ -296,7 +318,11 @@ describe("deleteAttachment", () => {
|
|
|
296
318
|
const msg1 = await addMessage(conv.id, "user", "First upload");
|
|
297
319
|
const msg2 = await addMessage(conv.id, "user", "Duplicate upload");
|
|
298
320
|
|
|
299
|
-
const first = uploadAttachment(
|
|
321
|
+
const first = await uploadAttachment(
|
|
322
|
+
"photo.png",
|
|
323
|
+
"image/png",
|
|
324
|
+
"SHAREDCONTENT1",
|
|
325
|
+
);
|
|
300
326
|
linkAttachmentToMessage(msg1.id, first.id, 0);
|
|
301
327
|
linkAttachmentToMessage(msg2.id, first.id, 0);
|
|
302
328
|
|
|
@@ -315,8 +341,12 @@ describe("deleteAttachment", () => {
|
|
|
315
341
|
expect(linked2).toHaveLength(1);
|
|
316
342
|
});
|
|
317
343
|
|
|
318
|
-
test("deletes attachment when no messages reference it", () => {
|
|
319
|
-
const stored = uploadAttachment(
|
|
344
|
+
test("deletes attachment when no messages reference it", async () => {
|
|
345
|
+
const stored = await uploadAttachment(
|
|
346
|
+
"lonely.txt",
|
|
347
|
+
"text/plain",
|
|
348
|
+
"UNREFERENCED",
|
|
349
|
+
);
|
|
320
350
|
// No linkAttachmentToMessage call -- zero references
|
|
321
351
|
const result = deleteAttachment(stored.id);
|
|
322
352
|
expect(result).toBe("deleted");
|
|
@@ -333,9 +363,9 @@ describe("deleteAttachment", () => {
|
|
|
333
363
|
describe("getAttachmentsByIds", () => {
|
|
334
364
|
beforeEach(resetTables);
|
|
335
365
|
|
|
336
|
-
test("returns matching attachments with hydrated dataBase64", () => {
|
|
337
|
-
const a = uploadAttachment("a.txt", "text/plain", "AAAA");
|
|
338
|
-
const b = uploadAttachment("b.txt", "text/plain", "BBBB");
|
|
366
|
+
test("returns matching attachments with hydrated dataBase64", async () => {
|
|
367
|
+
const a = await uploadAttachment("a.txt", "text/plain", "AAAA");
|
|
368
|
+
const b = await uploadAttachment("b.txt", "text/plain", "BBBB");
|
|
339
369
|
|
|
340
370
|
const results = getAttachmentsByIds([a.id, b.id], {
|
|
341
371
|
hydrateFileData: true,
|
|
@@ -350,8 +380,8 @@ describe("getAttachmentsByIds", () => {
|
|
|
350
380
|
expect(results).toHaveLength(0);
|
|
351
381
|
});
|
|
352
382
|
|
|
353
|
-
test("skips IDs that do not exist", () => {
|
|
354
|
-
const a = uploadAttachment("a.txt", "text/plain", "AAAA");
|
|
383
|
+
test("skips IDs that do not exist", async () => {
|
|
384
|
+
const a = await uploadAttachment("a.txt", "text/plain", "AAAA");
|
|
355
385
|
const results = getAttachmentsByIds([a.id, "nonexistent"]);
|
|
356
386
|
expect(results).toHaveLength(1);
|
|
357
387
|
});
|
|
@@ -364,8 +394,12 @@ describe("getAttachmentsByIds", () => {
|
|
|
364
394
|
describe("getAttachmentById", () => {
|
|
365
395
|
beforeEach(resetTables);
|
|
366
396
|
|
|
367
|
-
test("returns attachment with hydrated dataBase64 when found", () => {
|
|
368
|
-
const stored = uploadAttachment(
|
|
397
|
+
test("returns attachment with hydrated dataBase64 when found", async () => {
|
|
398
|
+
const stored = await uploadAttachment(
|
|
399
|
+
"report.pdf",
|
|
400
|
+
"application/pdf",
|
|
401
|
+
"JVBER",
|
|
402
|
+
);
|
|
369
403
|
const result = getAttachmentById(stored.id, { hydrateFileData: true });
|
|
370
404
|
|
|
371
405
|
expect(result).not.toBeNull();
|
|
@@ -392,7 +426,7 @@ describe("createInlineAttachment (workspace_ref persistence)", () => {
|
|
|
392
426
|
const msg = await addMessage(conv.id, "user", "hi");
|
|
393
427
|
|
|
394
428
|
// "aGVsbG8=" = "hello"
|
|
395
|
-
const stored = createInlineAttachment(
|
|
429
|
+
const stored = await createInlineAttachment(
|
|
396
430
|
conv.id,
|
|
397
431
|
conv.createdAt,
|
|
398
432
|
"note.txt",
|
|
@@ -431,14 +465,14 @@ describe("attachInlineAttachmentToMessage filename collisions", () => {
|
|
|
431
465
|
const msg2 = await addMessage(conv.id, "user", "re-upload after editing");
|
|
432
466
|
|
|
433
467
|
// "aGVsbG8=" = "hello", "d29ybGQ=" = "world"
|
|
434
|
-
const first = attachInlineAttachmentToMessage(
|
|
468
|
+
const first = await attachInlineAttachmentToMessage(
|
|
435
469
|
msg1.id,
|
|
436
470
|
0,
|
|
437
471
|
"report.csv",
|
|
438
472
|
"text/csv",
|
|
439
473
|
"aGVsbG8=",
|
|
440
474
|
);
|
|
441
|
-
const second = attachInlineAttachmentToMessage(
|
|
475
|
+
const second = await attachInlineAttachmentToMessage(
|
|
442
476
|
msg2.id,
|
|
443
477
|
0,
|
|
444
478
|
"report.csv",
|
|
@@ -463,7 +497,7 @@ describe("linkAttachmentToMessage + getAttachmentsForMessage", () => {
|
|
|
463
497
|
test("links attachment and retrieves it by message", async () => {
|
|
464
498
|
const conv = createConversation();
|
|
465
499
|
const msg = await addMessage(conv.id, "assistant", "Here is a chart");
|
|
466
|
-
const stored = uploadAttachment("chart.png", "image/png", "iVBORw0K");
|
|
500
|
+
const stored = await uploadAttachment("chart.png", "image/png", "iVBORw0K");
|
|
467
501
|
|
|
468
502
|
linkAttachmentToMessage(msg.id, stored.id, 0);
|
|
469
503
|
|
|
@@ -482,7 +516,11 @@ describe("linkAttachmentToMessage + getAttachmentsForMessage", () => {
|
|
|
482
516
|
const legacyDir = getLegacyConversationDirPath(conv.id, conv.createdAt);
|
|
483
517
|
rmSync(legacyDir, { recursive: true, force: true });
|
|
484
518
|
|
|
485
|
-
const stored = uploadAttachment(
|
|
519
|
+
const stored = await uploadAttachment(
|
|
520
|
+
"repaired.png",
|
|
521
|
+
"image/png",
|
|
522
|
+
"iVBORw0K",
|
|
523
|
+
);
|
|
486
524
|
linkAttachmentToMessage(msg.id, stored.id, 0);
|
|
487
525
|
|
|
488
526
|
const filePath = getFilePathForAttachment(stored.id);
|
|
@@ -501,7 +539,11 @@ describe("linkAttachmentToMessage + getAttachmentsForMessage", () => {
|
|
|
501
539
|
rmSync(canonicalDir, { recursive: true, force: true });
|
|
502
540
|
mkdirSync(legacyDir, { recursive: true });
|
|
503
541
|
|
|
504
|
-
const stored = uploadAttachment(
|
|
542
|
+
const stored = await uploadAttachment(
|
|
543
|
+
"legacy.png",
|
|
544
|
+
"image/png",
|
|
545
|
+
"iVBORw0K",
|
|
546
|
+
);
|
|
505
547
|
linkAttachmentToMessage(msg.id, stored.id, 0);
|
|
506
548
|
|
|
507
549
|
const filePath = getFilePathForAttachment(stored.id);
|
|
@@ -514,8 +556,8 @@ describe("linkAttachmentToMessage + getAttachmentsForMessage", () => {
|
|
|
514
556
|
test("returns attachments in position order", async () => {
|
|
515
557
|
const conv = createConversation();
|
|
516
558
|
const msg = await addMessage(conv.id, "assistant", "Multiple files");
|
|
517
|
-
const a = uploadAttachment("first.txt", "text/plain", "AAAA");
|
|
518
|
-
const b = uploadAttachment("second.txt", "text/plain", "BBBB");
|
|
559
|
+
const a = await uploadAttachment("first.txt", "text/plain", "AAAA");
|
|
560
|
+
const b = await uploadAttachment("second.txt", "text/plain", "BBBB");
|
|
519
561
|
|
|
520
562
|
// Link in reverse order
|
|
521
563
|
linkAttachmentToMessage(msg.id, b.id, 1);
|
|
@@ -543,8 +585,12 @@ describe("linkAttachmentToMessage + getAttachmentsForMessage", () => {
|
|
|
543
585
|
describe("deleteOrphanAttachments", () => {
|
|
544
586
|
beforeEach(resetTables);
|
|
545
587
|
|
|
546
|
-
test("removes candidate attachments with no message links", () => {
|
|
547
|
-
const stored = uploadAttachment(
|
|
588
|
+
test("removes candidate attachments with no message links", async () => {
|
|
589
|
+
const stored = await uploadAttachment(
|
|
590
|
+
"orphan.txt",
|
|
591
|
+
"text/plain",
|
|
592
|
+
"ZGF0YQ==",
|
|
593
|
+
);
|
|
548
594
|
|
|
549
595
|
const removed = deleteOrphanAttachments([stored.id]);
|
|
550
596
|
expect(removed).toBe(1);
|
|
@@ -553,7 +599,11 @@ describe("deleteOrphanAttachments", () => {
|
|
|
553
599
|
test("cleans up on-disk files when removing orphaned materialized attachments", async () => {
|
|
554
600
|
const conv = createConversation();
|
|
555
601
|
const msg = await addMessage(conv.id, "assistant", "Orphan me");
|
|
556
|
-
const stored = uploadAttachment(
|
|
602
|
+
const stored = await uploadAttachment(
|
|
603
|
+
"orphan.txt",
|
|
604
|
+
"text/plain",
|
|
605
|
+
"ZGF0YQ==",
|
|
606
|
+
);
|
|
557
607
|
linkAttachmentToMessage(msg.id, stored.id, 0);
|
|
558
608
|
const filePath = getFilePathForAttachment(stored.id);
|
|
559
609
|
expect(existsSync(filePath!)).toBe(true);
|
|
@@ -571,7 +621,11 @@ describe("deleteOrphanAttachments", () => {
|
|
|
571
621
|
test("preserves attachments that are still linked", async () => {
|
|
572
622
|
const conv = createConversation();
|
|
573
623
|
const msg = await addMessage(conv.id, "assistant", "With attachment");
|
|
574
|
-
const stored = uploadAttachment(
|
|
624
|
+
const stored = await uploadAttachment(
|
|
625
|
+
"linked.txt",
|
|
626
|
+
"text/plain",
|
|
627
|
+
"ZGF0YQ==",
|
|
628
|
+
);
|
|
575
629
|
linkAttachmentToMessage(msg.id, stored.id, 0);
|
|
576
630
|
|
|
577
631
|
const removed = deleteOrphanAttachments([stored.id]);
|
|
@@ -584,8 +638,8 @@ describe("deleteOrphanAttachments", () => {
|
|
|
584
638
|
test("removes only orphans when mixed candidates provided", async () => {
|
|
585
639
|
const conv = createConversation();
|
|
586
640
|
const msg = await addMessage(conv.id, "assistant", "Mixed");
|
|
587
|
-
const linked = uploadAttachment("linked.txt", "text/plain", "AAAA");
|
|
588
|
-
const orphan = uploadAttachment("orphan.txt", "text/plain", "BBBB");
|
|
641
|
+
const linked = await uploadAttachment("linked.txt", "text/plain", "AAAA");
|
|
642
|
+
const orphan = await uploadAttachment("orphan.txt", "text/plain", "BBBB");
|
|
589
643
|
linkAttachmentToMessage(msg.id, linked.id, 0);
|
|
590
644
|
|
|
591
645
|
const removed = deleteOrphanAttachments([linked.id, orphan.id]);
|
|
@@ -600,9 +654,17 @@ describe("deleteOrphanAttachments", () => {
|
|
|
600
654
|
expect(removed).toBe(0);
|
|
601
655
|
});
|
|
602
656
|
|
|
603
|
-
test("does not delete attachments outside the candidate set", () => {
|
|
604
|
-
const unrelated = uploadAttachment(
|
|
605
|
-
|
|
657
|
+
test("does not delete attachments outside the candidate set", async () => {
|
|
658
|
+
const unrelated = await uploadAttachment(
|
|
659
|
+
"unrelated.txt",
|
|
660
|
+
"text/plain",
|
|
661
|
+
"AAAA",
|
|
662
|
+
);
|
|
663
|
+
const candidate = await uploadAttachment(
|
|
664
|
+
"candidate.txt",
|
|
665
|
+
"text/plain",
|
|
666
|
+
"BBBB",
|
|
667
|
+
);
|
|
606
668
|
|
|
607
669
|
const removed = deleteOrphanAttachments([candidate.id]);
|
|
608
670
|
expect(removed).toBe(1);
|