@vellumai/assistant 0.8.8 → 0.8.9-staging.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bun.lock +2 -2
- package/examples/plugins/echo/README.md +61 -60
- package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
- package/examples/plugins/echo/hooks/stop.ts +16 -0
- package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
- package/examples/plugins/echo/package.json +1 -2
- package/examples/plugins/echo/src/emit.ts +19 -0
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
- package/openapi.yaml +236 -6
- package/package.json +2 -2
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +69 -14
- package/src/__tests__/agent-loop-exit-reason.test.ts +185 -140
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +50 -35
- package/src/__tests__/agent-loop-output-hooks.test.ts +357 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +25 -6
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +41 -21
- package/src/__tests__/agent-loop-thinking.test.ts +36 -20
- package/src/__tests__/agent-loop.test.ts +441 -96
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +14 -14
- package/src/__tests__/agent-wake-override-profile.test.ts +17 -21
- package/src/__tests__/anthropic-provider.test.ts +1 -1
- package/src/__tests__/app-control-flow.test.ts +1 -1
- package/src/__tests__/app-dir-path-guard.test.ts +1 -0
- package/src/__tests__/approval-cascade.test.ts +5 -4
- package/src/__tests__/approval-routes-http.test.ts +4 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +1 -1
- package/src/__tests__/channel-approvals.test.ts +1 -1
- package/src/__tests__/compaction-circuit.test.ts +258 -0
- package/src/__tests__/compaction-direct.test.ts +132 -0
- package/src/__tests__/compaction-events.test.ts +5 -5
- package/src/__tests__/conversation-abort-tool-results.test.ts +6 -4
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +7 -10
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +59 -103
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +94 -189
- package/src/__tests__/conversation-agent-loop.test.ts +249 -490
- package/src/__tests__/conversation-clean-command.test.ts +5 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +5 -4
- package/src/__tests__/conversation-crud-inference-profile.test.ts +7 -9
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +4 -4
- package/src/__tests__/conversation-process-callsite.test.ts +14 -14
- package/src/__tests__/conversation-provider-retry-repair.test.ts +18 -16
- package/src/__tests__/conversation-queue.test.ts +9 -9
- package/src/__tests__/conversation-runtime-assembly.test.ts +923 -231
- package/src/__tests__/conversation-runtime-workspace.test.ts +115 -20
- package/src/__tests__/conversation-slash-queue.test.ts +6 -4
- package/src/__tests__/conversation-slash-unknown.test.ts +6 -4
- package/src/__tests__/conversation-speed-override.test.ts +10 -9
- package/src/__tests__/conversation-starter-routes.test.ts +14 -6
- package/src/__tests__/conversation-workspace-cache-state.test.ts +23 -20
- package/src/__tests__/conversation-workspace-injection.test.ts +68 -6
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +14 -11
- package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
- package/src/__tests__/credential-security-invariants.test.ts +0 -1
- package/src/__tests__/db-acp-history.test.ts +101 -0
- package/src/__tests__/dynamic-page-surface.test.ts +31 -0
- package/src/__tests__/empty-response-hook.test.ts +1 -1
- package/src/__tests__/file-write-tool.test.ts +63 -0
- package/src/__tests__/gateway-only-guard.test.ts +12 -2
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +2 -4
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -0
- package/src/__tests__/history-repair-hook.test.ts +1 -1
- package/src/__tests__/host-app-control-routes.test.ts +1 -1
- package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
- package/src/__tests__/inference-profile-reaper.test.ts +62 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +86 -0
- package/src/__tests__/injector-background-turn.test.ts +13 -23
- package/src/__tests__/injector-chain.test.ts +268 -44
- package/src/__tests__/injector-disk-pressure.test.ts +210 -52
- package/src/__tests__/injector-document-comments.test.ts +97 -114
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
- package/src/__tests__/injector-v3-suppression.test.ts +4 -4
- package/src/__tests__/list-messages-client-message-id.test.ts +91 -0
- package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
- package/src/__tests__/memory-retrieval-hook.test.ts +73 -6
- package/src/__tests__/memory-v2-static-injector.test.ts +86 -8
- package/src/__tests__/parallel-tool.benchmark.test.ts +35 -8
- package/src/__tests__/plugin-api-shim.test.ts +6 -9
- package/src/__tests__/plugin-bootstrap.test.ts +12 -23
- package/src/__tests__/plugin-registry.test.ts +3 -49
- package/src/__tests__/plugin-types.test.ts +0 -70
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +4 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +33 -0
- package/src/__tests__/steer-tool-repair.test.ts +1 -1
- package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
- package/src/__tests__/subagent-detail.test.ts +25 -7
- package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
- package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
- package/src/__tests__/subagent-manager-notify.test.ts +1 -3
- package/src/__tests__/subagent-notify-parent.test.ts +1 -3
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
- package/src/__tests__/title-generate-hook.test.ts +1 -1
- package/src/__tests__/tool-error-hook.test.ts +1 -1
- package/src/__tests__/tool-result-truncate-hook.test.ts +1 -1
- package/src/__tests__/user-plugin-loader.test.ts +54 -286
- package/src/acp/__tests__/agent-process.test.ts +161 -0
- package/src/acp/__tests__/client-handler.test.ts +40 -0
- package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
- package/src/acp/__tests__/helpers/exec-file-stub.ts +101 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +137 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
- package/src/acp/__tests__/session-manager-resume.test.ts +736 -0
- package/src/acp/agent-process.ts +61 -1
- package/src/acp/auto-install.test.ts +196 -0
- package/src/acp/auto-install.ts +177 -0
- package/src/acp/client-handler.ts +31 -0
- package/src/acp/feature-gate.test.ts +48 -0
- package/src/acp/feature-gate.ts +34 -0
- package/src/acp/prepare-agent-env.ts +83 -29
- package/src/acp/resolve-agent.test.ts +320 -7
- package/src/acp/resolve-agent.ts +182 -18
- package/src/acp/resume-hint.ts +25 -0
- package/src/acp/session-manager.ts +495 -73
- package/src/acp/types.ts +8 -0
- package/src/agent/compaction-circuit.ts +60 -102
- package/src/agent/loop.ts +390 -240
- package/src/api/responses/conversation-message.ts +14 -1
- package/src/approvals/guardian-request-resolvers.ts +1 -1
- package/src/background-wake/next-wake.ts +1 -0
- package/src/cli/commands/db/__tests__/repair.test.ts +3 -1
- package/src/cli/commands/plugins.ts +43 -37
- package/src/cli/lib/__tests__/install-from-github.test.ts +429 -111
- package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +196 -0
- package/src/cli/lib/__tests__/plugin-details.test.ts +372 -0
- package/src/cli/lib/__tests__/plugin-marketplace.test.ts +220 -0
- package/src/cli/lib/__tests__/search-plugins.test.ts +226 -32
- package/src/cli/lib/install-from-github.ts +464 -55
- package/src/cli/lib/plugin-catalog-cache.ts +84 -0
- package/src/cli/lib/plugin-details.ts +409 -0
- package/src/cli/lib/plugin-marketplace.ts +197 -0
- package/src/cli/lib/search-plugins.ts +195 -29
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/acp-defaults.test.ts +10 -0
- package/src/config/acp-defaults.ts +6 -0
- package/src/config/bundled-skills/acp/SKILL.md +83 -31
- package/src/config/bundled-skills/acp/TOOLS.json +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +224 -381
- package/src/config/bundled-skills/app-builder/TOOLS.json +29 -0
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
- package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
- package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
- package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/feature-flag-registry.json +14 -5
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/context/strip-injections.ts +8 -2
- package/src/context/window-manager.ts +27 -13
- package/src/daemon/conversation-agent-loop-handlers.ts +10 -35
- package/src/daemon/conversation-agent-loop.ts +167 -1005
- package/src/daemon/conversation-lifecycle.ts +11 -255
- package/src/daemon/conversation-process.ts +8 -136
- package/src/daemon/conversation-registry.ts +159 -0
- package/src/daemon/conversation-runtime-assembly.ts +293 -392
- package/src/daemon/conversation-store.ts +9 -90
- package/src/daemon/conversation-surfaces.ts +24 -8
- package/src/daemon/conversation-workspace.ts +17 -0
- package/src/daemon/conversation.ts +383 -56
- package/src/daemon/external-plugins-bootstrap.ts +14 -19
- package/src/daemon/handlers/conversations.ts +3 -1
- package/src/daemon/handlers/skills.ts +4 -1
- package/src/daemon/host-proxy-preactivation.ts +1 -3
- package/src/daemon/lifecycle.ts +21 -0
- package/src/daemon/server.ts +2 -0
- package/src/daemon/wake-conversation-ops.ts +269 -0
- package/src/embedded/plugin-api.ts +2 -2
- package/src/export/__tests__/transcript-formatter.test.ts +5 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
- package/src/heartbeat/heartbeat-run-store.ts +23 -1
- package/src/heartbeat/heartbeat-service.ts +26 -0
- package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
- package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
- package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
- package/src/ipc/skill-routes/memory.ts +4 -2
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +87 -0
- package/src/memory/conversation-crud.ts +29 -19
- package/src/memory/conversation-starter-checkpoints.ts +1 -0
- package/src/memory/db-init.ts +2 -0
- package/src/memory/job-handlers/conversation-starters.ts +13 -2
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -4
- package/src/memory/jobs-worker.ts +25 -1
- package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
- package/src/memory/migrations/index.ts +1 -0
- package/src/memory/schema/acp.ts +4 -0
- package/src/memory/v2/__tests__/consolidation-job.test.ts +3 -3
- package/src/memory/v2/consolidation-job.ts +13 -4
- package/src/plugin-api/constants.ts +4 -0
- package/src/plugin-api/index.ts +6 -5
- package/src/plugin-api/types.ts +75 -0
- package/src/plugins/defaults/compaction/compact.ts +59 -0
- package/src/plugins/defaults/compaction/manager-store.ts +44 -0
- package/src/plugins/defaults/compaction/package.json +1 -2
- package/src/plugins/defaults/empty-response/package.json +0 -1
- package/src/plugins/defaults/history-repair/package.json +0 -1
- package/src/plugins/defaults/index.ts +135 -26
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +103 -38
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +167 -56
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
- package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +148 -73
- package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +223 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/assign.test.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +9 -6
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/maintain-job.test.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/orchestrate.test.ts +8 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/reconcile.test.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/render-injection.test.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/router.test.ts +10 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +8 -8
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selector.test.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/shadow-plugin.test.ts +16 -17
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/assign.ts +9 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/capabilities.ts +5 -2
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +75 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/maintain-job.ts +15 -8
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/orchestrate.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/package.json +14 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/page-content.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/provider-blocks.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/reconcile.ts +7 -3
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/router.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selection-log-store.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selector.ts +7 -7
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/shadow-plugin.ts +32 -94
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/tree.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/types.ts +1 -1
- package/src/plugins/defaults/title-generate/package.json +0 -1
- package/src/plugins/defaults/tool-error/package.json +0 -1
- package/src/plugins/defaults/tool-result-truncate/package.json +0 -1
- package/src/plugins/pipeline.ts +6 -293
- package/src/plugins/registry.ts +9 -37
- package/src/plugins/types.ts +76 -381
- package/src/plugins/user-loader.ts +30 -127
- package/src/proactive-artifact/aux-message-injector.ts +1 -1
- package/src/proactive-artifact/job.test.ts +1 -1
- package/src/prompts/__tests__/system-prompt.test.ts +6 -0
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +35 -3
- package/src/runtime/__tests__/agent-wake.test.ts +555 -691
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/agent-wake.ts +108 -209
- package/src/runtime/assistant-event-hub.ts +1 -1
- package/src/runtime/channel-approvals.ts +1 -1
- package/src/runtime/interactive-ui.ts +1 -1
- package/src/runtime/routes/__tests__/acp-routes.test.ts +283 -55
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +398 -73
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
- package/src/runtime/routes/acp-routes.test.ts +89 -25
- package/src/runtime/routes/acp-routes.ts +81 -29
- package/src/runtime/routes/approval-routes.ts +1 -1
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/browser-tabs-routes.ts +6 -10
- package/src/runtime/routes/conversation-cli-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +1 -1
- package/src/runtime/routes/conversation-query-routes.ts +1 -1
- package/src/runtime/routes/conversation-routes.ts +28 -2
- package/src/runtime/routes/conversation-starter-routes.ts +13 -7
- package/src/runtime/routes/conversations-import-routes.ts +24 -7
- package/src/runtime/routes/host-app-control-routes.ts +1 -1
- package/src/runtime/routes/host-cu-routes.ts +1 -1
- package/src/runtime/routes/identity-routes.ts +18 -3
- package/src/runtime/routes/inbound-message-handler.ts +1 -1
- package/src/runtime/routes/inference-profile-session-handler.ts +11 -0
- package/src/runtime/routes/inference-profile-session-reaper.ts +6 -0
- package/src/runtime/routes/memory-v3-routes.ts +16 -6
- package/src/runtime/routes/playground/helpers.ts +1 -1
- package/src/runtime/routes/plugins-routes.ts +336 -35
- package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
- package/src/runtime/routes/work-items-routes.ts +2 -4
- package/src/runtime/services/conversation-serializer.ts +1 -1
- package/src/signals/cancel.ts +2 -4
- package/src/subagent/manager.ts +21 -5
- package/src/tools/acp/context.ts +20 -0
- package/src/tools/acp/list-agents.test.ts +7 -1
- package/src/tools/acp/spawn.test.ts +158 -55
- package/src/tools/acp/spawn.ts +47 -72
- package/src/tools/acp/steer.test.ts +105 -8
- package/src/tools/acp/steer.ts +48 -17
- package/src/tools/apps/executors.ts +13 -8
- package/src/tools/filesystem/write.ts +34 -0
- package/src/tools/subagent/spawn.ts +2 -4
- package/src/tools/ui-surface/definitions.ts +25 -5
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +69 -45
- package/docs/plugins.md +0 -832
- package/examples/plugins/echo/register.ts +0 -143
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
- package/src/__tests__/compaction-pipeline.test.ts +0 -210
- package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
- package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -667
- package/src/__tests__/pipeline-runner.test.ts +0 -554
- package/src/__tests__/plugin-external-api.test.ts +0 -68
- package/src/daemon/wake-target-adapter.ts +0 -253
- package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
- package/src/plugins/defaults/circuit-breaker/package.json +0 -15
- package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
- package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
- package/src/plugins/defaults/compaction/register.ts +0 -35
- package/src/plugins/defaults/compaction/terminal.ts +0 -73
- package/src/plugins/defaults/empty-response/register.ts +0 -23
- package/src/plugins/defaults/history-repair/register.ts +0 -24
- package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
- package/src/plugins/defaults/overflow-reduce/package.json +0 -15
- package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
- package/src/plugins/defaults/title-generate/register.ts +0 -35
- package/src/plugins/defaults/tool-error/register.ts +0 -23
- package/src/plugins/defaults/tool-result-truncate/register.ts +0 -24
- package/src/plugins/external-api.ts +0 -104
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/capabilities.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/core.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/health.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/needle.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/provider-blocks.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/snapshot.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/tree.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/core.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/health.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/llm-retry.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/needle.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/snapshot.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +0 -0
|
@@ -100,7 +100,7 @@ mock.module("../config/loader.js", () => ({
|
|
|
100
100
|
// Can be a number (constant), a no-arg function, or a function that
|
|
101
101
|
// receives the messages array for dynamic behavior based on content.
|
|
102
102
|
// Both the calibrated entry point (`estimatePromptTokens`, which backs the
|
|
103
|
-
//
|
|
103
|
+
// loop's budget gate and the convergence path) and the raw entry point
|
|
104
104
|
// (`estimatePromptTokensRaw`, used by the pre-send calibration capture) are
|
|
105
105
|
// stubbed so either call site can drive the test.
|
|
106
106
|
let mockEstimateTokens: number | ((msgs?: Message[]) => number) = 1000;
|
|
@@ -113,7 +113,7 @@ mock.module("../context/token-estimator.js", () => ({
|
|
|
113
113
|
typeof mockEstimateTokens === "function"
|
|
114
114
|
? mockEstimateTokens(msgs)
|
|
115
115
|
: mockEstimateTokens,
|
|
116
|
-
// The
|
|
116
|
+
// The loop's budget gate calls this calibrated wrapper directly, so it
|
|
117
117
|
// must honor `mockEstimateTokens` too — otherwise the real implementation
|
|
118
118
|
// (which sums tool tokens onto the real calibrated estimate) ignores the
|
|
119
119
|
// per-test value and the overflow scenarios below never trigger.
|
|
@@ -202,7 +202,7 @@ mock.module("../memory/conversation-crud.js", () => ({
|
|
|
202
202
|
updateMessageMetadata: () => {},
|
|
203
203
|
setLastNotifiedInferenceProfile: () => {},
|
|
204
204
|
getLastUserTimestampBefore: () => 0,
|
|
205
|
-
|
|
205
|
+
resolveOverrideProfile: () => undefined,
|
|
206
206
|
reserveMessage: mock(async () => ({ id: "msg-reserve" })),
|
|
207
207
|
}));
|
|
208
208
|
|
|
@@ -422,10 +422,8 @@ mock.module("../memory/archive-store.js", () => ({
|
|
|
422
422
|
// ── Imports (after mocks) ────────────────────────────────────────────
|
|
423
423
|
|
|
424
424
|
import { AgentLoop } from "../agent/loop.js";
|
|
425
|
-
import {
|
|
426
|
-
|
|
427
|
-
runAgentLoopImpl,
|
|
428
|
-
} from "../daemon/conversation-agent-loop.js";
|
|
425
|
+
import type { Conversation } from "../daemon/conversation.js";
|
|
426
|
+
import { runAgentLoopImpl } from "../daemon/conversation-agent-loop.js";
|
|
429
427
|
import {
|
|
430
428
|
createMockProvider,
|
|
431
429
|
type ScriptedResponse,
|
|
@@ -436,13 +434,13 @@ import {
|
|
|
436
434
|
// ── Test helpers ─────────────────────────────────────────────────────
|
|
437
435
|
|
|
438
436
|
function makeCtx(
|
|
439
|
-
overrides?: Partial<
|
|
437
|
+
overrides?: Partial<Conversation> & {
|
|
440
438
|
providerResponses?: ScriptedResponse[];
|
|
441
439
|
loopProvider?: Provider;
|
|
442
440
|
loopTools?: ToolDefinition[];
|
|
443
441
|
toolExecutor?: LoopToolExecutor;
|
|
444
442
|
},
|
|
445
|
-
):
|
|
443
|
+
): Conversation {
|
|
446
444
|
const {
|
|
447
445
|
providerResponses,
|
|
448
446
|
loopProvider,
|
|
@@ -465,7 +463,9 @@ function makeCtx(
|
|
|
465
463
|
providerResponses ?? [textResponse("response")],
|
|
466
464
|
loopProviderName,
|
|
467
465
|
).provider;
|
|
468
|
-
const agentLoop = new AgentLoop(
|
|
466
|
+
const agentLoop = new AgentLoop({
|
|
467
|
+
provider: provider,
|
|
468
|
+
systemPrompt: "system prompt",
|
|
469
469
|
conversationId,
|
|
470
470
|
tools: loopTools ?? [],
|
|
471
471
|
toolExecutor,
|
|
@@ -495,13 +495,14 @@ function makeCtx(
|
|
|
495
495
|
usage: { inputTokens: 0, outputTokens: 0 },
|
|
496
496
|
stopReason: "end_turn",
|
|
497
497
|
}),
|
|
498
|
-
} as unknown as
|
|
498
|
+
} as unknown as Conversation["provider"],
|
|
499
499
|
systemPrompt: "system prompt",
|
|
500
500
|
|
|
501
501
|
contextWindowManager: {
|
|
502
|
+
updateConfig: () => {},
|
|
502
503
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
503
504
|
maybeCompact: async () => ({ compacted: false }),
|
|
504
|
-
} as unknown as
|
|
505
|
+
} as unknown as Conversation["contextWindowManager"],
|
|
505
506
|
contextCompactedMessageCount: 0,
|
|
506
507
|
contextCompactedAt: null,
|
|
507
508
|
|
|
@@ -515,8 +516,6 @@ function makeCtx(
|
|
|
515
516
|
currentTurnSurfaces: [],
|
|
516
517
|
|
|
517
518
|
workingDir: "/tmp",
|
|
518
|
-
workspaceTopLevelContext: null,
|
|
519
|
-
workspaceTopLevelDirty: false,
|
|
520
519
|
channelCapabilities: undefined,
|
|
521
520
|
commandIntent: undefined,
|
|
522
521
|
trustContext: undefined,
|
|
@@ -526,15 +525,15 @@ function makeCtx(
|
|
|
526
525
|
preactivatedSkillIds: undefined,
|
|
527
526
|
skillProjectionState: new Map(),
|
|
528
527
|
skillProjectionCache:
|
|
529
|
-
new Map() as unknown as
|
|
528
|
+
new Map() as unknown as Conversation["skillProjectionCache"],
|
|
530
529
|
|
|
531
530
|
traceEmitter: {
|
|
532
531
|
emit: () => {},
|
|
533
|
-
} as unknown as
|
|
532
|
+
} as unknown as Conversation["traceEmitter"],
|
|
534
533
|
profiler: {
|
|
535
534
|
startRequest: () => {},
|
|
536
535
|
emitSummary: () => {},
|
|
537
|
-
} as unknown as
|
|
536
|
+
} as unknown as Conversation["profiler"],
|
|
538
537
|
usageStats: {
|
|
539
538
|
totalInputTokens: 0,
|
|
540
539
|
totalOutputTokens: 0,
|
|
@@ -547,13 +546,12 @@ function makeCtx(
|
|
|
547
546
|
lastAttachmentWarnings: [],
|
|
548
547
|
|
|
549
548
|
hasNoClient: false,
|
|
550
|
-
prompter: {} as unknown as
|
|
551
|
-
queue: {} as unknown as
|
|
549
|
+
prompter: {} as unknown as Conversation["prompter"],
|
|
550
|
+
queue: {} as unknown as Conversation["queue"],
|
|
552
551
|
|
|
553
552
|
getWorkspaceGitService: () => ({ ensureInitialized: async () => {} }),
|
|
554
553
|
commitTurnChanges: async () => {},
|
|
555
554
|
|
|
556
|
-
refreshWorkspaceTopLevelContextIfNeeded: () => {},
|
|
557
555
|
markWorkspaceTopLevelDirty: () => {},
|
|
558
556
|
emitActivityState: () => {},
|
|
559
557
|
getQueueDepth: () => 0,
|
|
@@ -580,10 +578,10 @@ function makeCtx(
|
|
|
580
578
|
}),
|
|
581
579
|
retrackCachedNodes: () => {},
|
|
582
580
|
recordPkbQueryVectors: () => {},
|
|
583
|
-
} as unknown as
|
|
581
|
+
} as unknown as Conversation["graphMemory"],
|
|
584
582
|
|
|
585
583
|
...ctxOverrides,
|
|
586
|
-
} as
|
|
584
|
+
} as unknown as Conversation;
|
|
587
585
|
}
|
|
588
586
|
|
|
589
587
|
/**
|
|
@@ -651,10 +649,9 @@ beforeEach(() => {
|
|
|
651
649
|
recordUsageMock.mockClear();
|
|
652
650
|
setAgentLoopExitReasonOnLatestLogMock.mockClear();
|
|
653
651
|
addMessageMock.mockClear();
|
|
654
|
-
// Reset the plugin registry and re-register every default so the
|
|
655
|
-
//
|
|
656
|
-
//
|
|
657
|
-
// (`reduceContextOverflow`, `syncMessageToDisk`, …) these tests install.
|
|
652
|
+
// Reset the plugin registry and re-register every default so the compaction
|
|
653
|
+
// pipeline dispatches to the default middleware, which in turn hits the
|
|
654
|
+
// mocked collaborators (`syncMessageToDisk`, …) these tests install.
|
|
658
655
|
resetPluginRegistryAndRegisterDefaults();
|
|
659
656
|
});
|
|
660
657
|
|
|
@@ -768,9 +765,10 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
768
765
|
isError: false,
|
|
769
766
|
}),
|
|
770
767
|
contextWindowManager: {
|
|
768
|
+
updateConfig: () => {},
|
|
771
769
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
772
770
|
maybeCompact: async () => ({ compacted: false }),
|
|
773
|
-
} as unknown as
|
|
771
|
+
} as unknown as Conversation["contextWindowManager"],
|
|
774
772
|
});
|
|
775
773
|
|
|
776
774
|
await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
|
|
@@ -797,9 +795,9 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
797
795
|
const events: ServerMessage[] = [];
|
|
798
796
|
let reducerCalled = false;
|
|
799
797
|
|
|
800
|
-
// GIVEN the estimator reports 185k
|
|
801
|
-
//
|
|
802
|
-
//
|
|
798
|
+
// GIVEN the estimator reports 185k and the context manager's compaction
|
|
799
|
+
// is a no-op, so the first call proceeds to the provider without any
|
|
800
|
+
// up-front reduction.
|
|
803
801
|
mockEstimateTokens = 185_000;
|
|
804
802
|
|
|
805
803
|
// AND the post-run convergence reducer successfully compacts
|
|
@@ -842,9 +840,10 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
842
840
|
const ctx = makeCtx({
|
|
843
841
|
loopProvider: provider,
|
|
844
842
|
contextWindowManager: {
|
|
843
|
+
updateConfig: () => {},
|
|
845
844
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
846
845
|
maybeCompact: async () => ({ compacted: false }),
|
|
847
|
-
} as unknown as
|
|
846
|
+
} as unknown as Conversation["contextWindowManager"],
|
|
848
847
|
});
|
|
849
848
|
|
|
850
849
|
// WHEN the turn runs
|
|
@@ -918,9 +917,10 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
918
917
|
const ctx = makeCtx({
|
|
919
918
|
loopProvider: provider,
|
|
920
919
|
contextWindowManager: {
|
|
920
|
+
updateConfig: () => {},
|
|
921
921
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
922
922
|
maybeCompact: async () => ({ compacted: false }),
|
|
923
|
-
} as unknown as
|
|
923
|
+
} as unknown as Conversation["contextWindowManager"],
|
|
924
924
|
});
|
|
925
925
|
|
|
926
926
|
await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
|
|
@@ -1005,9 +1005,10 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1005
1005
|
loopProvider: provider,
|
|
1006
1006
|
messages: longHistory,
|
|
1007
1007
|
contextWindowManager: {
|
|
1008
|
+
updateConfig: () => {},
|
|
1008
1009
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
1009
1010
|
maybeCompact: async () => ({ compacted: false }),
|
|
1010
|
-
} as unknown as
|
|
1011
|
+
} as unknown as Conversation["contextWindowManager"],
|
|
1011
1012
|
});
|
|
1012
1013
|
|
|
1013
1014
|
await runAgentLoopImpl(ctx, "analyze this", "msg-1", (msg) =>
|
|
@@ -1087,6 +1088,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1087
1088
|
isError: false,
|
|
1088
1089
|
}),
|
|
1089
1090
|
contextWindowManager: {
|
|
1091
|
+
updateConfig: () => {},
|
|
1090
1092
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
1091
1093
|
maybeCompact: async (
|
|
1092
1094
|
_msgs: Message[],
|
|
@@ -1118,7 +1120,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1118
1120
|
}
|
|
1119
1121
|
return { compacted: false };
|
|
1120
1122
|
},
|
|
1121
|
-
} as unknown as
|
|
1123
|
+
} as unknown as Conversation["contextWindowManager"],
|
|
1122
1124
|
});
|
|
1123
1125
|
|
|
1124
1126
|
await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
|
|
@@ -1187,6 +1189,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1187
1189
|
isError: false,
|
|
1188
1190
|
}),
|
|
1189
1191
|
contextWindowManager: {
|
|
1192
|
+
updateConfig: () => {},
|
|
1190
1193
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
1191
1194
|
maybeCompact: async () => {
|
|
1192
1195
|
compactionCalled = true;
|
|
@@ -1211,7 +1214,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1211
1214
|
summaryModel: "mock-model",
|
|
1212
1215
|
};
|
|
1213
1216
|
},
|
|
1214
|
-
} as unknown as
|
|
1217
|
+
} as unknown as Conversation["contextWindowManager"],
|
|
1215
1218
|
});
|
|
1216
1219
|
|
|
1217
1220
|
await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
|
|
@@ -1293,6 +1296,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1293
1296
|
isError: false,
|
|
1294
1297
|
}),
|
|
1295
1298
|
contextWindowManager: {
|
|
1299
|
+
updateConfig: () => {},
|
|
1296
1300
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
1297
1301
|
maybeCompact: async () => {
|
|
1298
1302
|
compactionCalled = true;
|
|
@@ -1317,7 +1321,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1317
1321
|
summaryModel: "mock-model",
|
|
1318
1322
|
};
|
|
1319
1323
|
},
|
|
1320
|
-
} as unknown as
|
|
1324
|
+
} as unknown as Conversation["contextWindowManager"],
|
|
1321
1325
|
});
|
|
1322
1326
|
|
|
1323
1327
|
await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => {
|
|
@@ -1360,14 +1364,9 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1360
1364
|
|
|
1361
1365
|
// Budget = 200_000 * 0.95 = 190_000
|
|
1362
1366
|
// Mid-loop threshold = 190_000 * 0.85 = 161_500
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
// Preflight: below budget
|
|
1367
|
-
if (estimateCallCount === 1) return 100_000;
|
|
1368
|
-
// Every checkpoint call: above threshold — always triggers yield
|
|
1369
|
-
return 170_000;
|
|
1370
|
-
};
|
|
1367
|
+
// Every estimate is above the threshold, so the first-call gate compacts
|
|
1368
|
+
// before the first provider call and every checkpoint trips the yield.
|
|
1369
|
+
mockEstimateTokens = 170_000;
|
|
1371
1370
|
|
|
1372
1371
|
// The convergence reducer reduces tokens enough for the rerun to recover.
|
|
1373
1372
|
let convergenceReducerCalled = false;
|
|
@@ -1410,6 +1409,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1410
1409
|
],
|
|
1411
1410
|
toolExecutor: async () => ({ content: "output", isError: false }),
|
|
1412
1411
|
contextWindowManager: {
|
|
1412
|
+
updateConfig: () => {},
|
|
1413
1413
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
1414
1414
|
maybeCompact: async () => {
|
|
1415
1415
|
compactionCallCount++;
|
|
@@ -1441,7 +1441,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1441
1441
|
summaryModel: "mock-model",
|
|
1442
1442
|
};
|
|
1443
1443
|
},
|
|
1444
|
-
} as unknown as
|
|
1444
|
+
} as unknown as Conversation["contextWindowManager"],
|
|
1445
1445
|
});
|
|
1446
1446
|
|
|
1447
1447
|
await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
|
|
@@ -1480,16 +1480,11 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1480
1480
|
|
|
1481
1481
|
// Budget = 200_000 * 0.95 = 190_000
|
|
1482
1482
|
// Mid-loop threshold = 190_000 * 0.85 = 161_500
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
// Every checkpoint estimate: above threshold — always trips the
|
|
1489
|
-
// yield. Simulates a long turn where each tool call's result
|
|
1490
|
-
// inflates the context past 85% even after a successful compaction.
|
|
1491
|
-
return 170_000;
|
|
1492
|
-
};
|
|
1483
|
+
// Every estimate is above the threshold: the first-call gate compacts
|
|
1484
|
+
// before the first provider call, and each subsequent checkpoint trips
|
|
1485
|
+
// the yield even after a successful compaction (each tool result inflates
|
|
1486
|
+
// the context back past 85%).
|
|
1487
|
+
mockEstimateTokens = 170_000;
|
|
1493
1488
|
|
|
1494
1489
|
// A single tool round reaches one checkpoint; the in-loop budget gate
|
|
1495
1490
|
// trips there and compaction runs in place. The loop continues the run
|
|
@@ -1518,6 +1513,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1518
1513
|
],
|
|
1519
1514
|
toolExecutor: async () => ({ content: "output", isError: false }),
|
|
1520
1515
|
contextWindowManager: {
|
|
1516
|
+
updateConfig: () => {},
|
|
1521
1517
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
1522
1518
|
maybeCompact: async () => {
|
|
1523
1519
|
compactionCallCount++;
|
|
@@ -1542,7 +1538,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1542
1538
|
summaryModel: "mock-model",
|
|
1543
1539
|
};
|
|
1544
1540
|
},
|
|
1545
|
-
} as unknown as
|
|
1541
|
+
} as unknown as Conversation["contextWindowManager"],
|
|
1546
1542
|
});
|
|
1547
1543
|
|
|
1548
1544
|
await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
|
|
@@ -1633,6 +1629,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1633
1629
|
],
|
|
1634
1630
|
toolExecutor: async () => ({ content: "output", isError: false }),
|
|
1635
1631
|
contextWindowManager: {
|
|
1632
|
+
updateConfig: () => {},
|
|
1636
1633
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
1637
1634
|
// Under the new architecture (Compaction Re-homing Arc, Bullet 1)
|
|
1638
1635
|
// the retry budget lives inside `ContextWindowManager._maybeCompact`,
|
|
@@ -1660,7 +1657,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1660
1657
|
summaryModel: "mock-model",
|
|
1661
1658
|
exhausted: true,
|
|
1662
1659
|
}),
|
|
1663
|
-
} as unknown as
|
|
1660
|
+
} as unknown as Conversation["contextWindowManager"],
|
|
1664
1661
|
});
|
|
1665
1662
|
|
|
1666
1663
|
await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
|
|
@@ -1680,124 +1677,6 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1680
1677
|
);
|
|
1681
1678
|
});
|
|
1682
1679
|
|
|
1683
|
-
// ── Test 8 ────────────────────────────────────────────────────────
|
|
1684
|
-
// BUG: The preflight overflow reducer's budget check uses
|
|
1685
|
-
// step.estimatedTokens (computed on bare ctx.messages) without
|
|
1686
|
-
// accounting for tokens added by applyRuntimeInjections(). This
|
|
1687
|
-
// causes the reducer to stop early when the bare estimate is under
|
|
1688
|
-
// budget, even though post-injection tokens exceed it — leading to
|
|
1689
|
-
// a wasted provider round-trip that gets rejected.
|
|
1690
|
-
//
|
|
1691
|
-
// After fix: the budget check re-estimates on runMessages (with
|
|
1692
|
-
// injections) so the reducer continues to the next tier.
|
|
1693
|
-
test("preflight reducer continues when post-injection tokens exceed budget", async () => {
|
|
1694
|
-
const events: ServerMessage[] = [];
|
|
1695
|
-
|
|
1696
|
-
// Injections add an extra message, bumping the token count.
|
|
1697
|
-
const injectionMessage: Message = {
|
|
1698
|
-
role: "user" as const,
|
|
1699
|
-
content: [
|
|
1700
|
-
{
|
|
1701
|
-
type: "text" as const,
|
|
1702
|
-
text: "injected context " + "x".repeat(500),
|
|
1703
|
-
},
|
|
1704
|
-
],
|
|
1705
|
-
};
|
|
1706
|
-
mockApplyRuntimeInjections = (msgs) => [...msgs, injectionMessage];
|
|
1707
|
-
|
|
1708
|
-
// Budget = 200_000 * 0.95 = 190_000
|
|
1709
|
-
// The estimator returns different values based on whether the
|
|
1710
|
-
// injection message is present:
|
|
1711
|
-
// - bare history (no injection msg) → 195_000 (triggers preflight)
|
|
1712
|
-
// - after tier 1 bare → 185_000 (under budget, would stop early without fix)
|
|
1713
|
-
// - after tier 1 with injection → 195_000 (still over budget)
|
|
1714
|
-
// - after tier 2 bare → 170_000
|
|
1715
|
-
// - after tier 2 with injection → 175_000 (under budget, reducer stops)
|
|
1716
|
-
let reducerCallCount = 0;
|
|
1717
|
-
mockEstimateTokens = (msgs?: Message[]) => {
|
|
1718
|
-
const hasInjection = msgs?.some(
|
|
1719
|
-
(m) =>
|
|
1720
|
-
m.role === "user" &&
|
|
1721
|
-
Array.isArray(m.content) &&
|
|
1722
|
-
m.content.some(
|
|
1723
|
-
(b: { type: string; text?: string }) =>
|
|
1724
|
-
b.type === "text" &&
|
|
1725
|
-
typeof b.text === "string" &&
|
|
1726
|
-
b.text.startsWith("injected context"),
|
|
1727
|
-
),
|
|
1728
|
-
);
|
|
1729
|
-
if (reducerCallCount === 0) {
|
|
1730
|
-
// Before any reduction: preflight check on runMessages (with injection)
|
|
1731
|
-
return 195_000;
|
|
1732
|
-
}
|
|
1733
|
-
if (reducerCallCount === 1) {
|
|
1734
|
-
// After tier 1
|
|
1735
|
-
return hasInjection ? 195_000 : 185_000;
|
|
1736
|
-
}
|
|
1737
|
-
// After tier 2
|
|
1738
|
-
return hasInjection ? 175_000 : 170_000;
|
|
1739
|
-
};
|
|
1740
|
-
|
|
1741
|
-
mockReducerStepFn = (msgs: Message[]) => {
|
|
1742
|
-
reducerCallCount++;
|
|
1743
|
-
const tier =
|
|
1744
|
-
reducerCallCount === 1 ? "forced_compaction" : "tool_result_truncation";
|
|
1745
|
-
return {
|
|
1746
|
-
messages: msgs,
|
|
1747
|
-
tier,
|
|
1748
|
-
state: {
|
|
1749
|
-
appliedTiers:
|
|
1750
|
-
reducerCallCount === 1
|
|
1751
|
-
? ["forced_compaction"]
|
|
1752
|
-
: ["forced_compaction", "tool_result_truncation"],
|
|
1753
|
-
injectionMode: "full" as const,
|
|
1754
|
-
exhausted: reducerCallCount >= 2,
|
|
1755
|
-
},
|
|
1756
|
-
// Bare-history estimate (what the reducer sees on ctx.messages)
|
|
1757
|
-
estimatedTokens: reducerCallCount === 1 ? 185_000 : 170_000,
|
|
1758
|
-
compactionResult: {
|
|
1759
|
-
compacted: true,
|
|
1760
|
-
messages: msgs,
|
|
1761
|
-
compactedPersistedMessages: 5,
|
|
1762
|
-
summaryText: "Summary",
|
|
1763
|
-
previousEstimatedInputTokens: 195_000,
|
|
1764
|
-
estimatedInputTokens: reducerCallCount === 1 ? 185_000 : 170_000,
|
|
1765
|
-
maxInputTokens: 200_000,
|
|
1766
|
-
thresholdTokens: 160_000,
|
|
1767
|
-
compactedMessages: 10,
|
|
1768
|
-
summaryCalls: 1,
|
|
1769
|
-
summaryInputTokens: 500,
|
|
1770
|
-
summaryOutputTokens: 200,
|
|
1771
|
-
summaryModel: "mock-model",
|
|
1772
|
-
},
|
|
1773
|
-
};
|
|
1774
|
-
};
|
|
1775
|
-
|
|
1776
|
-
// The preflight overflow reducer runs in the orchestrator before the loop,
|
|
1777
|
-
// so a single successful provider turn is enough to drive the path.
|
|
1778
|
-
const ctx = makeCtx({
|
|
1779
|
-
providerResponses: [textResponse("done")],
|
|
1780
|
-
contextWindowManager: {
|
|
1781
|
-
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
1782
|
-
maybeCompact: async () => ({ compacted: false }),
|
|
1783
|
-
} as unknown as AgentLoopConversationContext["contextWindowManager"],
|
|
1784
|
-
});
|
|
1785
|
-
|
|
1786
|
-
await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
|
|
1787
|
-
|
|
1788
|
-
// The reducer must be called twice — the first tier's bare estimate
|
|
1789
|
-
// (185k) is under budget (190k), but post-injection tokens (195k)
|
|
1790
|
-
// still exceed it. Without the fix, the reducer would stop after
|
|
1791
|
-
// tier 1 and the provider call would likely fail.
|
|
1792
|
-
expect(reducerCallCount).toBe(2);
|
|
1793
|
-
|
|
1794
|
-
// Should succeed without errors
|
|
1795
|
-
const conversationError = events.find(
|
|
1796
|
-
(e) => e.type === "conversation_error",
|
|
1797
|
-
);
|
|
1798
|
-
expect(conversationError).toBeUndefined();
|
|
1799
|
-
});
|
|
1800
|
-
|
|
1801
1680
|
// ── Test 9 ────────────────────────────────────────────────────────
|
|
1802
1681
|
// When the `auto_compress_latest_turn` rerun (the last layer of the
|
|
1803
1682
|
// overflow-recovery ladder) still yields at the mid-loop checkpoint,
|
|
@@ -1854,14 +1733,15 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1854
1733
|
toolUseResponse("tu-1", "bash", { command: "ls" }),
|
|
1855
1734
|
]);
|
|
1856
1735
|
|
|
1857
|
-
// `maybeCompact` is invoked through three distinct call
|
|
1858
|
-
//
|
|
1859
|
-
//
|
|
1860
|
-
//
|
|
1861
|
-
//
|
|
1862
|
-
//
|
|
1863
|
-
//
|
|
1864
|
-
//
|
|
1736
|
+
// Every forced `maybeCompact` is invoked through three distinct call
|
|
1737
|
+
// sites, all owned by the loop's pre-call budget gate / recovery ladder:
|
|
1738
|
+
// 1. First-call (turn-start) gate (`force: true`) — the loop now owns
|
|
1739
|
+
// the turn-start compaction. It succeeds, but the mocked estimate
|
|
1740
|
+
// stays above the mid-loop threshold, so the turn proceeds and the
|
|
1741
|
+
// mid-loop gate still trips on the next iteration.
|
|
1742
|
+
// 2. Mid-loop after the first tool turn (`force: true`) — must signal
|
|
1743
|
+
// `exhausted: true` so the daemon escalates to the convergence
|
|
1744
|
+
// reducer instead of looping forever.
|
|
1865
1745
|
// 3. auto_compress_latest_turn emergency compaction (`force: true`,
|
|
1866
1746
|
// `minKeepRecentUserTurns: 0`) — succeeds and drops tokens below
|
|
1867
1747
|
// threshold; the subsequent rerun yields again and is classified
|
|
@@ -1881,22 +1761,47 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1881
1761
|
],
|
|
1882
1762
|
toolExecutor: async () => ({ content: "output", isError: false }),
|
|
1883
1763
|
contextWindowManager: {
|
|
1764
|
+
updateConfig: () => {},
|
|
1884
1765
|
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
1885
1766
|
maybeCompact: async (
|
|
1886
1767
|
_msgs: Message[],
|
|
1887
1768
|
_signal: AbortSignal,
|
|
1888
1769
|
opts?: { force?: boolean },
|
|
1889
1770
|
) => {
|
|
1890
|
-
//
|
|
1891
|
-
// no-op
|
|
1771
|
+
// Only forced compactions drive this test; any non-forced probe is
|
|
1772
|
+
// a no-op.
|
|
1892
1773
|
if (!opts?.force) {
|
|
1893
1774
|
return { compacted: false };
|
|
1894
1775
|
}
|
|
1895
1776
|
forcedMaybeCompactCallCount++;
|
|
1896
1777
|
if (forcedMaybeCompactCallCount === 1) {
|
|
1897
|
-
//
|
|
1898
|
-
//
|
|
1899
|
-
//
|
|
1778
|
+
// First-call (turn-start) gate: succeeds, but the mocked estimate
|
|
1779
|
+
// stays above the threshold so the turn proceeds to the call and
|
|
1780
|
+
// the mid-loop gate still trips next iteration.
|
|
1781
|
+
return {
|
|
1782
|
+
compacted: true,
|
|
1783
|
+
messages: [
|
|
1784
|
+
{
|
|
1785
|
+
role: "user" as const,
|
|
1786
|
+
content: [{ type: "text", text: "turn-start compacted" }],
|
|
1787
|
+
},
|
|
1788
|
+
] as Message[],
|
|
1789
|
+
compactedPersistedMessages: 5,
|
|
1790
|
+
summaryText: "Turn-start summary",
|
|
1791
|
+
previousEstimatedInputTokens: 170_000,
|
|
1792
|
+
estimatedInputTokens: 165_000,
|
|
1793
|
+
maxInputTokens: 200_000,
|
|
1794
|
+
thresholdTokens: 160_000,
|
|
1795
|
+
compactedMessages: 10,
|
|
1796
|
+
summaryCalls: 1,
|
|
1797
|
+
summaryInputTokens: 500,
|
|
1798
|
+
summaryOutputTokens: 200,
|
|
1799
|
+
summaryModel: "mock-model",
|
|
1800
|
+
};
|
|
1801
|
+
}
|
|
1802
|
+
if (forcedMaybeCompactCallCount === 2) {
|
|
1803
|
+
// Mid-loop call — the manager owns its own retry budget; signal
|
|
1804
|
+
// exhaustion to escalate to convergence.
|
|
1900
1805
|
return {
|
|
1901
1806
|
compacted: true,
|
|
1902
1807
|
messages: [
|
|
@@ -1941,7 +1846,7 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
1941
1846
|
summaryModel: "mock-model",
|
|
1942
1847
|
};
|
|
1943
1848
|
},
|
|
1944
|
-
} as unknown as
|
|
1849
|
+
} as unknown as Conversation["contextWindowManager"],
|
|
1945
1850
|
});
|
|
1946
1851
|
|
|
1947
1852
|
await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
|