@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
|
@@ -8,12 +8,18 @@ import {
|
|
|
8
8
|
} from "../security/untrusted-content.js";
|
|
9
9
|
import { getLogger } from "../util/logger.js";
|
|
10
10
|
import { isLexicalBackfillComplete } from "./checkpoints.js";
|
|
11
|
+
import { unseenAttentionStateConditions } from "./conversation-attention-store.js";
|
|
11
12
|
import type { ConversationRow } from "./conversation-crud.js";
|
|
12
13
|
import { parseConversation } from "./conversation-crud.js";
|
|
13
14
|
import { ensureDisplayOrderMigration } from "./conversation-display-order-migration.js";
|
|
14
15
|
import { ensureGroupMigration } from "./conversation-group-migration.js";
|
|
15
16
|
import { searchMessageIdsLexical } from "./conversation-search-lexical.js";
|
|
16
|
-
import
|
|
17
|
+
import {
|
|
18
|
+
type ConversationType,
|
|
19
|
+
NATIVE_ORIGIN_CHANNEL,
|
|
20
|
+
PINNED_GROUP_ID,
|
|
21
|
+
UNGROUPED_GROUP_ID,
|
|
22
|
+
} from "./conversation-types.js";
|
|
17
23
|
import { getDb } from "./db-connection.js";
|
|
18
24
|
import { tokenize } from "./embeddings/sparse-tokenize.js";
|
|
19
25
|
import {
|
|
@@ -21,7 +27,11 @@ import {
|
|
|
21
27
|
resolveMessageContentBlocks,
|
|
22
28
|
} from "./message-content-file.js";
|
|
23
29
|
import { rawAll } from "./raw-query.js";
|
|
24
|
-
import {
|
|
30
|
+
import {
|
|
31
|
+
conversationAssistantAttentionState,
|
|
32
|
+
conversations,
|
|
33
|
+
messages,
|
|
34
|
+
} from "./schema/index.js";
|
|
25
35
|
|
|
26
36
|
const log = getLogger("conversation-store");
|
|
27
37
|
|
|
@@ -169,6 +179,26 @@ function surfacedVisibilitySql(alias = "conversations"): string {
|
|
|
169
179
|
);
|
|
170
180
|
}
|
|
171
181
|
|
|
182
|
+
/**
|
|
183
|
+
* Raw SQL predicate for "not an automated background/scheduled row".
|
|
184
|
+
*
|
|
185
|
+
* A background or scheduled row counts as foreground only once it has been
|
|
186
|
+
* explicitly surfaced. {@link standardListingVisibilitySql} already admits
|
|
187
|
+
* such rows through its surfaced and custom-group arms, so a caller that
|
|
188
|
+
* must distinguish "visible in the listing" from "user-facing foreground"
|
|
189
|
+
* (unread counting) applies this on top.
|
|
190
|
+
*
|
|
191
|
+
* The SQL twin of `isBackgroundConversation` in the web client's
|
|
192
|
+
* `utils/conversation-predicates.ts`.
|
|
193
|
+
*/
|
|
194
|
+
function notBackgroundVisibilitySql(alias = "conversations"): string {
|
|
195
|
+
return (
|
|
196
|
+
`NOT ((${alias}.conversation_type IN ('background', 'scheduled')` +
|
|
197
|
+
` OR COALESCE(${alias}.group_id, 'system:all') IN ('system:background', 'system:scheduled'))` +
|
|
198
|
+
` AND ${alias}.surfaced_at IS NULL)`
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
|
|
172
202
|
/**
|
|
173
203
|
* SQL predicate selecting which bucket {@link listConversations} and
|
|
174
204
|
* {@link countConversations} return, keyed by the canonical
|
|
@@ -211,34 +241,133 @@ function conversationTypeClause(type: ConversationType) {
|
|
|
211
241
|
}
|
|
212
242
|
}
|
|
213
243
|
|
|
244
|
+
/**
|
|
245
|
+
* The predicates that select which conversations a listing covers, shared by
|
|
246
|
+
* {@link listConversations} and {@link countConversations} so a list and its
|
|
247
|
+
* count can never disagree about what they are describing.
|
|
248
|
+
*
|
|
249
|
+
* Named rather than positional on purpose: `originChannel` and `groupId` are
|
|
250
|
+
* both optional strings, and as adjacent positional arguments they were a
|
|
251
|
+
* transposition waiting to happen.
|
|
252
|
+
*/
|
|
253
|
+
export interface ConversationListFilter {
|
|
254
|
+
conversationType?: ConversationType;
|
|
255
|
+
archiveStatus?: ArchiveStatusFilter;
|
|
256
|
+
originChannel?: string;
|
|
257
|
+
/**
|
|
258
|
+
* Restrict to one group. {@link UNGROUPED_GROUP_ID} selects rows in no
|
|
259
|
+
* group (the sidebar's flat list), {@link PINNED_GROUP_ID} the Pinned
|
|
260
|
+
* section, and a UUID one custom group. Omit to span every group.
|
|
261
|
+
*/
|
|
262
|
+
groupId?: string;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export interface ConversationListQuery extends ConversationListFilter {
|
|
266
|
+
limit?: number;
|
|
267
|
+
offset?: number;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* SQL predicate for {@link ConversationListFilter.groupId}.
|
|
272
|
+
*
|
|
273
|
+
* The ungrouped case has to match NULL as well as the literal sentinel:
|
|
274
|
+
* `group_id` is only written when a conversation is filed somewhere, so the
|
|
275
|
+
* overwhelming majority of rows carry NULL rather than `'system:all'`.
|
|
276
|
+
*
|
|
277
|
+
* `group_id` is referenced as raw SQL because it is not a Drizzle column:
|
|
278
|
+
* it, `display_order`, and `is_pinned` are added by the lazy
|
|
279
|
+
* `ensureDisplayOrderMigration` / `ensureGroupMigration` steps rather than
|
|
280
|
+
* declared in `schema/conversations.ts`.
|
|
281
|
+
*/
|
|
282
|
+
function groupIdClause(groupId: string) {
|
|
283
|
+
if (groupId === UNGROUPED_GROUP_ID) {
|
|
284
|
+
// "Ungrouped" means every row the sidebar's flat list shows: not pinned
|
|
285
|
+
// and not filed in a custom group. It deliberately admits the system
|
|
286
|
+
// buckets, because a surfaced background or scheduled conversation keeps
|
|
287
|
+
// its `system:background` / `system:scheduled` group id (surfacing writes
|
|
288
|
+
// only `surfaced_at`) while the standard listing renders it in Recents.
|
|
289
|
+
// Whether such a row is actually visible stays with
|
|
290
|
+
// `conversationTypeClause`, which admits the surfaced ones and excludes
|
|
291
|
+
// the rest; matching on group id alone here would drop them.
|
|
292
|
+
return sql`(group_id IS NULL OR (group_id LIKE 'system:%' AND group_id != ${PINNED_GROUP_ID}))`;
|
|
293
|
+
}
|
|
294
|
+
// `group_id` is single-valued and authoritative, so a row belongs to
|
|
295
|
+
// exactly one section by construction. `is_pinned` is a derived duplicate
|
|
296
|
+
// that reads do not consult: `ensureGroupMigration` backfills
|
|
297
|
+
// `group_id = 'system:pinned'` for every legacy `is_pinned` row before any
|
|
298
|
+
// query runs, and pinning writes both together thereafter.
|
|
299
|
+
return sql`group_id = ${groupId}`;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* SQL predicate for {@link ConversationListFilter.originChannel}.
|
|
304
|
+
*
|
|
305
|
+
* `'vellum'` additionally matches NULL. `origin_channel` is left NULL at
|
|
306
|
+
* insert precisely so an inbound message can still claim the conversation for
|
|
307
|
+
* its channel (`setConversationOriginChannelIfUnset` is guarded on `isNull`),
|
|
308
|
+
* and migration 288 settles whatever was never claimed to `'vellum'` at daemon
|
|
309
|
+
* startup. NULL is therefore "not yet attributed", and it is what the
|
|
310
|
+
* overwhelming majority of rows carry between one boot and the next.
|
|
311
|
+
*
|
|
312
|
+
* A strict equality would put those rows in no section at all: not native, not
|
|
313
|
+
* any channel. Reading NULL as native is the self-correcting error of the two,
|
|
314
|
+
* since the only rows it can misplace are ones whose inbound message has not
|
|
315
|
+
* arrived yet, and that message moves them the moment it does.
|
|
316
|
+
*
|
|
317
|
+
* Every other channel matches exactly. A row is claimed for a channel only by
|
|
318
|
+
* that channel, so there is no ambiguity to be tolerant about.
|
|
319
|
+
*/
|
|
320
|
+
function originChannelClause(originChannel: string) {
|
|
321
|
+
if (originChannel === NATIVE_ORIGIN_CHANNEL) {
|
|
322
|
+
return sql`(origin_channel IS NULL OR origin_channel = ${NATIVE_ORIGIN_CHANNEL})`;
|
|
323
|
+
}
|
|
324
|
+
return eq(conversations.originChannel, originChannel);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function conversationListWhere(filter: ConversationListFilter) {
|
|
328
|
+
const {
|
|
329
|
+
conversationType = "standard",
|
|
330
|
+
archiveStatus = "active",
|
|
331
|
+
originChannel,
|
|
332
|
+
groupId,
|
|
333
|
+
} = filter;
|
|
334
|
+
return and(
|
|
335
|
+
conversationTypeClause(conversationType),
|
|
336
|
+
archiveStatusClause(archiveStatus) ?? undefined,
|
|
337
|
+
originChannel ? originChannelClause(originChannel) : undefined,
|
|
338
|
+
groupId ? groupIdClause(groupId) : undefined,
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
|
|
214
342
|
export function listConversations(
|
|
215
|
-
|
|
216
|
-
conversationType: ConversationType = "standard",
|
|
217
|
-
offset = 0,
|
|
218
|
-
archiveStatus: ArchiveStatusFilter = "active",
|
|
219
|
-
originChannel?: string,
|
|
343
|
+
query: ConversationListQuery = {},
|
|
220
344
|
): ConversationRow[] {
|
|
221
345
|
ensureDisplayOrderMigration();
|
|
222
346
|
ensureGroupMigration();
|
|
223
347
|
const db = getDb();
|
|
224
|
-
const
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
348
|
+
const { limit, offset = 0, ...filter } = query;
|
|
349
|
+
const recency = desc(
|
|
350
|
+
sql`COALESCE(${conversations.lastMessageAt}, ${conversations.updatedAt})`,
|
|
351
|
+
);
|
|
352
|
+
// `id` closes the ordering so the sort is a total order. Rows tied on every
|
|
353
|
+
// preceding key would otherwise have no defined relative order, which
|
|
354
|
+
// becomes duplicated and skipped rows once a cursor pages across a tie
|
|
355
|
+
// boundary.
|
|
356
|
+
//
|
|
357
|
+
// Deliberately untested here: SQLite returns a stable arrangement for
|
|
358
|
+
// identical queries over identical data, so no assertion at this layer can
|
|
359
|
+
// distinguish a total order from a lucky one. The guarantee becomes
|
|
360
|
+
// observable, and gets its test, with the keyset pagination work.
|
|
361
|
+
const tiebreak = desc(conversations.id);
|
|
362
|
+
return db
|
|
231
363
|
.select()
|
|
232
364
|
.from(conversations)
|
|
233
|
-
.where(
|
|
234
|
-
.orderBy(
|
|
235
|
-
desc(
|
|
236
|
-
sql`COALESCE(${conversations.lastMessageAt}, ${conversations.updatedAt})`,
|
|
237
|
-
),
|
|
238
|
-
)
|
|
365
|
+
.where(conversationListWhere(filter))
|
|
366
|
+
.orderBy(recency, tiebreak)
|
|
239
367
|
.limit(limit ?? 100)
|
|
240
|
-
.offset(offset)
|
|
241
|
-
|
|
368
|
+
.offset(offset)
|
|
369
|
+
.all()
|
|
370
|
+
.map(parseConversation);
|
|
242
371
|
}
|
|
243
372
|
|
|
244
373
|
/**
|
|
@@ -360,7 +489,6 @@ export function listPinnedConversations(
|
|
|
360
489
|
),
|
|
361
490
|
)
|
|
362
491
|
.orderBy(
|
|
363
|
-
sql`COALESCE(display_order, 999999) ASC`,
|
|
364
492
|
desc(
|
|
365
493
|
sql`COALESCE(${conversations.lastMessageAt}, ${conversations.updatedAt})`,
|
|
366
494
|
),
|
|
@@ -422,23 +550,69 @@ export function listConversationsByTitlePrefix(
|
|
|
422
550
|
}));
|
|
423
551
|
}
|
|
424
552
|
|
|
553
|
+
/**
|
|
554
|
+
* How many conversations {@link listConversations} would return for the same
|
|
555
|
+
* filter, ignoring `limit` / `offset`. Both read through
|
|
556
|
+
* {@link conversationListWhere}, so a page and its total always describe the
|
|
557
|
+
* same set.
|
|
558
|
+
*/
|
|
425
559
|
export function countConversations(
|
|
426
|
-
|
|
427
|
-
archiveStatus: ArchiveStatusFilter = "active",
|
|
428
|
-
originChannel?: string,
|
|
560
|
+
filter: ConversationListFilter = {},
|
|
429
561
|
): number {
|
|
430
562
|
ensureGroupMigration();
|
|
431
563
|
const db = getDb();
|
|
432
|
-
const typeCond = conversationTypeClause(conversationType);
|
|
433
|
-
const archiveCond = archiveStatusClause(archiveStatus);
|
|
434
|
-
const channelCond = originChannel
|
|
435
|
-
? eq(conversations.originChannel, originChannel)
|
|
436
|
-
: undefined;
|
|
437
|
-
const where = and(typeCond, archiveCond ?? undefined, channelCond);
|
|
438
564
|
const [{ total }] = db
|
|
439
565
|
.select({ total: count() })
|
|
440
566
|
.from(conversations)
|
|
441
|
-
.where(
|
|
567
|
+
.where(conversationListWhere(filter))
|
|
568
|
+
.all();
|
|
569
|
+
return total;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Count of foreground conversations whose latest assistant message is unseen.
|
|
574
|
+
*
|
|
575
|
+
* The server-side twin of the web client's `contributesToUnreadCount`
|
|
576
|
+
* predicate (`clients/web/src/utils/conversation-predicates.ts`), so the
|
|
577
|
+
* count returned by `GET /v1/conversations/unread-count` always matches what
|
|
578
|
+
* the sidebar's unread indicators would sum to over the full list.
|
|
579
|
+
*
|
|
580
|
+
* **Two definitions of one rule.** Changing what counts here means changing
|
|
581
|
+
* the client predicate too. Both sides assert the same named scenario matrix
|
|
582
|
+
* ("unread-count contract") so a one-sided change is visible in review: see
|
|
583
|
+
* `__tests__/conversation-list-routes.test.ts` here and
|
|
584
|
+
* `conversation-predicates.test.ts` there. The duplication exists only to
|
|
585
|
+
* keep a fallback for assistants without this route, and goes away with it.
|
|
586
|
+
*
|
|
587
|
+
* The rules:
|
|
588
|
+
*
|
|
589
|
+
* - visible in the standard (Recents) listing ({@link conversationTypeClause}),
|
|
590
|
+
* - not archived,
|
|
591
|
+
* - not an unsurfaced background/scheduled row
|
|
592
|
+
* ({@link notBackgroundVisibilitySql}), which excludes automated rows the
|
|
593
|
+
* listing admits through its custom-group arm,
|
|
594
|
+
* - unseen per the attention projection
|
|
595
|
+
* ({@link unseenAttentionStateConditions}); conversations without a
|
|
596
|
+
* projection row read as seen, hence the inner join.
|
|
597
|
+
*/
|
|
598
|
+
export function countUnreadConversations(): number {
|
|
599
|
+
ensureGroupMigration();
|
|
600
|
+
const db = getDb();
|
|
601
|
+
const [{ total }] = db
|
|
602
|
+
.select({ total: count() })
|
|
603
|
+
.from(conversations)
|
|
604
|
+
.innerJoin(
|
|
605
|
+
conversationAssistantAttentionState,
|
|
606
|
+
eq(conversationAssistantAttentionState.conversationId, conversations.id),
|
|
607
|
+
)
|
|
608
|
+
.where(
|
|
609
|
+
and(
|
|
610
|
+
conversationTypeClause("standard"),
|
|
611
|
+
isNull(conversations.archivedAt),
|
|
612
|
+
sql.raw(notBackgroundVisibilitySql()),
|
|
613
|
+
...unseenAttentionStateConditions(),
|
|
614
|
+
),
|
|
615
|
+
)
|
|
442
616
|
.all();
|
|
443
617
|
return total;
|
|
444
618
|
}
|
|
@@ -7,7 +7,32 @@
|
|
|
7
7
|
// `resolveConversationKind` classifier, and the pure predicates over a
|
|
8
8
|
// persisted message's `metadata` record.
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
type ChannelId,
|
|
12
|
+
parseChannelId,
|
|
13
|
+
parseClientOs,
|
|
14
|
+
} from "../channels/types.js";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Where a conversation came from, stated by whoever creates it.
|
|
18
|
+
*
|
|
19
|
+
* `conversations.origin_channel` records this. It is the caller's job to
|
|
20
|
+
* supply it, because the caller is the only party that knows: an inbound
|
|
21
|
+
* Slack message creates a conversation *because* it is Slack, and nothing
|
|
22
|
+
* downstream can recover that fact once the moment has passed.
|
|
23
|
+
*
|
|
24
|
+
* A bare {@link ChannelId} covers the cases where the origin is known
|
|
25
|
+
* outright, including `"vellum"` for a conversation started in the app.
|
|
26
|
+
* `inheritFrom` covers the derived ones, where the conversation belongs to
|
|
27
|
+
* whatever surface its parent belongs to: forks, subagent spawns, and
|
|
28
|
+
* scheduled wakes.
|
|
29
|
+
*
|
|
30
|
+
* Deliberately closed, and deliberately not optional. An optional string
|
|
31
|
+
* would let a caller decline to answer, which is how the column came to
|
|
32
|
+
* carry a third "not yet attributed" state that different readers resolve
|
|
33
|
+
* in contradictory directions. See JARVIS-1466.
|
|
34
|
+
*/
|
|
35
|
+
export type ConversationOrigin = ChannelId | { readonly inheritFrom: string };
|
|
11
36
|
|
|
12
37
|
/**
|
|
13
38
|
* Canonical `conversations.source` string for background memory v2
|
|
@@ -24,6 +49,15 @@ export type ConversationCreateType = "standard" | "background" | "scheduled";
|
|
|
24
49
|
/** Read-side alias of {@link ConversationCreateType}. */
|
|
25
50
|
export type ConversationType = ConversationCreateType;
|
|
26
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Conversation types minted outside the schedule pipeline. Scheduled rows are
|
|
54
|
+
* owned by it and created through `createConversation`.
|
|
55
|
+
*/
|
|
56
|
+
export type NonScheduledConversationType = Exclude<
|
|
57
|
+
ConversationCreateType,
|
|
58
|
+
"scheduled"
|
|
59
|
+
>;
|
|
60
|
+
|
|
27
61
|
/**
|
|
28
62
|
* Conversation types created by background machinery (heartbeat runs,
|
|
29
63
|
* scheduled runs, retrospective forks) rather than by a person. Exported as a
|
|
@@ -128,6 +162,29 @@ export function isEchoSuppressedUserMessage(
|
|
|
128
162
|
);
|
|
129
163
|
}
|
|
130
164
|
|
|
165
|
+
/**
|
|
166
|
+
* True when a queued message has no client-visible queued row, so every event
|
|
167
|
+
* and snapshot that describes the queue to clients must skip it.
|
|
168
|
+
*
|
|
169
|
+
* Same set as {@link isEchoSuppressedUserMessage}: a row that never renders as
|
|
170
|
+
* a user bubble must not render as a queued one either. A subagent's
|
|
171
|
+
* completion notification injected into a busy parent (`subagent/notify.ts`)
|
|
172
|
+
* is the common case — the user sees that run through its inline card, and a
|
|
173
|
+
* `[Subagent "…" — …]` row in the queue drawer is daemon scaffolding leaking
|
|
174
|
+
* into the transcript's place.
|
|
175
|
+
*
|
|
176
|
+
* Named separately from the echo predicate for the queue sites that must
|
|
177
|
+
* agree: the `message_queued` ack and its visible-position count, the
|
|
178
|
+
* corrective `message_requeued` position, the terminal
|
|
179
|
+
* `message_queued_deleted` on user delete and on abort discard, and the
|
|
180
|
+
* list-messages queued snapshot a cold reload reads.
|
|
181
|
+
*/
|
|
182
|
+
export function isSuppressedQueuedMessage(
|
|
183
|
+
metadata: Record<string, unknown> | undefined,
|
|
184
|
+
): boolean {
|
|
185
|
+
return isEchoSuppressedUserMessage(metadata);
|
|
186
|
+
}
|
|
187
|
+
|
|
131
188
|
/**
|
|
132
189
|
* True when a role-`"user"` row was persisted by the voice bridge for a live
|
|
133
190
|
* phone call or in-app voice session (every row `startVoiceTurn` persists, see
|
|
@@ -148,6 +205,34 @@ export function isVoiceSessionUserMessage(
|
|
|
148
205
|
return metadata?.voiceSessionTurn === true;
|
|
149
206
|
}
|
|
150
207
|
|
|
208
|
+
/**
|
|
209
|
+
* True when the row that opened the turn was sent from the macOS app, on that
|
|
210
|
+
* row's own evidence.
|
|
211
|
+
*
|
|
212
|
+
* Two markers, both required. The `client` bag's `os` entry is the only
|
|
213
|
+
* per-platform attribution on a message: `userMessageInterface` is `"web"` for
|
|
214
|
+
* the macOS app, the iOS app, and a desktop browser alike. `clientOsFromRequest`
|
|
215
|
+
* says that `os` was reported by this row's request or transport rather than
|
|
216
|
+
* inherited from the conversation's live client state, which names the surface
|
|
217
|
+
* of an earlier turn: a button tapped on the phone against a conversation last
|
|
218
|
+
* sent to from the Mac persists `os: "macos"` with no marker.
|
|
219
|
+
*
|
|
220
|
+
* Origin a row did not report itself is origin unknown. Callers gate
|
|
221
|
+
* suppression on this, so unknown has to read as not-macOS.
|
|
222
|
+
*/
|
|
223
|
+
export function isMacOriginatedUserMessage(
|
|
224
|
+
metadata: Record<string, unknown> | undefined,
|
|
225
|
+
): boolean {
|
|
226
|
+
if (metadata?.clientOsFromRequest !== true) {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
const client = metadata.client;
|
|
230
|
+
if (typeof client !== "object" || client === null) {
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
return parseClientOs((client as Record<string, unknown>).os) === "macos";
|
|
234
|
+
}
|
|
235
|
+
|
|
151
236
|
/**
|
|
152
237
|
* True when the row that opened the turn arrived over an external messaging
|
|
153
238
|
* surface (Slack, Telegram, WhatsApp, email, a phone call) rather than the
|
|
@@ -220,3 +305,24 @@ export function isReplyPushIneligibleUserMessage(
|
|
|
220
305
|
(!options?.replyDeliveredInAppOnly && isReplyDeliveredOffApp(metadata))
|
|
221
306
|
);
|
|
222
307
|
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* The reserved `group_id` values the sidebar's system sections use.
|
|
311
|
+
*
|
|
312
|
+
* `group_id` is nullable, and a conversation that has never been filed
|
|
313
|
+
* carries NULL rather than {@link UNGROUPED_GROUP_ID}, so predicates over the
|
|
314
|
+
* column read it through `COALESCE(group_id, 'system:all')`.
|
|
315
|
+
*/
|
|
316
|
+
export const UNGROUPED_GROUP_ID = "system:all";
|
|
317
|
+
export const PINNED_GROUP_ID = "system:pinned";
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* The `origin_channel` value for a conversation started in Vellum itself
|
|
321
|
+
* rather than arriving from an external channel.
|
|
322
|
+
*
|
|
323
|
+
* Named because reads have to treat it as "vellum or not yet attributed":
|
|
324
|
+
* `origin_channel` is deliberately NULL at insert so an inbound message can
|
|
325
|
+
* claim the conversation for its own channel, and migration 288 settles the
|
|
326
|
+
* unclaimed ones to this value at daemon startup.
|
|
327
|
+
*/
|
|
328
|
+
export const NATIVE_ORIGIN_CHANNEL = "vellum";
|
|
@@ -794,10 +794,19 @@ export function claimMemoryJobs(
|
|
|
794
794
|
|
|
795
795
|
export function completeMemoryJob(id: string): void {
|
|
796
796
|
const db = memoryDb();
|
|
797
|
+
// Guarded on `running` so a late return from an abandoned execution cannot
|
|
798
|
+
// overwrite a terminal state another writer already recorded (the stalled-job
|
|
799
|
+
// watchdog's `failed`, or a successor worker's re-claimed row).
|
|
797
800
|
db.update(memoryJobs)
|
|
798
801
|
.set({ status: "completed", updatedAt: Date.now(), lastError: null })
|
|
799
|
-
.where(eq(memoryJobs.id, id))
|
|
802
|
+
.where(and(eq(memoryJobs.id, id), eq(memoryJobs.status, "running")))
|
|
800
803
|
.run();
|
|
804
|
+
if (rawMemoryChanges() === 0) {
|
|
805
|
+
log.warn(
|
|
806
|
+
{ jobId: id },
|
|
807
|
+
"completeMemoryJob: row was not running; late completion suppressed",
|
|
808
|
+
);
|
|
809
|
+
}
|
|
801
810
|
}
|
|
802
811
|
|
|
803
812
|
/** Max times a job can be deferred before it is marked as failed. */
|
|
@@ -820,7 +829,17 @@ const DEFER_MAX_DELAY_MS = 5 * 60 * 1000;
|
|
|
820
829
|
* Returns `'deferred'` if the job was put back, or `'failed'` if max deferrals
|
|
821
830
|
* were exceeded and the job was marked as failed.
|
|
822
831
|
*/
|
|
823
|
-
export function deferMemoryJob(
|
|
832
|
+
export function deferMemoryJob(
|
|
833
|
+
id: string,
|
|
834
|
+
options?: {
|
|
835
|
+
/**
|
|
836
|
+
* Terminal `last_error` recorded when the deferral budget is exhausted.
|
|
837
|
+
* Defaults to the backend-unavailable wording used by the worker's
|
|
838
|
+
* infrastructure deferrals.
|
|
839
|
+
*/
|
|
840
|
+
exhaustedMessage?: string;
|
|
841
|
+
},
|
|
842
|
+
): "deferred" | "failed" {
|
|
824
843
|
const db = memoryDb();
|
|
825
844
|
const row = db.select().from(memoryJobs).where(eq(memoryJobs.id, id)).get();
|
|
826
845
|
if (!row) {
|
|
@@ -840,9 +859,11 @@ export function deferMemoryJob(id: string): "deferred" | "failed" {
|
|
|
840
859
|
status: "failed",
|
|
841
860
|
deferrals,
|
|
842
861
|
updatedAt: now,
|
|
843
|
-
lastError:
|
|
862
|
+
lastError:
|
|
863
|
+
options?.exhaustedMessage ??
|
|
864
|
+
`Backend unavailable after ${deferrals} deferrals`,
|
|
844
865
|
})
|
|
845
|
-
.where(eq(memoryJobs.id, id))
|
|
866
|
+
.where(and(eq(memoryJobs.id, id), eq(memoryJobs.status, "running")))
|
|
846
867
|
.run();
|
|
847
868
|
return "failed";
|
|
848
869
|
}
|
|
@@ -868,7 +889,7 @@ export function deferMemoryJob(id: string): "deferred" | "failed" {
|
|
|
868
889
|
runAfter: now + delay,
|
|
869
890
|
updatedAt: now,
|
|
870
891
|
})
|
|
871
|
-
.where(eq(memoryJobs.id, id))
|
|
892
|
+
.where(and(eq(memoryJobs.id, id), eq(memoryJobs.status, "running")))
|
|
872
893
|
.run();
|
|
873
894
|
return "deferred";
|
|
874
895
|
}
|
|
@@ -886,7 +907,7 @@ export function rescheduleMemoryJob(id: string, delayMs: number): void {
|
|
|
886
907
|
memoryDb()
|
|
887
908
|
.update(memoryJobs)
|
|
888
909
|
.set({ status: "pending", runAfter: now + delayMs, updatedAt: now })
|
|
889
|
-
.where(eq(memoryJobs.id, id))
|
|
910
|
+
.where(and(eq(memoryJobs.id, id), eq(memoryJobs.status, "running")))
|
|
890
911
|
.run();
|
|
891
912
|
}
|
|
892
913
|
|
|
@@ -904,6 +925,9 @@ export function failMemoryJob(
|
|
|
904
925
|
}
|
|
905
926
|
const attempts = row.attempts + 1;
|
|
906
927
|
const now = Date.now();
|
|
928
|
+
// Both transitions are guarded on `running` for the same reason as
|
|
929
|
+
// `completeMemoryJob`: a late writer must not overwrite a terminal state
|
|
930
|
+
// recorded by the stalled-job watchdog or a successor worker.
|
|
907
931
|
if (attempts >= maxAttempts) {
|
|
908
932
|
db.update(memoryJobs)
|
|
909
933
|
.set({
|
|
@@ -912,7 +936,7 @@ export function failMemoryJob(
|
|
|
912
936
|
updatedAt: now,
|
|
913
937
|
lastError: truncate(error, 2000, ""),
|
|
914
938
|
})
|
|
915
|
-
.where(eq(memoryJobs.id, id))
|
|
939
|
+
.where(and(eq(memoryJobs.id, id), eq(memoryJobs.status, "running")))
|
|
916
940
|
.run();
|
|
917
941
|
return;
|
|
918
942
|
}
|
|
@@ -924,7 +948,7 @@ export function failMemoryJob(
|
|
|
924
948
|
updatedAt: now,
|
|
925
949
|
lastError: truncate(error, 2000, ""),
|
|
926
950
|
})
|
|
927
|
-
.where(eq(memoryJobs.id, id))
|
|
951
|
+
.where(and(eq(memoryJobs.id, id), eq(memoryJobs.status, "running")))
|
|
928
952
|
.run();
|
|
929
953
|
}
|
|
930
954
|
|
|
@@ -258,6 +258,21 @@ export interface UnreportedUsageEvent extends UsageEvent {
|
|
|
258
258
|
* Null when there's no parent conversation.
|
|
259
259
|
*/
|
|
260
260
|
parentTurnIndex: number | null;
|
|
261
|
+
/**
|
|
262
|
+
* Role of the subagent that owns this LLM call's conversation, from
|
|
263
|
+
* `SUBAGENT_ROLE_REGISTRY`. Null for every LLM call that did not run inside
|
|
264
|
+
* a subagent conversation, and for subagent conversations created before
|
|
265
|
+
* migration 362 whose `subagents` row had already been disposed.
|
|
266
|
+
*/
|
|
267
|
+
subagentRole: string | null;
|
|
268
|
+
/**
|
|
269
|
+
* How that subagent was spawned, one of the modes described on
|
|
270
|
+
* `SubagentSpawnMode` in `subagent/types.ts`. Orthogonal to `subagentRole`:
|
|
271
|
+
* the role selects the child's capabilities, the spawn mode selects its
|
|
272
|
+
* context inheritance and lifecycle. Null under the same conditions as
|
|
273
|
+
* `subagentRole`.
|
|
274
|
+
*/
|
|
275
|
+
subagentSpawnMode: string | null;
|
|
261
276
|
}
|
|
262
277
|
|
|
263
278
|
export function queryUnreportedUsageEvents(
|
|
@@ -357,6 +372,11 @@ export function queryUnreportedUsageEvents(
|
|
|
357
372
|
// the cutoff (child creation for subagent spawns, fork boundary
|
|
358
373
|
// message for retrospective forks). Same eligibility filter as
|
|
359
374
|
// `turnIndex` above.
|
|
375
|
+
// Stamped on the conversation row at spawn (migration 362) rather than
|
|
376
|
+
// joined from `subagents`, whose rows are deleted on dispose while this
|
|
377
|
+
// watermark query can trail far behind after an ingest outage.
|
|
378
|
+
subagentRole: conversations.subagentRole,
|
|
379
|
+
subagentSpawnMode: conversations.subagentSpawnMode,
|
|
360
380
|
parentTurnIndex: sql<number | null>`(
|
|
361
381
|
CASE WHEN ${parentIdSql} IS NULL THEN NULL
|
|
362
382
|
ELSE (
|
|
@@ -399,6 +419,8 @@ export function queryUnreportedUsageEvents(
|
|
|
399
419
|
parentConversationId: row.parentConversationId,
|
|
400
420
|
parentTurnIndex:
|
|
401
421
|
row.parentTurnIndex === null ? null : Number(row.parentTurnIndex),
|
|
422
|
+
subagentRole: row.subagentRole,
|
|
423
|
+
subagentSpawnMode: row.subagentSpawnMode,
|
|
402
424
|
}));
|
|
403
425
|
}
|
|
404
426
|
|