@ouispec/agent-worker 0.13.0 → 0.13.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.
Files changed (88) hide show
  1. package/README.md +9 -9
  2. package/dist/approvals/client.d.ts +2 -2
  3. package/dist/approvals/continuation.d.ts +2 -2
  4. package/dist/approvals/preview.d.ts +1 -1
  5. package/dist/approvals/preview.js +1 -1
  6. package/dist/approvals/requirement.js +1 -1
  7. package/dist/attachments/content.d.ts +2 -2
  8. package/dist/attachments/guard.js +1 -1
  9. package/dist/attachments/limits.d.ts +2 -2
  10. package/dist/attachments/limits.d.ts.map +1 -1
  11. package/dist/attachments/limits.js +2 -2
  12. package/dist/attachments/limits.js.map +1 -1
  13. package/dist/attachments/store.d.ts +3 -3
  14. package/dist/attachments/store.d.ts.map +1 -1
  15. package/dist/attachments/tools.js +2 -2
  16. package/dist/attachments/tools.js.map +1 -1
  17. package/dist/authz/tool-policy.d.ts +4 -4
  18. package/dist/authz/tool-policy.d.ts.map +1 -1
  19. package/dist/index.d.ts +1 -1
  20. package/dist/index.js +6 -6
  21. package/dist/index.js.map +1 -1
  22. package/dist/model.d.ts +1 -1
  23. package/dist/openapi/executor.d.ts +1 -1
  24. package/dist/openapi/index.d.ts +1 -1
  25. package/dist/openapi/index.js +1 -1
  26. package/dist/openapi/loader.d.ts +4 -4
  27. package/dist/openapi/loader.js +7 -7
  28. package/dist/openapi/loader.js.map +1 -1
  29. package/dist/openapi/x-agent.d.ts +2 -2
  30. package/dist/openapi/x-agent.js +2 -2
  31. package/dist/orchestrator.d.ts +1 -1
  32. package/dist/orchestrator.js +42 -42
  33. package/dist/orchestrator.js.map +1 -1
  34. package/dist/prompt/rules/ui-control.d.ts +3 -3
  35. package/dist/prompt/rules/ui-control.js +3 -3
  36. package/dist/prompt/spoken-input.d.ts +1 -1
  37. package/dist/prompt/spoken-input.js +1 -1
  38. package/dist/runtime/config.js +1 -1
  39. package/dist/runtime/turn-runner.d.ts +2 -2
  40. package/dist/runtime/turn-runner.d.ts.map +1 -1
  41. package/dist/runtime/turn-runner.js +5 -5
  42. package/dist/runtime/turn-runner.js.map +1 -1
  43. package/dist/runtime/types.d.ts +16 -16
  44. package/dist/runtime/types.d.ts.map +1 -1
  45. package/dist/stop/partial.d.ts +1 -1
  46. package/dist/stop/partial.js +1 -1
  47. package/dist/stop/results.d.ts +1 -1
  48. package/dist/stop/turn-stop.d.ts +3 -3
  49. package/dist/stop/turn-stop.d.ts.map +1 -1
  50. package/dist/stop/turn-stop.js +1 -1
  51. package/dist/stop/turn-stop.js.map +1 -1
  52. package/dist/testing/desk-events.d.ts +1 -1
  53. package/dist/testing/desk-events.js +1 -1
  54. package/dist/time-hand-back.d.ts +3 -3
  55. package/dist/time-hand-back.js +3 -3
  56. package/dist/tools/async-binding.d.ts +1 -1
  57. package/dist/tools/builtin-tools.d.ts +3 -3
  58. package/dist/tools/entity-tools.d.ts.map +1 -1
  59. package/dist/tools/entity-tools.js +0 -1
  60. package/dist/tools/entity-tools.js.map +1 -1
  61. package/dist/tools/load-all-tools.d.ts.map +1 -1
  62. package/dist/tools/load-all-tools.js +0 -1
  63. package/dist/tools/load-all-tools.js.map +1 -1
  64. package/dist/tools/schema-loader.d.ts.map +1 -1
  65. package/dist/tools/schema-loader.js +1 -2
  66. package/dist/tools/schema-loader.js.map +1 -1
  67. package/dist/tools/types.d.ts +9 -9
  68. package/dist/tools/types.d.ts.map +1 -1
  69. package/dist/turn-ledger.d.ts +1 -1
  70. package/dist/turn-ledger.js +1 -1
  71. package/dist/types.d.ts +13 -13
  72. package/dist/types.d.ts.map +1 -1
  73. package/dist/ui/answer-image.d.ts +1 -1
  74. package/dist/ui/answer-image.js +1 -1
  75. package/dist/ui/channel.d.ts +1 -1
  76. package/dist/ui/knowledge.d.ts +2 -2
  77. package/dist/ui/observations.d.ts +2 -2
  78. package/dist/ui/observations.js +2 -2
  79. package/dist/ui/outline.d.ts +1 -1
  80. package/dist/ui/outline.js +1 -1
  81. package/dist/ui/page-index.d.ts +1 -1
  82. package/dist/ui/page-index.js +1 -1
  83. package/dist/ui/snapshot.d.ts +2 -2
  84. package/dist/ui/snapshot.d.ts.map +1 -1
  85. package/dist/ui/ui-tools.d.ts +1 -1
  86. package/dist/ui/ui-tools.js +8 -8
  87. package/dist/ui/ui-tools.js.map +1 -1
  88. package/package.json +6 -6
@@ -1,10 +1,10 @@
1
1
  /**
2
- * `x-agent`: how an operation opts in as an agent tool (ADR-0181 §3, ADR-0227 §2.1).
2
+ * `x-agent`: how an operation opts in as an agent tool.
3
3
  *
4
4
  * ```yaml
5
5
  * x-agent:
6
6
  * expose: true # without it, the operation is not a tool
7
- * effect: mutate # ADR-0226 §2.6: view | file | mutate | job | transaction, or its object form
7
+ * effect: mutate # view | file | mutate | job | transaction, or its object form
8
8
  * destructive: true # optional, on a write: removes or replaces something the person made
9
9
  * consequence: "..." # optional: what happens, for the tool's description and an approval's preview
10
10
  * pa: true # optional: the product's own assistant may call it; only on a read
@@ -5,7 +5,7 @@ import type { AgentWorkerConfig, AgentTurnInput, AgentTurnResult } from './types
5
5
  * A turn runs in one or more segments. Each segment is one `streamText` call
6
6
  * with a fixed tool set. When a UI action changes what the client's page
7
7
  * offers (navigating is the common case), the segment ends and the turn
8
- * continues in a new one whose tools are the new page's (ADR-0209 D3). The
8
+ * continues in a new one whose tools are the new page's. The
9
9
  * round cap counts across segments.
10
10
  */
11
11
  export declare function runAgentTurn(config: AgentWorkerConfig, input: AgentTurnInput): Promise<AgentTurnResult>;
@@ -2,7 +2,7 @@
2
2
  * Agent Orchestrator — powered by Vercel AI SDK.
3
3
  *
4
4
  * The model is the host's: any `ai` library model, passed in configuration
5
- * (ADR-0227 §2.2, "Model"). The core names no provider. The AI SDK handles:
5
+ * ("Model"). The core names no provider. The AI SDK handles:
6
6
  * - each provider's wire format (internal, never exposed)
7
7
  * - tool_use / tool_result pairing (automatic, no manual repair needed)
8
8
  * - Multi-round tool loops (via stopWhen)
@@ -11,7 +11,7 @@
11
11
  * - Error categorization and retries
12
12
  *
13
13
  * Our value-add stays:
14
- * - UI tools from the client's OUI surfaces, answered by the client (ADR-0209)
14
+ * - UI tools from the client's OUI surfaces, answered by the client
15
15
  * - Schema-based tool loading
16
16
  * - Persona/prompt compilation
17
17
  * - Emit adapter (realtime socket streaming)
@@ -93,7 +93,7 @@ const notRun = (payload) => ({ text: JSON.stringify(payload), ran: false });
93
93
  * A turn runs in one or more segments. Each segment is one `streamText` call
94
94
  * with a fixed tool set. When a UI action changes what the client's page
95
95
  * offers (navigating is the common case), the segment ends and the turn
96
- * continues in a new one whose tools are the new page's (ADR-0209 D3). The
96
+ * continues in a new one whose tools are the new page's. The
97
97
  * round cap counts across segments.
98
98
  */
99
99
  export async function runAgentTurn(config, input) {
@@ -107,7 +107,7 @@ export async function runAgentTurn(config, input) {
107
107
  const uiResultTimeoutMs = config.ui?.resultTimeoutMs ?? DEFAULT_UI_RESULT_TIMEOUT_MS;
108
108
  const uiJobWaitMs = jobWaitOf({ jobWaitMs: config.ui?.jobWaitMs });
109
109
  if (!config.model) {
110
- throw new Error('[agent-sdk] config.model is required: pass an `ai` library model (ADR-0227 §2.2)');
110
+ throw new Error('[agent-sdk] config.model is required: pass an `ai` library model');
111
111
  }
112
112
  const { turnId, socketRoom } = input;
113
113
  log('info', 'agent:turn', 'Turn started', {
@@ -120,7 +120,7 @@ export async function runAgentTurn(config, input) {
120
120
  maxTokens,
121
121
  temperature,
122
122
  });
123
- // ─── The client's UI (ADR-0209 D1) ─────────────────────────────────────────
123
+ // ─── The client's UI ─────────────────────────────────────────
124
124
  // The turn carries the surfaces of the client that sent it. They are the only
125
125
  // source of UI tools, so the tools always describe the page the user is on.
126
126
  const client = readClientPage(input.context ?? null);
@@ -128,7 +128,7 @@ export async function runAgentTurn(config, input) {
128
128
  throw new Error('[agent-sdk] The turn carries UI surfaces but the worker has no UI action channel (config.ui): ' +
129
129
  'its UI actions could be sent but never answered.');
130
130
  }
131
- // What the page offers, in index (ADR-0245 §2.1): kept current by every answer.
131
+ // What the page offers, in index: kept current by every answer.
132
132
  let currentPage = client?.page ?? [];
133
133
  // The turn's UI actions run one at a time, in the order the model called them (ui-sequence.ts).
134
134
  const uiSequence = createUISequence();
@@ -137,14 +137,14 @@ export async function runAgentTurn(config, input) {
137
137
  uiSequence.record(client.page, client.surfacesHash);
138
138
  // The definitions the turn holds: those a client sent, and those fetched since.
139
139
  const heldDefinitions = client?.held ?? new Map();
140
- // Whether the page can be seen (ADR-0245 §2.5): nothing that changes it runs while it cannot.
140
+ // Whether the page can be seen: nothing that changes it runs while it cannot.
141
141
  const sight = createPageSight();
142
142
  const uiCounts = { describes: 0, reads: 0, acts: 0, guides: 0 };
143
143
  // Answers whose page state was moved to the end of what the model reads, summed over the turn's steps.
144
144
  let pageStatesMoved = 0;
145
145
  // The knowledge the client sent for its page goes after the host's prompt.
146
146
  const knowledge = readClientKnowledge(input.context ?? null);
147
- // ─── Files (ADR-0252 §2.11, §2.12) ─────────────────────────────────────────
147
+ // ─── Files ─────────────────────────────────────────
148
148
  // With the host's file area, the turn's files go to the model with its
149
149
  // message, the attachment tools reach every file of the conversation, and the
150
150
  // cost guard caps what the model is given of them.
@@ -201,7 +201,7 @@ export async function runAgentTurn(config, input) {
201
201
  const hostPrompt = typeof config.systemPrompt === 'function'
202
202
  ? config.systemPrompt({ userId: input.userId, accountId: input.accountId, context: withoutClientUI(input.context) })
203
203
  : config.systemPrompt;
204
- // With a file area, the model is told a file's name and content are data, never instructions (ADR-0252 §2.11).
204
+ // With a file area, the model is told a file's name and content are data, never instructions.
205
205
  const systemPrompt = withClientKnowledge(fileArea ? `${hostPrompt}\n\n${ATTACHMENT_DATA_NOTE}` : hostPrompt, input.context);
206
206
  log('debug', 'agent:prompt', 'System prompt built', { turnId, promptLength: systemPrompt.length, hostPromptLength: hostPrompt.length });
207
207
  // Wall-clock deadline: abort the entire streamText call if it exceeds turnDeadlineMs.
@@ -209,14 +209,14 @@ export async function runAgentTurn(config, input) {
209
209
  // A UI tool waiting on work it started stops in time for the model to answer.
210
210
  const uiWaitDeadline = () => turnStartedAt + turnDeadlineMs - UI_ANSWER_MARGIN_MS;
211
211
  const abortController = new AbortController();
212
- // ─── Stopping (ADR-0252) ───────────────────────────────────────────────────
212
+ // ─── Stopping ───────────────────────────────────────────────────
213
213
  // The person's Stop, or a newer message superseding this turn, is kept by the
214
214
  // realtime server; the watch asks for it for as long as the turn runs. A stop
215
215
  // aborts the turn's signal with a typed reason, which is what everything that
216
216
  // waits (the model stream, a UI action's answer, a job's outcome) already
217
217
  // honours. What the turn had produced is then stored and announced (below).
218
218
  const stopWatch = input.stopWatch ?? watchTurnStop(config.stops, turnId, input.userId);
219
- /** Set when the turn begins its own end: a stop that lands after is not one (§2.4). */
219
+ /** Set when the turn begins its own end: a stop that lands after is not one. */
220
220
  let ending = false;
221
221
  /** Kept back from a stopped turn's grace for storing and announcing it. */
222
222
  const STOP_STORE_MARGIN_MS = 3_000;
@@ -251,10 +251,10 @@ export async function runAgentTurn(config, input) {
251
251
  abortController.abort(stop);
252
252
  };
253
253
  stopWatch.onStop((record) => stopTurn(new TurnStopped(record.reason, record.at)));
254
- // The turn's deadline ends it on the same path (ADR-0252 §6.4): what it did
254
+ // The turn's deadline ends it on the same path: what it did
255
255
  // before it ran out of time is kept, marked, and the next turn is told.
256
256
  const deadlineTimer = setTimeout(() => stopTurn(new TurnStopped('deadline', Date.now())), turnDeadlineMs);
257
- // Before the deadline, the turn hands back with an answer when time is short (ADR-0269 §2.1).
257
+ // Before the deadline, the turn hands back with an answer when time is short.
258
258
  const stepClock = createStepClock({
259
259
  deadlineAt: turnStartedAt + turnDeadlineMs,
260
260
  turnDeadlineMs,
@@ -304,16 +304,16 @@ export async function runAgentTurn(config, input) {
304
304
  const toolInvocationCounts = new Map();
305
305
  const DEFAULT_TOOL_QUOTA = 12;
306
306
  const SIDE_EFFECT_TOOL_QUOTA = 2;
307
- // A UI action is not counted (session 24611234: filling 12 slides of 3 values each
307
+ // A UI action is not counted (filling 12 slides of 3 values each
308
308
  // ran one action 36 times, and a cap of 12 stopped it). What is refused is a loop:
309
309
  // the same call with the same input, made again after it changed nothing three
310
310
  // times in a row. Undo five times, or nudge a layer five times, is work: each changes the page.
311
311
  const UNCHANGED_REPEATS = 3;
312
312
  const uiRepeats = new Map();
313
313
  // What each call of the turn did: said back to the model before every step
314
- // after one did not succeed, so its reply matches it (ADR-0244 §2.5).
314
+ // after one did not succeed, so its reply matches it.
315
315
  const ledger = createTurnLedger();
316
- // ─── Approvals (ADR-0228) ──────────────────────────────────────────────────
316
+ // ─── Approvals ──────────────────────────────────────────────────
317
317
  // The first call in a turn that needs the user's approval stops the turn:
318
318
  // it is stored as a pending approval, the card is shown, and nothing else
319
319
  // runs until they decide. Each call is approved separately.
@@ -348,7 +348,7 @@ export async function runAgentTurn(config, input) {
348
348
  * A call refused before its tool ran: invalid input, over its quota, or
349
349
  * denied by policy. The model gets the reason; so does the client, as a
350
350
  * call that started and failed, so a session's record holds every call
351
- * the model made with its arguments (ADR-0244 §2.7).
351
+ * the model made with its arguments.
352
352
  */
353
353
  const refused = async (payload, given) => {
354
354
  ledger.record({ tool: t.name, ok: false, error: payload.error });
@@ -377,7 +377,7 @@ export async function runAgentTurn(config, input) {
377
377
  const timeoutMs = isUI
378
378
  ? Math.max(toolTimeoutMs, uiResultTimeoutMs + 5_000, Math.min(uiJobWaitMs, Math.max(0, uiWaitDeadline() - Date.now())) + uiResultTimeoutMs + 5_000)
379
379
  : toolTimeoutMs;
380
- // ── No changes while blind (ADR-0245 §2.5) ──
380
+ // ── No changes while blind ──
381
381
  // After an answer that came without the page's state, or no answer, only
382
382
  // reading runs until a read shows the page again. A change called then is
383
383
  // refused here, before its definition is fetched or policy is asked; one
@@ -395,7 +395,7 @@ export async function runAgentTurn(config, input) {
395
395
  // Before quota and policy: an invalid call consumes no quota and never
396
396
  // reaches the host. The model gets the errors so it can correct the call.
397
397
  // A UI action's schema is its definition's, fetched from the page when the
398
- // action is first used (ADR-0245 §2.1).
398
+ // action is first used.
399
399
  let schema = (t.inputSchema ?? {});
400
400
  if (t.resolveInputSchema) {
401
401
  try {
@@ -428,7 +428,7 @@ export async function runAgentTurn(config, input) {
428
428
  }, rawArgs);
429
429
  }
430
430
  const args = validation.value;
431
- // ── Attached files named in the call (ADR-0252 §2.13) ──
431
+ // ── Attached files named in the call ──
432
432
  // Each must be a file of this turn's conversation, ready, and of a type the
433
433
  // input takes, checked before anything is dispatched; the page then
434
434
  // resolves it through its own host. An action declaring a file where none
@@ -492,13 +492,13 @@ export async function runAgentTurn(config, input) {
492
492
  // The call as a repeat is judged by: its name and its exact input. Set for a UI action that changes the page.
493
493
  let repeatKey = null;
494
494
  // ── Quota enforcement ──
495
- // UI actions run as the user in their own session (ADR-0182 §3), so the
496
- // backend side-effect cap does not apply to them (ADR-0209 D5). They are
495
+ // UI actions run as the user in their own session, so the
496
+ // backend side-effect cap does not apply to them. They are
497
497
  // bounded by the turn's steps and deadline; only a repeated identical call is refused.
498
498
  const currentCount = toolInvocationCounts.get(t.name) ?? 0;
499
499
  const isSideEffecting = schema.sideEffects !== false; // fail-closed: undefined = side-effecting
500
500
  if (isUI) {
501
- // A UI action that only reads (a room's inspect and query, ADR-0244 §2.2)
501
+ // A UI action that only reads (a room's inspect and query)
502
502
  // changes nothing however often it is called.
503
503
  if (!reads) {
504
504
  let input;
@@ -530,7 +530,7 @@ export async function runAgentTurn(config, input) {
530
530
  toolInvocationCounts.set(t.name, currentCount + 1);
531
531
  }
532
532
  // ── Policy enforcement ──
533
- // A deny always wins, over an approval too (ADR-0228 §2.1).
533
+ // A deny always wins, over an approval too.
534
534
  const requirement = approvalRequirement(t);
535
535
  let policyRequiresApproval = false;
536
536
  if (config.toolPolicy) {
@@ -551,7 +551,7 @@ export async function runAgentTurn(config, input) {
551
551
  }
552
552
  policyRequiresApproval = decision.action === 'require_approval';
553
553
  }
554
- // ── Approval (ADR-0228) ──
554
+ // ── Approval ──
555
555
  // Checked and set with no await in between, so of the calls in one
556
556
  // response exactly the first that needs approval stops the turn.
557
557
  if (approvalHold && !approved) {
@@ -696,12 +696,12 @@ export async function runAgentTurn(config, input) {
696
696
  };
697
697
  };
698
698
  /**
699
- * Stops the turn at a call that needs the user's approval (ADR-0228 §2.2.1):
699
+ * Stops the turn at a call that needs the user's approval:
700
700
  * stores it as a pending approval, shows the card, and tells the model only
701
701
  * that it is waiting. The model never sees a token.
702
702
  */
703
703
  const requestApproval = async (t, args, toolUseId, requirement, files) => {
704
- // A file is shown by its name and size; the approval stays bound to its id (ADR-0252 §2.13).
704
+ // A file is shown by its name and size; the approval stays bound to its id.
705
705
  const preview = buildApprovalPreview(t, args, files);
706
706
  approvalHold = { approvalId: toolUseId, title: preview.title };
707
707
  const refuse = (why) => {
@@ -842,7 +842,7 @@ export async function runAgentTurn(config, input) {
842
842
  return builtUI;
843
843
  }
844
844
  // The host's tools the model is given. A host tool with a UI tool's name, or
845
- // with the id of an action of the page, is withheld (ADR-0209 D6): for a
845
+ // with the id of an action of the page, is withheld: for a
846
846
  // UI-only agent, the page is the authority.
847
847
  function hostTools(ui) {
848
848
  const sdkOwned = new Set(fileTools.map((t) => t.name));
@@ -952,7 +952,7 @@ export async function runAgentTurn(config, input) {
952
952
  return tools;
953
953
  }
954
954
  /**
955
- * The turn after the user's decision on an approval card (ADR-0228 §2.2.5):
955
+ * The turn after the user's decision on an approval card:
956
956
  * redeem the token and run exactly the stored call, or learn that they
957
957
  * declined. What happened goes to the model as an `<approval>` note.
958
958
  *
@@ -1130,7 +1130,7 @@ export async function runAgentTurn(config, input) {
1130
1130
  const stoppedBeforeStart = stopOf(abortController.signal);
1131
1131
  if (stoppedBeforeStart)
1132
1132
  return await finishStopped(stoppedBeforeStart, { expired: null, continued: null });
1133
- // ─── The turn after an approval decision (ADR-0228 §2.2.5) ────────────────
1133
+ // ─── The turn after an approval decision ────────────────
1134
1134
  const continued = input.approval ? await continueApproval(input.approval) : null;
1135
1135
  // ─── Calls still stored as waiting, whose approval expired undecided ──────
1136
1136
  //
@@ -1170,7 +1170,7 @@ export async function runAgentTurn(config, input) {
1170
1170
  continue;
1171
1171
  // The user had approved it and it was never run, or nobody decided: the result says which.
1172
1172
  const wasApproved = answer.decided === 'approved';
1173
- // Withdrawn (a new message, or its turn stopped) is said as that, not as time running out (ADR-0252 §2.6).
1173
+ // Withdrawn (a new message, or its turn stopped) is said as that, not as time running out.
1174
1174
  const content = notRunResult(answer.withdrawn
1175
1175
  ? withdrawnMarker(answer.withdrawn, wasApproved)
1176
1176
  : wasApproved
@@ -1224,7 +1224,7 @@ export async function runAgentTurn(config, input) {
1224
1224
  turnFilesGiven && input.history?.at(-1)?.role === 'user' ? input.history.length - 1 : null),
1225
1225
  ...(continued?.messages ?? []),
1226
1226
  ];
1227
- // The turn's files go with its message, after everything said about it (ADR-0252 §2.11).
1227
+ // The turn's files go with its message, after everything said about it.
1228
1228
  // A file that cannot be had is named with why; the turn goes on with the others.
1229
1229
  if (fileArea && turnFilesGiven) {
1230
1230
  try {
@@ -1363,9 +1363,9 @@ export async function runAgentTurn(config, input) {
1363
1363
  stopWhen: [
1364
1364
  isStepCount(maxRounds - allSteps.length),
1365
1365
  ...USER_INPUT_TOOLS.map((name) => hasToolCall(name)),
1366
- // A call is waiting for the user's approval: the turn ends here (ADR-0228).
1366
+ // A call is waiting for the user's approval: the turn ends here.
1367
1367
  () => approvalHold !== null,
1368
- // The step that handed the turn back for time was its last (ADR-0269 §2.1).
1368
+ // The step that handed the turn back for time was its last.
1369
1369
  () => handedBackForTime,
1370
1370
  ],
1371
1371
  ...(temperature !== undefined ? { temperature } : {}),
@@ -1464,7 +1464,7 @@ export async function runAgentTurn(config, input) {
1464
1464
  if (trimmed.newest !== undefined)
1465
1465
  newestAnswerState = trimmed.newest;
1466
1466
  }
1467
- // The files this step would carry, within the turn's and the conversation's caps (ADR-0252 §2.11).
1467
+ // The files this step would carry, within the turn's and the conversation's caps.
1468
1468
  const leftOutNow = fileGuard.beforeStep();
1469
1469
  if (leftOutNow.length > 0) {
1470
1470
  log('info', 'agent:tool', 'Files left out of the next step to keep within the cap', {
@@ -1580,7 +1580,7 @@ export async function runAgentTurn(config, input) {
1580
1580
  if (!stopOf(abortController.signal))
1581
1581
  throw err;
1582
1582
  }
1583
- // The model's tools no longer change with the page (ADR-0245 §2.2): what
1583
+ // The model's tools no longer change with the page: what
1584
1584
  // the page offers reaches it in each answer, so the turn runs as one segment.
1585
1585
  break;
1586
1586
  }
@@ -1655,7 +1655,7 @@ export async function runAgentTurn(config, input) {
1655
1655
  promptTokens: usage.promptTokens,
1656
1656
  cacheReadTokens: usage.cacheReadTokens,
1657
1657
  cacheWriteTokens: usage.cacheWriteTokens,
1658
- // How the page was worked (ADR-0245 §2.6).
1658
+ // How the page was worked.
1659
1659
  ...(client
1660
1660
  ? {
1661
1661
  ui: {
@@ -1726,7 +1726,7 @@ export async function runAgentTurn(config, input) {
1726
1726
  stopWatch.close();
1727
1727
  }
1728
1728
  /**
1729
- * The end of a stopped turn (ADR-0252 §2.4): settle what was in flight, store
1729
+ * The end of a stopped turn: settle what was in flight, store
1730
1730
  * what the turn had produced, then say so. Persist first, announce after, as
1731
1731
  * a turn that ends by itself does.
1732
1732
  *
@@ -1757,7 +1757,7 @@ export async function runAgentTurn(config, input) {
1757
1757
  clearTimeout(timer);
1758
1758
  }
1759
1759
  // A stopped turn leaves no live card: an approval it asked for as the stop came
1760
- // is withdrawn now, and a later turn records it as that (§2.6).
1760
+ // is withdrawn now, and a later turn records it as that.
1761
1761
  const held = approvalHold;
1762
1762
  if (held && config.approvals?.withdraw) {
1763
1763
  try {
@@ -1835,7 +1835,7 @@ export async function runAgentTurn(config, input) {
1835
1835
  return true;
1836
1836
  };
1837
1837
  // Whether what the turn had produced was stored: a deadline stop that could not store it is
1838
- // not a stopped turn but one that ran out of time with nothing kept (ADR-0252 §6.4).
1838
+ // not a stopped turn but one that ran out of time with nothing kept.
1839
1839
  let stored = true;
1840
1840
  if (config.beforeTurnComplete) {
1841
1841
  try {
@@ -1936,11 +1936,11 @@ turnMessageAt = null) {
1936
1936
  for (let idx = 0; idx < history.length; idx++) {
1937
1937
  const msg = history[idx];
1938
1938
  if (msg.role === 'user') {
1939
- // A message's files are in history as their reference lines, never their content (ADR-0252 §2.11).
1939
+ // A message's files are in history as their reference lines, never their content.
1940
1940
  messages.push({ role: 'user', content: idx === turnMessageAt ? msg.content : withReferenceLines(msg.content, msg.attachments ?? undefined) });
1941
1941
  }
1942
1942
  else if (msg.role === 'assistant') {
1943
- // A stopped turn's last message says so after its text (ADR-0252 §2.3).
1943
+ // A stopped turn's last message says so after its text.
1944
1944
  // A message that has only that carries the line as its whole text: an
1945
1945
  // empty text block is refused by a model provider.
1946
1946
  const stoppedLine = msg.stopped ? turnStoppedNote(msg.stopped) : null;