@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
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
3
|
import { resolveCapabilities } from "../../runtime/capabilities.js";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
formatScheduleInferenceProfile,
|
|
6
|
+
validateScheduleInferenceProfile,
|
|
7
|
+
} from "../../schedule/inference-profile.js";
|
|
5
8
|
import { validateRruleSetLines } from "../../schedule/recurrence-engine.js";
|
|
6
9
|
import {
|
|
7
10
|
detectScheduleSyntax,
|
|
@@ -17,6 +20,7 @@ import {
|
|
|
17
20
|
describeCronExpression,
|
|
18
21
|
formatLocalDate,
|
|
19
22
|
getSchedule,
|
|
23
|
+
setUserEnabled,
|
|
20
24
|
updateSchedule,
|
|
21
25
|
} from "../../schedule/schedule-store.js";
|
|
22
26
|
import { resolveGroupReference } from "../conversation-groups/group_shared.js";
|
|
@@ -45,8 +49,9 @@ const VALID_ROUTING_INTENTS: RoutingIntent[] = [
|
|
|
45
49
|
* preprocessing that would silently turn an explicit update into a no-op.
|
|
46
50
|
* - `timezone` and `script` are nullable at runtime though advertised as
|
|
47
51
|
* plain strings: `updateSchedule` persists null as "clear this field".
|
|
48
|
-
* - `timeout_ms` / `
|
|
49
|
-
* to the default);
|
|
52
|
+
* - `timeout_ms` / `group` advertise null (it reverts to the default), and
|
|
53
|
+
* `inference_profile` advertises null (it re-pins to the current default);
|
|
54
|
+
* the executor's bespoke handling stays.
|
|
50
55
|
* - `mode`, `routing_intent`, `workflow_name`, and `workflow_args` are
|
|
51
56
|
* deliberately UNDECLARED (loose passthrough): the first two keep bespoke
|
|
52
57
|
* `VALID_*` errors; `workflow_name` has bespoke coercion semantics in the
|
|
@@ -94,10 +99,11 @@ export async function executeScheduleUpdate(
|
|
|
94
99
|
return { content: "Error: job_id is required", isError: true };
|
|
95
100
|
}
|
|
96
101
|
|
|
102
|
+
const existing = getSchedule(jobId);
|
|
103
|
+
|
|
97
104
|
// Prevent changing a one-shot to recurring or vice versa. (`fire_at` is
|
|
98
105
|
// not an advertised update field, so it stays a raw-input read.)
|
|
99
106
|
if (parsed.expression !== undefined || input.fire_at !== undefined) {
|
|
100
|
-
const existing = getSchedule(jobId);
|
|
101
107
|
if (!existing) {
|
|
102
108
|
return { content: `Error: Schedule not found: ${jobId}`, isError: true };
|
|
103
109
|
}
|
|
@@ -203,8 +209,8 @@ export async function executeScheduleUpdate(
|
|
|
203
209
|
updates.retryBackoffMs = parsed.retry_backoff_ms;
|
|
204
210
|
}
|
|
205
211
|
|
|
206
|
-
// Inference profile
|
|
207
|
-
//
|
|
212
|
+
// Inference profile (null re-pins the schedule to the currently resolved
|
|
213
|
+
// default rather than leaving it to follow whatever the default becomes)
|
|
208
214
|
if (parsed.inference_profile !== undefined) {
|
|
209
215
|
if (parsed.inference_profile === null) {
|
|
210
216
|
updates.inferenceProfile = null;
|
|
@@ -278,6 +284,22 @@ export async function executeScheduleUpdate(
|
|
|
278
284
|
};
|
|
279
285
|
}
|
|
280
286
|
|
|
287
|
+
// A plugin-sourced schedule accepts only the enabled toggle, recorded as
|
|
288
|
+
// the user_enabled override exactly like the HTTP toggle route. Every other
|
|
289
|
+
// field is owned by the plugin's schedule file, and the reconciler would
|
|
290
|
+
// overwrite a direct edit on its next pass.
|
|
291
|
+
const isPluginSourced = existing?.sourceKey != null;
|
|
292
|
+
if (
|
|
293
|
+
isPluginSourced &&
|
|
294
|
+
Object.keys(updates).some((field) => field !== "enabled")
|
|
295
|
+
) {
|
|
296
|
+
return {
|
|
297
|
+
content:
|
|
298
|
+
"Error: This schedule is managed by a plugin, so only enabled can be changed here. To change anything else, edit the plugin's schedule file.",
|
|
299
|
+
isError: true,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
281
303
|
// Mirror the HTTP route: a schedule whose RESULTING mode is `workflow` must
|
|
282
304
|
// carry a non-empty workflowName. Compute the post-update
|
|
283
305
|
// state (the update's value if present, else the persisted one) so both
|
|
@@ -285,7 +307,6 @@ export async function executeScheduleUpdate(
|
|
|
285
307
|
// schedule" are rejected — otherwise the scheduler hits the `!job.workflowName`
|
|
286
308
|
// skip branch and a one-shot firing job wedges.
|
|
287
309
|
if (updates.mode !== undefined || updates.workflowName !== undefined) {
|
|
288
|
-
const existing = getSchedule(jobId);
|
|
289
310
|
if (existing) {
|
|
290
311
|
const resultingMode =
|
|
291
312
|
updates.mode !== undefined ? (updates.mode as string) : existing.mode;
|
|
@@ -325,31 +346,33 @@ export async function executeScheduleUpdate(
|
|
|
325
346
|
}
|
|
326
347
|
|
|
327
348
|
try {
|
|
328
|
-
const job =
|
|
329
|
-
jobId,
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
349
|
+
const job = isPluginSourced
|
|
350
|
+
? await setUserEnabled(jobId, updates.enabled as boolean)
|
|
351
|
+
: await updateSchedule(
|
|
352
|
+
jobId,
|
|
353
|
+
updates as {
|
|
354
|
+
name?: string;
|
|
355
|
+
description?: string;
|
|
356
|
+
cronExpression?: string;
|
|
357
|
+
timezone?: string | null;
|
|
358
|
+
message?: string;
|
|
359
|
+
script?: string | null;
|
|
360
|
+
enabled?: boolean;
|
|
361
|
+
syntax?: ScheduleSyntax;
|
|
362
|
+
expression?: string;
|
|
363
|
+
mode?: ScheduleMode;
|
|
364
|
+
routingIntent?: RoutingIntent;
|
|
365
|
+
routingHints?: Record<string, unknown>;
|
|
366
|
+
quiet?: boolean;
|
|
367
|
+
reuseConversation?: boolean;
|
|
368
|
+
maxRetries?: number;
|
|
369
|
+
retryBackoffMs?: number;
|
|
370
|
+
timeoutMs?: number | null;
|
|
371
|
+
workflowName?: string | null;
|
|
372
|
+
workflowArgs?: unknown;
|
|
373
|
+
inferenceProfile?: string | null;
|
|
374
|
+
},
|
|
375
|
+
);
|
|
353
376
|
|
|
354
377
|
if (!job) {
|
|
355
378
|
return { content: `Error: Schedule not found: ${jobId}`, isError: true };
|
|
@@ -369,7 +392,7 @@ export async function executeScheduleUpdate(
|
|
|
369
392
|
` Description: ${job.description}`,
|
|
370
393
|
` Syntax: ${job.syntax}`,
|
|
371
394
|
` Mode: ${job.mode}`,
|
|
372
|
-
` Inference profile: ${job.inferenceProfile
|
|
395
|
+
` Inference profile: ${formatScheduleInferenceProfile(job.inferenceProfile)}`,
|
|
373
396
|
` Schedule: ${scheduleDescription}${job.timezone ? ` (${job.timezone})` : ""}`,
|
|
374
397
|
` Enabled: ${job.enabled}`,
|
|
375
398
|
` Next run: ${job.enabled ? formatLocalDate(job.nextRunAt) : "n/a (disabled)"}`,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readFile, stat as fsStat } from "node:fs/promises";
|
|
2
2
|
import { basename, extname } from "node:path";
|
|
3
3
|
|
|
4
4
|
import { GEMINI_MAX_INLINE_AUDIO_BYTES } from "../../../providers/gemini/inline-media.js";
|
|
@@ -67,7 +67,9 @@ function buildAudioToolResult(
|
|
|
67
67
|
* The caller is responsible for path resolution and sandbox enforcement —
|
|
68
68
|
* `resolvedPath` must be an already-validated absolute path.
|
|
69
69
|
*/
|
|
70
|
-
export function readAudioFile(
|
|
70
|
+
export async function readAudioFile(
|
|
71
|
+
resolvedPath: string,
|
|
72
|
+
): Promise<ToolExecutionResult> {
|
|
71
73
|
const mimeType = EXTENSION_MIME[extname(resolvedPath).toLowerCase()];
|
|
72
74
|
if (!mimeType) {
|
|
73
75
|
// Defensive: callers gate on AUDIO_EXTENSIONS, so this is unreachable.
|
|
@@ -79,7 +81,7 @@ export function readAudioFile(resolvedPath: string): ToolExecutionResult {
|
|
|
79
81
|
|
|
80
82
|
let stat;
|
|
81
83
|
try {
|
|
82
|
-
stat =
|
|
84
|
+
stat = await fsStat(resolvedPath);
|
|
83
85
|
} catch {
|
|
84
86
|
return { content: `Error: file not found: ${resolvedPath}`, isError: true };
|
|
85
87
|
}
|
|
@@ -96,7 +98,7 @@ export function readAudioFile(resolvedPath: string): ToolExecutionResult {
|
|
|
96
98
|
|
|
97
99
|
let buffer: Buffer;
|
|
98
100
|
try {
|
|
99
|
-
buffer =
|
|
101
|
+
buffer = (await readFile(resolvedPath)) as Buffer;
|
|
100
102
|
} catch (err) {
|
|
101
103
|
const msg = err instanceof Error ? err.message : String(err);
|
|
102
104
|
return { content: `Error reading file: ${msg}`, isError: true };
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
lstatSync,
|
|
3
|
-
readdirSync,
|
|
4
|
-
readFileSync,
|
|
5
|
-
statSync,
|
|
6
|
-
writeFileSync,
|
|
7
|
-
} from "node:fs";
|
|
1
|
+
import { lstat, readdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
8
2
|
import { dirname, join } from "node:path";
|
|
9
3
|
|
|
10
4
|
import { minimatch } from "minimatch";
|
|
@@ -42,6 +36,32 @@ export type PathPolicy = (
|
|
|
42
36
|
// Service
|
|
43
37
|
// ---------------------------------------------------------------------------
|
|
44
38
|
|
|
39
|
+
// Serialize mutations per resolved path. The agent loop executes sibling
|
|
40
|
+
// tool calls in parallel, and the async read -> apply -> write window would
|
|
41
|
+
// otherwise let two edits of the same file both read the same old content and
|
|
42
|
+
// have the later write silently drop the earlier edit (the previous
|
|
43
|
+
// synchronous service made each mutation atomic within the event loop).
|
|
44
|
+
const fileWriteLocks = new Map<string, Promise<void>>();
|
|
45
|
+
|
|
46
|
+
async function withFileWriteLock<T>(
|
|
47
|
+
filePath: string,
|
|
48
|
+
fn: () => Promise<T>,
|
|
49
|
+
): Promise<T> {
|
|
50
|
+
const prev = fileWriteLocks.get(filePath) ?? Promise.resolve();
|
|
51
|
+
const run = prev.then(fn, fn);
|
|
52
|
+
const tail = run.then(
|
|
53
|
+
() => undefined,
|
|
54
|
+
() => undefined,
|
|
55
|
+
);
|
|
56
|
+
fileWriteLocks.set(filePath, tail);
|
|
57
|
+
void tail.then(() => {
|
|
58
|
+
if (fileWriteLocks.get(filePath) === tail) {
|
|
59
|
+
fileWriteLocks.delete(filePath);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
return run;
|
|
63
|
+
}
|
|
64
|
+
|
|
45
65
|
function pathError(
|
|
46
66
|
path: string,
|
|
47
67
|
reason: PathFailureReason,
|
|
@@ -57,6 +77,29 @@ function pathError(
|
|
|
57
77
|
}
|
|
58
78
|
}
|
|
59
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Lines returned by a read that names no `limit`. Without a default the read
|
|
82
|
+
* returns the whole file, and a file-read result is honored in full for the
|
|
83
|
+
* rest of the turn (see `isSpoolEligible` in `context/tool-result-spool.ts`),
|
|
84
|
+
* so one unbounded read of a large file rides every subsequent LLM call in
|
|
85
|
+
* that turn. The cap bounds that; `offset`/`limit` page past it, and
|
|
86
|
+
* {@link truncationNotice} tells the model when it is looking at a window
|
|
87
|
+
* rather than the whole file.
|
|
88
|
+
*/
|
|
89
|
+
export const DEFAULT_READ_LINE_LIMIT = 2000;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Trailing marker appended when a read stops short of the last line. Silent
|
|
93
|
+
* truncation is the failure mode worth avoiding: a model that cannot tell a
|
|
94
|
+
* window from a whole file reasons about code it never saw.
|
|
95
|
+
*/
|
|
96
|
+
function truncationNotice(
|
|
97
|
+
lastLineReturned: number,
|
|
98
|
+
totalLines: number,
|
|
99
|
+
): string {
|
|
100
|
+
return `\n\n[Truncated: showing through line ${lastLineReturned} of ${totalLines}. Read on with offset=${lastLineReturned + 1}, or pass an explicit limit.]`;
|
|
101
|
+
}
|
|
102
|
+
|
|
60
103
|
export class FileSystemOps {
|
|
61
104
|
private policy: PathPolicy;
|
|
62
105
|
private sizeLimit: number | undefined;
|
|
@@ -70,7 +113,7 @@ export class FileSystemOps {
|
|
|
70
113
|
// Read
|
|
71
114
|
// -------------------------------------------------------------------------
|
|
72
115
|
|
|
73
|
-
readFileSafe(input: ReadInput): ReadResult {
|
|
116
|
+
async readFileSafe(input: ReadInput): Promise<ReadResult> {
|
|
74
117
|
const pathCheck = this.policy(input.path, { mustExist: true });
|
|
75
118
|
if (!pathCheck.ok) {
|
|
76
119
|
return {
|
|
@@ -84,23 +127,24 @@ export class FileSystemOps {
|
|
|
84
127
|
return { ok: false, error: Err.notFound(filePath) };
|
|
85
128
|
}
|
|
86
129
|
|
|
87
|
-
const
|
|
88
|
-
if (!
|
|
130
|
+
const pathStat = await stat(filePath);
|
|
131
|
+
if (!pathStat.isFile()) {
|
|
89
132
|
return { ok: false, error: Err.notAFile(filePath) };
|
|
90
133
|
}
|
|
91
134
|
|
|
92
|
-
const sizeErr = checkFileSizeOnDisk(filePath, this.sizeLimit);
|
|
135
|
+
const sizeErr = await checkFileSizeOnDisk(filePath, this.sizeLimit);
|
|
93
136
|
if (sizeErr) {
|
|
94
137
|
return { ok: false, error: Err.sizeLimitExceeded(filePath, sizeErr) };
|
|
95
138
|
}
|
|
96
139
|
|
|
97
140
|
try {
|
|
98
|
-
const raw =
|
|
141
|
+
const raw = await readFile(filePath, "utf-8");
|
|
99
142
|
const lines = raw.split("\n");
|
|
100
143
|
|
|
101
144
|
const offset = (input.offset ?? 1) - 1;
|
|
102
|
-
const
|
|
103
|
-
const
|
|
145
|
+
const start = Math.max(0, offset);
|
|
146
|
+
const limit = input.limit ?? DEFAULT_READ_LINE_LIMIT;
|
|
147
|
+
const selected = lines.slice(start, offset + limit);
|
|
104
148
|
|
|
105
149
|
const numbered = selected
|
|
106
150
|
.map((line, i) => {
|
|
@@ -109,7 +153,16 @@ export class FileSystemOps {
|
|
|
109
153
|
})
|
|
110
154
|
.join("\n");
|
|
111
155
|
|
|
112
|
-
|
|
156
|
+
// Only when the window stops before the last line. An empty window means
|
|
157
|
+
// the caller paged past the end or asked for nothing, which is not a
|
|
158
|
+
// truncated read.
|
|
159
|
+
const lastLineReturned = start + selected.length;
|
|
160
|
+
const content =
|
|
161
|
+
selected.length > 0 && lastLineReturned < lines.length
|
|
162
|
+
? numbered + truncationNotice(lastLineReturned, lines.length)
|
|
163
|
+
: numbered;
|
|
164
|
+
|
|
165
|
+
return { ok: true, value: { content } };
|
|
113
166
|
} catch (err) {
|
|
114
167
|
const msg = err instanceof Error ? err.message : String(err);
|
|
115
168
|
return { ok: false, error: Err.ioError(filePath, msg) };
|
|
@@ -120,7 +173,7 @@ export class FileSystemOps {
|
|
|
120
173
|
// Write
|
|
121
174
|
// -------------------------------------------------------------------------
|
|
122
175
|
|
|
123
|
-
writeFileSafe(input: WriteInput): WriteResult {
|
|
176
|
+
async writeFileSafe(input: WriteInput): Promise<WriteResult> {
|
|
124
177
|
const pathCheck = this.policy(input.path, { mustExist: false });
|
|
125
178
|
if (!pathCheck.ok) {
|
|
126
179
|
return {
|
|
@@ -135,41 +188,43 @@ export class FileSystemOps {
|
|
|
135
188
|
return { ok: false, error: Err.sizeLimitExceeded(filePath, sizeErr) };
|
|
136
189
|
}
|
|
137
190
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
191
|
+
return withFileWriteLock(filePath, async (): Promise<WriteResult> => {
|
|
192
|
+
try {
|
|
193
|
+
ensureDir(dirname(filePath));
|
|
194
|
+
|
|
195
|
+
let oldContent = "";
|
|
196
|
+
const isNewFile = !pathExists(filePath);
|
|
197
|
+
if (!isNewFile) {
|
|
198
|
+
try {
|
|
199
|
+
oldContent = await readFile(filePath, "utf-8");
|
|
200
|
+
} catch {
|
|
201
|
+
// Unreadable existing file - keep oldContent as empty string.
|
|
202
|
+
}
|
|
148
203
|
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
writeFileSync(filePath, input.content);
|
|
152
204
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
205
|
+
await writeFile(filePath, input.content);
|
|
206
|
+
|
|
207
|
+
return {
|
|
208
|
+
ok: true,
|
|
209
|
+
value: {
|
|
210
|
+
filePath,
|
|
211
|
+
isNewFile,
|
|
212
|
+
oldContent,
|
|
213
|
+
newContent: input.content,
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
} catch (err) {
|
|
217
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
218
|
+
return { ok: false, error: Err.ioError(filePath, msg) };
|
|
219
|
+
}
|
|
220
|
+
});
|
|
166
221
|
}
|
|
167
222
|
|
|
168
223
|
// -------------------------------------------------------------------------
|
|
169
224
|
// Edit
|
|
170
225
|
// -------------------------------------------------------------------------
|
|
171
226
|
|
|
172
|
-
editFileSafe(input: EditInput): EditResult {
|
|
227
|
+
async editFileSafe(input: EditInput): Promise<EditResult> {
|
|
173
228
|
const pathCheck = this.policy(input.path, { mustExist: true });
|
|
174
229
|
if (!pathCheck.ok) {
|
|
175
230
|
return {
|
|
@@ -179,82 +234,85 @@ export class FileSystemOps {
|
|
|
179
234
|
}
|
|
180
235
|
const filePath = pathCheck.resolved;
|
|
181
236
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
237
|
+
return withFileWriteLock(filePath, async (): Promise<EditResult> => {
|
|
238
|
+
// Size-check the file on disk (swallow ENOENT - the read below gives a
|
|
239
|
+
// clearer error)
|
|
240
|
+
try {
|
|
241
|
+
const sizeErr = await checkFileSizeOnDisk(filePath, this.sizeLimit);
|
|
242
|
+
if (sizeErr) {
|
|
243
|
+
return { ok: false, error: Err.sizeLimitExceeded(filePath, sizeErr) };
|
|
244
|
+
}
|
|
245
|
+
} catch {
|
|
246
|
+
// Fall through - the read below will surface NOT_FOUND.
|
|
187
247
|
}
|
|
188
|
-
} catch {
|
|
189
|
-
// Fall through - the readFileSync below will surface NOT_FOUND.
|
|
190
|
-
}
|
|
191
248
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
249
|
+
let content: string;
|
|
250
|
+
try {
|
|
251
|
+
content = await readFile(filePath, "utf-8");
|
|
252
|
+
} catch (err) {
|
|
253
|
+
const code =
|
|
254
|
+
err instanceof Error && "code" in err
|
|
255
|
+
? (err as NodeJS.ErrnoException).code
|
|
256
|
+
: undefined;
|
|
257
|
+
if (code === "EISDIR") {
|
|
258
|
+
return { ok: false, error: Err.notAFile(filePath) };
|
|
259
|
+
}
|
|
260
|
+
if (code === "ENOENT") {
|
|
261
|
+
return { ok: false, error: Err.notFound(filePath) };
|
|
262
|
+
}
|
|
263
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
264
|
+
return { ok: false, error: Err.ioError(filePath, msg) };
|
|
202
265
|
}
|
|
203
|
-
|
|
204
|
-
|
|
266
|
+
|
|
267
|
+
if (input.oldString.length === 0) {
|
|
268
|
+
return { ok: false, error: Err.matchNotFound(filePath) };
|
|
205
269
|
}
|
|
206
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
207
|
-
return { ok: false, error: Err.ioError(filePath, msg) };
|
|
208
|
-
}
|
|
209
270
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
271
|
+
const result = applyEdit(
|
|
272
|
+
content,
|
|
273
|
+
input.oldString,
|
|
274
|
+
input.newString,
|
|
275
|
+
input.replaceAll,
|
|
276
|
+
);
|
|
213
277
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
278
|
+
if (!result.ok) {
|
|
279
|
+
if (result.reason === "not_found") {
|
|
280
|
+
return { ok: false, error: Err.matchNotFound(filePath) };
|
|
281
|
+
}
|
|
282
|
+
return {
|
|
283
|
+
ok: false,
|
|
284
|
+
error: Err.matchAmbiguous(filePath, result.matchCount),
|
|
285
|
+
};
|
|
286
|
+
}
|
|
220
287
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
288
|
+
try {
|
|
289
|
+
await writeFile(filePath, result.updatedContent);
|
|
290
|
+
} catch (err) {
|
|
291
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
292
|
+
return { ok: false, error: Err.ioError(filePath, msg) };
|
|
224
293
|
}
|
|
294
|
+
|
|
225
295
|
return {
|
|
226
|
-
ok:
|
|
227
|
-
|
|
296
|
+
ok: true,
|
|
297
|
+
value: {
|
|
298
|
+
filePath,
|
|
299
|
+
matchCount: result.matchCount,
|
|
300
|
+
oldContent: content,
|
|
301
|
+
newContent: result.updatedContent,
|
|
302
|
+
matchMethod: result.matchMethod,
|
|
303
|
+
similarity: result.similarity,
|
|
304
|
+
actualOld: result.actualOld,
|
|
305
|
+
actualNew: result.actualNew,
|
|
306
|
+
},
|
|
228
307
|
};
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
try {
|
|
232
|
-
writeFileSync(filePath, result.updatedContent);
|
|
233
|
-
} catch (err) {
|
|
234
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
235
|
-
return { ok: false, error: Err.ioError(filePath, msg) };
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
return {
|
|
239
|
-
ok: true,
|
|
240
|
-
value: {
|
|
241
|
-
filePath,
|
|
242
|
-
matchCount: result.matchCount,
|
|
243
|
-
oldContent: content,
|
|
244
|
-
newContent: result.updatedContent,
|
|
245
|
-
matchMethod: result.matchMethod,
|
|
246
|
-
similarity: result.similarity,
|
|
247
|
-
actualOld: result.actualOld,
|
|
248
|
-
actualNew: result.actualNew,
|
|
249
|
-
},
|
|
250
|
-
};
|
|
308
|
+
});
|
|
251
309
|
}
|
|
252
310
|
|
|
253
311
|
// -------------------------------------------------------------------------
|
|
254
312
|
// List
|
|
255
313
|
// -------------------------------------------------------------------------
|
|
256
314
|
|
|
257
|
-
listDirSafe(input: ListInput): ListResult {
|
|
315
|
+
async listDirSafe(input: ListInput): Promise<ListResult> {
|
|
258
316
|
const pathCheck = this.policy(input.path, { mustExist: true });
|
|
259
317
|
if (!pathCheck.ok) {
|
|
260
318
|
return {
|
|
@@ -268,13 +326,13 @@ export class FileSystemOps {
|
|
|
268
326
|
return { ok: false, error: Err.notFound(resolved) };
|
|
269
327
|
}
|
|
270
328
|
|
|
271
|
-
const
|
|
272
|
-
if (!
|
|
329
|
+
const pathStat = await stat(resolved);
|
|
330
|
+
if (!pathStat.isDirectory()) {
|
|
273
331
|
return { ok: false, error: Err.notADirectory(resolved) };
|
|
274
332
|
}
|
|
275
333
|
|
|
276
334
|
try {
|
|
277
|
-
let entries =
|
|
335
|
+
let entries = await readdir(resolved, { withFileTypes: true });
|
|
278
336
|
|
|
279
337
|
if (input.glob) {
|
|
280
338
|
const pattern = input.glob;
|
|
@@ -294,16 +352,18 @@ export class FileSystemOps {
|
|
|
294
352
|
const truncated = sorted.length > MAX_ENTRIES;
|
|
295
353
|
const visible = sorted.slice(0, MAX_ENTRIES);
|
|
296
354
|
|
|
297
|
-
const lines =
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
355
|
+
const lines = await Promise.all(
|
|
356
|
+
visible.map(async (entry) => {
|
|
357
|
+
if (entry.isDirectory()) {
|
|
358
|
+
return `${entry.name}/`;
|
|
359
|
+
}
|
|
360
|
+
if (entry.isSymbolicLink()) {
|
|
361
|
+
return `${entry.name}@`;
|
|
362
|
+
}
|
|
363
|
+
const fileStat = await lstat(join(resolved, entry.name));
|
|
364
|
+
return `${entry.name} ${formatSize(fileStat.size)}`;
|
|
365
|
+
}),
|
|
366
|
+
);
|
|
307
367
|
|
|
308
368
|
if (truncated) {
|
|
309
369
|
lines.push(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readFile, stat as fsStat } from "node:fs/promises";
|
|
2
2
|
|
|
3
3
|
import { optimizeImageForTransport } from "../../../agent/image-optimize.js";
|
|
4
4
|
import type { ImageContent } from "../../../providers/types.js";
|
|
@@ -63,10 +63,10 @@ export function detectMediaType(buf: Buffer): string | null {
|
|
|
63
63
|
return null;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
function buildImageToolResult(
|
|
66
|
+
async function buildImageToolResult(
|
|
67
67
|
buffer: Buffer,
|
|
68
68
|
sourceLabel: string,
|
|
69
|
-
): ToolExecutionResult {
|
|
69
|
+
): Promise<ToolExecutionResult> {
|
|
70
70
|
if (buffer.length > MAX_SOURCE_SIZE_BYTES) {
|
|
71
71
|
const sizeMB = (buffer.length / (1024 * 1024)).toFixed(1);
|
|
72
72
|
return {
|
|
@@ -87,10 +87,8 @@ function buildImageToolResult(
|
|
|
87
87
|
|
|
88
88
|
// Optimize before size-checking — oversized images may compress under the limit.
|
|
89
89
|
const rawBase64 = buffer.toString("base64");
|
|
90
|
-
const { data: base64Data, mediaType: finalType } =
|
|
91
|
-
rawBase64,
|
|
92
|
-
detectedType,
|
|
93
|
-
);
|
|
90
|
+
const { data: base64Data, mediaType: finalType } =
|
|
91
|
+
await optimizeImageForTransport(rawBase64, detectedType);
|
|
94
92
|
const optimized = base64Data !== rawBase64;
|
|
95
93
|
|
|
96
94
|
const optimizedBytes = Buffer.from(base64Data, "base64").length;
|
|
@@ -124,10 +122,10 @@ function buildImageToolResult(
|
|
|
124
122
|
};
|
|
125
123
|
}
|
|
126
124
|
|
|
127
|
-
export function readImageBase64(
|
|
125
|
+
export async function readImageBase64(
|
|
128
126
|
base64Data: string,
|
|
129
127
|
sourceLabel: string,
|
|
130
|
-
): ToolExecutionResult {
|
|
128
|
+
): Promise<ToolExecutionResult> {
|
|
131
129
|
return buildImageToolResult(Buffer.from(base64Data, "base64"), sourceLabel);
|
|
132
130
|
}
|
|
133
131
|
|
|
@@ -138,10 +136,12 @@ export function readImageBase64(
|
|
|
138
136
|
* The caller is responsible for path resolution and sandbox enforcement -
|
|
139
137
|
* `resolvedPath` must be an already-validated absolute path.
|
|
140
138
|
*/
|
|
141
|
-
export function readImageFile(
|
|
139
|
+
export async function readImageFile(
|
|
140
|
+
resolvedPath: string,
|
|
141
|
+
): Promise<ToolExecutionResult> {
|
|
142
142
|
let stat;
|
|
143
143
|
try {
|
|
144
|
-
stat =
|
|
144
|
+
stat = await fsStat(resolvedPath);
|
|
145
145
|
} catch {
|
|
146
146
|
return {
|
|
147
147
|
content: `Error: file not found: ${resolvedPath}`,
|
|
@@ -163,7 +163,7 @@ export function readImageFile(resolvedPath: string): ToolExecutionResult {
|
|
|
163
163
|
|
|
164
164
|
let buffer: Buffer;
|
|
165
165
|
try {
|
|
166
|
-
buffer =
|
|
166
|
+
buffer = (await readFile(resolvedPath)) as Buffer;
|
|
167
167
|
} catch (err) {
|
|
168
168
|
const msg = err instanceof Error ? err.message : String(err);
|
|
169
169
|
return { content: `Error reading file: ${msg}`, isError: true };
|