@vellumai/assistant 0.8.7-dev.202606052232.2ddc989 → 0.8.8
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/docs/plugins.md +832 -0
- package/examples/plugins/echo/README.md +60 -61
- package/examples/plugins/echo/package.json +2 -1
- package/examples/plugins/echo/register.ts +143 -0
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +6 -7
- package/openapi.yaml +5 -15
- package/package.json +2 -2
- package/src/__tests__/agent-loop-exit-reason.test.ts +56 -3
- 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 +0 -1
- package/src/__tests__/approval-routes-http.test.ts +1 -4
- package/src/__tests__/channel-approval-routes.test.ts +1 -1
- package/src/__tests__/channel-approvals.test.ts +1 -1
- package/src/__tests__/circuit-breaker-pipeline.test.ts +405 -0
- package/src/__tests__/compaction-pipeline.test.ts +210 -0
- package/src/__tests__/compaction-timeout-recovery.test.ts +251 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +3 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +3 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +7 -3
- package/src/__tests__/conversation-agent-loop.test.ts +39 -42
- package/src/__tests__/conversation-clean-command.test.ts +2 -5
- package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -4
- package/src/__tests__/conversation-runtime-assembly.test.ts +71 -140
- package/src/__tests__/conversation-runtime-workspace.test.ts +27 -108
- package/src/__tests__/conversation-starter-routes.test.ts +6 -14
- package/src/__tests__/conversation-workspace-cache-state.test.ts +16 -17
- package/src/__tests__/conversation-workspace-injection.test.ts +1 -61
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -7
- package/src/__tests__/db-acp-history.test.ts +0 -101
- package/src/__tests__/dynamic-page-surface.test.ts +0 -31
- package/src/__tests__/file-write-tool.test.ts +0 -63
- package/src/__tests__/gateway-only-guard.test.ts +2 -12
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +4 -2
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +0 -1
- package/src/__tests__/heartbeat-service.test.ts +0 -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__/injector-background-turn.test.ts +1 -1
- package/src/__tests__/injector-chain.test.ts +6 -34
- package/src/__tests__/injector-disk-pressure.test.ts +34 -77
- package/src/__tests__/injector-document-comments.test.ts +1 -1
- package/src/__tests__/list-messages-hidden-metadata.test.ts +0 -38
- package/src/__tests__/memory-v2-static-injector.test.ts +1 -1
- package/src/__tests__/{overflow-reduction-loop.test.ts → overflow-reduce-pipeline.test.ts} +284 -64
- package/src/__tests__/pipeline-runner.test.ts +554 -0
- package/src/__tests__/plugin-api-shim.test.ts +6 -3
- package/src/__tests__/plugin-bootstrap.test.ts +23 -12
- package/src/__tests__/plugin-registry.test.ts +49 -3
- package/src/__tests__/plugin-types.test.ts +70 -0
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +1 -4
- package/src/__tests__/skill-feature-flags-integration.test.ts +0 -33
- package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
- package/src/__tests__/subagent-fork-notifications.test.ts +3 -1
- package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
- package/src/__tests__/subagent-manager-notify.test.ts +3 -1
- package/src/__tests__/subagent-notify-parent.test.ts +3 -1
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
- package/src/__tests__/user-plugin-loader.test.ts +286 -54
- package/src/acp/__tests__/client-handler.test.ts +0 -40
- package/src/acp/__tests__/prepare-agent-env.test.ts +0 -137
- package/src/acp/__tests__/session-manager-persistence.test.ts +28 -95
- package/src/acp/agent-process.ts +1 -61
- package/src/acp/client-handler.ts +0 -31
- package/src/acp/prepare-agent-env.ts +29 -83
- package/src/acp/resolve-agent.test.ts +7 -320
- package/src/acp/resolve-agent.ts +18 -182
- package/src/acp/session-manager.ts +73 -495
- package/src/acp/types.ts +0 -8
- package/src/agent/compaction-circuit.ts +102 -60
- package/src/agent/loop.ts +59 -32
- package/src/api/responses/conversation-message.ts +1 -7
- package/src/approvals/guardian-request-resolvers.ts +1 -1
- package/src/background-wake/next-wake.ts +0 -1
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/acp-defaults.test.ts +0 -10
- package/src/config/acp-defaults.ts +0 -6
- package/src/config/bundled-skills/acp/SKILL.md +31 -83
- package/src/config/bundled-skills/acp/TOOLS.json +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +381 -224
- package/src/config/bundled-skills/app-builder/TOOLS.json +0 -29
- package/src/config/bundled-skills/document-editor/SKILL.md +23 -28
- package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
- package/src/config/bundled-tool-registry.ts +0 -2
- package/src/config/feature-flag-registry.json +5 -14
- package/src/config/schemas/heartbeat.ts +0 -9
- package/src/context/strip-injections.ts +2 -8
- package/src/context/window-manager.ts +1 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +11 -0
- package/src/daemon/conversation-agent-loop.ts +279 -62
- package/src/daemon/conversation-runtime-assembly.ts +69 -106
- package/src/daemon/conversation-store.ts +90 -9
- package/src/daemon/conversation-workspace.ts +0 -17
- package/src/daemon/conversation.ts +6 -0
- package/src/daemon/external-plugins-bootstrap.ts +11 -11
- package/src/daemon/handlers/conversations.ts +1 -3
- package/src/daemon/handlers/skills.ts +1 -4
- package/src/daemon/lifecycle.ts +0 -21
- package/src/daemon/server.ts +0 -2
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -3
- package/src/heartbeat/heartbeat-run-store.ts +1 -23
- package/src/heartbeat/heartbeat-service.ts +0 -26
- 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 +0 -15
- package/src/ipc/skill-routes/memory.ts +2 -4
- package/src/memory/conversation-starter-checkpoints.ts +0 -1
- package/src/memory/db-init.ts +0 -2
- package/src/memory/job-handlers/conversation-starters.ts +2 -13
- package/src/memory/jobs-worker.ts +1 -1
- package/src/memory/migrations/index.ts +0 -1
- package/src/memory/schema/acp.ts +0 -4
- package/src/memory/v2/__tests__/consolidation-job.test.ts +3 -3
- package/src/memory/v2/consolidation-job.ts +4 -13
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/assign.test.ts +4 -4
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/live-integration.test.ts +4 -4
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/maintain-job.test.ts +5 -5
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/orchestrate.test.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/reconcile.test.ts +2 -2
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/render-injection.test.ts +1 -1
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/router.test.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/selection-log-store.test.ts +8 -8
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/selector.test.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/shadow-plugin.test.ts +12 -12
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/assign.ts +5 -5
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/capabilities.ts +2 -2
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/maintain-job.ts +8 -8
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/page-content.ts +2 -2
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/provider-blocks.ts +1 -1
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/reconcile.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/render-injection.ts +1 -1
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/router.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/selection-log-store.ts +4 -4
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/selector.ts +4 -4
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/shadow-plugin.ts +90 -28
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/tree.ts +1 -1
- package/src/plugin-api/index.ts +5 -0
- package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +93 -0
- package/src/plugins/defaults/{memory-v3-shadow → circuit-breaker}/package.json +2 -2
- package/src/plugins/defaults/circuit-breaker/register.ts +39 -0
- package/src/plugins/defaults/compaction/middlewares/compaction.ts +25 -0
- package/src/plugins/defaults/compaction/package.json +1 -1
- package/src/plugins/defaults/compaction/register.ts +19 -8
- package/src/plugins/defaults/compaction/terminal.ts +73 -0
- package/src/plugins/defaults/index.ts +5 -3
- package/src/plugins/defaults/{memory-retrieval/injectors.ts → injectors/register.ts} +7 -45
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +7 -11
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
- package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +126 -0
- package/src/plugins/defaults/overflow-reduce/package.json +15 -0
- package/src/plugins/defaults/overflow-reduce/register.ts +42 -0
- package/src/plugins/external-api.ts +2 -2
- package/src/plugins/pipeline.ts +293 -6
- package/src/plugins/registry.ts +37 -9
- package/src/plugins/types.ts +336 -32
- package/src/plugins/user-loader.ts +127 -30
- 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 +0 -6
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +2 -4
- package/src/runtime/__tests__/agent-wake.test.ts +5 -5
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/agent-wake.ts +3 -0
- 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 +55 -283
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +4 -5
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +1 -4
- package/src/runtime/routes/acp-routes.test.ts +25 -89
- package/src/runtime/routes/acp-routes.ts +29 -81
- 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 +10 -6
- 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 +2 -15
- package/src/runtime/routes/conversation-starter-routes.ts +7 -13
- package/src/runtime/routes/conversations-import-routes.ts +7 -24
- 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 +3 -18
- package/src/runtime/routes/inbound-message-handler.ts +1 -1
- package/src/runtime/routes/memory-v3-routes.ts +6 -16
- package/src/runtime/routes/playground/helpers.ts +1 -1
- package/src/runtime/routes/surface-conversation-resolver.ts +3 -4
- package/src/runtime/routes/work-items-routes.ts +4 -2
- package/src/runtime/services/conversation-serializer.ts +1 -1
- package/src/signals/cancel.ts +4 -2
- package/src/subagent/manager.ts +5 -17
- package/src/tools/acp/list-agents.test.ts +1 -7
- package/src/tools/acp/spawn.test.ts +55 -158
- package/src/tools/acp/spawn.ts +72 -47
- package/src/tools/acp/steer.test.ts +8 -105
- package/src/tools/acp/steer.ts +17 -48
- package/src/tools/apps/executors.ts +8 -13
- package/src/tools/filesystem/write.ts +0 -34
- package/src/tools/subagent/spawn.ts +4 -2
- package/src/tools/ui-surface/definitions.ts +4 -25
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +5 -4
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +45 -69
- package/examples/plugins/echo/hooks/post-tool-use.ts +0 -18
- package/examples/plugins/echo/hooks/stop.ts +0 -16
- package/examples/plugins/echo/hooks/user-prompt-submit.ts +0 -18
- package/examples/plugins/echo/src/emit.ts +0 -19
- package/src/__tests__/compaction-circuit.test.ts +0 -258
- package/src/__tests__/compaction-direct.test.ts +0 -132
- package/src/__tests__/conversations-import-system-filter.test.ts +0 -101
- package/src/acp/__tests__/agent-process.test.ts +0 -161
- package/src/acp/__tests__/helpers/acp-history-db.ts +0 -82
- package/src/acp/__tests__/helpers/exec-file-stub.ts +0 -101
- package/src/acp/__tests__/session-manager-resume.test.ts +0 -736
- package/src/acp/auto-install.test.ts +0 -196
- package/src/acp/auto-install.ts +0 -177
- package/src/acp/feature-gate.test.ts +0 -48
- package/src/acp/feature-gate.ts +0 -34
- package/src/acp/resume-hint.ts +0 -25
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +0 -48
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +0 -57
- package/src/config/bundled-skills/app-builder/references/SLIDES.md +0 -38
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +0 -62
- package/src/daemon/conversation-registry.ts +0 -159
- package/src/daemon/overflow-reduction-loop.ts +0 -230
- package/src/memory/migrations/272-acp-session-history-cwd.ts +0 -36
- package/src/plugins/defaults/compaction/compact.ts +0 -59
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +0 -14
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +0 -19
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +0 -75
- package/src/plugins/defaults/memory-v3-shadow/register.ts +0 -26
- package/src/tools/acp/context.ts +0 -20
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/capabilities.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/core.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/fixtures/eval-turns.json +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/fixtures/live-turns.json +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/health.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/needle.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/provider-blocks.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/snapshot.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/tree.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/types.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/working-set-eviction.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/working-set-skeleton.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/core.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/README.md +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/assignments.json +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/core.json +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/leaves/domain-a/topic-x.md +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/leaves/domain-a/topic-y.md +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/leaves/domain-b/topic-z.md +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/health.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/llm-retry.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/needle.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/orchestrate.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/snapshot.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/types.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/working-set.ts +0 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the compaction call-site recovery path added in JARVIS-587.
|
|
3
|
+
*
|
|
4
|
+
* When the `compaction` pipeline exceeds its 30s budget (manifest-wide
|
|
5
|
+
* `DEFAULT_TIMEOUTS.compaction`), the pipeline runner throws
|
|
6
|
+
* `PluginTimeoutError`. The three compaction call sites in
|
|
7
|
+
* `conversation-agent-loop.ts` (start-of-turn, mid-loop, emergency) catch
|
|
8
|
+
* that error, record the failure on the loop-held `CompactionCircuit`
|
|
9
|
+
* (`recordOutcome(turn, true, ...)`) so the circuit breaker counts it, and degrade
|
|
10
|
+
* gracefully.
|
|
11
|
+
*
|
|
12
|
+
* This file asserts the tight coupling between:
|
|
13
|
+
* (1) a `PluginTimeoutError`-driven failure and
|
|
14
|
+
* (2) the compaction circuit breaker's 3-strike threshold.
|
|
15
|
+
*
|
|
16
|
+
* The existing `circuit-breaker-pipeline.test.ts` already exercises the
|
|
17
|
+
* breaker's transitions end-to-end. These tests verify that our new
|
|
18
|
+
* catch-blocks feed the breaker the same `"failure"` outcome a normal
|
|
19
|
+
* summary-LLM throw would, and that repeated timeouts therefore trip the
|
|
20
|
+
* same 3-strike trip.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
24
|
+
|
|
25
|
+
import {
|
|
26
|
+
type CircuitTurnInfo,
|
|
27
|
+
CompactionCircuit,
|
|
28
|
+
} from "../agent/compaction-circuit.js";
|
|
29
|
+
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
30
|
+
import type { TrustContext } from "../daemon/trust-context.js";
|
|
31
|
+
import { COMPACTION_CIRCUIT_FAILURE_THRESHOLD } from "../plugins/defaults/circuit-breaker/middlewares/circuitBreaker.js";
|
|
32
|
+
import { defaultCircuitBreakerPlugin } from "../plugins/defaults/circuit-breaker/register.js";
|
|
33
|
+
import { DEFAULT_TIMEOUTS, runPipeline } from "../plugins/pipeline.js";
|
|
34
|
+
import {
|
|
35
|
+
getMiddlewaresFor,
|
|
36
|
+
registerPlugin,
|
|
37
|
+
resetPluginRegistryForTests,
|
|
38
|
+
} from "../plugins/registry.js";
|
|
39
|
+
import {
|
|
40
|
+
type CompactionArgs,
|
|
41
|
+
type CompactionResult,
|
|
42
|
+
type Middleware,
|
|
43
|
+
PluginTimeoutError,
|
|
44
|
+
type TurnContext,
|
|
45
|
+
} from "../plugins/types.js";
|
|
46
|
+
|
|
47
|
+
// ─── Fixtures ───────────────────────────────────────────────────────────────
|
|
48
|
+
|
|
49
|
+
function makeCircuit(conversationId = "conv-timeout-test"): CompactionCircuit {
|
|
50
|
+
return new CompactionCircuit(conversationId);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const turn: CircuitTurnInfo = {
|
|
54
|
+
turnCount: 0,
|
|
55
|
+
trustContext: { sourceChannel: "vellum", trustClass: "guardian" },
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const trust: TrustContext = {
|
|
59
|
+
sourceChannel: "vellum",
|
|
60
|
+
trustClass: "guardian",
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
function makeTurnCtx(conversationId: string): TurnContext {
|
|
64
|
+
return {
|
|
65
|
+
requestId: "req-timeout-test",
|
|
66
|
+
conversationId,
|
|
67
|
+
turnIndex: 0,
|
|
68
|
+
trust,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function collectEvents(): {
|
|
73
|
+
events: ServerMessage[];
|
|
74
|
+
onEvent: (msg: ServerMessage) => void;
|
|
75
|
+
} {
|
|
76
|
+
const events: ServerMessage[] = [];
|
|
77
|
+
return { events, onEvent: (msg) => events.push(msg) };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ─── Tests ──────────────────────────────────────────────────────────────────
|
|
81
|
+
|
|
82
|
+
describe("compaction timeout recovery (JARVIS-587)", () => {
|
|
83
|
+
beforeEach(() => {
|
|
84
|
+
resetPluginRegistryForTests();
|
|
85
|
+
registerPlugin(defaultCircuitBreakerPlugin);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
afterEach(() => {
|
|
89
|
+
resetPluginRegistryForTests();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("runPipeline('compaction', ...) throws PluginTimeoutError on budget breach", async () => {
|
|
93
|
+
// Baseline: the compaction pipeline still surfaces PluginTimeoutError when
|
|
94
|
+
// its timer fires. This guards the outer race from silently swallowing
|
|
95
|
+
// the timeout when the inner call is aborted by our Part A wiring.
|
|
96
|
+
const hang: Middleware<CompactionArgs, CompactionResult> = async (
|
|
97
|
+
_args,
|
|
98
|
+
_next,
|
|
99
|
+
) =>
|
|
100
|
+
new Promise<CompactionResult>(() => {
|
|
101
|
+
// intentionally never resolves
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
let caught: unknown;
|
|
105
|
+
try {
|
|
106
|
+
await runPipeline<CompactionArgs, CompactionResult>(
|
|
107
|
+
"compaction",
|
|
108
|
+
[hang],
|
|
109
|
+
async () => ({ compacted: false }) as unknown as CompactionResult,
|
|
110
|
+
{ messages: [] as unknown, signal: undefined, options: undefined },
|
|
111
|
+
makeTurnCtx("conv-budget-breach"),
|
|
112
|
+
// Override the manifest timeout to keep the test fast.
|
|
113
|
+
20,
|
|
114
|
+
);
|
|
115
|
+
} catch (err) {
|
|
116
|
+
caught = err;
|
|
117
|
+
}
|
|
118
|
+
expect(caught).toBeInstanceOf(PluginTimeoutError);
|
|
119
|
+
expect((caught as PluginTimeoutError).pipeline).toBe("compaction");
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test("recordOutcome(failed=true) driven by PluginTimeoutError trips the breaker at the 3rd strike", async () => {
|
|
123
|
+
// Simulates the production sequence: each mid-loop compaction hits the
|
|
124
|
+
// pipeline's 30s ceiling, the catch path calls
|
|
125
|
+
// `circuit.recordOutcome(turn, true, onEvent)`. After three such catches
|
|
126
|
+
// the circuit breaker must be open — matching the same invariant the
|
|
127
|
+
// existing breaker test file exercises for normal summary-LLM throws.
|
|
128
|
+
const circuit = makeCircuit();
|
|
129
|
+
const { onEvent, events } = collectEvents();
|
|
130
|
+
|
|
131
|
+
// First two timeouts — circuit still closed.
|
|
132
|
+
await circuit.recordOutcome(turn, true, onEvent);
|
|
133
|
+
await circuit.recordOutcome(turn, true, onEvent);
|
|
134
|
+
expect(circuit.consecutiveCompactionFailures).toBe(2);
|
|
135
|
+
expect(circuit.compactionCircuitOpenUntil).toBeNull();
|
|
136
|
+
expect(events).toHaveLength(0);
|
|
137
|
+
|
|
138
|
+
// Third timeout — breaker trips and emits the canonical transition event.
|
|
139
|
+
await circuit.recordOutcome(turn, true, onEvent);
|
|
140
|
+
expect(circuit.consecutiveCompactionFailures).toBe(
|
|
141
|
+
COMPACTION_CIRCUIT_FAILURE_THRESHOLD,
|
|
142
|
+
);
|
|
143
|
+
expect(circuit.compactionCircuitOpenUntil).not.toBeNull();
|
|
144
|
+
expect(events).toHaveLength(1);
|
|
145
|
+
expect(events[0]).toEqual({
|
|
146
|
+
type: "compaction_circuit_open",
|
|
147
|
+
conversationId: circuit.conversationId,
|
|
148
|
+
reason: "3_consecutive_failures",
|
|
149
|
+
openUntil: circuit.compactionCircuitOpenUntil as number,
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test("a successful compaction after two timeouts resets the counter", async () => {
|
|
154
|
+
// The recovery path doesn't interfere with the breaker's normal reset —
|
|
155
|
+
// once a compaction call eventually succeeds, the streak is broken and
|
|
156
|
+
// the next failure starts counting from 1.
|
|
157
|
+
const circuit = makeCircuit();
|
|
158
|
+
const { onEvent } = collectEvents();
|
|
159
|
+
|
|
160
|
+
await circuit.recordOutcome(turn, true, onEvent);
|
|
161
|
+
await circuit.recordOutcome(turn, true, onEvent);
|
|
162
|
+
expect(circuit.consecutiveCompactionFailures).toBe(2);
|
|
163
|
+
|
|
164
|
+
await circuit.recordOutcome(turn, false, onEvent);
|
|
165
|
+
expect(circuit.consecutiveCompactionFailures).toBe(0);
|
|
166
|
+
expect(circuit.compactionCircuitOpenUntil).toBeNull();
|
|
167
|
+
|
|
168
|
+
await circuit.recordOutcome(turn, true, onEvent);
|
|
169
|
+
expect(circuit.consecutiveCompactionFailures).toBe(1);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test("compaction call-site recovery remains defense-in-depth even when DEFAULT_TIMEOUTS.compaction is null", () => {
|
|
173
|
+
// At the time this PR landed, `DEFAULT_TIMEOUTS.compaction` was null
|
|
174
|
+
// (pipeline timeouts globally disabled — see #27608). That makes the
|
|
175
|
+
// call-site catch blocks unreachable in production right now, but the
|
|
176
|
+
// catch blocks still matter: any future reintroduction of a per-pipeline
|
|
177
|
+
// compaction timeout immediately benefits from circuit-breaker recording
|
|
178
|
+
// and graceful-degradation without needing to re-touch every call site.
|
|
179
|
+
//
|
|
180
|
+
// This test just documents the current value so a future change that
|
|
181
|
+
// reintroduces a timeout must also decide (intentionally) whether the
|
|
182
|
+
// recovery path should continue to fire.
|
|
183
|
+
const value = DEFAULT_TIMEOUTS.compaction;
|
|
184
|
+
expect(value === null || typeof value === "number").toBe(true);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
describe("abort propagation end-to-end (Part A + updateSummary fallback)", () => {
|
|
189
|
+
beforeEach(() => {
|
|
190
|
+
resetPluginRegistryForTests();
|
|
191
|
+
registerPlugin(defaultCircuitBreakerPlugin);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
afterEach(() => {
|
|
195
|
+
resetPluginRegistryForTests();
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
test("caller-provided signal is replaced with a linked signal that fires on timeout", async () => {
|
|
199
|
+
// Minimal proof that Part A actually wires the signal through the
|
|
200
|
+
// compaction pipeline: when the pipeline runner's timer fires, the
|
|
201
|
+
// signal seen by the inner terminal is aborted — allowing
|
|
202
|
+
// `updateSummary`'s try/catch around `provider.sendMessage` to trigger
|
|
203
|
+
// the local-fallback path instead of the call hanging indefinitely.
|
|
204
|
+
let observedSignal: AbortSignal | undefined;
|
|
205
|
+
const waitForAbort: Middleware<CompactionArgs, CompactionResult> = async (
|
|
206
|
+
args,
|
|
207
|
+
_next,
|
|
208
|
+
) => {
|
|
209
|
+
observedSignal = args.signal;
|
|
210
|
+
return new Promise<CompactionResult>((_resolve, reject) => {
|
|
211
|
+
args.signal?.addEventListener("abort", () => {
|
|
212
|
+
reject(
|
|
213
|
+
Object.assign(new Error("aborted by signal"), {
|
|
214
|
+
name: "AbortError",
|
|
215
|
+
}),
|
|
216
|
+
);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
const callerController = new AbortController();
|
|
222
|
+
|
|
223
|
+
let caught: unknown;
|
|
224
|
+
try {
|
|
225
|
+
await runPipeline<CompactionArgs, CompactionResult>(
|
|
226
|
+
"compaction",
|
|
227
|
+
[waitForAbort, ...getMiddlewaresFor("compaction")],
|
|
228
|
+
async () => ({ compacted: false }) as unknown as CompactionResult,
|
|
229
|
+
{
|
|
230
|
+
messages: [] as unknown,
|
|
231
|
+
signal: callerController.signal,
|
|
232
|
+
options: undefined,
|
|
233
|
+
},
|
|
234
|
+
makeTurnCtx("conv-abort-test"),
|
|
235
|
+
20,
|
|
236
|
+
);
|
|
237
|
+
} catch (err) {
|
|
238
|
+
caught = err;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
expect(caught).toBeInstanceOf(PluginTimeoutError);
|
|
242
|
+
expect(observedSignal).toBeDefined();
|
|
243
|
+
// The runner swaps the caller's signal for a linked signal — the two are
|
|
244
|
+
// distinct objects but both should end up aborted once the timer fires.
|
|
245
|
+
expect(observedSignal).not.toBe(callerController.signal);
|
|
246
|
+
expect(observedSignal!.aborted).toBe(true);
|
|
247
|
+
// Caller's own signal is untouched — pipeline timeout does not cascade
|
|
248
|
+
// outward onto the caller's controller.
|
|
249
|
+
expect(callerController.signal.aborted).toBe(false);
|
|
250
|
+
});
|
|
251
|
+
});
|
|
@@ -145,6 +145,8 @@ function makeCtx(
|
|
|
145
145
|
surfaceActionRequestIds: new Set<string>(),
|
|
146
146
|
currentTurnSurfaces: [],
|
|
147
147
|
workingDir: "/tmp",
|
|
148
|
+
workspaceTopLevelContext: null,
|
|
149
|
+
workspaceTopLevelDirty: false,
|
|
148
150
|
channelCapabilities: undefined,
|
|
149
151
|
commandIntent: undefined,
|
|
150
152
|
trustContext: undefined,
|
|
@@ -170,6 +172,7 @@ function makeCtx(
|
|
|
170
172
|
hasNoClient: false,
|
|
171
173
|
prompter: {} as Context["prompter"],
|
|
172
174
|
queue: {} as Context["queue"],
|
|
175
|
+
refreshWorkspaceTopLevelContextIfNeeded: () => {},
|
|
173
176
|
markWorkspaceTopLevelDirty: () => {},
|
|
174
177
|
emitActivityState: () => {},
|
|
175
178
|
getQueueDepth: () => 0,
|
|
@@ -435,6 +435,8 @@ function makeCtx(
|
|
|
435
435
|
currentTurnSurfaces: [],
|
|
436
436
|
|
|
437
437
|
workingDir: "/tmp",
|
|
438
|
+
workspaceTopLevelContext: null,
|
|
439
|
+
workspaceTopLevelDirty: false,
|
|
438
440
|
channelCapabilities: undefined,
|
|
439
441
|
commandIntent: undefined,
|
|
440
442
|
trustContext: undefined,
|
|
@@ -471,6 +473,7 @@ function makeCtx(
|
|
|
471
473
|
getWorkspaceGitService: () => ({ ensureInitialized: async () => {} }),
|
|
472
474
|
commitTurnChanges: async () => {},
|
|
473
475
|
|
|
476
|
+
refreshWorkspaceTopLevelContextIfNeeded: () => {},
|
|
474
477
|
markWorkspaceTopLevelDirty: () => {},
|
|
475
478
|
emitActivityState: () => {},
|
|
476
479
|
getQueueDepth: () => 0,
|
|
@@ -515,6 +515,8 @@ function makeCtx(
|
|
|
515
515
|
currentTurnSurfaces: [],
|
|
516
516
|
|
|
517
517
|
workingDir: "/tmp",
|
|
518
|
+
workspaceTopLevelContext: null,
|
|
519
|
+
workspaceTopLevelDirty: false,
|
|
518
520
|
channelCapabilities: undefined,
|
|
519
521
|
commandIntent: undefined,
|
|
520
522
|
trustContext: undefined,
|
|
@@ -551,6 +553,7 @@ function makeCtx(
|
|
|
551
553
|
getWorkspaceGitService: () => ({ ensureInitialized: async () => {} }),
|
|
552
554
|
commitTurnChanges: async () => {},
|
|
553
555
|
|
|
556
|
+
refreshWorkspaceTopLevelContextIfNeeded: () => {},
|
|
554
557
|
markWorkspaceTopLevelDirty: () => {},
|
|
555
558
|
emitActivityState: () => {},
|
|
556
559
|
getQueueDepth: () => 0,
|
|
@@ -648,9 +651,10 @@ beforeEach(() => {
|
|
|
648
651
|
recordUsageMock.mockClear();
|
|
649
652
|
setAgentLoopExitReasonOnLatestLogMock.mockClear();
|
|
650
653
|
addMessageMock.mockClear();
|
|
651
|
-
// Reset the plugin registry and re-register every default so the
|
|
652
|
-
//
|
|
653
|
-
//
|
|
654
|
+
// Reset the plugin registry and re-register every default so the
|
|
655
|
+
// orchestrator's pipelines (`overflowReduce`, `persistence`, …) dispatch to
|
|
656
|
+
// the default middleware, which in turn hits the mocked collaborators
|
|
657
|
+
// (`reduceContextOverflow`, `syncMessageToDisk`, …) these tests install.
|
|
654
658
|
resetPluginRegistryAndRegisterDefaults();
|
|
655
659
|
});
|
|
656
660
|
|
|
@@ -316,14 +316,12 @@ const buildUnifiedTurnContextBlockMock = mock(
|
|
|
316
316
|
(options: Record<string, unknown>) =>
|
|
317
317
|
`<turn_context>\ncurrent_time: ${String(options.timestamp)}\n</turn_context>`,
|
|
318
318
|
);
|
|
319
|
-
const
|
|
320
|
-
msgs: Message[],
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
});
|
|
326
|
-
const applyRuntimeInjectionsMock = mock(defaultApplyRuntimeInjectionsImpl);
|
|
319
|
+
const applyRuntimeInjectionsMock = mock(
|
|
320
|
+
async (msgs: Message[], _options?: unknown) => ({
|
|
321
|
+
messages: msgs,
|
|
322
|
+
blocks: { ...mockInjectionBlocks },
|
|
323
|
+
}),
|
|
324
|
+
);
|
|
327
325
|
let mockSlackChronologicalContext: {
|
|
328
326
|
renderedMessages: Array<{
|
|
329
327
|
message: Message;
|
|
@@ -638,6 +636,8 @@ function makeCtx(
|
|
|
638
636
|
currentTurnSurfaces: [],
|
|
639
637
|
|
|
640
638
|
workingDir: "/tmp",
|
|
639
|
+
workspaceTopLevelContext: null,
|
|
640
|
+
workspaceTopLevelDirty: false,
|
|
641
641
|
channelCapabilities: undefined,
|
|
642
642
|
commandIntent: undefined,
|
|
643
643
|
trustContext: undefined,
|
|
@@ -674,6 +674,7 @@ function makeCtx(
|
|
|
674
674
|
getWorkspaceGitService: () => ({ ensureInitialized: async () => {} }),
|
|
675
675
|
commitTurnChanges: async () => {},
|
|
676
676
|
|
|
677
|
+
refreshWorkspaceTopLevelContextIfNeeded: () => {},
|
|
677
678
|
markWorkspaceTopLevelDirty: () => {},
|
|
678
679
|
emitActivityState: () => {},
|
|
679
680
|
getQueueDepth: () => 0,
|
|
@@ -743,9 +744,6 @@ beforeEach(() => {
|
|
|
743
744
|
setConversationHistoryStrippedAtMock.mockClear();
|
|
744
745
|
setConversationHistoryStrippedAtMock.mockImplementation(() => {});
|
|
745
746
|
applyRuntimeInjectionsMock.mockClear();
|
|
746
|
-
applyRuntimeInjectionsMock.mockImplementation(
|
|
747
|
-
defaultApplyRuntimeInjectionsImpl,
|
|
748
|
-
);
|
|
749
747
|
buildUnifiedTurnContextBlockMock.mockClear();
|
|
750
748
|
resolveTurnTimezoneContextMock.mockClear();
|
|
751
749
|
formatTurnTimestampMock.mockClear();
|
|
@@ -759,10 +757,11 @@ beforeEach(() => {
|
|
|
759
757
|
projectAssistantMessageMock.mockClear();
|
|
760
758
|
publishSyncInvalidationMock.mockClear();
|
|
761
759
|
mockMessageById = null;
|
|
762
|
-
//
|
|
763
|
-
// re-register every default so
|
|
764
|
-
// mocked collaborators these tests
|
|
765
|
-
//
|
|
760
|
+
// Orchestrator pipelines (overflowReduce, persistence, …) run through the
|
|
761
|
+
// plugin registry; reset and re-register every default so the pipelines
|
|
762
|
+
// dispatch to middleware backed by the mocked collaborators these tests
|
|
763
|
+
// install (`reduceContextOverflow`, `syncMessageToDisk`, etc.) instead of
|
|
764
|
+
// hitting the bare terminals.
|
|
766
765
|
resetPluginRegistryAndRegisterDefaults();
|
|
767
766
|
});
|
|
768
767
|
|
|
@@ -881,23 +880,7 @@ describe("session-agent-loop", () => {
|
|
|
881
880
|
});
|
|
882
881
|
|
|
883
882
|
describe("disk pressure injection context", () => {
|
|
884
|
-
|
|
885
|
-
// turn (the disk-pressure-warning injector reads it via the per-conversation
|
|
886
|
-
// registry) and resets it in the turn-end cleanup path. Snapshot the flag at
|
|
887
|
-
// each `applyRuntimeInjections` call so assertions observe its value while
|
|
888
|
-
// injection runs, not the post-turn reset.
|
|
889
|
-
function captureCleanupFlagDuringInjection(ctx: {
|
|
890
|
-
diskPressureCleanupModeActive?: boolean;
|
|
891
|
-
}): () => Array<boolean | undefined> {
|
|
892
|
-
const observed: Array<boolean | undefined> = [];
|
|
893
|
-
applyRuntimeInjectionsMock.mockImplementation(async (msgs: Message[]) => {
|
|
894
|
-
observed.push(ctx.diskPressureCleanupModeActive);
|
|
895
|
-
return { messages: msgs, blocks: { ...mockInjectionBlocks } };
|
|
896
|
-
});
|
|
897
|
-
return () => observed;
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
test("sets the cleanup-mode flag on the conversation for cleanup-mode turns", async () => {
|
|
883
|
+
test("passes cleanup context into runtime injections for cleanup-mode turns", async () => {
|
|
901
884
|
mockDiskPressureDecision = {
|
|
902
885
|
action: "allow-cleanup-mode",
|
|
903
886
|
reason: "guardian",
|
|
@@ -920,7 +903,6 @@ describe("session-agent-loop", () => {
|
|
|
920
903
|
trustClass: "guardian",
|
|
921
904
|
} as AgentLoopConversationContext["trustContext"],
|
|
922
905
|
});
|
|
923
|
-
const cleanupFlagDuringInjection = captureCleanupFlagDuringInjection(ctx);
|
|
924
906
|
|
|
925
907
|
await runAgentLoopImpl(ctx, "free up space", "msg-1", () => {});
|
|
926
908
|
|
|
@@ -939,16 +921,21 @@ describe("session-agent-loop", () => {
|
|
|
939
921
|
},
|
|
940
922
|
}),
|
|
941
923
|
);
|
|
942
|
-
|
|
924
|
+
const firstInjectionOptions = applyRuntimeInjectionsMock.mock
|
|
925
|
+
.calls[0]![1] as {
|
|
926
|
+
diskPressureContext?: { cleanupModeActive: boolean } | null;
|
|
927
|
+
};
|
|
928
|
+
expect(firstInjectionOptions.diskPressureContext).toEqual({
|
|
929
|
+
cleanupModeActive: true,
|
|
930
|
+
});
|
|
943
931
|
});
|
|
944
932
|
|
|
945
|
-
test("
|
|
933
|
+
test("passes cleanup context into runtime injections for local-owner turns", async () => {
|
|
946
934
|
mockDiskPressureDecision = {
|
|
947
935
|
action: "allow-cleanup-mode",
|
|
948
936
|
reason: "local-owner",
|
|
949
937
|
};
|
|
950
938
|
const ctx = makeCtx();
|
|
951
|
-
const cleanupFlagDuringInjection = captureCleanupFlagDuringInjection(ctx);
|
|
952
939
|
|
|
953
940
|
await runAgentLoopImpl(ctx, "free up space", "msg-1", () => {});
|
|
954
941
|
|
|
@@ -960,10 +947,16 @@ describe("session-agent-loop", () => {
|
|
|
960
947
|
trustContext: null,
|
|
961
948
|
}),
|
|
962
949
|
);
|
|
963
|
-
|
|
950
|
+
const firstInjectionOptions = applyRuntimeInjectionsMock.mock
|
|
951
|
+
.calls[0]![1] as {
|
|
952
|
+
diskPressureContext?: { cleanupModeActive: boolean } | null;
|
|
953
|
+
};
|
|
954
|
+
expect(firstInjectionOptions.diskPressureContext).toEqual({
|
|
955
|
+
cleanupModeActive: true,
|
|
956
|
+
});
|
|
964
957
|
});
|
|
965
958
|
|
|
966
|
-
test("keeps
|
|
959
|
+
test("keeps cleanup context on overflow recovery reinjection", async () => {
|
|
967
960
|
mockDiskPressureDecision = {
|
|
968
961
|
action: "allow-cleanup-mode",
|
|
969
962
|
reason: "guardian",
|
|
@@ -985,14 +978,18 @@ describe("session-agent-loop", () => {
|
|
|
985
978
|
trustClass: "guardian",
|
|
986
979
|
} as AgentLoopConversationContext["trustContext"],
|
|
987
980
|
});
|
|
988
|
-
const cleanupFlagDuringInjection = captureCleanupFlagDuringInjection(ctx);
|
|
989
981
|
|
|
990
982
|
await runAgentLoopImpl(ctx, "free up space", "msg-1", () => {});
|
|
991
983
|
|
|
992
984
|
expect(applyRuntimeInjectionsMock.mock.calls.length).toBeGreaterThan(1);
|
|
993
|
-
const
|
|
994
|
-
|
|
995
|
-
|
|
985
|
+
for (const call of applyRuntimeInjectionsMock.mock.calls) {
|
|
986
|
+
const options = call[1] as {
|
|
987
|
+
diskPressureContext?: { cleanupModeActive: boolean } | null;
|
|
988
|
+
};
|
|
989
|
+
expect(options.diskPressureContext).toEqual({
|
|
990
|
+
cleanupModeActive: true,
|
|
991
|
+
});
|
|
992
|
+
}
|
|
996
993
|
});
|
|
997
994
|
|
|
998
995
|
test("blocks policy-denied turns before runtime injection or model execution", async () => {
|
|
@@ -120,7 +120,7 @@ describe("stripInjectionsForCompaction preserves history shape", () => {
|
|
|
120
120
|
expect(out[3]).toEqual(messages[3]);
|
|
121
121
|
});
|
|
122
122
|
|
|
123
|
-
test("
|
|
123
|
+
test("leaves <turn_context>, <workspace>, and <memory __injected> alone", () => {
|
|
124
124
|
const messages: Message[] = [
|
|
125
125
|
{
|
|
126
126
|
role: "user",
|
|
@@ -132,9 +132,6 @@ describe("stripInjectionsForCompaction preserves history shape", () => {
|
|
|
132
132
|
},
|
|
133
133
|
];
|
|
134
134
|
const out = stripInjectionsForCompaction(messages);
|
|
135
|
-
expect(out[0].content).toEqual([
|
|
136
|
-
{ type: "text", text: "<turn_context>\nnow\n</turn_context>" },
|
|
137
|
-
{ type: "text", text: "<memory __injected>\nrecent\n</memory>" },
|
|
138
|
-
]);
|
|
135
|
+
expect(out[0].content).toEqual(messages[0].content);
|
|
139
136
|
});
|
|
140
137
|
});
|
|
@@ -486,10 +486,11 @@ describe("provider ordering error retry", () => {
|
|
|
486
486
|
firstRunErrorMode = "ordering";
|
|
487
487
|
maybeCompactCalls = [];
|
|
488
488
|
forceCompactionEnabled = false;
|
|
489
|
-
//
|
|
490
|
-
// every default so
|
|
491
|
-
//
|
|
492
|
-
//
|
|
489
|
+
// Orchestrator pipelines (`overflowReduce`, `persistence`, …) run through
|
|
490
|
+
// the plugin registry; re-register every default so each pipeline has a
|
|
491
|
+
// middleware to dispatch to. The `context-overflow-reducer` module itself
|
|
492
|
+
// (and other collaborators) are mocked above, so the default plugins'
|
|
493
|
+
// delegates go through the mocked implementations.
|
|
493
494
|
resetPluginRegistryAndRegisterDefaults();
|
|
494
495
|
});
|
|
495
496
|
|