@moxxy/sdk 0.26.0 → 0.28.0

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.
Files changed (78) hide show
  1. package/dist/channel.d.ts +13 -0
  2. package/dist/channel.d.ts.map +1 -1
  3. package/dist/channel.js +19 -0
  4. package/dist/channel.js.map +1 -1
  5. package/dist/event-store.d.ts +5 -1
  6. package/dist/event-store.d.ts.map +1 -1
  7. package/dist/event-store.js +24 -1
  8. package/dist/event-store.js.map +1 -1
  9. package/dist/events.d.ts +9 -3
  10. package/dist/events.d.ts.map +1 -1
  11. package/dist/first-party.d.ts +17 -0
  12. package/dist/first-party.d.ts.map +1 -0
  13. package/dist/first-party.js +19 -0
  14. package/dist/first-party.js.map +1 -0
  15. package/dist/index.d.ts +9 -5
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +12 -5
  18. package/dist/index.js.map +1 -1
  19. package/dist/isolation.d.ts +14 -0
  20. package/dist/isolation.d.ts.map +1 -1
  21. package/dist/isolation.js +75 -0
  22. package/dist/isolation.js.map +1 -1
  23. package/dist/mode/checkpoint.d.ts +107 -0
  24. package/dist/mode/checkpoint.d.ts.map +1 -0
  25. package/dist/mode/checkpoint.js +2 -0
  26. package/dist/mode/checkpoint.js.map +1 -0
  27. package/dist/mode/react-loop.d.ts +129 -0
  28. package/dist/mode/react-loop.d.ts.map +1 -0
  29. package/dist/mode/react-loop.js +480 -0
  30. package/dist/mode/react-loop.js.map +1 -0
  31. package/dist/mode/stuck-loop.d.ts +7 -0
  32. package/dist/mode/stuck-loop.d.ts.map +1 -1
  33. package/dist/mode/stuck-loop.js +4 -0
  34. package/dist/mode/stuck-loop.js.map +1 -1
  35. package/dist/mode-helpers.d.ts +4 -0
  36. package/dist/mode-helpers.d.ts.map +1 -1
  37. package/dist/mode-helpers.js +3 -0
  38. package/dist/mode-helpers.js.map +1 -1
  39. package/dist/mode.d.ts +43 -2
  40. package/dist/mode.d.ts.map +1 -1
  41. package/dist/mode.js.map +1 -1
  42. package/dist/plugin.d.ts +10 -1
  43. package/dist/plugin.d.ts.map +1 -1
  44. package/dist/reflector.d.ts +58 -0
  45. package/dist/reflector.d.ts.map +1 -0
  46. package/dist/reflector.js +2 -0
  47. package/dist/reflector.js.map +1 -0
  48. package/dist/schemas.d.ts +215 -8
  49. package/dist/schemas.d.ts.map +1 -1
  50. package/dist/schemas.js +37 -0
  51. package/dist/schemas.js.map +1 -1
  52. package/dist/session-like.d.ts +52 -0
  53. package/dist/session-like.d.ts.map +1 -1
  54. package/dist/tool-dispatch.d.ts +35 -1
  55. package/dist/tool-dispatch.d.ts.map +1 -1
  56. package/dist/tool-dispatch.js +51 -0
  57. package/dist/tool-dispatch.js.map +1 -1
  58. package/package.json +1 -1
  59. package/src/channel.ts +25 -0
  60. package/src/event-store.ts +16 -1
  61. package/src/events.ts +9 -2
  62. package/src/exit-after-pair.test.ts +32 -0
  63. package/src/first-party.test.ts +26 -0
  64. package/src/first-party.ts +19 -0
  65. package/src/index.ts +32 -4
  66. package/src/isolation-aggregate.test.ts +69 -0
  67. package/src/isolation.ts +67 -0
  68. package/src/mode/checkpoint.ts +105 -0
  69. package/src/mode/react-loop.ts +694 -0
  70. package/src/mode/stuck-loop.ts +11 -0
  71. package/src/mode-helpers.ts +16 -0
  72. package/src/mode.ts +43 -2
  73. package/src/plugin.ts +10 -1
  74. package/src/reflector.ts +61 -0
  75. package/src/schemas.ts +41 -0
  76. package/src/session-like.ts +49 -0
  77. package/src/tool-dispatch.test.ts +77 -0
  78. package/src/tool-dispatch.ts +82 -1
@@ -0,0 +1,480 @@
1
+ import { isContextOverflowError, runCompactionIfNeeded } from '../compactor-helpers.js';
2
+ import { runElisionIfNeeded } from '../elision-helpers.js';
3
+ import { asPluginId } from '../ids.js';
4
+ import { usageEventFields } from '../token-accounting.js';
5
+ import { emitRequestsAndDetectStuck, emitRequestsAndNudgeOnStuck, executeToolUses, } from '../tool-dispatch.js';
6
+ import { nextBackoffMs, sleepWithAbort } from './abort-backoff.js';
7
+ import { collectProviderStream } from './collect-stream.js';
8
+ import { buildSystemPromptWithSkills, projectMessages } from './project-messages.js';
9
+ import { createStuckLoopDetector } from './stuck-loop.js';
10
+ /**
11
+ * The shared ReAct loop core every tool-calling mode runs on. One hardened
12
+ * copy of the plumbing that used to be duplicated per mode (default / goal /
13
+ * collab-agent): provider retry with bounded exponential back-off, reactive
14
+ * compaction on context overflow, turn-boundary elision, stuck-loop
15
+ * detection, abort handling on every await — plus the turn-end checkpoint
16
+ * gate ({@link TurnCheckpoint}) that lets a mode verify a completion claim
17
+ * (run lints, spawn a reviewer agent) before the turn is allowed to end.
18
+ *
19
+ * Modes express their POLICY through {@link ReactLoopOptions}: hooks fire at
20
+ * fixed points (iteration start, provider success, tool batch end, iteration
21
+ * cap) and checkpoints fire at the turn-end candidate. Hooks emit their own
22
+ * events via `ctx.emit` — the live event channel is the log subscription
23
+ * (`runTurn` discards the yielded stream), so emit order is what channels
24
+ * and tests observe.
25
+ */
26
+ /** Bounded back-off for retryable provider errors — see the field docs. */
27
+ export const MAX_CONSECUTIVE_RETRIES = 6;
28
+ const RETRY_BACKOFF_BASE_MS = 500;
29
+ const RETRY_BACKOFF_CAP_MS = 30_000;
30
+ const DEFAULT_MAX_ITERATIONS = 500;
31
+ const MAX_REACTIVE_COMPACTIONS = 2;
32
+ const DEFAULT_MAX_INJECTIONS = 3;
33
+ const DEFAULT_MAX_INJECT_CHARS = 16_384;
34
+ const DEFAULT_CHECKPOINT_TIMEOUT_MS = 120_000;
35
+ const CHECKPOINT_EVENT_PLUGIN_ID = asPluginId('react-loop');
36
+ // Abort-aware sleep, injectable for tests so back-off paths run instantly and
37
+ // deterministically. Production delegates to sleepWithAbort: a real timer that
38
+ // clears (and drops its abort listener) when the signal fires, so a pending
39
+ // back-off never outlives a cancelled turn.
40
+ let sleepImpl = (ms, signal) => sleepWithAbort(ms, signal);
41
+ /**
42
+ * Override the retry back-off sleep (test seam). Returns a restore fn that
43
+ * callers MUST invoke (in a `finally`) — `sleepImpl` is a module-scoped
44
+ * singleton shared process-wide, so a leaked override bleeds the fake sleep
45
+ * into every other turn/test running in the same worker (parallel subagent
46
+ * fan-out, multiple Sessions in one host). Test-only; never call from prod.
47
+ */
48
+ export function __setRetrySleepForTests(fn) {
49
+ const prev = sleepImpl;
50
+ sleepImpl = fn;
51
+ return () => {
52
+ sleepImpl = prev;
53
+ };
54
+ }
55
+ export async function* runReactLoop(ctx, opts) {
56
+ if (opts.preflightAbortReason && ctx.signal.aborted) {
57
+ yield await emitAbort(ctx, opts.preflightAbortReason);
58
+ return;
59
+ }
60
+ // Coerce a caller/config-supplied bound to a positive integer; a degenerate
61
+ // value (0, negative, NaN, fractional) would otherwise make the loop never
62
+ // run and emit a misleading "exceeded maxIterations" fatal. The config
63
+ // schema validates this, but programmatic callers (subagents/workflows)
64
+ // bypass that schema.
65
+ const requestedMaxIterations = ctx.maxIterations;
66
+ const maxIterations = typeof requestedMaxIterations === 'number' && Number.isFinite(requestedMaxIterations)
67
+ ? Math.max(1, Math.floor(requestedMaxIterations))
68
+ : (opts.defaultMaxIterations ?? DEFAULT_MAX_ITERATIONS);
69
+ const detector = createStuckLoopDetector(ctx.loopGuard);
70
+ const stuckReport = buildStuckReport(opts);
71
+ const prefix = opts.errorPrefix ?? '';
72
+ // Recursion backstop: a checkpoint that spawns a child running a
73
+ // checkpoint-bearing mode would gate the child's turn-end, spawn a
74
+ // grandchild, and so on forever. Checkpoint authors should spawn children
75
+ // as `mode: 'default'`; this disarm means a mistake degrades to an ungated
76
+ // child instead of unbounded recursion.
77
+ const checkpoints = ctx.isSubagent ? [] : (opts.checkpoints ?? []);
78
+ const injectionBudget = Math.max(0, Math.floor(opts.maxInjections ?? DEFAULT_MAX_INJECTIONS));
79
+ const maxInjectChars = Math.max(1024, Math.floor(opts.maxInjectChars ?? DEFAULT_MAX_INJECT_CHARS));
80
+ let injectionsUsed = 0;
81
+ let consecutiveIdle = 0;
82
+ // A volatile injection from the previous round's checkpoint (goal's nudge),
83
+ // consumed by the next provider call only.
84
+ let pendingVolatileText;
85
+ // Reactive-compaction budget per overflow episode and consecutive
86
+ // retryable-error count; both reset on any clean provider call so a long
87
+ // turn can recover from multiple transient episodes.
88
+ let reactiveCompactions = 0;
89
+ let consecutiveRetries = 0;
90
+ for (let iteration = 1; iteration <= maxIterations; iteration++) {
91
+ if (ctx.signal.aborted) {
92
+ yield await emitAbort(ctx, 'signal aborted');
93
+ return;
94
+ }
95
+ yield await ctx.emit({
96
+ type: 'mode_iteration',
97
+ sessionId: ctx.sessionId,
98
+ turnId: ctx.turnId,
99
+ source: 'system',
100
+ strategy: opts.strategyName,
101
+ iteration,
102
+ });
103
+ // Auto-compact before composing the next provider request, then apply
104
+ // turn-boundary elision (context-on-demand). Both mutate the log's
105
+ // projection, not the loop's state.
106
+ await runCompactionIfNeeded(ctx);
107
+ await runElisionIfNeeded(ctx);
108
+ const hookStart = opts.onIterationStart
109
+ ? await opts.onIterationStart(ctx, iteration)
110
+ : undefined;
111
+ // At most ONE volatile trailing user message per call: a pending
112
+ // checkpoint nudge and an iteration-start note merge into it.
113
+ const volatileParts = [pendingVolatileText, hookStart?.volatileUserText].filter((s) => typeof s === 'string' && s.length > 0);
114
+ pendingVolatileText = undefined;
115
+ const volatileText = volatileParts.length > 0 ? volatileParts.join('\n\n') : undefined;
116
+ // onIterationStart may block for a long time (collab's cooperative-pause
117
+ // poll idles here until the human resumes) — re-check the signal so an
118
+ // abort during the hook ends the turn cleanly instead of burning a
119
+ // provider call that is already cancelled.
120
+ if (ctx.signal.aborted) {
121
+ yield await emitAbort(ctx, 'signal aborted');
122
+ return;
123
+ }
124
+ const systemPrompt = buildSystemPromptWithSkills(ctx.systemPrompt, ctx.skills.list());
125
+ const { messages, stablePrefixIndex } = projectMessages(ctx, {
126
+ ...(systemPrompt ? { systemPrompt } : {}),
127
+ ...(volatileText ? { trailingUserText: volatileText } : {}),
128
+ });
129
+ yield await ctx.emit({
130
+ type: 'provider_request',
131
+ sessionId: ctx.sessionId,
132
+ turnId: ctx.turnId,
133
+ source: 'system',
134
+ provider: ctx.provider.name,
135
+ model: ctx.model,
136
+ });
137
+ const { text, toolUses, stopReason, error, usage, reasoning } = await collectProviderStream(ctx, messages, {
138
+ iteration,
139
+ stablePrefixIndex,
140
+ // Volatile text is injected for this call only, never appended to the
141
+ // log — the cache strategy must keep its rolling tail breakpoint
142
+ // BEFORE it, or every such call caches a prefix ending in a message
143
+ // that won't exist at that position next call: a guaranteed-wasted
144
+ // cache write.
145
+ ...(volatileText ? { volatileTailCount: 1 } : {}),
146
+ });
147
+ // A user cancellation WHILE the provider stream was being consumed
148
+ // surfaces as a non-retryable provider `error` ("The operation was
149
+ // aborted") rather than a clean abort — collectProviderStream catches the
150
+ // fetch AbortError and classifies it as fatal. Treat it as the
151
+ // cancellation it is so channels render a 'stopped' turn, not a failed one.
152
+ if (ctx.signal.aborted) {
153
+ yield await emitAbort(ctx, 'signal aborted during provider stream');
154
+ return;
155
+ }
156
+ yield await ctx.emit({
157
+ type: 'provider_response',
158
+ sessionId: ctx.sessionId,
159
+ turnId: ctx.turnId,
160
+ source: 'system',
161
+ provider: ctx.provider.name,
162
+ model: ctx.model,
163
+ ...usageEventFields(usage),
164
+ });
165
+ if (error) {
166
+ const overflow = isContextOverflowError(error.message);
167
+ // The request was too big for the model's window: our token estimate
168
+ // lagged the provider's real tokenizer, so the proactive compactor
169
+ // didn't fire. Force a compaction and retry rather than dying.
170
+ if (overflow && reactiveCompactions < MAX_REACTIVE_COMPACTIONS) {
171
+ const compacted = await runCompactionIfNeeded(ctx, { force: true });
172
+ if (compacted) {
173
+ // Only count an attempt that actually compacted against the budget —
174
+ // a no-op (overflow lives in the un-compactable recent tail) must
175
+ // not deny a later, genuinely compactable overflow its retry.
176
+ reactiveCompactions += 1;
177
+ yield await emitError(ctx, 'retryable', 'context window exceeded — compacted older turns, retrying');
178
+ continue;
179
+ }
180
+ }
181
+ // A context overflow that can't be compacted further is fatal regardless
182
+ // of the provider's `retryable` flag: some providers mark "reduce the
183
+ // length" errors retryable, but the prompt cannot shrink, so a retry
184
+ // just re-sends the identical over-budget request and overflows again.
185
+ if (!error.retryable || overflow) {
186
+ yield await emitError(ctx, 'fatal', `${prefix}${error.message}`);
187
+ return;
188
+ }
189
+ // Retryable: surface it, then back off before retrying. A persistent
190
+ // retryable condition (sustained 429 / outage) must NOT busy-loop the
191
+ // provider — give up with a fatal error after the bounded retry count.
192
+ consecutiveRetries += 1;
193
+ yield await emitError(ctx, 'retryable', `${prefix}${error.message}`);
194
+ if (consecutiveRetries >= MAX_CONSECUTIVE_RETRIES) {
195
+ yield await emitError(ctx, 'fatal', `${prefix}provider kept returning a retryable error ${consecutiveRetries} times in a row ` +
196
+ `(last: ${error.message}); giving up rather than hammering the provider.`);
197
+ return;
198
+ }
199
+ await sleepImpl(nextBackoffMs(consecutiveRetries, RETRY_BACKOFF_BASE_MS, RETRY_BACKOFF_CAP_MS), ctx.signal);
200
+ if (ctx.signal.aborted) {
201
+ yield await emitAbort(ctx, 'signal aborted during retry back-off');
202
+ return;
203
+ }
204
+ continue;
205
+ }
206
+ // Clean provider call — reset the overflow-recovery + retry budgets.
207
+ reactiveCompactions = 0;
208
+ consecutiveRetries = 0;
209
+ // Finalize the reasoning summary for THIS call BEFORE any exit decision or
210
+ // tool/assistant emits, so the log order is reasoning → tool_use → text
211
+ // (projection attaches the signed thinking block as content[0] of the
212
+ // same assistant turn) and every exit path logs it consistently.
213
+ if (reasoning) {
214
+ yield await ctx.emit({
215
+ type: 'reasoning_message',
216
+ sessionId: ctx.sessionId,
217
+ turnId: ctx.turnId,
218
+ source: 'model',
219
+ content: reasoning.text,
220
+ ...(reasoning.signature ? { signature: reasoning.signature } : {}),
221
+ ...(reasoning.redacted ? { redacted: true } : {}),
222
+ ...(reasoning.encrypted ? { encrypted: reasoning.encrypted } : {}),
223
+ });
224
+ }
225
+ if (opts.onProviderSuccess) {
226
+ const directive = await opts.onProviderSuccess(ctx, {
227
+ text,
228
+ stopReason,
229
+ toolUses,
230
+ ...(usage ? { usage } : {}),
231
+ iteration,
232
+ });
233
+ if (directive?.action === 'stop')
234
+ return;
235
+ }
236
+ if (opts.stuck?.action === 'nudge') {
237
+ const trip = yield* emitRequestsAndNudgeOnStuck(ctx, toolUses, detector, {
238
+ nearHint: stuckReport.nearHint,
239
+ warnMessage: (info) => `${opts.strategyName} loop noticed a repetitive pattern: tool "${info.toolName}" called ` +
240
+ `${info.count} times ${info.how} — steering the model to change approach (the run continues).`,
241
+ ...(stuckReport.extraOnStuck ? { extraOnStuck: stuckReport.extraOnStuck } : {}),
242
+ });
243
+ if (trip) {
244
+ const nudge = opts.stuck.nudgeText?.(trip) ?? defaultStuckNudge(trip);
245
+ // Ride the NEXT provider call; merge with anything already pending.
246
+ pendingVolatileText = pendingVolatileText ? `${pendingVolatileText}\n\n${nudge}` : nudge;
247
+ }
248
+ }
249
+ else {
250
+ const stuck = yield* emitRequestsAndDetectStuck(ctx, toolUses, detector, stuckReport);
251
+ // A stuck trip kills the turn — it never reaches the checkpoint gate;
252
+ // gating a turn that is being aborted would just burn a checker run.
253
+ if (stuck)
254
+ return;
255
+ }
256
+ if (text || stopReason === 'end_turn' || toolUses.length === 0) {
257
+ // A completion with no text, no tool uses, and a non-natural stop (e.g.
258
+ // 'max_tokens' truncated to nothing) yields a blank assistant bubble
259
+ // that silently swallows the truncation signal. Surface a retryable
260
+ // note so the user sees why, alongside the (preserved) empty
261
+ // assistant_message.
262
+ if (!text && toolUses.length === 0 && stopReason !== 'end_turn') {
263
+ yield await emitError(ctx, 'retryable', `provider returned an empty completion (stopReason: ${stopReason ?? 'unknown'})`);
264
+ }
265
+ yield await ctx.emit({
266
+ type: 'assistant_message',
267
+ sessionId: ctx.sessionId,
268
+ turnId: ctx.turnId,
269
+ source: 'model',
270
+ content: text,
271
+ stopReason,
272
+ });
273
+ }
274
+ if (toolUses.length === 0) {
275
+ // ── The turn-end candidate: the model stopped calling tools. ──
276
+ consecutiveIdle += 1;
277
+ const verdict = yield* runCheckpointGate(ctx, checkpoints, {
278
+ candidateText: text,
279
+ stopReason,
280
+ iteration,
281
+ consecutiveIdle,
282
+ injectionsUsed,
283
+ injectionBudget,
284
+ maxInjectChars,
285
+ });
286
+ if (verdict.kind === 'end')
287
+ return;
288
+ injectionsUsed += 1;
289
+ if (verdict.volatileText !== undefined)
290
+ pendingVolatileText = verdict.volatileText;
291
+ continue;
292
+ }
293
+ consecutiveIdle = 0;
294
+ // The injection budget is per idle-EPISODE, not per turn: it exists to
295
+ // stop a permanently-failing gate from looping a turn that makes no
296
+ // progress. Once the model does real tool work again the episode is over —
297
+ // without this reset, a long unattended run died on its Nth *spread-out*
298
+ // idle round ("checkpoint budget exhausted") even though every earlier
299
+ // nudge had successfully put the model back to work.
300
+ injectionsUsed = 0;
301
+ // Execute whenever the model requested tools, regardless of stopReason.
302
+ // Providers vary in how reliably they report `stopReason: 'tool_use'`;
303
+ // trusting only stopReason silently dropped tool calls on providers that
304
+ // mis-map it, leaving orphaned tool_call_requested events.
305
+ const exited = yield* executeToolUses(ctx, toolUses, iteration);
306
+ if (exited)
307
+ return;
308
+ if (opts.onToolBatchEnd) {
309
+ const directive = await opts.onToolBatchEnd(ctx, { toolUses, iteration });
310
+ if (directive?.action === 'stop')
311
+ return;
312
+ }
313
+ }
314
+ if (opts.onMaxIterations) {
315
+ await opts.onMaxIterations(ctx, maxIterations);
316
+ return;
317
+ }
318
+ yield await emitError(ctx, 'fatal', `${opts.strategyName} mode loop exceeded maxIterations (${maxIterations})`);
319
+ }
320
+ async function* runCheckpointGate(ctx, checkpoints, round) {
321
+ // Natural completions face every checkpoint; truncated/errored candidates
322
+ // only face the idle-tolerant ones — reviewing a half-sentence as if it
323
+ // were a completion claim wastes a checker run and confuses the model.
324
+ const eligible = checkpoints.filter((cp) => round.stopReason === 'end_turn' || (cp.gateOn ?? 'end_turn') === 'idle');
325
+ if (eligible.length === 0)
326
+ return { kind: 'end' };
327
+ // Budget exhausted → the answer ships as-is, but LOUDLY: silent
328
+ // degradation would let the user believe a gated answer passed its gates.
329
+ if (round.injectionsUsed >= round.injectionBudget) {
330
+ yield await emitError(ctx, 'retryable', `checkpoint budget exhausted (${round.injectionBudget} rounds) — ` +
331
+ `ending the turn with unresolved checkpoint feedback; verify the result manually.`);
332
+ return { kind: 'end' };
333
+ }
334
+ for (const cp of eligible) {
335
+ // User cancelled mid-gate: end the turn WITHOUT retracting the
336
+ // already-logged answer — an abort must never un-say what was said.
337
+ if (ctx.signal.aborted)
338
+ return { kind: 'end' };
339
+ yield await emitCheckpointEvent(ctx, 'checkpoint_started', {
340
+ name: cp.name,
341
+ iteration: round.iteration,
342
+ });
343
+ const timeoutMs = Math.max(1_000, cp.timeoutMs ?? DEFAULT_CHECKPOINT_TIMEOUT_MS);
344
+ const timeoutCtl = new AbortController();
345
+ const timer = setTimeout(() => timeoutCtl.abort(), timeoutMs);
346
+ timer.unref?.();
347
+ let result;
348
+ try {
349
+ result = await cp.run({
350
+ candidateText: round.candidateText,
351
+ stopReason: round.stopReason,
352
+ iteration: round.iteration,
353
+ consecutiveIdle: round.consecutiveIdle,
354
+ injectionsUsed: round.injectionsUsed,
355
+ injectionBudget: round.injectionBudget,
356
+ signal: AbortSignal.any([ctx.signal, timeoutCtl.signal]),
357
+ }, ctx);
358
+ }
359
+ catch (err) {
360
+ if (ctx.signal.aborted)
361
+ return { kind: 'end' };
362
+ // Fail OPEN, visibly. A crashed or timed-out checker downgrades the
363
+ // gate to a warning — it must never wedge the turn (fail-closed is a
364
+ // turn that can never end) and never crash it (the answer is already
365
+ // logged).
366
+ const why = timeoutCtl.signal.aborted
367
+ ? `timed out after ${timeoutMs}ms`
368
+ : `failed: ${err instanceof Error ? err.message : String(err)}`;
369
+ yield await emitError(ctx, 'retryable', `checkpoint "${cp.name}" ${why} — proceeding unchecked`);
370
+ continue;
371
+ }
372
+ finally {
373
+ clearTimeout(timer);
374
+ }
375
+ switch (result.action) {
376
+ case 'pass': {
377
+ yield await emitCheckpointEvent(ctx, 'checkpoint_passed', { name: cp.name });
378
+ continue;
379
+ }
380
+ case 'stop': {
381
+ // The checkpoint already emitted its own wrap-up events.
382
+ yield await emitCheckpointEvent(ctx, 'checkpoint_stopped', { name: cp.name });
383
+ return { kind: 'end' };
384
+ }
385
+ case 'retry': {
386
+ yield await emitCheckpointEvent(ctx, 'checkpoint_retry', { name: cp.name });
387
+ return { kind: 'loop' };
388
+ }
389
+ case 'inject': {
390
+ // Guard the guard: an inject with blank text would loop the turn
391
+ // with no new signal for the model — a checker bug; fail open.
392
+ const feedback = result.text?.trim();
393
+ if (!feedback) {
394
+ yield await emitError(ctx, 'retryable', `checkpoint "${cp.name}" injected empty feedback — ignored`);
395
+ continue;
396
+ }
397
+ const clamped = clampChars(feedback, round.maxInjectChars);
398
+ if (result.volatile) {
399
+ yield await emitCheckpointEvent(ctx, 'checkpoint_injected', {
400
+ name: cp.name,
401
+ volatile: true,
402
+ });
403
+ return { kind: 'loop', volatileText: clamped };
404
+ }
405
+ // Persistent: a checkpoint-origin user prompt. Projected as a
406
+ // user-role message by the existing projection case, marked via the
407
+ // same `origin` machinery trigger prompts use, cache-safe because it
408
+ // is an ordinary append at the log tail.
409
+ yield await ctx.emit({
410
+ type: 'user_prompt',
411
+ sessionId: ctx.sessionId,
412
+ turnId: ctx.turnId,
413
+ source: 'system',
414
+ text: clamped,
415
+ origin: { kind: 'checkpoint', name: cp.name },
416
+ });
417
+ yield await emitCheckpointEvent(ctx, 'checkpoint_injected', {
418
+ name: cp.name,
419
+ volatile: false,
420
+ });
421
+ return { kind: 'loop' };
422
+ }
423
+ }
424
+ }
425
+ return { kind: 'end' };
426
+ }
427
+ function defaultStuckNudge(trip) {
428
+ return (`You have called the tool \`${trip.toolName}\` ${trip.count} times ${trip.how}. ` +
429
+ `Repeating the same call will not produce a different result. Step back, reassess what ` +
430
+ `you learned from the previous attempts, and take a DIFFERENT next action or approach.`);
431
+ }
432
+ function buildStuckReport(opts) {
433
+ const name = opts.strategyName;
434
+ return {
435
+ abortedResultMessage: opts.stuck?.abortedResultMessage ??
436
+ `${name} mode loop aborted (stuck pattern) before this call ran`,
437
+ nearHint: opts.stuck?.nearHint ?? 'against the same target (only volatile args like maxBytes varied)',
438
+ fatalMessage: opts.stuck?.fatalMessage ??
439
+ (({ toolName, count, how }) => `${name} mode loop aborted — detected stuck pattern: tool "${toolName}" called ` +
440
+ `${count} times ${how}. The model is likely looping on the same call; ` +
441
+ `reset or rephrase.`),
442
+ ...(opts.stuck?.extraOnStuck ? { extraOnStuck: opts.stuck.extraOnStuck } : {}),
443
+ };
444
+ }
445
+ function clampChars(text, max) {
446
+ if (text.length <= max)
447
+ return text;
448
+ return `${text.slice(0, max)}\n…[checkpoint feedback truncated: ${text.length - max} chars dropped]`;
449
+ }
450
+ async function emitAbort(ctx, reason) {
451
+ return ctx.emit({
452
+ type: 'abort',
453
+ sessionId: ctx.sessionId,
454
+ turnId: ctx.turnId,
455
+ source: 'system',
456
+ reason,
457
+ });
458
+ }
459
+ async function emitError(ctx, kind, message) {
460
+ return ctx.emit({
461
+ type: 'error',
462
+ sessionId: ctx.sessionId,
463
+ turnId: ctx.turnId,
464
+ source: 'system',
465
+ kind,
466
+ message,
467
+ });
468
+ }
469
+ async function emitCheckpointEvent(ctx, subtype, payload) {
470
+ return ctx.emit({
471
+ type: 'plugin_event',
472
+ sessionId: ctx.sessionId,
473
+ turnId: ctx.turnId,
474
+ source: 'system',
475
+ pluginId: CHECKPOINT_EVENT_PLUGIN_ID,
476
+ subtype,
477
+ payload,
478
+ });
479
+ }
480
+ //# sourceMappingURL=react-loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-loop.js","sourceRoot":"","sources":["../../src/mode/react-loop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AACxF,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAIvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EACL,0BAA0B,EAC1B,2BAA2B,EAC3B,eAAe,GAGhB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEnE,OAAO,EAAE,qBAAqB,EAAyB,MAAM,qBAAqB,CAAC;AACnF,OAAO,EAAE,2BAA2B,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACrF,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE1D;;;;;;;;;;;;;;;GAeG;AAEH,2EAA2E;AAC3E,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC;AACzC,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAClC,MAAM,oBAAoB,GAAG,MAAM,CAAC;AACpC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AACnC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AACnC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AACjC,MAAM,wBAAwB,GAAG,MAAM,CAAC;AACxC,MAAM,6BAA6B,GAAG,OAAO,CAAC;AAC9C,MAAM,0BAA0B,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;AAE5D,8EAA8E;AAC9E,+EAA+E;AAC/E,4EAA4E;AAC5E,4CAA4C;AAC5C,IAAI,SAAS,GAAG,CAAC,EAAU,EAAE,MAAmB,EAAiB,EAAE,CAAC,cAAc,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;AAE/F;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CACrC,EAAsD;IAEtD,MAAM,IAAI,GAAG,SAAS,CAAC;IACvB,SAAS,GAAG,EAAE,CAAC;IACf,OAAO,GAAG,EAAE;QACV,SAAS,GAAG,IAAI,CAAC;IACnB,CAAC,CAAC;AACJ,CAAC;AA2GD,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,YAAY,CACjC,GAAgB,EAChB,IAAsB;IAEtB,IAAI,IAAI,CAAC,oBAAoB,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpD,MAAM,MAAM,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;QACtD,OAAO;IACT,CAAC;IAED,4EAA4E;IAC5E,2EAA2E;IAC3E,uEAAuE;IACvE,wEAAwE;IACxE,sBAAsB;IACtB,MAAM,sBAAsB,GAAG,GAAG,CAAC,aAAa,CAAC;IACjD,MAAM,aAAa,GACjB,OAAO,sBAAsB,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACnF,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,IAAI,sBAAsB,CAAC,CAAC;IAE5D,MAAM,QAAQ,GAAG,uBAAuB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACxD,MAAM,WAAW,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC;IAEtC,iEAAiE;IACjE,mEAAmE;IACnE,0EAA0E;IAC1E,2EAA2E;IAC3E,wCAAwC;IACxC,MAAM,WAAW,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;IACnE,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,IAAI,sBAAsB,CAAC,CAAC,CAAC;IAC9F,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,IAAI,wBAAwB,CAAC,CAAC,CAAC;IACnG,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,IAAI,eAAe,GAAG,CAAC,CAAC;IACxB,4EAA4E;IAC5E,2CAA2C;IAC3C,IAAI,mBAAuC,CAAC;IAE5C,kEAAkE;IAClE,yEAAyE;IACzE,qDAAqD;IACrD,IAAI,mBAAmB,GAAG,CAAC,CAAC;IAC5B,IAAI,kBAAkB,GAAG,CAAC,CAAC;IAE3B,KAAK,IAAI,SAAS,GAAG,CAAC,EAAE,SAAS,IAAI,aAAa,EAAE,SAAS,EAAE,EAAE,CAAC;QAChE,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACvB,MAAM,MAAM,SAAS,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;YAC7C,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC;YACnB,IAAI,EAAE,gBAAgB;YACtB,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,MAAM,EAAE,QAAQ;YAChB,QAAQ,EAAE,IAAI,CAAC,YAAY;YAC3B,SAAS;SACV,CAAC,CAAC;QAEH,sEAAsE;QACtE,mEAAmE;QACnE,oCAAoC;QACpC,MAAM,qBAAqB,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,kBAAkB,CAAC,GAAG,CAAC,CAAC;QAE9B,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB;YACrC,CAAC,CAAC,MAAM,IAAI,CAAC,gBAAgB,CAAC,GAAG,EAAE,SAAS,CAAC;YAC7C,CAAC,CAAC,SAAS,CAAC;QACd,iEAAiE;QACjE,8DAA8D;QAC9D,MAAM,aAAa,GAAG,CAAC,mBAAmB,EAAE,SAAS,EAAE,gBAAgB,CAAC,CAAC,MAAM,CAC7E,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAC1D,CAAC;QACF,mBAAmB,GAAG,SAAS,CAAC;QAChC,MAAM,YAAY,GAAG,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAEvF,yEAAyE;QACzE,uEAAuE;QACvE,mEAAmE;QACnE,2CAA2C;QAC3C,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACvB,MAAM,MAAM,SAAS,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;YAC7C,OAAO;QACT,CAAC;QAED,MAAM,YAAY,GAAG,2BAA2B,CAAC,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QACtF,MAAM,EAAE,QAAQ,EAAE,iBAAiB,EAAE,GAAG,eAAe,CAAC,GAAG,EAAE;YAC3D,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC5D,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC;YACnB,IAAI,EAAE,kBAAkB;YACxB,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,MAAM,EAAE,QAAQ;YAChB,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,IAAI;YAC3B,KAAK,EAAE,GAAG,CAAC,KAAK;SACjB,CAAC,CAAC;QAEH,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,MAAM,qBAAqB,CACzF,GAAG,EACH,QAAQ,EACR;YACE,SAAS;YACT,iBAAiB;YACjB,sEAAsE;YACtE,iEAAiE;YACjE,oEAAoE;YACpE,mEAAmE;YACnE,eAAe;YACf,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAClD,CACF,CAAC;QAEF,mEAAmE;QACnE,mEAAmE;QACnE,0EAA0E;QAC1E,+DAA+D;QAC/D,4EAA4E;QAC5E,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACvB,MAAM,MAAM,SAAS,CAAC,GAAG,EAAE,uCAAuC,CAAC,CAAC;YACpE,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC;YACnB,IAAI,EAAE,mBAAmB;YACzB,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,MAAM,EAAE,QAAQ;YAChB,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,IAAI;YAC3B,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,GAAG,gBAAgB,CAAC,KAAK,CAAC;SAC3B,CAAC,CAAC;QAEH,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,QAAQ,GAAG,sBAAsB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACvD,qEAAqE;YACrE,mEAAmE;YACnE,+DAA+D;YAC/D,IAAI,QAAQ,IAAI,mBAAmB,GAAG,wBAAwB,EAAE,CAAC;gBAC/D,MAAM,SAAS,GAAG,MAAM,qBAAqB,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBACpE,IAAI,SAAS,EAAE,CAAC;oBACd,qEAAqE;oBACrE,kEAAkE;oBAClE,8DAA8D;oBAC9D,mBAAmB,IAAI,CAAC,CAAC;oBACzB,MAAM,MAAM,SAAS,CAAC,GAAG,EAAE,WAAW,EAAE,2DAA2D,CAAC,CAAC;oBACrG,SAAS;gBACX,CAAC;YACH,CAAC;YACD,yEAAyE;YACzE,sEAAsE;YACtE,qEAAqE;YACrE,uEAAuE;YACvE,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,QAAQ,EAAE,CAAC;gBACjC,MAAM,MAAM,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,MAAM,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;gBACjE,OAAO;YACT,CAAC;YACD,qEAAqE;YACrE,sEAAsE;YACtE,uEAAuE;YACvE,kBAAkB,IAAI,CAAC,CAAC;YACxB,MAAM,MAAM,SAAS,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,MAAM,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACrE,IAAI,kBAAkB,IAAI,uBAAuB,EAAE,CAAC;gBAClD,MAAM,MAAM,SAAS,CACnB,GAAG,EACH,OAAO,EACP,GAAG,MAAM,6CAA6C,kBAAkB,kBAAkB;oBACxF,UAAU,KAAK,CAAC,OAAO,kDAAkD,CAC5E,CAAC;gBACF,OAAO;YACT,CAAC;YACD,MAAM,SAAS,CACb,aAAa,CAAC,kBAAkB,EAAE,qBAAqB,EAAE,oBAAoB,CAAC,EAC9E,GAAG,CAAC,MAAM,CACX,CAAC;YACF,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACvB,MAAM,MAAM,SAAS,CAAC,GAAG,EAAE,sCAAsC,CAAC,CAAC;gBACnE,OAAO;YACT,CAAC;YACD,SAAS;QACX,CAAC;QACD,qEAAqE;QACrE,mBAAmB,GAAG,CAAC,CAAC;QACxB,kBAAkB,GAAG,CAAC,CAAC;QAEvB,2EAA2E;QAC3E,wEAAwE;QACxE,sEAAsE;QACtE,iEAAiE;QACjE,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC;gBACnB,IAAI,EAAE,mBAAmB;gBACzB,SAAS,EAAE,GAAG,CAAC,SAAS;gBACxB,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,MAAM,EAAE,OAAO;gBACf,OAAO,EAAE,SAAS,CAAC,IAAI;gBACvB,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAClE,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACjD,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACnE,CAAC,CAAC;QACL,CAAC;QAED,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3B,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,GAAG,EAAE;gBAClD,IAAI;gBACJ,UAAU;gBACV,QAAQ;gBACR,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC3B,SAAS;aACV,CAAC,CAAC;YACH,IAAI,SAAS,EAAE,MAAM,KAAK,MAAM;gBAAE,OAAO;QAC3C,CAAC;QAED,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,2BAA2B,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE;gBACvE,QAAQ,EAAE,WAAW,CAAC,QAAQ;gBAC9B,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CACpB,GAAG,IAAI,CAAC,YAAY,6CAA6C,IAAI,CAAC,QAAQ,WAAW;oBACzF,GAAG,IAAI,CAAC,KAAK,UAAU,IAAI,CAAC,GAAG,+DAA+D;gBAChG,GAAG,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,WAAW,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAChF,CAAC,CAAC;YACH,IAAI,IAAI,EAAE,CAAC;gBACT,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBACtE,oEAAoE;gBACpE,mBAAmB,GAAG,mBAAmB,CAAC,CAAC,CAAC,GAAG,mBAAmB,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;YAC3F,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,0BAA0B,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;YACtF,sEAAsE;YACtE,qEAAqE;YACrE,IAAI,KAAK;gBAAE,OAAO;QACpB,CAAC;QAED,IAAI,IAAI,IAAI,UAAU,KAAK,UAAU,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/D,wEAAwE;YACxE,qEAAqE;YACrE,oEAAoE;YACpE,6DAA6D;YAC7D,qBAAqB;YACrB,IAAI,CAAC,IAAI,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,UAAU,KAAK,UAAU,EAAE,CAAC;gBAChE,MAAM,MAAM,SAAS,CACnB,GAAG,EACH,WAAW,EACX,sDAAsD,UAAU,IAAI,SAAS,GAAG,CACjF,CAAC;YACJ,CAAC;YACD,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC;gBACnB,IAAI,EAAE,mBAAmB;gBACzB,SAAS,EAAE,GAAG,CAAC,SAAS;gBACxB,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,MAAM,EAAE,OAAO;gBACf,OAAO,EAAE,IAAI;gBACb,UAAU;aACX,CAAC,CAAC;QACL,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,iEAAiE;YACjE,eAAe,IAAI,CAAC,CAAC;YACrB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,iBAAiB,CAAC,GAAG,EAAE,WAAW,EAAE;gBACzD,aAAa,EAAE,IAAI;gBACnB,UAAU;gBACV,SAAS;gBACT,eAAe;gBACf,cAAc;gBACd,eAAe;gBACf,cAAc;aACf,CAAC,CAAC;YACH,IAAI,OAAO,CAAC,IAAI,KAAK,KAAK;gBAAE,OAAO;YACnC,cAAc,IAAI,CAAC,CAAC;YACpB,IAAI,OAAO,CAAC,YAAY,KAAK,SAAS;gBAAE,mBAAmB,GAAG,OAAO,CAAC,YAAY,CAAC;YACnF,SAAS;QACX,CAAC;QACD,eAAe,GAAG,CAAC,CAAC;QACpB,uEAAuE;QACvE,oEAAoE;QACpE,2EAA2E;QAC3E,yEAAyE;QACzE,uEAAuE;QACvE,qDAAqD;QACrD,cAAc,GAAG,CAAC,CAAC;QAEnB,wEAAwE;QACxE,uEAAuE;QACvE,yEAAyE;QACzE,2DAA2D;QAC3D,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,eAAe,CAAC,GAAG,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;QAChE,IAAI,MAAM;YAAE,OAAO;QAEnB,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;YAC1E,IAAI,SAAS,EAAE,MAAM,KAAK,MAAM;gBAAE,OAAO;QAC3C,CAAC;IACH,CAAC;IAED,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;QACzB,MAAM,IAAI,CAAC,eAAe,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;QAC/C,OAAO;IACT,CAAC;IACD,MAAM,MAAM,SAAS,CACnB,GAAG,EACH,OAAO,EACP,GAAG,IAAI,CAAC,YAAY,sCAAsC,aAAa,GAAG,CAC3E,CAAC;AACJ,CAAC;AAeD,KAAK,SAAS,CAAC,CAAC,iBAAiB,CAC/B,GAAgB,EAChB,WAA0C,EAC1C,KAAgB;IAEhB,0EAA0E;IAC1E,wEAAwE;IACxE,uEAAuE;IACvE,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CACjC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,KAAK,UAAU,IAAI,CAAC,EAAE,CAAC,MAAM,IAAI,UAAU,CAAC,KAAK,MAAM,CAChF,CAAC;IACF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IAElD,gEAAgE;IAChE,0EAA0E;IAC1E,IAAI,KAAK,CAAC,cAAc,IAAI,KAAK,CAAC,eAAe,EAAE,CAAC;QAClD,MAAM,MAAM,SAAS,CACnB,GAAG,EACH,WAAW,EACX,gCAAgC,KAAK,CAAC,eAAe,aAAa;YAChE,kFAAkF,CACrF,CAAC;QACF,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACzB,CAAC;IAED,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;QAC1B,+DAA+D;QAC/D,oEAAoE;QACpE,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QAE/C,MAAM,MAAM,mBAAmB,CAAC,GAAG,EAAE,oBAAoB,EAAE;YACzD,IAAI,EAAE,EAAE,CAAC,IAAI;YACb,SAAS,EAAE,KAAK,CAAC,SAAS;SAC3B,CAAC,CAAC;QAEH,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,IAAI,6BAA6B,CAAC,CAAC;QACjF,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;QAC9D,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;QAChB,IAAI,MAAwB,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,CACnB;gBACE,aAAa,EAAE,KAAK,CAAC,aAAa;gBAClC,UAAU,EAAE,KAAK,CAAC,UAAU;gBAC5B,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,eAAe,EAAE,KAAK,CAAC,eAAe;gBACtC,cAAc,EAAE,KAAK,CAAC,cAAc;gBACpC,eAAe,EAAE,KAAK,CAAC,eAAe;gBACtC,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;aACzD,EACD,GAAG,CACJ,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO;gBAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;YAC/C,oEAAoE;YACpE,qEAAqE;YACrE,qEAAqE;YACrE,WAAW;YACX,MAAM,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,OAAO;gBACnC,CAAC,CAAC,mBAAmB,SAAS,IAAI;gBAClC,CAAC,CAAC,WAAW,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YAClE,MAAM,MAAM,SAAS,CAAC,GAAG,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC,IAAI,KAAK,GAAG,yBAAyB,CAAC,CAAC;YACjG,SAAS;QACX,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;QAED,QAAQ,MAAM,CAAC,MAAM,EAAE,CAAC;YACtB,KAAK,MAAM,CAAC,CAAC,CAAC;gBACZ,MAAM,MAAM,mBAAmB,CAAC,GAAG,EAAE,mBAAmB,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC7E,SAAS;YACX,CAAC;YACD,KAAK,MAAM,CAAC,CAAC,CAAC;gBACZ,yDAAyD;gBACzD,MAAM,MAAM,mBAAmB,CAAC,GAAG,EAAE,oBAAoB,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC9E,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;YACzB,CAAC;YACD,KAAK,OAAO,CAAC,CAAC,CAAC;gBACb,MAAM,MAAM,mBAAmB,CAAC,GAAG,EAAE,kBAAkB,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC5E,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;YAC1B,CAAC;YACD,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,iEAAiE;gBACjE,+DAA+D;gBAC/D,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;gBACrC,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACd,MAAM,MAAM,SAAS,CACnB,GAAG,EACH,WAAW,EACX,eAAe,EAAE,CAAC,IAAI,qCAAqC,CAC5D,CAAC;oBACF,SAAS;gBACX,CAAC;gBACD,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;gBAC3D,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;oBACpB,MAAM,MAAM,mBAAmB,CAAC,GAAG,EAAE,qBAAqB,EAAE;wBAC1D,IAAI,EAAE,EAAE,CAAC,IAAI;wBACb,QAAQ,EAAE,IAAI;qBACf,CAAC,CAAC;oBACH,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC;gBACjD,CAAC;gBACD,8DAA8D;gBAC9D,oEAAoE;gBACpE,qEAAqE;gBACrE,yCAAyC;gBACzC,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC;oBACnB,IAAI,EAAE,aAAa;oBACnB,SAAS,EAAE,GAAG,CAAC,SAAS;oBACxB,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,MAAM,EAAE,QAAQ;oBAChB,IAAI,EAAE,OAAO;oBACb,MAAM,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE;iBAC9C,CAAC,CAAC;gBACH,MAAM,MAAM,mBAAmB,CAAC,GAAG,EAAE,qBAAqB,EAAE;oBAC1D,IAAI,EAAE,EAAE,CAAC,IAAI;oBACb,QAAQ,EAAE,KAAK;iBAChB,CAAC,CAAC;gBACH,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;YAC1B,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACzB,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAmB;IAC5C,OAAO,CACL,8BAA8B,IAAI,CAAC,QAAQ,MAAM,IAAI,CAAC,KAAK,UAAU,IAAI,CAAC,GAAG,IAAI;QACjF,wFAAwF;QACxF,uFAAuF,CACxF,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAsB;IAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC;IAC/B,OAAO;QACL,oBAAoB,EAClB,IAAI,CAAC,KAAK,EAAE,oBAAoB;YAChC,GAAG,IAAI,yDAAyD;QAClE,QAAQ,EACN,IAAI,CAAC,KAAK,EAAE,QAAQ,IAAI,mEAAmE;QAC7F,YAAY,EACV,IAAI,CAAC,KAAK,EAAE,YAAY;YACxB,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,CAC5B,GAAG,IAAI,sDAAsD,QAAQ,WAAW;gBAChF,GAAG,KAAK,UAAU,GAAG,kDAAkD;gBACvE,oBAAoB,CAAC;QACzB,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/E,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,IAAY,EAAE,GAAW;IAC3C,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,IAAI,CAAC;IACpC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,sCAAsC,IAAI,CAAC,MAAM,GAAG,GAAG,iBAAiB,CAAC;AACvG,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,GAAgB,EAAE,MAAc;IACvD,OAAO,GAAG,CAAC,IAAI,CAAC;QACd,IAAI,EAAE,OAAO;QACb,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,MAAM,EAAE,QAAQ;QAChB,MAAM;KACP,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,SAAS,CACtB,GAAgB,EAChB,IAA2B,EAC3B,OAAe;IAEf,OAAO,GAAG,CAAC,IAAI,CAAC;QACd,IAAI,EAAE,OAAO;QACb,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,MAAM,EAAE,QAAQ;QAChB,IAAI;QACJ,OAAO;KACR,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,mBAAmB,CAChC,GAAgB,EAChB,OAAe,EACf,OAAgB;IAEhB,OAAO,GAAG,CAAC,IAAI,CAAC;QACd,IAAI,EAAE,cAAc;QACpB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,MAAM,EAAE,QAAQ;QAChB,QAAQ,EAAE,0BAA0B;QACpC,OAAO;QACP,OAAO;KACR,CAAC,CAAC;AACL,CAAC"}
@@ -29,6 +29,13 @@ export interface StuckLoopDetector {
29
29
  readonly repeatThreshold: number;
30
30
  /** Record the call and report whether the loop guard should trip. */
31
31
  record(toolName: string, input: unknown): StuckSignal;
32
+ /**
33
+ * Clear both sliding windows. Used by the nudge (steer-don't-stop) stuck
34
+ * policy: after a trip is surfaced to the model, the detector starts a fresh
35
+ * episode — otherwise every subsequent call inside the still-full window
36
+ * would re-trip and re-nudge on each iteration.
37
+ */
38
+ reset(): void;
32
39
  }
33
40
  /**
34
41
  * User-tunable loop-guard settings (config `context.loopGuard`). All optional —
@@ -1 +1 @@
1
- {"version":3,"file":"stuck-loop.d.ts","sourceRoot":"","sources":["../../src/mode/stuck-loop.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,WAAW;IAC1B,4CAA4C;IAC5C,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,4DAA4D;IAC5D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,qEAAqE;IACrE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,WAAW,CAAC;CACvD;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAED;;;;iDAIiD;AACjD,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAC3C,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAgB/C,wBAAgB,uBAAuB,CAAC,IAAI,GAAE,iBAAsB,GAAG,iBAAiB,CAkCvF"}
1
+ {"version":3,"file":"stuck-loop.d.ts","sourceRoot":"","sources":["../../src/mode/stuck-loop.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,WAAW;IAC1B,4CAA4C;IAC5C,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,4DAA4D;IAC5D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,qEAAqE;IACrE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,WAAW,CAAC;IACtD;;;;;OAKG;IACH,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAED;;;;iDAIiD;AACjD,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAC3C,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAgB/C,wBAAgB,uBAAuB,CAAC,IAAI,GAAE,iBAAsB,GAAG,iBAAiB,CAsCvF"}
@@ -57,6 +57,10 @@ export function createStuckLoopDetector(opts = {}) {
57
57
  }
58
58
  return { stuck: false, count: Math.max(exactCount, nearCount), kind: 'exact' };
59
59
  },
60
+ reset() {
61
+ recent.length = 0;
62
+ recentNear.length = 0;
63
+ },
60
64
  };
61
65
  }
62
66
  //# sourceMappingURL=stuck-loop.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stuck-loop.js","sourceRoot":"","sources":["../../src/mode/stuck-loop.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"stuck-loop.js","sourceRoot":"","sources":["../../src/mode/stuck-loop.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,8 @@
9
9
  * - `./mode/single-shot.ts` — single-shot (no-tools) provider turn
10
10
  * - `./mode/stuck-loop.ts` — sliding-window stuck-tool-call detector
11
11
  * - `./mode/stable-hash.ts` — key-order-canonical input hash util
12
+ * - `./mode/react-loop.ts` — the shared ReAct loop core (+ checkpoint gate)
13
+ * - `./mode/checkpoint.ts` — turn-end checkpoint contract
12
14
  */
13
15
  export { ELISION_SYSTEM_NOTE, buildSystemPromptWithSkills, projectMessagesFromLog, projectMessages, type ProjectMessagesOptions, type ProjectedMessages, } from './mode/project-messages.js';
14
16
  export { collectProviderStream, type CollectedToolUse, type StreamResult, } from './mode/collect-stream.js';
@@ -16,4 +18,6 @@ export { runSingleShotTurn } from './mode/single-shot.js';
16
18
  export { sleepWithAbort, nextBackoffMs } from './mode/abort-backoff.js';
17
19
  export { createStuckLoopDetector, type StuckLoopDetector, type StuckSignal, type LoopGuardSettings, } from './mode/stuck-loop.js';
18
20
  export { stableHash } from './mode/stable-hash.js';
21
+ export { runReactLoop, MAX_CONSECUTIVE_RETRIES, __setRetrySleepForTests, type ReactLoopOptions, type ProviderSuccessInfo, type ToolBatchInfo, type StopDirective, } from './mode/react-loop.js';
22
+ export type { CheckpointContext, CheckpointResult, TurnCheckpoint, } from './mode/checkpoint.js';
19
23
  //# sourceMappingURL=mode-helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mode-helpers.d.ts","sourceRoot":"","sources":["../src/mode-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,mBAAmB,EACnB,2BAA2B,EAC3B,sBAAsB,EACtB,eAAe,EACf,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,GACvB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,qBAAqB,EACrB,KAAK,gBAAgB,EACrB,KAAK,YAAY,GAClB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EACL,uBAAuB,EACvB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,iBAAiB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"mode-helpers.d.ts","sourceRoot":"","sources":["../src/mode-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,mBAAmB,EACnB,2BAA2B,EAC3B,sBAAsB,EACtB,eAAe,EACf,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,GACvB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,qBAAqB,EACrB,KAAK,gBAAgB,EACrB,KAAK,YAAY,GAClB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EACL,uBAAuB,EACvB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,iBAAiB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EACL,YAAY,EACZ,uBAAuB,EACvB,uBAAuB,EACvB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,aAAa,GACnB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,GACf,MAAM,sBAAsB,CAAC"}
@@ -9,6 +9,8 @@
9
9
  * - `./mode/single-shot.ts` — single-shot (no-tools) provider turn
10
10
  * - `./mode/stuck-loop.ts` — sliding-window stuck-tool-call detector
11
11
  * - `./mode/stable-hash.ts` — key-order-canonical input hash util
12
+ * - `./mode/react-loop.ts` — the shared ReAct loop core (+ checkpoint gate)
13
+ * - `./mode/checkpoint.ts` — turn-end checkpoint contract
12
14
  */
13
15
  export { ELISION_SYSTEM_NOTE, buildSystemPromptWithSkills, projectMessagesFromLog, projectMessages, } from './mode/project-messages.js';
14
16
  export { collectProviderStream, } from './mode/collect-stream.js';
@@ -16,4 +18,5 @@ export { runSingleShotTurn } from './mode/single-shot.js';
16
18
  export { sleepWithAbort, nextBackoffMs } from './mode/abort-backoff.js';
17
19
  export { createStuckLoopDetector, } from './mode/stuck-loop.js';
18
20
  export { stableHash } from './mode/stable-hash.js';
21
+ export { runReactLoop, MAX_CONSECUTIVE_RETRIES, __setRetrySleepForTests, } from './mode/react-loop.js';
19
22
  //# sourceMappingURL=mode-helpers.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mode-helpers.js","sourceRoot":"","sources":["../src/mode-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,mBAAmB,EACnB,2BAA2B,EAC3B,sBAAsB,EACtB,eAAe,GAGhB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,qBAAqB,GAGtB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EACL,uBAAuB,GAIxB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"mode-helpers.js","sourceRoot":"","sources":["../src/mode-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,mBAAmB,EACnB,2BAA2B,EAC3B,sBAAsB,EACtB,eAAe,GAGhB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,qBAAqB,GAGtB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EACL,uBAAuB,GAIxB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EACL,YAAY,EACZ,uBAAuB,EACvB,uBAAuB,GAKxB,MAAM,sBAAsB,CAAC"}