@vellumai/assistant 0.11.3 → 0.11.4-dev.202608190019.b94dbf2
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/AGENTS.md +9 -3
- package/ARCHITECTURE.md +32 -10
- package/docs/architecture/memory.md +43 -5
- package/docs/architecture/security.md +96 -152
- package/docs/architecture/turn-actor.md +70 -0
- package/docs/browser-use-architecture-phase2.md +128 -56
- package/docs/flux-turn-detection-spike.md +248 -0
- package/docs/guardian-request-flow.md +35 -0
- package/docs/stt-provider-onboarding.md +3 -1
- package/knip.json +3 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +34 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +166 -1
- package/node_modules/@vellumai/gateway-client/src/index.ts +2 -0
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/url-normalization.test.ts +135 -0
- package/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/remote-web-pairing.ts +60 -0
- package/node_modules/@vellumai/service-contracts/src/url-normalization.ts +107 -0
- package/openapi.yaml +289 -113
- package/package.json +1 -1
- package/scripts/voice-ttft-spike.ts +3 -3
- package/scripts/write-plugin-api-shim.ts +10 -0
- package/src/__tests__/app-compiler.test.ts +38 -3
- package/src/__tests__/app-control-flow.test.ts +1 -0
- package/src/__tests__/approval-routes-http.test.ts +2 -2
- package/src/__tests__/assistant-feature-flag-guard.test.ts +25 -3
- package/src/__tests__/attachments-store.test.ts +21 -12
- package/src/__tests__/byok-default-profile-ensure.test.ts +17 -0
- package/src/__tests__/call-setup-flow-name-capture.test.ts +0 -1
- package/src/__tests__/call-site-routing-provider.test.ts +1 -1
- package/src/__tests__/channel-availability-routes.test.ts +14 -1
- package/src/__tests__/channel-capabilities-dedupe.test.ts +214 -0
- package/src/__tests__/channel-delivery-store.test.ts +14 -14
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +4 -4
- package/src/__tests__/channel-setup-panel-ack.test.ts +1 -1
- package/src/__tests__/checker.test.ts +20 -314
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +6 -2
- package/src/__tests__/compaction-events.test.ts +8 -10
- package/src/__tests__/config-loader-backfill.test.ts +3 -3
- package/src/__tests__/config-schema.test.ts +25 -10
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +8 -11
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +8 -11
- package/src/__tests__/conversation-agent-loop.test.ts +32 -21
- package/src/__tests__/conversation-attachments.test.ts +0 -1
- package/src/__tests__/conversation-attention-store.test.ts +63 -0
- package/src/__tests__/conversation-confirmation-signals.test.ts +112 -0
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -4
- package/src/__tests__/conversation-fork-crud.test.ts +69 -0
- package/src/__tests__/conversation-fork-referential.test.ts +67 -0
- package/src/__tests__/conversation-fork-retrospective.test.ts +24 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +209 -0
- package/src/__tests__/conversation-notifiers-provenance.test.ts +59 -0
- package/src/__tests__/conversation-queue.test.ts +154 -4
- package/src/__tests__/conversation-routes-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-routes-enabled-plugins.test.ts +1 -1
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +9 -9
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +1 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +187 -102
- package/src/__tests__/conversation-runtime-workspace.test.ts +14 -10
- package/src/__tests__/conversation-slash-queue.test.ts +3 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-app-open.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +21 -14
- package/src/__tests__/conversation-surfaces-queued-emit.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-standalone.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-state-update.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-table-action.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +1 -1
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +1 -1
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +1 -1
- package/src/__tests__/credential-prompt-route.test.ts +7 -10
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/cu-unified-flow.test.ts +1 -0
- package/src/__tests__/custom-profile-ensure.test.ts +5 -1
- package/src/__tests__/default-plugin-names-guard.test.ts +12 -1
- package/src/__tests__/discord-access-request-privacy.test.ts +5 -1
- package/src/__tests__/discord-requester-notice-privacy.test.ts +3 -3
- package/src/__tests__/document-append-idempotency.test.ts +233 -0
- package/src/__tests__/document-sync-tags.test.ts +0 -75
- package/src/__tests__/dynamic-skill-background-guard.test.ts +0 -2
- package/src/__tests__/edit-propagation.test.ts +107 -11
- package/src/__tests__/file-ops-service.test.ts +163 -30
- package/src/__tests__/filesystem-tools.test.ts +23 -24
- package/src/__tests__/gateway-only-guard.test.ts +2 -5
- package/src/__tests__/helpers/gateway-classify-mock.ts +27 -6
- package/src/__tests__/helpers/mock-actor-context.ts +49 -0
- package/src/__tests__/helpers/mock-conversation.ts +13 -1
- package/src/__tests__/host-file-read-tool.test.ts +16 -19
- package/src/__tests__/http-user-message-parity.test.ts +1 -1
- package/src/__tests__/init-feature-flag-overrides.test.ts +49 -0
- package/src/__tests__/injector-chain.test.ts +63 -41
- package/src/__tests__/injector-disk-pressure.test.ts +11 -23
- package/src/__tests__/inline-skill-load-permissions.test.ts +47 -36
- package/src/__tests__/llm-context-resolution.test.ts +73 -1
- package/src/__tests__/llm-schema.test.ts +5 -2
- package/src/__tests__/managed-skill-lifecycle.test.ts +7 -0
- package/src/__tests__/mcp-list-plugin-servers.test.ts +250 -0
- package/src/__tests__/media-generate-image.test.ts +131 -21
- package/src/__tests__/memory-retrieval-hook.test.ts +100 -7
- package/src/__tests__/messages-read-boundary-guard.test.ts +134 -0
- package/src/__tests__/mtime-cache.test.ts +3 -1
- package/src/__tests__/non-member-access-request.test.ts +0 -20
- package/src/__tests__/outbound-slack-persistence.test.ts +40 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +0 -4
- package/src/__tests__/plugin-api-store-credential.test.ts +261 -0
- package/src/__tests__/plugin-api-webhook-url.test.ts +10 -7
- package/src/__tests__/plugin-disabled-state.test.ts +2 -0
- package/src/__tests__/plugin-effective-enabled-set.test.ts +55 -3
- package/src/__tests__/plugin-execution-context.test.ts +73 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +5 -1
- package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +7 -4
- package/src/__tests__/plugin-secret-pattern-contribution.test.ts +1 -1
- package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +14 -7
- package/src/__tests__/provider-commit-message-generator.test.ts +20 -0
- package/src/__tests__/proxy-approval-callback.test.ts +1 -0
- package/src/__tests__/qdrant-manager.test.ts +14 -1
- package/src/__tests__/reaction-persistence.test.ts +200 -7
- package/src/__tests__/require-fresh-approval.test.ts +0 -4
- package/src/__tests__/risk-classification-boundary-guard.test.ts +115 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +460 -105
- package/src/__tests__/run-due-schedules.test.ts +21 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +187 -18
- package/src/__tests__/schedule-routes.test.ts +23 -0
- package/src/__tests__/schedule-store.test.ts +17 -0
- package/src/__tests__/scoped-approval-grants.test.ts +11 -6
- package/src/__tests__/secret-ingress-channel.test.ts +0 -1
- package/src/__tests__/secret-ingress-http.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +3 -3
- package/src/__tests__/skills.test.ts +32 -0
- package/src/__tests__/slack-edit-ordering-characterization.test.ts +0 -1
- package/src/__tests__/starter-task-flow.test.ts +5 -4
- package/src/__tests__/subagent-call-site-routing.test.ts +31 -19
- package/src/__tests__/subagent-fork-prompt-role.test.ts +1 -1
- package/src/__tests__/subagent-spawn-and-await.test.ts +18 -17
- package/src/__tests__/subagent-tool-gate-mode.test.ts +1 -1
- package/src/__tests__/subagent-tools.test.ts +81 -101
- package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +1 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +132 -5
- package/src/__tests__/tool-executor.test.ts +68 -39
- package/src/__tests__/turn-events-store.test.ts +43 -0
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +1 -1
- package/src/__tests__/ui-shape-teaching.test.ts +33 -0
- package/src/__tests__/ui-visual-surface.test.ts +1 -1
- package/src/__tests__/ui-voice-picker-surface.test.ts +128 -0
- package/src/__tests__/ui-work-result-surface.test.ts +1 -1
- package/src/__tests__/user-plugin-loader.test.ts +3 -1
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
- package/src/__tests__/visible-app-context.test.ts +16 -9
- package/src/__tests__/voice-config-update.test.ts +40 -0
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +5 -3
- package/src/__tests__/voice-session-bridge.test.ts +85 -29
- package/src/__tests__/worker-entrypoint-guards.test.ts +54 -0
- package/src/__tests__/worker-plugin-surface.test.ts +77 -0
- package/src/__tests__/workspace-migration-142-consolidate-voice-front-door.test.ts +158 -0
- package/src/__tests__/workspace-migration-143-repair-deprecated-codex-model-id.test.ts +133 -0
- package/src/__tests__/workspace-migration-144-convert-stranded-subscription-openai-profiles.test.ts +316 -0
- package/src/__tests__/workspace-migration-145-collapse-profile-bindings-to-entries.test.ts +325 -0
- package/src/__tests__/workspace-migration-146-repair-retired-fireworks-deepseek-flash-model-id.test.ts +235 -0
- package/src/acp/__tests__/acp-claude-oauth.test.ts +10 -2
- package/src/acp/__tests__/auth-required.test.ts +161 -0
- package/src/acp/acp-claude-oauth.ts +19 -2
- package/src/acp/agent-process.test.ts +100 -0
- package/src/acp/agent-process.ts +29 -26
- package/src/acp/auth-required.ts +102 -0
- package/src/acp/session-manager.test.ts +119 -0
- package/src/acp/session-manager.ts +76 -3
- package/src/api/events/acp-auth-required.ts +55 -0
- package/src/api/events/host-file.ts +2 -2
- package/src/api/index.ts +7 -0
- package/src/api/surfaces.ts +12 -3
- package/src/apps/app-store.ts +3 -0
- package/src/bundler/package-resolver.ts +2 -30
- package/src/calls/__tests__/voice-session-bridge.test.ts +194 -11
- package/src/calls/__tests__/voice-triage-escalate.test.ts +102 -0
- package/src/calls/call-controller.ts +19 -3
- package/src/calls/call-setup-flow.ts +0 -1
- package/src/calls/media-stream-stt-session.ts +15 -0
- package/src/calls/voice-session-bridge.ts +115 -41
- package/src/calls/voice-triage-escalate.ts +105 -2
- package/src/channels/__tests__/plugin-channel-declarations.test.ts +161 -0
- package/src/channels/config.ts +13 -0
- package/src/channels/plugin-channel-declarations.ts +108 -0
- package/src/channels/types.ts +30 -0
- package/src/cli/AGENTS.md +5 -2
- package/src/cli/bundled-modules.ts +29 -0
- package/src/cli/commands/credentials.help.ts +2 -2
- package/src/cli/commands/db/repair.ts +4 -8
- package/src/cli/commands/domain.ts +6 -3
- package/src/cli/commands/email.ts +6 -3
- package/src/cli/commands/inference-providers.ts +1 -1
- package/src/cli/commands/keys.ts +8 -3
- package/src/cli/commands/mcp.help.ts +13 -4
- package/src/cli/commands/mcp.ts +9 -0
- package/src/cli/commands/memory/__tests__/memory-v2.test.ts +57 -7
- package/src/cli/commands/memory/__tests__/memory-v3.test.ts +128 -5
- package/src/cli/commands/memory/index.help.ts +84 -28
- package/src/cli/commands/memory/index.ts +2 -0
- package/src/cli/commands/memory/memory-v2.ts +58 -54
- package/src/cli/commands/memory/memory-v3.ts +64 -0
- package/src/cli/commands/memory/memory-validate.ts +18 -0
- package/src/cli/commands/plugins.ts +85 -36
- package/src/cli/commands/schedules.ts +35 -1
- package/src/cli/commands/stt.help.ts +27 -2
- package/src/cli/commands/trust.ts +3 -14
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +39 -0
- package/src/cli/lib/bundled-marketplace.json +14 -1
- package/src/cli/lib/upgrade-plugin.ts +42 -0
- package/src/config/__tests__/balanced-model-experiment.test.ts +278 -0
- package/src/config/__tests__/default-profile-catalog.test.ts +34 -2
- package/src/config/__tests__/default-provider.test.ts +6 -1
- package/src/config/__tests__/profile-materialization.test.ts +75 -19
- package/src/config/assistant-feature-flags.ts +36 -15
- package/src/config/balanced-model-experiment.ts +35 -0
- package/src/config/bundled-skills/acp/SKILL.md +6 -7
- package/src/config/bundled-skills/document-editor/SKILL.md +2 -2
- package/src/config/bundled-skills/document-editor/TOOLS.json +2 -2
- package/src/config/bundled-skills/image-studio/SKILL.md +5 -4
- package/src/config/bundled-skills/image-studio/TOOLS.json +1 -1
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +101 -0
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +14 -4
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.test.ts +65 -0
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +7 -1
- package/src/config/bundled-skills/settings/tools/shared.ts +16 -0
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -1
- package/src/config/bundled-skills/skill-management/TOOLS.json +9 -3
- package/src/config/bundled-skills/subagent/SKILL.md +17 -12
- package/src/config/bundled-skills/subagent/TOOLS.json +4 -4
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +22 -1
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +9 -2
- package/src/config/call-site-defaults.ts +11 -5
- package/src/config/default-profile-catalog.ts +179 -16
- package/src/config/default-profile-names.ts +4 -1
- package/src/config/default-provider-resolution.ts +4 -0
- package/src/config/feature-flag-registry.json +12 -12
- package/src/config/llm-context-resolution.ts +11 -3
- package/src/config/llm-resolver.ts +28 -1
- package/src/config/profile-materialization.ts +70 -22
- package/src/config/schemas/__tests__/live-voice.test.ts +107 -4
- package/src/config/schemas/call-site-catalog.ts +4 -4
- package/src/config/schemas/live-voice.ts +57 -23
- package/src/config/schemas/llm.ts +59 -32
- package/src/config/schemas/mcp.ts +23 -0
- package/src/config/schemas/plugin-updates.ts +6 -2
- package/src/config/schemas/stt.ts +1 -0
- package/src/config/skills.ts +9 -2
- package/src/context/outbound-sanitize.ts +96 -1
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +1 -1
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +82 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +15 -10
- package/src/daemon/conversation-agent-loop.ts +31 -19
- package/src/daemon/conversation-messaging.ts +5 -1
- package/src/daemon/conversation-notifiers.ts +20 -10
- package/src/daemon/conversation-process.ts +20 -6
- package/src/daemon/conversation-runtime-assembly.ts +12 -6
- package/src/daemon/conversation-store.ts +14 -4
- package/src/daemon/conversation-surfaces.ts +75 -26
- package/src/daemon/conversation-tool-setup.ts +3 -6
- package/src/daemon/conversation.ts +154 -51
- package/src/daemon/doordash-steps.ts +2 -2
- package/src/daemon/lifecycle.ts +14 -1
- package/src/daemon/mcp-reload-service.ts +36 -6
- package/src/daemon/process-message.ts +13 -26
- package/src/daemon/providers-setup.ts +6 -3
- package/src/daemon/trust-context-types.ts +29 -0
- package/src/daemon/trust-context.ts +12 -7
- package/src/daemon/wake-conversation-ops.ts +3 -2
- package/src/daemon/windows-compiled-entry.ts +4 -0
- package/src/documents/document-store.ts +143 -240
- package/src/hooks/hook-loader.ts +3 -3
- package/src/hooks/registry.ts +103 -45
- package/src/hooks/types.ts +5 -0
- package/src/inbound/__tests__/oauth-callback-url.test.ts +83 -0
- package/src/inbound/oauth-callback-url.ts +61 -0
- package/src/ipc/gateway-client.test.ts +1 -1
- package/src/ipc/gateway-client.ts +14 -21
- package/src/ipc/gateway-flag-listener.ts +17 -3
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +1 -104
- package/src/live-voice/__tests__/live-voice-events.test.ts +7 -8
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +1050 -0
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +115 -8
- package/src/live-voice/__tests__/live-voice-photo.test.ts +100 -0
- package/src/live-voice/__tests__/live-voice-progress.test.ts +60 -194
- package/src/live-voice/__tests__/live-voice-stt.test.ts +14 -0
- package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +29 -0
- package/src/live-voice/__tests__/live-voice-tts-session.test.ts +0 -483
- package/src/live-voice/__tests__/live-voice-vad.test.ts +0 -16
- package/src/live-voice/__tests__/progress-narration.test.ts +214 -0
- package/src/live-voice/live-voice-archive.ts +2 -0
- package/src/live-voice/live-voice-manager.ts +16 -3
- package/src/live-voice/live-voice-metrics.ts +57 -32
- package/src/live-voice/live-voice-photo.ts +1 -2
- package/src/live-voice/live-voice-session.ts +598 -323
- package/src/live-voice/progress-narration.ts +277 -0
- package/src/live-voice/protocol.ts +21 -1
- package/src/live-voice/windows-compiled-live-voice.ts +4 -0
- package/src/mcp/__tests__/effective-config.test.ts +238 -0
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
- package/src/mcp/__tests__/mcp-oauth-client-registration.test.ts +200 -0
- package/src/mcp/__tests__/mcp-oauth-provider.test.ts +9 -9
- package/src/mcp/__tests__/plugin-server-credential-isolation.test.ts +95 -0
- package/src/mcp/client.ts +16 -11
- package/src/mcp/effective-config.ts +113 -0
- package/src/mcp/manager.ts +11 -6
- package/src/mcp/mcp-auth-orchestrator.ts +13 -22
- package/src/mcp/mcp-oauth-provider.ts +205 -240
- package/src/monitoring/__tests__/plugin-auto-update.test.ts +166 -3
- package/src/monitoring/control.ts +1 -0
- package/src/monitoring/db-integrity-sample.ts +4 -5
- package/src/monitoring/plugin-auto-update.ts +128 -24
- package/src/notifications/AGENTS.md +2 -0
- package/src/notifications/approval-card-data.ts +33 -0
- package/src/notifications/signal.ts +1 -0
- package/src/permissions/AGENTS.md +16 -0
- package/src/permissions/checker.test.ts +75 -122
- package/src/permissions/checker.ts +44 -560
- package/src/permissions/confirmation-guardian-request.test.ts +15 -11
- package/src/permissions/confirmation-guardian-request.ts +2 -2
- package/src/permissions/prompter.ts +1 -5
- package/src/permissions/question-guardian-request.test.ts +14 -6
- package/src/permissions/question-guardian-request.ts +1 -2
- package/src/persistence/attachments-store.ts +8 -1
- package/src/persistence/bookmark-crud.ts +3 -7
- package/src/persistence/conversation-attention-store.ts +16 -45
- package/src/persistence/conversation-crud.ts +33 -4
- package/src/persistence/conversation-lineage.ts +9 -0
- package/src/persistence/conversation-queries.ts +182 -52
- package/src/persistence/delivery-crud.ts +150 -36
- package/src/persistence/embeddings/qdrant-manager.ts +84 -49
- package/src/persistence/external-conversation-store.ts +32 -4
- package/src/persistence/llm-request-log-store.ts +4 -10
- package/src/persistence/llm-usage-store.ts +8 -3
- package/src/persistence/message-reads.test.ts +197 -0
- package/src/persistence/message-reads.ts +211 -0
- package/src/persistence/migrations/360-add-document-workspace-path.ts +5 -14
- package/src/persistence/migrations/366-chatgpt-subscription-row-identity.test.ts +120 -0
- package/src/persistence/migrations/366-chatgpt-subscription-row-identity.ts +62 -0
- package/src/persistence/real-user-turn-filter.ts +27 -3
- package/src/persistence/schema/documents.ts +4 -4
- package/src/persistence/steps.ts +9 -0
- package/src/plugin-api/__tests__/oauth-callback-url-export.test.ts +29 -0
- package/src/plugin-api/constants.ts +8 -0
- package/src/plugin-api/conversation-turn.ts +195 -5
- package/src/plugin-api/index.ts +38 -6
- package/src/plugin-api/resolve-credential.ts +3 -2
- package/src/plugin-api/store-credential.ts +146 -0
- package/src/plugin-api/vision-support.test.ts +1 -1
- package/src/plugin-api/webhook-url.ts +13 -11
- package/src/plugins/__tests__/mcp-servers.test.ts +371 -0
- package/src/plugins/defaults/main.ts +21 -7
- package/src/plugins/defaults/memory/AGENTS.md +15 -3
- package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +204 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +72 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +4 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +4 -1
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +0 -1
- package/src/plugins/defaults/memory/buffer-format.ts +165 -0
- package/src/plugins/defaults/memory/context-search/sources/conversations.ts +6 -0
- package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +77 -0
- package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +24 -6
- package/src/plugins/defaults/memory/graph/image-ref-utils.ts +3 -0
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +1 -30
- package/src/plugins/defaults/memory/graph-topology/pending-buffer.test.ts +34 -0
- package/src/plugins/defaults/memory/graph-topology/pending-buffer.ts +17 -24
- package/src/plugins/defaults/memory/hooks/post-compact.ts +1 -4
- package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +53 -5
- package/src/plugins/defaults/memory/indexer.ts +3 -1
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +19 -7
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +4 -4
- package/src/plugins/defaults/memory/src/__tests__/memory-v3-gate-stats.test.ts +281 -0
- package/src/plugins/defaults/memory/src/memory-v2-routes.ts +12 -10
- package/src/plugins/defaults/memory/src/memory-v3-routes.ts +207 -0
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +147 -0
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +8 -0
- package/src/plugins/defaults/memory/substrate/__tests__/edge-index.test.ts +0 -30
- package/src/plugins/defaults/memory/substrate/__tests__/ingest.test.ts +73 -1
- package/src/plugins/defaults/memory/substrate/__tests__/page-index.test.ts +37 -0
- package/src/plugins/defaults/memory/substrate/__tests__/page-links.test.ts +208 -0
- package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +158 -1
- package/src/plugins/defaults/memory/substrate/__tests__/static-context.test.ts +195 -58
- package/src/plugins/defaults/memory/substrate/consolidation-job.ts +93 -24
- package/src/plugins/defaults/memory/substrate/edge-index.ts +0 -31
- package/src/plugins/defaults/memory/substrate/ingest.ts +59 -0
- package/src/plugins/defaults/memory/substrate/page-index.ts +35 -8
- package/src/plugins/defaults/memory/substrate/page-links.ts +133 -0
- package/src/plugins/defaults/memory/substrate/page-store.ts +10 -0
- package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +124 -34
- package/src/plugins/defaults/memory/substrate/skill-content.ts +8 -1
- package/src/plugins/defaults/memory/substrate/static-context.ts +160 -33
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +2 -4
- package/src/plugins/defaults/memory/v1/graph/extraction.ts +3 -1
- package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +18 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +66 -1
- package/src/plugins/defaults/memory/v3/card.ts +9 -9
- package/src/plugins/defaults/memory/v3/core-set.test.ts +7 -0
- package/src/plugins/defaults/memory/v3/core-set.ts +5 -1
- package/src/plugins/defaults/memory/v3/edge.ts +13 -57
- package/src/plugins/defaults/memory/v3/injector.ts +8 -0
- package/src/plugins/defaults/memory/v3/prune.ts +2 -0
- package/src/plugins/defaults/memory/v3/selection-log-store.ts +2 -0
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +23 -9
- package/src/plugins/defaults/memory/worker-control.ts +1 -0
- package/src/plugins/defaults/memory/worker.ts +6 -3
- package/src/plugins/defaults/worker-entrypoints.ts +3 -0
- package/src/plugins/external-plugin-loader.ts +47 -0
- package/src/plugins/mcp-servers.ts +361 -0
- package/src/plugins/mtime-cache.ts +37 -46
- package/src/plugins/pipeline.ts +14 -7
- package/src/plugins/plugin-execution-context.ts +35 -11
- package/src/plugins/worker-plugin-surface.ts +33 -0
- package/src/prompts/templates/system-sections.ts +0 -7
- package/src/providers/__tests__/connection-model-compat.test.ts +1 -1
- package/src/providers/__tests__/context-overflow-error.test.ts +24 -0
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +214 -2
- package/src/providers/__tests__/preflight-resolved-config.test.ts +57 -0
- package/src/providers/__tests__/retry-callsite.test.ts +25 -2
- package/src/providers/anthropic/__tests__/pause-turn-continuation.test.ts +170 -0
- package/src/providers/anthropic/client.ts +332 -241
- package/src/providers/call-site-routing.ts +30 -3
- package/src/providers/connection-resolution.ts +194 -11
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +4 -0
- package/src/providers/inference/adapter-factory.ts +3 -0
- package/src/providers/inference/auth.ts +6 -0
- package/src/providers/inference/connection-availability.ts +24 -2
- package/src/providers/inference/connections.ts +2 -0
- package/src/providers/model-catalog.ts +3 -3
- package/src/providers/model-intents.ts +28 -8
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +163 -40
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +125 -2
- package/src/providers/openai/chat-completions-provider.ts +133 -36
- package/src/providers/openai/codex-models.ts +2 -1
- package/src/providers/provider-send-message.ts +32 -3
- package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +433 -0
- package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +625 -0
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +34 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +285 -6
- package/src/providers/speech-to-text/deepgram-flux-frames.ts +395 -0
- package/src/providers/speech-to-text/deepgram-flux-realtime.ts +679 -0
- package/src/providers/speech-to-text/provider-catalog.ts +99 -8
- package/src/providers/speech-to-text/resolve.ts +25 -2
- package/src/routes/control.ts +1 -0
- package/src/routes/route-host-client.ts +1 -0
- package/src/routes/route-host-protocol.ts +7 -0
- package/src/routes/worker.ts +48 -15
- package/src/runtime/AGENTS.md +16 -17
- package/src/runtime/access-request-helper.ts +9 -12
- package/src/runtime/agent-wake.ts +18 -15
- package/src/runtime/effective-capabilities.test.ts +43 -0
- package/src/runtime/effective-capabilities.ts +27 -0
- package/src/runtime/guardian-reply-router.ts +6 -2
- package/src/runtime/pre-first-message-gate.ts +4 -0
- package/src/runtime/routes/__tests__/acp-claude-auth-routes.test.ts +12 -4
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +522 -2
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +52 -0
- package/src/runtime/routes/__tests__/default-provider-routes.test.ts +61 -0
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +44 -0
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +102 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +132 -35
- package/src/runtime/routes/__tests__/schedule-routes-disarm-reason.test.ts +215 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +25 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +55 -6
- package/src/runtime/routes/__tests__/user-route-dispatcher-host.test.ts +52 -1
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +133 -1
- package/src/runtime/routes/channel-availability-routes.ts +32 -14
- package/src/runtime/routes/channel-route-shared.ts +0 -6
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +6 -6
- package/src/runtime/routes/conversation-list-routes.ts +181 -23
- package/src/runtime/routes/conversation-management-routes.ts +17 -12
- package/src/runtime/routes/conversation-query-routes.ts +40 -27
- package/src/runtime/routes/conversation-routes.ts +43 -29
- package/src/runtime/routes/credential-prompt-routes.ts +4 -7
- package/src/runtime/routes/credential-routes.ts +26 -82
- package/src/runtime/routes/default-provider-routes.ts +15 -0
- package/src/runtime/routes/documents-routes.ts +3 -222
- package/src/runtime/routes/inbound-message-handler.ts +21 -45
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +0 -1
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -9
- package/src/runtime/routes/inbound-stages/admission-policy.ts +1 -17
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.test.ts +0 -1
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -3
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +101 -79
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +0 -1
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +12 -7
- package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +91 -8
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +72 -79
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +2 -3
- package/src/runtime/routes/inference-profiles-routes.ts +20 -11
- package/src/runtime/routes/inference-provider-connection-routes.ts +77 -15
- package/src/runtime/routes/log-export-routes.ts +3 -0
- package/src/runtime/routes/mcp-auth-routes.ts +148 -57
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +2 -0
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +3 -0
- package/src/runtime/routes/playground/inject-failures.ts +2 -2
- package/src/runtime/routes/playground/reset-circuit.ts +1 -1
- package/src/runtime/routes/plugins-routes.ts +38 -8
- package/src/runtime/routes/schedule-routes.ts +94 -7
- package/src/runtime/routes/settings-routes.ts +6 -6
- package/src/runtime/routes/stt-routes.ts +31 -25
- package/src/runtime/routes/surface-action-routes.ts +20 -19
- package/src/runtime/routes/surface-conversation-resolver.ts +3 -0
- package/src/runtime/routes/user-route-dispatcher.ts +69 -15
- package/src/runtime/routes/user-route-import.ts +108 -0
- package/src/runtime/routes/user-route-resolution.ts +18 -1
- package/src/runtime/routes/workspace-routes.ts +0 -9
- package/src/runtime/routes/workspace-utils.ts +3 -13
- package/src/runtime/services/conversation-serializer.ts +7 -2
- package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +68 -5
- package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +81 -0
- package/src/schedule/plugin-schedule-availability.ts +58 -0
- package/src/schedule/plugin-schedule-declarations.ts +23 -27
- package/src/schedule/plugin-schedule-reconciler.ts +12 -3
- package/src/schedule/schedule-store.ts +5 -1
- package/src/schedule/scheduler.ts +9 -4
- package/src/schedule/worker-control.ts +1 -0
- package/src/schedule/worker.ts +6 -0
- package/src/security/oauth2.ts +6 -22
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +22 -0
- package/src/stt/__tests__/types.test.ts +94 -0
- package/src/stt/daemon-batch-transcriber.ts +10 -0
- package/src/stt/stt-stream-session.ts +8 -4
- package/src/stt/types.ts +103 -0
- package/src/subagent/__tests__/consult-prompt.test.ts +26 -15
- package/src/subagent/consult-context.ts +11 -11
- package/src/subagent/consult-prompt.ts +26 -35
- package/src/subagent/manager.ts +21 -40
- package/src/subagent/notify.ts +7 -1
- package/src/subagent/types.ts +15 -12
- package/src/tools/__tests__/tool-input-schemas.test.ts +7 -7
- package/src/tools/acp/spawn.test.ts +97 -0
- package/src/tools/acp/spawn.ts +38 -4
- package/src/tools/credentials/ref-parse.ts +35 -0
- package/src/tools/credentials/resolve.ts +4 -10
- package/src/tools/credentials/store.ts +168 -0
- package/src/tools/document/document-tool.ts +12 -3
- package/src/tools/executor.ts +53 -15
- package/src/tools/filesystem/read.ts +27 -10
- package/src/tools/host-filesystem/read.ts +27 -15
- package/src/tools/network/url-safety.ts +9 -16
- package/src/tools/permission-checker.ts +43 -52
- package/src/tools/registry.ts +2 -1
- package/src/tools/shared/filesystem/file-ops-service.ts +63 -35
- package/src/tools/shared/filesystem/legacy-read-args.ts +22 -0
- package/src/tools/shared/filesystem/types.ts +5 -5
- package/src/tools/skills/scaffold-managed.ts +25 -7
- package/src/tools/subagent/spawn.ts +28 -88
- package/src/tools/tool-types.ts +26 -13
- package/src/tools/types.ts +6 -6
- package/src/tools/ui-surface/surface-shape-docs.ts +12 -1
- package/src/tools/workflows/run-workflow.ts +1 -2
- package/src/tts/__tests__/reasoning-tag-filter.test.ts +78 -0
- package/src/tts/reasoning-tag-filter.ts +89 -0
- package/src/util/__tests__/worker-process-command.test.ts +37 -0
- package/src/util/logger.ts +16 -0
- package/src/util/think-tag-stream.ts +95 -0
- package/src/util/worker-process.ts +37 -4
- package/src/windows-compiled-cli.ts +32 -0
- package/src/windows-compiled-entry.ts +4 -0
- package/src/windows-compiled-logger.ts +6 -0
- package/src/windows-compiled-worker-entry.ts +29 -0
- package/src/workspace/byok-default-profile-ensure.ts +76 -24
- package/src/workspace/custom-profile-ensure.ts +4 -24
- package/src/workspace/migrations/142-consolidate-voice-front-door.ts +70 -0
- package/src/workspace/migrations/143-repair-deprecated-codex-model-id.ts +134 -0
- package/src/workspace/migrations/144-convert-stranded-subscription-openai-profiles.ts +265 -0
- package/src/workspace/migrations/145-collapse-profile-bindings-to-entries.ts +328 -0
- package/src/workspace/migrations/146-repair-retired-fireworks-deepseek-flash-model-id.ts +195 -0
- package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +0 -10
- package/src/workspace/migrations/registry.ts +10 -0
- package/src/workspace/provider-commit-message-generator.ts +7 -5
- package/src/__tests__/document-workspace-file.test.ts +0 -467
- package/src/live-voice/__tests__/front-decision.test.ts +0 -645
- package/src/live-voice/front-decision.ts +0 -476
- package/src/permissions/ipc-risk-types.ts +0 -143
- package/src/permissions/risk-types.ts +0 -76
- package/src/subagent/__tests__/consult-transcript.test.ts +0 -184
- package/src/subagent/consult-transcript.ts +0 -90
|
@@ -10,10 +10,11 @@ import { tmpdir } from "node:os";
|
|
|
10
10
|
import { join } from "node:path";
|
|
11
11
|
import { afterEach, describe, expect, test } from "bun:test";
|
|
12
12
|
|
|
13
|
+
import { THRESHOLD_CHARS } from "../context/post-turn-tool-result-truncation.js";
|
|
13
14
|
import {
|
|
14
|
-
DEFAULT_READ_LINE_LIMIT,
|
|
15
15
|
FileSystemOps,
|
|
16
16
|
type PathPolicy,
|
|
17
|
+
READ_CHAR_BUDGET,
|
|
17
18
|
} from "../tools/shared/filesystem/file-ops-service.js";
|
|
18
19
|
import { sandboxPolicy } from "../tools/shared/filesystem/path-policy.js";
|
|
19
20
|
|
|
@@ -111,34 +112,28 @@ describe("FileSystemOps.readFileSafe", () => {
|
|
|
111
112
|
expect(result.error.code).toBe("PATH_OUT_OF_BOUNDS");
|
|
112
113
|
});
|
|
113
114
|
|
|
114
|
-
test("respects
|
|
115
|
+
test("respects startIndex and maxChars", async () => {
|
|
115
116
|
const dir = makeTempDir();
|
|
116
117
|
writeFileSync(join(dir, "lines.txt"), "a\nb\nc\nd\ne\n");
|
|
117
118
|
const ops = new FileSystemOps(sandboxPolicyFor(dir));
|
|
118
119
|
|
|
119
120
|
const result = await ops.readFileSafe({
|
|
120
121
|
path: "lines.txt",
|
|
121
|
-
|
|
122
|
-
|
|
122
|
+
startIndex: 2,
|
|
123
|
+
maxChars: 3,
|
|
123
124
|
});
|
|
124
125
|
expect(result.ok).toBe(true);
|
|
125
126
|
if (!result.ok) {
|
|
126
127
|
return;
|
|
127
128
|
}
|
|
128
|
-
// Assert on the numbered lines rather than bare letters: the truncation
|
|
129
|
-
// notice is prose, so a bare `toContain("d")` matches its wording.
|
|
130
129
|
const [body] = result.value.content.split("\n\n[Truncated:");
|
|
131
|
-
expect(body).
|
|
132
|
-
expect(body).toContain(" 3 c");
|
|
133
|
-
expect(body).not.toContain(" 1 a");
|
|
134
|
-
expect(body).not.toContain(" 4 d");
|
|
130
|
+
expect(body).toBe("b\nc");
|
|
135
131
|
});
|
|
136
132
|
|
|
137
|
-
test("caps an unbounded read at the
|
|
133
|
+
test("caps an unbounded read at the character budget and says so", async () => {
|
|
138
134
|
const dir = makeTempDir();
|
|
139
|
-
const total =
|
|
140
|
-
|
|
141
|
-
writeFileSync(join(dir, "big.txt"), lines.join("\n"));
|
|
135
|
+
const total = READ_CHAR_BUDGET + 500;
|
|
136
|
+
writeFileSync(join(dir, "big.txt"), "x".repeat(total));
|
|
142
137
|
const ops = new FileSystemOps(sandboxPolicyFor(dir));
|
|
143
138
|
|
|
144
139
|
const result = await ops.readFileSafe({ path: "big.txt" });
|
|
@@ -146,36 +141,74 @@ describe("FileSystemOps.readFileSafe", () => {
|
|
|
146
141
|
if (!result.ok) {
|
|
147
142
|
return;
|
|
148
143
|
}
|
|
149
|
-
const
|
|
150
|
-
expect(
|
|
151
|
-
expect(content).
|
|
152
|
-
|
|
153
|
-
`[Truncated: showing through line ${DEFAULT_READ_LINE_LIMIT} of ${total}. Read on with offset=${DEFAULT_READ_LINE_LIMIT + 1}`,
|
|
144
|
+
const [body] = result.value.content.split("\n\n[Truncated:");
|
|
145
|
+
expect(body).toHaveLength(READ_CHAR_BUDGET);
|
|
146
|
+
expect(result.value.content).toContain(
|
|
147
|
+
`[Truncated: characters 0-${READ_CHAR_BUDGET} of ${total}. Read on with start_index=${READ_CHAR_BUDGET}.]`,
|
|
154
148
|
);
|
|
155
149
|
});
|
|
156
150
|
|
|
157
|
-
test("
|
|
151
|
+
test("a maxChars above the budget is clamped to it", async () => {
|
|
158
152
|
const dir = makeTempDir();
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
(_, i) => `line${i + 1}`,
|
|
162
|
-
);
|
|
163
|
-
writeFileSync(join(dir, "big.txt"), lines.join("\n"));
|
|
153
|
+
const total = READ_CHAR_BUDGET + 500;
|
|
154
|
+
writeFileSync(join(dir, "big.txt"), "x".repeat(total));
|
|
164
155
|
const ops = new FileSystemOps(sandboxPolicyFor(dir));
|
|
165
156
|
|
|
166
157
|
const result = await ops.readFileSafe({
|
|
167
158
|
path: "big.txt",
|
|
168
|
-
|
|
159
|
+
maxChars: total,
|
|
169
160
|
});
|
|
170
161
|
expect(result.ok).toBe(true);
|
|
171
162
|
if (!result.ok) {
|
|
172
163
|
return;
|
|
173
164
|
}
|
|
174
|
-
|
|
175
|
-
expect(
|
|
165
|
+
const [body] = result.value.content.split("\n\n[Truncated:");
|
|
166
|
+
expect(body).toHaveLength(READ_CHAR_BUDGET);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test("a maxChars below the budget is honored as given", async () => {
|
|
170
|
+
const dir = makeTempDir();
|
|
171
|
+
writeFileSync(join(dir, "big.txt"), "x".repeat(500));
|
|
172
|
+
const ops = new FileSystemOps(sandboxPolicyFor(dir));
|
|
173
|
+
|
|
174
|
+
const result = await ops.readFileSafe({ path: "big.txt", maxChars: 10 });
|
|
175
|
+
expect(result.ok).toBe(true);
|
|
176
|
+
if (!result.ok) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const [body] = result.value.content.split("\n\n[Truncated:");
|
|
180
|
+
expect(body).toHaveLength(10);
|
|
181
|
+
expect(result.value.content).toContain(
|
|
182
|
+
"[Truncated: characters 0-10 of 500. Read on with start_index=10.]",
|
|
183
|
+
);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
test("paging with the offset from a notice returns the next window", async () => {
|
|
187
|
+
const dir = makeTempDir();
|
|
188
|
+
writeFileSync(join(dir, "big.txt"), "abcdefghij");
|
|
189
|
+
const ops = new FileSystemOps(sandboxPolicyFor(dir));
|
|
190
|
+
|
|
191
|
+
const first = await ops.readFileSafe({ path: "big.txt", maxChars: 4 });
|
|
192
|
+
expect(first.ok).toBe(true);
|
|
193
|
+
if (!first.ok) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
expect(first.value.content).toContain("start_index=4");
|
|
197
|
+
|
|
198
|
+
const second = await ops.readFileSafe({
|
|
199
|
+
path: "big.txt",
|
|
200
|
+
startIndex: 4,
|
|
201
|
+
maxChars: 4,
|
|
202
|
+
});
|
|
203
|
+
expect(second.ok).toBe(true);
|
|
204
|
+
if (!second.ok) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const [body] = second.value.content.split("\n\n[Truncated:");
|
|
208
|
+
expect(body).toBe("efgh");
|
|
176
209
|
});
|
|
177
210
|
|
|
178
|
-
test("a read that reaches the
|
|
211
|
+
test("a read that reaches the end carries no truncation notice", async () => {
|
|
179
212
|
const dir = makeTempDir();
|
|
180
213
|
writeFileSync(join(dir, "small.txt"), "a\nb\nc");
|
|
181
214
|
const ops = new FileSystemOps(sandboxPolicyFor(dir));
|
|
@@ -193,13 +226,113 @@ describe("FileSystemOps.readFileSafe", () => {
|
|
|
193
226
|
writeFileSync(join(dir, "small.txt"), "a\nb\nc");
|
|
194
227
|
const ops = new FileSystemOps(sandboxPolicyFor(dir));
|
|
195
228
|
|
|
196
|
-
const result = await ops.readFileSafe({
|
|
229
|
+
const result = await ops.readFileSafe({
|
|
230
|
+
path: "small.txt",
|
|
231
|
+
startIndex: 100,
|
|
232
|
+
});
|
|
197
233
|
expect(result.ok).toBe(true);
|
|
198
234
|
if (!result.ok) {
|
|
199
235
|
return;
|
|
200
236
|
}
|
|
201
237
|
expect(result.value.content).not.toContain("[Truncated:");
|
|
202
238
|
});
|
|
239
|
+
|
|
240
|
+
test("a window boundary inside a surrogate pair does not corrupt it", async () => {
|
|
241
|
+
const dir = makeTempDir();
|
|
242
|
+
// "ab" + a 2-unit emoji + "cd": a maxChars of 3 would split the pair.
|
|
243
|
+
writeFileSync(join(dir, "emoji.txt"), `ab\u{1F600}cd`);
|
|
244
|
+
const ops = new FileSystemOps(sandboxPolicyFor(dir));
|
|
245
|
+
|
|
246
|
+
const result = await ops.readFileSafe({ path: "emoji.txt", maxChars: 3 });
|
|
247
|
+
expect(result.ok).toBe(true);
|
|
248
|
+
if (!result.ok) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const [body] = result.value.content.split("\n\n[Truncated:");
|
|
252
|
+
expect(body).toBe("ab");
|
|
253
|
+
expect(body).not.toContain("\uFFFD");
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
test("paging across a surrogate pair reassembles the whole file", async () => {
|
|
257
|
+
const dir = makeTempDir();
|
|
258
|
+
const original = `ab\u{1F600}cd`;
|
|
259
|
+
writeFileSync(join(dir, "emoji.txt"), original);
|
|
260
|
+
const ops = new FileSystemOps(sandboxPolicyFor(dir));
|
|
261
|
+
|
|
262
|
+
let assembled = "";
|
|
263
|
+
let startIndex = 0;
|
|
264
|
+
for (let i = 0; i < 10; i++) {
|
|
265
|
+
const result = await ops.readFileSafe({
|
|
266
|
+
path: "emoji.txt",
|
|
267
|
+
startIndex,
|
|
268
|
+
maxChars: 3,
|
|
269
|
+
});
|
|
270
|
+
expect(result.ok).toBe(true);
|
|
271
|
+
if (!result.ok) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
const [body] = result.value.content.split("\n\n[Truncated:");
|
|
275
|
+
assembled += body;
|
|
276
|
+
const match = /start_index=(\d+)/.exec(result.value.content);
|
|
277
|
+
if (match?.[1] === undefined) {
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
startIndex = Number(match[1]);
|
|
281
|
+
}
|
|
282
|
+
expect(assembled).toBe(original);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
test("a lone-low-surrogate startIndex backs up onto the whole pair", async () => {
|
|
286
|
+
const dir = makeTempDir();
|
|
287
|
+
writeFileSync(join(dir, "emoji.txt"), `ab\u{1F600}cd`);
|
|
288
|
+
const ops = new FileSystemOps(sandboxPolicyFor(dir));
|
|
289
|
+
|
|
290
|
+
// Index 3 (0-indexed) is the low half of the emoji.
|
|
291
|
+
const result = await ops.readFileSafe({
|
|
292
|
+
path: "emoji.txt",
|
|
293
|
+
startIndex: 3,
|
|
294
|
+
maxChars: 2,
|
|
295
|
+
});
|
|
296
|
+
expect(result.ok).toBe(true);
|
|
297
|
+
if (!result.ok) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
const [body] = result.value.content.split("\n\n[Truncated:");
|
|
301
|
+
expect(body).toBe(`\u{1F600}`);
|
|
302
|
+
expect(body).not.toContain("\uFFFD");
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
test("legacy offset/limit are rejected rather than silently ignored", async () => {
|
|
306
|
+
const { fileReadTool } = await import("../tools/filesystem/read.js");
|
|
307
|
+
const dir = makeTempDir();
|
|
308
|
+
writeFileSync(join(dir, "big.txt"), "x".repeat(500));
|
|
309
|
+
|
|
310
|
+
const result = await fileReadTool.execute(
|
|
311
|
+
{ path: join(dir, "big.txt"), offset: 2001, limit: 2000 },
|
|
312
|
+
{ workingDir: dir } as never,
|
|
313
|
+
);
|
|
314
|
+
expect(result.isError).toBe(true);
|
|
315
|
+
expect(result.content).toContain("no longer takes");
|
|
316
|
+
expect(result.content).toContain("start_index");
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
test("legacy fields alongside current ones do not trigger the guard", async () => {
|
|
320
|
+
const { fileReadTool } = await import("../tools/filesystem/read.js");
|
|
321
|
+
const dir = makeTempDir();
|
|
322
|
+
writeFileSync(join(dir, "big.txt"), "abcdefghij");
|
|
323
|
+
|
|
324
|
+
const result = await fileReadTool.execute(
|
|
325
|
+
{ path: join(dir, "big.txt"), offset: 1, max_chars: 4 },
|
|
326
|
+
{ workingDir: dir } as never,
|
|
327
|
+
);
|
|
328
|
+
expect(result.isError).toBe(false);
|
|
329
|
+
const [body] = result.content.split("\n\n[Truncated:");
|
|
330
|
+
expect(body).toBe("abcd");
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
test("the read budget stays under the tool-result spool threshold", () => {
|
|
334
|
+
expect(READ_CHAR_BUDGET).toBeLessThan(THRESHOLD_CHARS);
|
|
335
|
+
});
|
|
203
336
|
});
|
|
204
337
|
|
|
205
338
|
// ---------------------------------------------------------------------------
|
|
@@ -125,16 +125,19 @@ describe("FileSystemOps symlink handling", () => {
|
|
|
125
125
|
});
|
|
126
126
|
|
|
127
127
|
// ===========================================================================
|
|
128
|
-
// FileSystemOps: read
|
|
128
|
+
// FileSystemOps: read character-window edge cases
|
|
129
129
|
// ===========================================================================
|
|
130
130
|
|
|
131
|
-
describe("FileSystemOps read
|
|
132
|
-
test("
|
|
131
|
+
describe("FileSystemOps read character-window edge cases", () => {
|
|
132
|
+
test("startIndex beyond file length returns empty content", async () => {
|
|
133
133
|
const dir = makeTempDir();
|
|
134
134
|
writeFileSync(join(dir, "short.txt"), "a\nb\nc");
|
|
135
135
|
const ops = new FileSystemOps(sandboxPolicyFor(dir));
|
|
136
136
|
|
|
137
|
-
const result = await ops.readFileSafe({
|
|
137
|
+
const result = await ops.readFileSafe({
|
|
138
|
+
path: "short.txt",
|
|
139
|
+
startIndex: 100,
|
|
140
|
+
});
|
|
138
141
|
expect(result.ok).toBe(true);
|
|
139
142
|
if (!result.ok) {
|
|
140
143
|
return;
|
|
@@ -142,12 +145,12 @@ describe("FileSystemOps read offset/limit edge cases", () => {
|
|
|
142
145
|
expect(result.value.content).toBe("");
|
|
143
146
|
});
|
|
144
147
|
|
|
145
|
-
test("
|
|
148
|
+
test("maxChars of zero returns empty content", async () => {
|
|
146
149
|
const dir = makeTempDir();
|
|
147
150
|
writeFileSync(join(dir, "file.txt"), "a\nb\nc");
|
|
148
151
|
const ops = new FileSystemOps(sandboxPolicyFor(dir));
|
|
149
152
|
|
|
150
|
-
const result = await ops.readFileSafe({ path: "file.txt",
|
|
153
|
+
const result = await ops.readFileSafe({ path: "file.txt", maxChars: 0 });
|
|
151
154
|
expect(result.ok).toBe(true);
|
|
152
155
|
if (!result.ok) {
|
|
153
156
|
return;
|
|
@@ -155,61 +158,57 @@ describe("FileSystemOps read offset/limit edge cases", () => {
|
|
|
155
158
|
expect(result.value.content).toBe("");
|
|
156
159
|
});
|
|
157
160
|
|
|
158
|
-
test("
|
|
161
|
+
test("startIndex=0 reads from the first character (0-indexed)", async () => {
|
|
159
162
|
const dir = makeTempDir();
|
|
160
163
|
writeFileSync(join(dir, "file.txt"), "first\nsecond\nthird");
|
|
161
164
|
const ops = new FileSystemOps(sandboxPolicyFor(dir));
|
|
162
165
|
|
|
163
166
|
const result = await ops.readFileSafe({
|
|
164
167
|
path: "file.txt",
|
|
165
|
-
|
|
166
|
-
|
|
168
|
+
startIndex: 0,
|
|
169
|
+
maxChars: 5,
|
|
167
170
|
});
|
|
168
171
|
expect(result.ok).toBe(true);
|
|
169
172
|
if (!result.ok) {
|
|
170
173
|
return;
|
|
171
174
|
}
|
|
172
|
-
|
|
173
|
-
expect(
|
|
175
|
+
const [body] = result.value.content.split("\n\n[Truncated:");
|
|
176
|
+
expect(body).toBe("first");
|
|
174
177
|
});
|
|
175
178
|
|
|
176
|
-
test("
|
|
179
|
+
test("maxChars exceeding file length returns the rest of the file", async () => {
|
|
177
180
|
const dir = makeTempDir();
|
|
178
181
|
writeFileSync(join(dir, "file.txt"), "a\nb");
|
|
179
182
|
const ops = new FileSystemOps(sandboxPolicyFor(dir));
|
|
180
183
|
|
|
181
184
|
const result = await ops.readFileSafe({
|
|
182
185
|
path: "file.txt",
|
|
183
|
-
|
|
184
|
-
|
|
186
|
+
startIndex: 0,
|
|
187
|
+
maxChars: 1000,
|
|
185
188
|
});
|
|
186
189
|
expect(result.ok).toBe(true);
|
|
187
190
|
if (!result.ok) {
|
|
188
191
|
return;
|
|
189
192
|
}
|
|
190
|
-
expect(result.value.content).
|
|
191
|
-
expect(result.value.content).toContain("b");
|
|
193
|
+
expect(result.value.content).toBe("a\nb");
|
|
192
194
|
});
|
|
193
195
|
|
|
194
|
-
test("
|
|
196
|
+
test("the window starts at startIndex and carries no line numbers", async () => {
|
|
195
197
|
const dir = makeTempDir();
|
|
196
198
|
writeFileSync(join(dir, "file.txt"), "a\nb\nc\nd\ne");
|
|
197
199
|
const ops = new FileSystemOps(sandboxPolicyFor(dir));
|
|
198
200
|
|
|
199
201
|
const result = await ops.readFileSafe({
|
|
200
202
|
path: "file.txt",
|
|
201
|
-
|
|
202
|
-
|
|
203
|
+
startIndex: 4,
|
|
204
|
+
maxChars: 3,
|
|
203
205
|
});
|
|
204
206
|
expect(result.ok).toBe(true);
|
|
205
207
|
if (!result.ok) {
|
|
206
208
|
return;
|
|
207
209
|
}
|
|
208
|
-
|
|
209
|
-
expect(
|
|
210
|
-
expect(result.value.content).toContain("4");
|
|
211
|
-
expect(result.value.content).toContain("c");
|
|
212
|
-
expect(result.value.content).toContain("d");
|
|
210
|
+
const [body] = result.value.content.split("\n\n[Truncated:");
|
|
211
|
+
expect(body).toBe("c\nd");
|
|
213
212
|
});
|
|
214
213
|
});
|
|
215
214
|
|
|
@@ -83,11 +83,8 @@ function isGatewayInternal(filePath: string): boolean {
|
|
|
83
83
|
/** Additional files allowed for the interpolated-port check only (use gateway port, not runtime). */
|
|
84
84
|
const INTERPOLATED_PORT_ALLOWLIST = new Set([
|
|
85
85
|
"clients/macos/src/main/bundle-flow.ts",
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
// class as bundle-flow.ts. Added with #34049 (host proxy for cloud/managed
|
|
89
|
-
// assistants); the allowlist entry was missed there.
|
|
90
|
-
"clients/macos/src/main/host-proxy-router.ts",
|
|
86
|
+
// Desktop clients connect to local assistants through their loopback gateway.
|
|
87
|
+
"packages/electron-desktop/src/host-proxy/router.ts",
|
|
91
88
|
]);
|
|
92
89
|
|
|
93
90
|
/** Shared violation filter: exempt test files, gateway internals, and allowlisted paths. */
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* installIpcMock();
|
|
18
18
|
*
|
|
19
19
|
* mockIpcResponse("classify_risk",
|
|
20
|
-
* { risk: "low", reason: "ls", matchType: "
|
|
20
|
+
* { risk: "low", reason: "ls", matchType: "registry", scopeOptions: [] });
|
|
21
21
|
*
|
|
22
22
|
* const result = await classifyRisk("bash", { command: "ls" });
|
|
23
23
|
*/
|
|
@@ -36,12 +36,26 @@ export function mockIpcResponse(method: string, response: unknown): void {
|
|
|
36
36
|
responses.set(method, response);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
/** Clear all registered responses. */
|
|
39
|
+
/** Clear all registered responses and captured params. */
|
|
40
40
|
export function clearIpcMocks(): void {
|
|
41
41
|
responses.clear();
|
|
42
|
+
lastParams.clear();
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
const lastParams = new Map<string, Record<string, unknown> | undefined>();
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The params of the most recent call to `method`, for asserting what the
|
|
49
|
+
* daemon sent rather than what it did with the answer.
|
|
50
|
+
*/
|
|
51
|
+
export function lastIpcParams(
|
|
52
|
+
method: string,
|
|
53
|
+
): Record<string, unknown> | undefined {
|
|
54
|
+
return lastParams.get(method);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function handleCall(method: string, params?: Record<string, unknown>): unknown {
|
|
58
|
+
lastParams.set(method, params);
|
|
45
59
|
const response = responses.get(method);
|
|
46
60
|
if (response !== undefined) {
|
|
47
61
|
return response;
|
|
@@ -57,11 +71,18 @@ function handleCall(method: string): unknown {
|
|
|
57
71
|
*/
|
|
58
72
|
export function installIpcMock(): void {
|
|
59
73
|
mock.module("@vellumai/gateway-client/ipc-client", () => ({
|
|
60
|
-
ipcCall: async (
|
|
74
|
+
ipcCall: async (
|
|
75
|
+
_socketPath: string,
|
|
76
|
+
method: string,
|
|
77
|
+
params?: Record<string, unknown>,
|
|
78
|
+
) => handleCall(method, params),
|
|
61
79
|
|
|
62
80
|
PersistentIpcClient: class MockPersistentIpcClient {
|
|
63
|
-
async call(
|
|
64
|
-
|
|
81
|
+
async call(
|
|
82
|
+
method: string,
|
|
83
|
+
params?: Record<string, unknown>,
|
|
84
|
+
): Promise<unknown> {
|
|
85
|
+
return handleCall(method, params);
|
|
65
86
|
}
|
|
66
87
|
destroy(): void {}
|
|
67
88
|
},
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed fixture factories for actor identity in tests.
|
|
3
|
+
*
|
|
4
|
+
* A fixture built here is a complete, type-checked `TrustContext` or
|
|
5
|
+
* `AuthContext` with conservative defaults; a test overrides only the fields
|
|
6
|
+
* its scenario is about, and the compiler guards the rest. Hand-rolled
|
|
7
|
+
* literals cannot make that guarantee: a missing required field needs a cast
|
|
8
|
+
* to satisfy the checker, and the cast then hides every other mistake in the
|
|
9
|
+
* literal.
|
|
10
|
+
*
|
|
11
|
+
* Type-only imports keep this helper out of the runtime import graph, per the
|
|
12
|
+
* test-machinery isolation rules in `assistant/CLAUDE.md`.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import type { TrustContext } from "../../daemon/trust-context-types.js";
|
|
16
|
+
import type { AuthContext, Scope } from "../../runtime/auth/types.js";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A complete `TrustContext`. Defaults to the guardian on the vellum channel;
|
|
20
|
+
* pass overrides for anything the test cares about.
|
|
21
|
+
*/
|
|
22
|
+
export function mockTrustContext(
|
|
23
|
+
overrides: Partial<TrustContext> = {},
|
|
24
|
+
): TrustContext {
|
|
25
|
+
return {
|
|
26
|
+
sourceChannel: "vellum",
|
|
27
|
+
trustClass: "guardian",
|
|
28
|
+
...overrides,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* A complete `AuthContext`. Defaults to a local principal with no scopes, the
|
|
34
|
+
* conservative shape, so a test that forgets to opt in exercises the
|
|
35
|
+
* restrictive branch rather than a silently permissive one.
|
|
36
|
+
*/
|
|
37
|
+
export function mockAuthContext(
|
|
38
|
+
overrides: Partial<AuthContext> = {},
|
|
39
|
+
): AuthContext {
|
|
40
|
+
return {
|
|
41
|
+
subject: "local:self:test",
|
|
42
|
+
principalType: "local",
|
|
43
|
+
assistantId: "self",
|
|
44
|
+
scopeProfile: "local_v1",
|
|
45
|
+
scopes: new Set<Scope>(),
|
|
46
|
+
policyEpoch: 0,
|
|
47
|
+
...overrides,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
@@ -26,7 +26,19 @@ import type { ChannelCapabilities } from "../../daemon/conversation-runtime-asse
|
|
|
26
26
|
export function asConversation<TExtra extends object = object>(
|
|
27
27
|
mock: Partial<Conversation> & TExtra,
|
|
28
28
|
): Conversation & TExtra {
|
|
29
|
-
|
|
29
|
+
// Trust accessors, derived from the double's own fields exactly as the real
|
|
30
|
+
// class derives them, so a double that sets (or later mutates) the fields
|
|
31
|
+
// resolves the same values production would. Supplied only when the double
|
|
32
|
+
// does not bring its own, and reading through `merged` rather than `mock`
|
|
33
|
+
// so a test that reassigns the fields on the returned object is honoured.
|
|
34
|
+
const merged: Partial<Conversation> & TExtra = {
|
|
35
|
+
getTurnTrust: () => merged.currentTurnTrustContext,
|
|
36
|
+
getTrustContext: () => merged.trustContext,
|
|
37
|
+
getTurnOrRestingTrust: () =>
|
|
38
|
+
merged.currentTurnTrustContext ?? merged.trustContext,
|
|
39
|
+
...mock,
|
|
40
|
+
};
|
|
41
|
+
return merged as unknown as Conversation & TExtra;
|
|
30
42
|
}
|
|
31
43
|
|
|
32
44
|
/**
|
|
@@ -27,7 +27,7 @@ mock.module("../daemon/host-file-proxy.js", () => ({
|
|
|
27
27
|
}));
|
|
28
28
|
|
|
29
29
|
import { hostFileReadTool } from "../tools/host-filesystem/read.js";
|
|
30
|
-
import {
|
|
30
|
+
import { READ_CHAR_BUDGET } from "../tools/shared/filesystem/file-ops-service.js";
|
|
31
31
|
import type { ToolContext } from "../tools/types.js";
|
|
32
32
|
|
|
33
33
|
const testDirs: string[] = [];
|
|
@@ -77,19 +77,19 @@ describe("host_file_read tool", () => {
|
|
|
77
77
|
expect(result.content).toContain("must be absolute");
|
|
78
78
|
});
|
|
79
79
|
|
|
80
|
-
test("reads
|
|
80
|
+
test("reads a character window", async () => {
|
|
81
81
|
const dir = mkdtempSync(join(tmpdir(), "host-file-read-test-"));
|
|
82
82
|
testDirs.push(dir);
|
|
83
83
|
const filePath = join(dir, "sample.txt");
|
|
84
84
|
writeFileSync(filePath, "first\nsecond\nthird\n");
|
|
85
85
|
|
|
86
86
|
const result = await hostFileReadTool.execute(
|
|
87
|
-
{ path: filePath,
|
|
87
|
+
{ path: filePath, start_index: 6, max_chars: 6 },
|
|
88
88
|
makeContext(),
|
|
89
89
|
);
|
|
90
90
|
expect(result.isError).toBe(false);
|
|
91
|
-
expect(result.content).toContain("
|
|
92
|
-
expect(result.content).toContain("
|
|
91
|
+
expect(result.content).toContain("second");
|
|
92
|
+
expect(result.content).not.toContain("first");
|
|
93
93
|
});
|
|
94
94
|
|
|
95
95
|
test("returns error when file does not exist", async () => {
|
|
@@ -128,7 +128,7 @@ describe("host_file_read tool", () => {
|
|
|
128
128
|
expect(result.content).toContain('Invalid input for tool "host_file_read"');
|
|
129
129
|
});
|
|
130
130
|
|
|
131
|
-
test("reads
|
|
131
|
+
test("reads the whole file when no window is specified", async () => {
|
|
132
132
|
const dir = mkdtempSync(join(tmpdir(), "host-file-read-test-"));
|
|
133
133
|
testDirs.push(dir);
|
|
134
134
|
const filePath = join(dir, "full.txt");
|
|
@@ -139,9 +139,7 @@ describe("host_file_read tool", () => {
|
|
|
139
139
|
makeContext(),
|
|
140
140
|
);
|
|
141
141
|
expect(result.isError).toBe(false);
|
|
142
|
-
expect(result.content).
|
|
143
|
-
expect(result.content).toContain("2 line2");
|
|
144
|
-
expect(result.content).toContain("3 line3");
|
|
142
|
+
expect(result.content).toBe("line1\nline2\nline3\n");
|
|
145
143
|
});
|
|
146
144
|
|
|
147
145
|
test("handles empty file", async () => {
|
|
@@ -157,20 +155,19 @@ describe("host_file_read tool", () => {
|
|
|
157
155
|
expect(result.isError).toBe(false);
|
|
158
156
|
});
|
|
159
157
|
|
|
160
|
-
test("
|
|
158
|
+
test("start_index is 0-indexed", async () => {
|
|
161
159
|
const dir = mkdtempSync(join(tmpdir(), "host-file-read-test-"));
|
|
162
160
|
testDirs.push(dir);
|
|
163
161
|
const filePath = join(dir, "lines.txt");
|
|
164
162
|
writeFileSync(filePath, "a\nb\nc\nd\ne\n");
|
|
165
163
|
|
|
166
164
|
const result = await hostFileReadTool.execute(
|
|
167
|
-
{ path: filePath,
|
|
165
|
+
{ path: filePath, start_index: 4, max_chars: 1 },
|
|
168
166
|
makeContext(),
|
|
169
167
|
);
|
|
170
168
|
expect(result.isError).toBe(false);
|
|
171
|
-
|
|
172
|
-
expect(
|
|
173
|
-
expect(result.content).not.toContain("4 d");
|
|
169
|
+
const [body] = result.content.split("\n\n[Truncated:");
|
|
170
|
+
expect(body).toBe("c");
|
|
174
171
|
});
|
|
175
172
|
|
|
176
173
|
test("reads a file with symlinks resolved", async () => {
|
|
@@ -228,15 +225,15 @@ describe("host_file_read image support", () => {
|
|
|
228
225
|
expect(result.isError).toBe(false);
|
|
229
226
|
expect(result.contentBlocks).toHaveLength(1);
|
|
230
227
|
// The proxied request carries the resolved default window, so a host read
|
|
231
|
-
// is bounded by the same
|
|
228
|
+
// is bounded by the same budget as a local one rather than streaming a
|
|
232
229
|
// whole file across the bridge.
|
|
233
230
|
expect(requests).toEqual([
|
|
234
231
|
{
|
|
235
232
|
input: {
|
|
236
233
|
operation: "read",
|
|
237
234
|
path: "/host/screenshot.png",
|
|
238
|
-
|
|
239
|
-
|
|
235
|
+
startIndex: undefined,
|
|
236
|
+
maxChars: READ_CHAR_BUDGET,
|
|
240
237
|
},
|
|
241
238
|
conversationId: "test-conversation",
|
|
242
239
|
signal: undefined,
|
|
@@ -306,8 +303,8 @@ describe("host_file_read image support", () => {
|
|
|
306
303
|
);
|
|
307
304
|
|
|
308
305
|
expect(result.isError).toBe(false);
|
|
309
|
-
expect(result.content).toContain("
|
|
310
|
-
expect(result.content).toContain("
|
|
306
|
+
expect(result.content).toContain("hello world");
|
|
307
|
+
expect(result.content).toContain("second line");
|
|
311
308
|
expect((result as any).contentBlocks).toBeUndefined();
|
|
312
309
|
});
|
|
313
310
|
|
|
@@ -189,7 +189,7 @@ const _testAuthContext: AuthContext = {
|
|
|
189
189
|
function makeConversation(overrides: Record<string, unknown> = {}) {
|
|
190
190
|
return {
|
|
191
191
|
setTrustContext: () => {},
|
|
192
|
-
|
|
192
|
+
replayActivityState: () => {},
|
|
193
193
|
setHostBrowserProxy: () => {},
|
|
194
194
|
setHostCuProxy: () => {},
|
|
195
195
|
setHostAppControlProxy: () => {},
|