@ouispec/agent-worker 0.10.1 → 0.12.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 (54) hide show
  1. package/README.md +1 -0
  2. package/dist/index.d.ts +2 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +2 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/orchestrator.d.ts.map +1 -1
  7. package/dist/orchestrator.js +134 -77
  8. package/dist/orchestrator.js.map +1 -1
  9. package/dist/prompt/clock.d.ts +17 -7
  10. package/dist/prompt/clock.d.ts.map +1 -1
  11. package/dist/prompt/clock.js +4 -16
  12. package/dist/prompt/clock.js.map +1 -1
  13. package/dist/prompt/rules/base.d.ts.map +1 -1
  14. package/dist/prompt/rules/base.js +1 -0
  15. package/dist/prompt/rules/base.js.map +1 -1
  16. package/dist/prompt/rules/ui-control.js +1 -1
  17. package/dist/prompt/spoken-input.d.ts +6 -12
  18. package/dist/prompt/spoken-input.d.ts.map +1 -1
  19. package/dist/prompt/spoken-input.js +7 -19
  20. package/dist/prompt/spoken-input.js.map +1 -1
  21. package/dist/runtime/turn-runner.d.ts.map +1 -1
  22. package/dist/runtime/turn-runner.js +4 -1
  23. package/dist/runtime/turn-runner.js.map +1 -1
  24. package/dist/runtime/types.d.ts +20 -1
  25. package/dist/runtime/types.d.ts.map +1 -1
  26. package/dist/step-messages.d.ts +23 -0
  27. package/dist/step-messages.d.ts.map +1 -0
  28. package/dist/step-messages.js +51 -0
  29. package/dist/step-messages.js.map +1 -0
  30. package/dist/stop/partial.d.ts.map +1 -1
  31. package/dist/stop/partial.js +2 -1
  32. package/dist/stop/partial.js.map +1 -1
  33. package/dist/types.d.ts +16 -0
  34. package/dist/types.d.ts.map +1 -1
  35. package/dist/ui/answer-fit.d.ts +34 -0
  36. package/dist/ui/answer-fit.d.ts.map +1 -0
  37. package/dist/ui/answer-fit.js +105 -0
  38. package/dist/ui/answer-fit.js.map +1 -0
  39. package/dist/ui/page-state-at-end.d.ts +40 -0
  40. package/dist/ui/page-state-at-end.d.ts.map +1 -0
  41. package/dist/ui/{newest-page-state.js → page-state-at-end.js} +30 -31
  42. package/dist/ui/page-state-at-end.js.map +1 -0
  43. package/dist/ui/ui-tools.d.ts +2 -0
  44. package/dist/ui/ui-tools.d.ts.map +1 -1
  45. package/dist/ui/ui-tools.js +7 -3
  46. package/dist/ui/ui-tools.js.map +1 -1
  47. package/package.json +3 -3
  48. package/dist/prompt/user-text.d.ts +0 -19
  49. package/dist/prompt/user-text.d.ts.map +0 -1
  50. package/dist/prompt/user-text.js +0 -20
  51. package/dist/prompt/user-text.js.map +0 -1
  52. package/dist/ui/newest-page-state.d.ts +0 -25
  53. package/dist/ui/newest-page-state.d.ts.map +0 -1
  54. package/dist/ui/newest-page-state.js.map +0 -1
package/README.md CHANGED
@@ -19,6 +19,7 @@ Optional tuning, with its defaults:
19
19
  - `maxRounds`: 12
20
20
  - `maxTokens`: 32,000 per model response, thinking included. A step cut off there before it says or calls anything runs once more, told to plan less; if that is cut off too, the person is told and the turn ends with `stopReason: 'output_limit'`.
21
21
  - `temperature`: 0.3
22
+ - `forcedToolChoice`: true. Set `false` for a model that refuses a forced tool choice (Claude Sonnet 5.5 answers 400 to one): a step the turn policy forces to a tool is given only that tool and told to call it.
22
23
  - `toolTimeoutMs`: 30 s
23
24
  - `turnDeadlineMs`: 14 min (keep it below your host's own limit)
24
25
  - `retries`: 3
package/dist/index.d.ts CHANGED
@@ -54,6 +54,7 @@ export type { UISequence } from './ui/ui-sequence.js';
54
54
  export type { AgentApiSurface, EntityInstance, EntityFilter, EntityMutation, IntentResult, ViewAnnotationState, NavigationState, SessionApiSurface, LearningApiSurface, } from '@ouispec/agent-core';
55
55
  export { runAgentTurn } from './orchestrator.js';
56
56
  export { PROMPT_CACHE_BREAKPOINTS, describeModel } from './model.js';
57
+ export { answerWithoutState } from './ui/page-state-at-end.js';
57
58
  export type { LanguageModel, ProviderOptions } from './model.js';
58
59
  export type { TurnPolicy, StepTool } from './turn-policy.js';
59
60
  export { defaultTurnPolicy } from './turn-policy.js';
@@ -62,7 +63,7 @@ export type { HttpEmitAdapterConfig } from './emit/http-adapter.js';
62
63
  export { createAgentTurnRunner, categorizeError, payloadRefusal, TURN_DEADLINE_EXCEEDED } from './runtime/turn-runner.js';
63
64
  export type { AgentTurnRunner, TurnOutcome, CategorizedError } from './runtime/turn-runner.js';
64
65
  export { assertAgentRuntimeConfig } from './runtime/config.js';
65
- export type { AgentRuntimeConfig, LambdaAgentConfig, AgentTurnPayload, HistoryRequest } from './runtime/types.js';
66
+ export type { AgentRuntimeConfig, LambdaAgentConfig, AgentTurnPayload, HistoryRequest, TurnHistory } from './runtime/types.js';
66
67
  export { createLambdaAgentHandler } from './lambda/handler.js';
67
68
  export { startContainerAgentWorker } from './container/server.js';
68
69
  export type { ContainerAgentConfig, ContainerAgentWorker } from './container/server.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -44,6 +44,8 @@ export { createUISequence } from './ui/ui-sequence.js';
44
44
  export { runAgentTurn } from './orchestrator.js';
45
45
  // The model seam: any `ai` library model; the worker imports no provider.
46
46
  export { PROMPT_CACHE_BREAKPOINTS, describeModel } from './model.js';
47
+ // An answer as the model is sent it and as it is stored, for a host that fits answers stored before 0.11 (ADR-0263 §2.2).
48
+ export { answerWithoutState } from './ui/page-state-at-end.js';
47
49
  export { defaultTurnPolicy } from './turn-policy.js';
48
50
  export { createHttpEmitAdapter } from './emit/http-adapter.js';
49
51
  // The runtime: one core, two host adapters (Lambda + SQS, container)
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,eAAe,EAAmC,MAAM,YAAY,CAAC;AAqGtH;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,eAAe,CAAC,CA2xD1B"}
1
+ {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"AAkCA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,eAAe,EAAmC,MAAM,YAAY,CAAC;AAqGtH;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,eAAe,CAAC,CAw2D1B"}
@@ -28,10 +28,10 @@ import { evaluateToolPolicySafe } from './authz/tool-policy.js';
28
28
  import { createToolInputValidator } from './tools/input-validation.js';
29
29
  import { readClientPage, withoutClientUI } from './ui/snapshot.js';
30
30
  import { KNOWLEDGE_TOOL, knowledgeTool, readClientKnowledge, withClientKnowledge } from './ui/knowledge.js';
31
- import { withNewestPageStateOnly } from './ui/newest-page-state.js';
32
- import { withClock } from './prompt/clock.js';
33
- import { withSpokenInput } from './prompt/spoken-input.js';
34
- import { withUserText } from './prompt/user-text.js';
31
+ import { answerWithoutState, withStatesAtEnd } from './ui/page-state-at-end.js';
32
+ import { stepMessages as forStep, STEP_NOTE_CLOSE, STEP_NOTE_OPEN } from './step-messages.js';
33
+ import { clockText, readClientTimeZone } from './prompt/clock.js';
34
+ import { readClientMessageInput, spokenInputText } from './prompt/spoken-input.js';
35
35
  import { AttachmentGuard } from './attachments/guard.js';
36
36
  import { ATTACHMENT_DATA_NOTE, turnAttachmentParts, withReferenceLines, withTurnAttachments, withoutLeftOut } from './attachments/content.js';
37
37
  import { attachmentTools } from './attachments/tools.js';
@@ -139,8 +139,8 @@ export async function runAgentTurn(config, input) {
139
139
  // Whether the page can be seen (ADR-0245 §2.5): nothing that changes it runs while it cannot.
140
140
  const sight = createPageSight();
141
141
  const uiCounts = { describes: 0, reads: 0, acts: 0, guides: 0 };
142
- // Earlier answers' page states replaced, summed over the turn's steps.
143
- let pageStatesNotRepeated = 0;
142
+ // Answers whose page state was moved to the end of what the model reads, summed over the turn's steps.
143
+ let pageStatesMoved = 0;
144
144
  // The knowledge the client sent for its page goes after the host's prompt.
145
145
  const knowledge = readClientKnowledge(input.context ?? null);
146
146
  // ─── Files (ADR-0252 §2.11, §2.12) ─────────────────────────────────────────
@@ -797,6 +797,7 @@ export async function runAgentTurn(config, input) {
797
797
  channel: config.ui.channel,
798
798
  resultTimeoutMs: uiResultTimeoutMs,
799
799
  maxObservationChars: config.ui.maxObservationChars,
800
+ maxAnswerDataChars: config.ui.maxAnswerDataChars,
800
801
  waitDeadline: uiWaitDeadline,
801
802
  jobWaitMs: uiJobWaitMs,
802
803
  currentPage: () => currentPage,
@@ -1093,11 +1094,18 @@ export async function runAgentTurn(config, input) {
1093
1094
  // The system prompt has to travel as a message rather than the top-level
1094
1095
  // `system` field, because only a message carries `providerOptions`.
1095
1096
  //
1096
- // Two breakpoints, both on content that is append-only:
1097
+ // Three breakpoints, each on content that is append-only:
1097
1098
  // 1. system (+ tools) — identical for every round of a segment, and for
1098
1099
  // every turn on the same page.
1099
1100
  // 2. the end of the incoming history — stable across the rounds that follow
1100
1101
  // it, since a round appends rather than rewrites.
1102
+ // 3. the end of the conversation as each step sends it, moved forward every
1103
+ // step, so the next step reads this one's calls and answers from the
1104
+ // cache. With only the first two, everything after the user's message
1105
+ // went uncached at every step: on dev a turn's UI answers (up to tens of
1106
+ // thousands of tokens each) were paid in full again on every later step.
1107
+ // What a step alone is told (its notes) goes after the third, so it never
1108
+ // changes a prefix (step-messages.ts).
1101
1109
  //
1102
1110
  // Caching is a PREFIX match: one byte earlier in the prefix invalidates
1103
1111
  // everything after it. Nothing volatile may move ahead of these points — no
@@ -1186,27 +1194,25 @@ export async function runAgentTurn(config, input) {
1186
1194
  const stoppedBeforeModel = stopOf(abortController.signal);
1187
1195
  if (stoppedBeforeModel)
1188
1196
  return await finishStopped(stoppedBeforeModel, { expired, continued });
1189
- // Convert history to AI SDK CoreMessage format. The page the user is on
1190
- // travels with their message, not in the system prompt: it changes on every
1191
- // page, and in the system prompt it would invalidate the cached prefix. An
1192
- // approved call that ran is the result of the call the model made (see
1197
+ // Convert history to AI SDK CoreMessage format. Everything before the end
1198
+ // of the conversation is sent exactly as it was sent before, so the prompt
1199
+ // cache reads it (step-messages.ts). What is true only now — the page's
1200
+ // index and values, the user's clock, a note on calls whose approval
1201
+ // expired, the host's step context — is not added to the user's message,
1202
+ // where the next turn would send that message without it and write the
1203
+ // conversation from there to the cache again: the index goes after the
1204
+ // system prompt, the rest after the conversation (`stepTail`). An approved
1205
+ // call that ran is the result of the call the model made (see
1193
1206
  // continueApproval).
1194
- // The date and time on the user's clock travel with their message too: a
1195
- // model has no clock, and the changing minute must stay out of the cached
1196
- // system prompt (prompt/clock.ts).
1197
- // A message the person spoke says so straight after their words: it may hold a mis-heard word
1198
- // (prompt/spoken-input.ts). A click on an approval card is not a message, so it says nothing.
1199
1207
  const turnFilesGiven = !!fileArea && (input.attachments?.length ?? 0) > 0;
1200
1208
  const messages = [
1201
- ...withClock(withPageState(withNote(withSpokenInput(convertHistoryToCoreMessages(
1209
+ ...convertHistoryToCoreMessages(
1202
1210
  // An approved call's outcome, and an expired one's, is a later result of the call already in the
1203
1211
  // history: it takes that call's place.
1204
1212
  [...(input.history ?? []), ...expired.outcomes, ...(continued?.outcome ? [continued.outcome] : [])], [input.content, continued?.note].filter(Boolean).join('\n\n'),
1205
1213
  // The turn's own message, when the history already holds it: its files are given below,
1206
1214
  // each with its line, so the history's copy of the message does not name them again.
1207
- turnFilesGiven && input.history?.at(-1)?.role === 'user' ? input.history.length - 1 : null), input.approval ? null : (input.context ?? null)),
1208
- // Said on the user's message whether or not the host's history already holds that message.
1209
- expired.outcomes.length > 0 ? expiredNote(expired) : null), client, config.ui?.maxObservationChars ?? DEFAULT_PAGE_STATE_CHARS, config.ui?.maxIndexChars ?? DEFAULT_INDEX_CHARS), input.context ?? null),
1215
+ turnFilesGiven && input.history?.at(-1)?.role === 'user' ? input.history.length - 1 : null),
1210
1216
  ...(continued?.messages ?? []),
1211
1217
  ];
1212
1218
  // The turn's files go with its message, after everything said about it (ADR-0252 §2.11).
@@ -1248,11 +1254,69 @@ export async function runAgentTurn(config, input) {
1248
1254
  // `instructions` takes `string | SystemModelMessage | SystemModelMessage[]`,
1249
1255
  // and the message form carries `providerOptions`, so the breakpoint travels
1250
1256
  // with it. (`system` is the deprecated alias for the same type.)
1251
- const instructions = {
1257
+ const systemMessage = {
1252
1258
  role: 'system',
1253
1259
  content: systemPrompt,
1254
1260
  ...(cachePoint ? { providerOptions: cachePoint } : {}),
1255
1261
  };
1262
+ // What the page offers, after the system prompt with a breakpoint of its own:
1263
+ // it is the same for every step and every turn on the same page, so it is
1264
+ // read from the cache, and when the page changes only it and what follows are
1265
+ // written again. A change during the turn reaches the model in the answer
1266
+ // that made it (ui-tools.ts `forModel`).
1267
+ const pageIndex = client && client.page.length > 0
1268
+ ? {
1269
+ role: 'system',
1270
+ content: [
1271
+ '<page_index>',
1272
+ `The user's screen offers these surfaces and actions. Run an action with ${UI_ACT_TOOL}; ${UI_DESCRIBE_TOOL} says what one takes.`,
1273
+ indexText(client.page, config.ui?.maxIndexChars ?? DEFAULT_INDEX_CHARS),
1274
+ '</page_index>',
1275
+ ].join('\n'),
1276
+ ...(cachePoint ? { providerOptions: cachePoint } : {}),
1277
+ }
1278
+ : null;
1279
+ const instructions = pageIndex ? [systemMessage, pageIndex] : systemMessage;
1280
+ // ─── What is true now, after the conversation (step-messages.ts) ───────────
1281
+ // The turn's own message: answers after it are this turn's, and only those
1282
+ // are newer than the page the turn began on.
1283
+ const turnMessageAt = messages.map((m) => m.role).lastIndexOf('user');
1284
+ const turnClock = clockText(new Date(), readClientTimeZone(input.context ?? null));
1285
+ const turnSpoken = input.approval ? null : readClientMessageInput(input.context ?? null);
1286
+ const turnPageValues = client && client.page.length > 0
1287
+ ? [
1288
+ observationsText(client.observations, config.ui?.maxObservationChars ?? DEFAULT_PAGE_STATE_CHARS, {
1289
+ schemas: observationSchemas(client.page),
1290
+ }),
1291
+ client.fit?.observations?.length ? `Not shown: ${fitNotes(client.fit.observations).join(' ')}` : null,
1292
+ ]
1293
+ : null;
1294
+ /** The page's state from this turn's newest answer that carried one; until then, as the user's screen sent it. */
1295
+ let newestAnswerState;
1296
+ const stepTail = (notes) => [
1297
+ ...(turnPageValues
1298
+ ? [
1299
+ [
1300
+ '<page_state>',
1301
+ sight.blind()
1302
+ ? `Not current: an answer came without the page's state (${sight.blind()}). These values are from before it, so read the page before you change anything.`
1303
+ : newestAnswerState !== undefined
1304
+ ? 'The page as it is now, from the newest answer that carried its state.'
1305
+ : 'The page as it was when the user sent their message.',
1306
+ `Current values: ${newestAnswerState !== undefined ? JSON.stringify(newestAnswerState) : turnPageValues[0]}`,
1307
+ ...(newestAnswerState === undefined && turnPageValues[1] ? [turnPageValues[1]] : []),
1308
+ '</page_state>',
1309
+ ].join('\n'),
1310
+ ]
1311
+ : []),
1312
+ turnClock,
1313
+ // A message the person spoke may hold a mis-heard word (prompt/spoken-input.ts). A click on an
1314
+ // approval card is not a message, so it says nothing.
1315
+ ...(turnSpoken ? [spokenInputText(turnSpoken)] : []),
1316
+ ...(expired.outcomes.length > 0 ? [expiredNote(expired)] : []),
1317
+ ...(input.stepContext?.trim() ? [input.stepContext.trim()] : []),
1318
+ ...(notes.length > 0 ? [[STEP_NOTE_OPEN, ...notes, STEP_NOTE_CLOSE].join('\n')] : []),
1319
+ ];
1256
1320
  const withCachePoint = (msgs) => !cachePoint ? msgs : [
1257
1321
  ...msgs.slice(0, -1),
1258
1322
  ...msgs.slice(-1).map((m) => ({
@@ -1329,26 +1393,47 @@ export async function runAgentTurn(config, input) {
1329
1393
  forced,
1330
1394
  only: allowed && allowed.length < actionIds.length ? new Set(allowed) : null,
1331
1395
  };
1396
+ // The tool the policy forces, as the model knows it: an action is run through `ui_act`.
1397
+ const forcedTool = forced ? UI_ACT_TOOL : typeof policy.toolChoice === 'object' ? policy.toolChoice.toolName : null;
1398
+ const mustCall = forcedTool !== null || policy.toolChoice === 'required';
1399
+ // A model that refuses a forced choice (Claude Sonnet 5.5 answers 400 to `tool` and
1400
+ // `required`) is held to the step another way: it is given only the forced tool, and
1401
+ // told to call it. It can still answer in words instead, which a forced choice cannot.
1402
+ const held = mustCall && config.forcedToolChoice === false;
1332
1403
  const constraints = {
1333
- ...(policy.toolChoice ? { toolChoice: forced ? { type: 'tool', toolName: UI_ACT_TOOL } : policy.toolChoice } : {}),
1334
- ...(policy.activeTools
1335
- ? {
1336
- activeTools: [
1337
- ...policy.activeTools.filter((n) => !isAction(n)),
1338
- ...(allowed && allowed.length > 0 && !policy.activeTools.includes(UI_ACT_TOOL) ? [UI_ACT_TOOL] : []),
1339
- ],
1340
- }
1341
- : {}),
1404
+ ...(policy.toolChoice && !held ? { toolChoice: forced ? { type: 'tool', toolName: UI_ACT_TOOL } : policy.toolChoice } : {}),
1405
+ ...(held && forcedTool
1406
+ ? { activeTools: [forcedTool] }
1407
+ : policy.activeTools
1408
+ ? {
1409
+ activeTools: [
1410
+ ...policy.activeTools.filter((n) => !isAction(n)),
1411
+ ...(allowed && allowed.length > 0 && !policy.activeTools.includes(UI_ACT_TOOL) ? [UI_ACT_TOOL] : []),
1412
+ ],
1413
+ }
1414
+ : {}),
1342
1415
  };
1343
- // The policy's note goes after the system prompt, for this step only.
1344
- // ai carries an instructions override forward to later steps, so a step
1345
- // without a note sets the plain instructions back.
1346
- // So does the turn's record, once a call has not succeeded.
1347
- const notes = [note, forced ? `This step: call ${UI_ACT_TOOL} with action "${forced}".` : null, ledger.note(), outputLimitNote].filter((n) => !!n);
1348
- // The page's state on the newest answer only: an earlier page is not the page now.
1349
- const trimmed = messages ? withNewestPageStateOnly(messages) : null;
1350
- if (trimmed)
1351
- pageStatesNotRepeated += trimmed.replaced;
1416
+ // The policy's note, the forced action and the turn's record (once a call
1417
+ // has not succeeded) are for this step only. They go at the end of what
1418
+ // the model reads, after the moving cache breakpoint, never in the system
1419
+ // prompt: a note there changed the prefix of the whole conversation, so
1420
+ // the step that carried one, and the step after it, wrote the conversation
1421
+ // to the cache again instead of reading it.
1422
+ const stepCall = forced
1423
+ ? `This step: call ${UI_ACT_TOOL} with action "${forced}".`
1424
+ : held
1425
+ ? forcedTool
1426
+ ? `This step: call ${forcedTool}. It is the only tool this step has.`
1427
+ : 'This step: call a tool.'
1428
+ : null;
1429
+ const notes = [note, stepCall, ledger.note(), outputLimitNote].filter((n) => !!n);
1430
+ // Every answer gives its page state up the same way; the newest of this turn's is read at the end.
1431
+ const trimmed = messages ? withStatesAtEnd(messages, turnMessageAt) : null;
1432
+ if (trimmed) {
1433
+ pageStatesMoved += trimmed.moved;
1434
+ if (trimmed.newest !== undefined)
1435
+ newestAnswerState = trimmed.newest;
1436
+ }
1352
1437
  // The files this step would carry, within the turn's and the conversation's caps (ADR-0252 §2.11).
1353
1438
  const leftOutNow = fileGuard.beforeStep();
1354
1439
  if (leftOutNow.length > 0) {
@@ -1358,13 +1443,11 @@ export async function runAgentTurn(config, input) {
1358
1443
  });
1359
1444
  }
1360
1445
  const leftOut = fileGuard.leftOutParts();
1361
- const stepMessages = leftOut.length > 0 && messages ? withoutLeftOut(trimmed?.messages ?? messages, leftOut) : trimmed?.messages;
1446
+ const stepMessages = leftOut.length > 0 && messages ? withoutLeftOut(trimmed?.messages ?? messages, leftOut) : trimmed?.messages ?? messages;
1362
1447
  return {
1363
1448
  ...constraints,
1364
- ...(stepMessages ? { messages: stepMessages } : {}),
1365
- instructions: notes.length
1366
- ? [instructions, ...notes.map((content) => ({ role: 'system', content }))]
1367
- : instructions,
1449
+ ...(stepMessages ? { messages: forStep(stepMessages, stepTail(notes), cachePoint) } : {}),
1450
+ instructions,
1368
1451
  };
1369
1452
  },
1370
1453
  onStepEnd: async ({ text, toolCalls, usage: stepUsage, finishReason }) => {
@@ -1388,6 +1471,10 @@ export async function runAgentTurn(config, input) {
1388
1471
  totalTextEmitted,
1389
1472
  finishReason,
1390
1473
  outputTokens: stepUsage?.outputTokens ?? 0,
1474
+ // How this step's input was billed: read from the cache, written to it, or neither.
1475
+ inputTokens: stepUsage?.inputTokens ?? 0,
1476
+ cacheReadTokens: stepUsage?.inputTokenDetails?.cacheReadTokens ?? 0,
1477
+ cacheWriteTokens: stepUsage?.inputTokenDetails?.cacheWriteTokens ?? 0,
1391
1478
  });
1392
1479
  },
1393
1480
  });
@@ -1546,7 +1633,7 @@ export async function runAgentTurn(config, input) {
1546
1633
  // What bounds the model: the page's index as it reads it, against the most it is given
1547
1634
  // before the furthest surfaces are listed by id only.
1548
1635
  indexChars: indexText(client.page, Infinity).length,
1549
- pageStatesNotRepeated,
1636
+ pageStatesMoved,
1550
1637
  maxIndexChars: config.ui?.maxIndexChars ?? DEFAULT_INDEX_CHARS,
1551
1638
  },
1552
1639
  }
@@ -1762,37 +1849,6 @@ export async function runAgentTurn(config, input) {
1762
1849
  };
1763
1850
  }
1764
1851
  }
1765
- /** Put a note for the model on the turn's user message, after what the user said. */
1766
- function withNote(messages, note) {
1767
- const last = messages[messages.length - 1];
1768
- if (!note || !last || last.role !== 'user')
1769
- return messages;
1770
- return [...messages.slice(0, -1), withUserText(last, note)];
1771
- }
1772
- /**
1773
- * Put the client's page on the user's message: what it offers, as an index of
1774
- * its actions, and its latest observations. The model reads it as part of what
1775
- * the user said, where it is true for this message only. The index has its own
1776
- * budget, so it never crowds the page's state out (ADR-0245 §2.2).
1777
- */
1778
- function withPageState(messages, client, maxChars, maxIndexChars) {
1779
- if (!client || client.page.length === 0)
1780
- return messages;
1781
- const last = messages[messages.length - 1];
1782
- if (!last || last.role !== 'user')
1783
- return messages;
1784
- const observations = observationsText(client.observations, maxChars, { schemas: observationSchemas(client.page) });
1785
- const notShown = client.fit?.observations?.length ? fitNotes(client.fit.observations) : [];
1786
- const pageState = [
1787
- '<page_state>',
1788
- `The user's screen offers these surfaces and actions. Run an action with ${UI_ACT_TOOL}; ${UI_DESCRIBE_TOOL} says what one takes.`,
1789
- indexText(client.page, maxIndexChars),
1790
- `Current values: ${observations}`,
1791
- ...(notShown.length ? [`Not shown: ${notShown.join(' ')}`] : []),
1792
- '</page_state>',
1793
- ].join('\n');
1794
- return [...messages.slice(0, -1), withUserText(last, pageState)];
1795
- }
1796
1852
  /**
1797
1853
  * Convert our TurnHistoryMessage[] to AI SDK CoreMessage[].
1798
1854
  * The AI SDK handles each provider's message format internally.
@@ -2009,7 +2065,8 @@ function convertResponseToTurnMessages(result, executedToolResults) {
2009
2065
  const tracked = executedToolResults[resultIdx++];
2010
2066
  turnMessages.push({
2011
2067
  role: 'tool',
2012
- content: tracked.result,
2068
+ // Stored as the model is sent it, so the history sends it the same way every turn.
2069
+ content: answerWithoutState(tracked.result),
2013
2070
  toolCallId: tracked.toolCallId,
2014
2071
  name: tracked.toolName,
2015
2072
  });