@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.
- package/README.md +9 -9
- package/dist/approvals/client.d.ts +2 -2
- package/dist/approvals/continuation.d.ts +2 -2
- package/dist/approvals/preview.d.ts +1 -1
- package/dist/approvals/preview.js +1 -1
- package/dist/approvals/requirement.js +1 -1
- package/dist/attachments/content.d.ts +2 -2
- package/dist/attachments/guard.js +1 -1
- package/dist/attachments/limits.d.ts +2 -2
- package/dist/attachments/limits.d.ts.map +1 -1
- package/dist/attachments/limits.js +2 -2
- package/dist/attachments/limits.js.map +1 -1
- package/dist/attachments/store.d.ts +3 -3
- package/dist/attachments/store.d.ts.map +1 -1
- package/dist/attachments/tools.js +2 -2
- package/dist/attachments/tools.js.map +1 -1
- package/dist/authz/tool-policy.d.ts +4 -4
- package/dist/authz/tool-policy.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/dist/model.d.ts +1 -1
- package/dist/openapi/executor.d.ts +1 -1
- package/dist/openapi/index.d.ts +1 -1
- package/dist/openapi/index.js +1 -1
- package/dist/openapi/loader.d.ts +4 -4
- package/dist/openapi/loader.js +7 -7
- package/dist/openapi/loader.js.map +1 -1
- package/dist/openapi/x-agent.d.ts +2 -2
- package/dist/openapi/x-agent.js +2 -2
- package/dist/orchestrator.d.ts +1 -1
- package/dist/orchestrator.js +42 -42
- package/dist/orchestrator.js.map +1 -1
- package/dist/prompt/rules/ui-control.d.ts +3 -3
- package/dist/prompt/rules/ui-control.js +3 -3
- package/dist/prompt/spoken-input.d.ts +1 -1
- package/dist/prompt/spoken-input.js +1 -1
- package/dist/runtime/config.js +1 -1
- package/dist/runtime/turn-runner.d.ts +2 -2
- package/dist/runtime/turn-runner.d.ts.map +1 -1
- package/dist/runtime/turn-runner.js +5 -5
- package/dist/runtime/turn-runner.js.map +1 -1
- package/dist/runtime/types.d.ts +16 -16
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/stop/partial.d.ts +1 -1
- package/dist/stop/partial.js +1 -1
- package/dist/stop/results.d.ts +1 -1
- package/dist/stop/turn-stop.d.ts +3 -3
- package/dist/stop/turn-stop.d.ts.map +1 -1
- package/dist/stop/turn-stop.js +1 -1
- package/dist/stop/turn-stop.js.map +1 -1
- package/dist/testing/desk-events.d.ts +1 -1
- package/dist/testing/desk-events.js +1 -1
- package/dist/time-hand-back.d.ts +3 -3
- package/dist/time-hand-back.js +3 -3
- package/dist/tools/async-binding.d.ts +1 -1
- package/dist/tools/builtin-tools.d.ts +3 -3
- package/dist/tools/entity-tools.d.ts.map +1 -1
- package/dist/tools/entity-tools.js +0 -1
- package/dist/tools/entity-tools.js.map +1 -1
- package/dist/tools/load-all-tools.d.ts.map +1 -1
- package/dist/tools/load-all-tools.js +0 -1
- package/dist/tools/load-all-tools.js.map +1 -1
- package/dist/tools/schema-loader.d.ts.map +1 -1
- package/dist/tools/schema-loader.js +1 -2
- package/dist/tools/schema-loader.js.map +1 -1
- package/dist/tools/types.d.ts +9 -9
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/turn-ledger.d.ts +1 -1
- package/dist/turn-ledger.js +1 -1
- package/dist/types.d.ts +13 -13
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/answer-image.d.ts +1 -1
- package/dist/ui/answer-image.js +1 -1
- package/dist/ui/channel.d.ts +1 -1
- package/dist/ui/knowledge.d.ts +2 -2
- package/dist/ui/observations.d.ts +2 -2
- package/dist/ui/observations.js +2 -2
- package/dist/ui/outline.d.ts +1 -1
- package/dist/ui/outline.js +1 -1
- package/dist/ui/page-index.d.ts +1 -1
- package/dist/ui/page-index.js +1 -1
- package/dist/ui/snapshot.d.ts +2 -2
- package/dist/ui/snapshot.d.ts.map +1 -1
- package/dist/ui/ui-tools.d.ts +1 -1
- package/dist/ui/ui-tools.js +8 -8
- package/dist/ui/ui-tools.js.map +1 -1
- package/package.json +6 -6
package/dist/openapi/x-agent.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `x-agent`: how an operation opts in as an agent tool
|
|
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 #
|
|
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
|
package/dist/orchestrator.d.ts
CHANGED
|
@@ -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
|
|
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>;
|
package/dist/orchestrator.js
CHANGED
|
@@ -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
|
-
* (
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 (
|
|
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
|
|
314
|
+
// after one did not succeed, so its reply matches it.
|
|
315
315
|
const ledger = createTurnLedger();
|
|
316
|
-
// ─── Approvals
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
496
|
-
// backend side-effect cap does not apply to them
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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;
|