zidane 5.13.26 → 5.14.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.
- package/dist/{acp-CjAoILwj.js → acp-DgKEJH3P.js} +7 -7
- package/dist/{acp-CjAoILwj.js.map → acp-DgKEJH3P.js.map} +1 -1
- package/dist/acp-cli.js +11 -6
- package/dist/acp-cli.js.map +1 -1
- package/dist/acp.d.ts +2 -2
- package/dist/acp.js +1 -1
- package/dist/{tools-B32lZXLE.js → agent-B-cKanSC.js} +8035 -9459
- package/dist/agent-B-cKanSC.js.map +1 -0
- package/dist/{agent-DQIL5BFk.d.ts → agent-BAgOgS37.d.ts} +367 -208
- package/dist/agent-BAgOgS37.d.ts.map +1 -0
- package/dist/agent.d.ts +3 -0
- package/dist/agent.js +5 -0
- package/dist/anthropic-RGqsJlC8.js +807 -0
- package/dist/anthropic-RGqsJlC8.js.map +1 -0
- package/dist/{atomic-write-Bgtr5JPu.js → atomic-write-B7zr1ddF.js} +2 -2
- package/dist/{atomic-write-Bgtr5JPu.js.map → atomic-write-B7zr1ddF.js.map} +1 -1
- package/dist/{auth-DPrSP1YV.js → auth-C-ms5N2x.js} +33 -5
- package/dist/{auth-DPrSP1YV.js.map → auth-C-ms5N2x.js.map} +1 -1
- package/dist/cache-telemetry-BKAwsNxm.js +169 -0
- package/dist/cache-telemetry-BKAwsNxm.js.map +1 -0
- package/dist/chat/pure.d.ts +3 -3
- package/dist/chat/pure.js +1 -1
- package/dist/chat.d.ts +21 -7
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +30 -5
- package/dist/chat.js.map +1 -1
- package/dist/contexts/daytona.d.ts +1 -1
- package/dist/contexts/docker.js +0 -1
- package/dist/contexts/docker.js.map +1 -1
- package/dist/contexts/e2b.d.ts +1 -1
- package/dist/errors-CkTvg97v.d.ts +203 -0
- package/dist/errors-CkTvg97v.d.ts.map +1 -0
- package/dist/errors.d.ts +3 -0
- package/dist/errors.js +3 -0
- package/dist/eval.d.ts +1 -1
- package/dist/eval.js +2 -2
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +406 -1
- package/dist/headless.js.map +1 -0
- package/dist/{index-YY3vp2F2.d.ts → index-CLuLFFLa.d.ts} +88 -418
- package/dist/index-CLuLFFLa.d.ts.map +1 -0
- package/dist/{index-C5qw3pj7.d.ts → index-CgBIl2mX.d.ts} +2 -2
- package/dist/{index-C5qw3pj7.d.ts.map → index-CgBIl2mX.d.ts.map} +1 -1
- package/dist/index.d.ts +9 -5
- package/dist/index.js +113 -167
- package/dist/index.js.map +1 -1
- package/dist/{logger-C2ngE8CY.d.ts → logger-CJ-lpKPy.d.ts} +2 -2
- package/dist/{logger-C2ngE8CY.d.ts.map → logger-CJ-lpKPy.d.ts.map} +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/messages-YZQLKaz2.js +1157 -0
- package/dist/messages-YZQLKaz2.js.map +1 -0
- package/dist/oauth-8LqbeI_Q.js +292 -0
- package/dist/oauth-8LqbeI_Q.js.map +1 -0
- package/dist/{messages-Iy_vEycX.js → openai-compat-0Y7jcncn.js} +27 -1379
- package/dist/openai-compat-0Y7jcncn.js.map +1 -0
- package/dist/output/stream-json.d.ts +2 -2
- package/dist/output/stream-json.js +1 -1
- package/dist/output/terminal.d.ts +2 -2
- package/dist/{presets-B9nDwmaz.js → presets-Pr02ZNcy.js} +3 -2
- package/dist/{presets-B9nDwmaz.js.map → presets-Pr02ZNcy.js.map} +1 -1
- package/dist/presets.d.ts +2 -2
- package/dist/presets.js +1 -1
- package/dist/prompt.d.ts +2 -0
- package/dist/prompt.js +210 -0
- package/dist/prompt.js.map +1 -0
- package/dist/providers/anthropic.d.ts +2 -0
- package/dist/providers/anthropic.js +2 -0
- package/dist/providers/arcee.d.ts +2 -0
- package/dist/providers/arcee.js +42 -0
- package/dist/providers/arcee.js.map +1 -0
- package/dist/providers/baseten.d.ts +2 -0
- package/dist/providers/baseten.js +66 -0
- package/dist/providers/baseten.js.map +1 -0
- package/dist/providers/cerebras.d.ts +2 -0
- package/dist/providers/cerebras.js +31 -0
- package/dist/providers/cerebras.js.map +1 -0
- package/dist/providers/local.d.ts +2 -0
- package/dist/providers/local.js +44 -0
- package/dist/providers/local.js.map +1 -0
- package/dist/providers/openai-compat.d.ts +2 -0
- package/dist/providers/openai-compat.js +2 -0
- package/dist/providers/openai.d.ts +2 -0
- package/dist/providers/openai.js +504 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/providers/openrouter.d.ts +2 -0
- package/dist/providers/openrouter.js +52 -0
- package/dist/providers/openrouter.js.map +1 -0
- package/dist/providers/xai.d.ts +2 -0
- package/dist/providers/xai.js +2 -0
- package/dist/providers-DgmdYGKm.js +168 -0
- package/dist/providers-DgmdYGKm.js.map +1 -0
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +10 -2
- package/dist/restate.d.ts +1 -1
- package/dist/run-summary-DAnBZnrt.d.ts +249 -0
- package/dist/run-summary-DAnBZnrt.d.ts.map +1 -0
- package/dist/run-summary-nD3IQ4ZQ.js +253 -0
- package/dist/run-summary-nD3IQ4ZQ.js.map +1 -0
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/{session-CiA1_8SB.js → session-CqrAFAKJ.js} +2 -2
- package/dist/{session-CiA1_8SB.js.map → session-CqrAFAKJ.js.map} +1 -1
- package/dist/session.d.ts +1 -1
- package/dist/session.js +2 -2
- package/dist/skills.d.ts +2 -2
- package/dist/system-prompt-BlsdjcUi.d.ts +139 -0
- package/dist/system-prompt-BlsdjcUi.d.ts.map +1 -0
- package/dist/timeout-CpFm0jJ6.d.ts +10 -0
- package/dist/timeout-CpFm0jJ6.d.ts.map +1 -0
- package/dist/timeout-kGGSXagK.js +84 -0
- package/dist/timeout-kGGSXagK.js.map +1 -0
- package/dist/{tool-formatters-w5oaoCS4.d.ts → tool-formatters-Ch8oRpYR.d.ts} +2 -2
- package/dist/{tool-formatters-w5oaoCS4.d.ts.map → tool-formatters-Ch8oRpYR.d.ts.map} +1 -1
- package/dist/tools/fetch-url.d.ts +1 -1
- package/dist/tools/web-search.d.ts +1 -1
- package/dist/tools-00_Nqazv.js +1689 -0
- package/dist/tools-00_Nqazv.js.map +1 -0
- package/dist/tools.d.ts +2 -2
- package/dist/tools.js +2 -1
- package/dist/{transcript-anchors-BUtOd-qa.js → transcript-anchors-BUmvPnis.js} +10 -9
- package/dist/{transcript-anchors-BUtOd-qa.js.map → transcript-anchors-BUmvPnis.js.map} +1 -1
- package/dist/{transcript-anchors-BJ-ESWnm.d.ts → transcript-anchors-CL9UM_M4.d.ts} +4 -4
- package/dist/{transcript-anchors-BJ-ESWnm.d.ts.map → transcript-anchors-CL9UM_M4.d.ts.map} +1 -1
- package/dist/tui.d.ts +3 -3
- package/dist/tui.js +38 -13
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-BSSQHNq1.d.ts → turn-operations-Cj6v_ypW.d.ts} +3 -3
- package/dist/{turn-operations-BSSQHNq1.d.ts.map → turn-operations-Cj6v_ypW.d.ts.map} +1 -1
- package/dist/{turn-operations-B_XeuNp-.js → turn-operations-tG0vuBNc.js} +2 -2
- package/dist/{turn-operations-B_XeuNp-.js.map → turn-operations-tG0vuBNc.js.map} +1 -1
- package/dist/types-CyVGdbia.js.map +1 -1
- package/dist/types.d.ts +4 -3
- package/dist/xai-tPdbAGkq.js +379 -0
- package/dist/xai-tPdbAGkq.js.map +1 -0
- package/docs/ARCHITECTURE.md +4 -2
- package/docs/CHAT.md +4 -0
- package/docs/SKILL.md +31 -5
- package/package.json +63 -1
- package/dist/agent-DQIL5BFk.d.ts.map +0 -1
- package/dist/headless-2SH7dvoW.js +0 -656
- package/dist/headless-2SH7dvoW.js.map +0 -1
- package/dist/index-YY3vp2F2.d.ts.map +0 -1
- package/dist/messages-Iy_vEycX.js.map +0 -1
- package/dist/providers-BMw1D_lj.js +0 -2332
- package/dist/providers-BMw1D_lj.js.map +0 -1
- package/dist/tools-B32lZXLE.js.map +0 -1
package/dist/headless.js
CHANGED
|
@@ -1,2 +1,407 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as documentBlockMarker, n as assertResolvedMediaBlock, s as toolResultToText } from "./types-CyVGdbia.js";
|
|
2
|
+
import { t as createAgent } from "./agent-B-cKanSC.js";
|
|
3
|
+
import { n as createProcessContext } from "./contexts-BebciJyQ.js";
|
|
4
|
+
import { t as audioFormatFromMediaType } from "./media-sniff-Bn76JxAu.js";
|
|
5
|
+
import { p as toAnthropic, s as ensureToolResultPairing } from "./messages-YZQLKaz2.js";
|
|
6
|
+
import { i as basic_default } from "./presets-Pr02ZNcy.js";
|
|
7
|
+
import { t as createRunSummaryCollector } from "./run-summary-nD3IQ4ZQ.js";
|
|
8
|
+
import { a as createMemoryStore, t as createSession } from "./session-CqrAFAKJ.js";
|
|
9
|
+
//#region src/headless.ts
|
|
10
|
+
function exitCodeForHeadlessResult(result) {
|
|
11
|
+
switch (result.status) {
|
|
12
|
+
case "completed": return 0;
|
|
13
|
+
case "timeout": return 124;
|
|
14
|
+
case "aborted": return 130;
|
|
15
|
+
default: return 1;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** Serialize one event as a newline-terminated JSON line (stream-json). */
|
|
19
|
+
function headlessEventToJsonl(event) {
|
|
20
|
+
return `${JSON.stringify(event)}\n`;
|
|
21
|
+
}
|
|
22
|
+
function formattedHeadlessTurnEventToJsonl(event) {
|
|
23
|
+
return `${JSON.stringify(event)}\n`;
|
|
24
|
+
}
|
|
25
|
+
function providerTranscriptFormatForProvider(providerName) {
|
|
26
|
+
return providerName === "anthropic" ? "anthropic" : "openai";
|
|
27
|
+
}
|
|
28
|
+
function transcriptToProviderMessages(turns, providerName) {
|
|
29
|
+
if (providerTranscriptFormatForProvider(providerName) === "anthropic") return turns.filter((turn) => turn.role === "user" || turn.role === "assistant").map((turn) => toAnthropic({
|
|
30
|
+
role: turn.role,
|
|
31
|
+
content: turn.content
|
|
32
|
+
}));
|
|
33
|
+
return transcriptToOpenAIMessages(turns, { strictToolPairing: false });
|
|
34
|
+
}
|
|
35
|
+
function formatHeadlessResult(result, options) {
|
|
36
|
+
if (options.format === "zidane") return result;
|
|
37
|
+
return transcriptToProviderMessages(result.transcript, options.providerName);
|
|
38
|
+
}
|
|
39
|
+
function formatHeadlessTurnEvent(event, options) {
|
|
40
|
+
if (options.format === "zidane") return event;
|
|
41
|
+
return transcriptToProviderMessages([event.turn], options.providerName);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Run a prompt to completion, headless, and return a single serializable
|
|
45
|
+
* {@link HeadlessResult}. Safe to call concurrently for parallel rollouts —
|
|
46
|
+
* each call builds its own agent + session and tears them down in `finally`.
|
|
47
|
+
*/
|
|
48
|
+
async function runHeadless(opts) {
|
|
49
|
+
const startedAt = Date.now();
|
|
50
|
+
const execution = opts.execution ?? createProcessContext({ cwd: opts.cwd });
|
|
51
|
+
const session = opts.session ?? await createSession({ store: opts.store ?? createMemoryStore() });
|
|
52
|
+
const behavior = { ...opts.behavior ?? {} };
|
|
53
|
+
if (opts.maxTurns !== void 0) behavior.maxTurns = opts.maxTurns;
|
|
54
|
+
if (opts.maxTokens !== void 0) behavior.maxTokens = opts.maxTokens;
|
|
55
|
+
if (opts.schema !== void 0) behavior.schema = opts.schema;
|
|
56
|
+
const agent = createAgent({
|
|
57
|
+
...basic_default,
|
|
58
|
+
provider: opts.provider,
|
|
59
|
+
execution,
|
|
60
|
+
session,
|
|
61
|
+
behavior,
|
|
62
|
+
...opts.tools !== void 0 ? { tools: opts.tools } : {},
|
|
63
|
+
...opts.mcpServers !== void 0 ? { mcpServers: opts.mcpServers } : {},
|
|
64
|
+
...opts.skills !== void 0 ? { skills: opts.skills } : {}
|
|
65
|
+
});
|
|
66
|
+
const collector = createRunSummaryCollector();
|
|
67
|
+
const uninstallSummary = collector.install(agent.hooks);
|
|
68
|
+
const uninstallEvents = opts.onEvent ? installHeadlessEventAdapter(agent.hooks, opts.onEvent) : noop;
|
|
69
|
+
const runStartIndex = session.turns.length;
|
|
70
|
+
const controller = new AbortController();
|
|
71
|
+
const onExternalAbort = () => controller.abort(opts.signal.reason);
|
|
72
|
+
if (opts.signal) if (opts.signal.aborted) controller.abort(opts.signal.reason);
|
|
73
|
+
else opts.signal.addEventListener("abort", onExternalAbort, { once: true });
|
|
74
|
+
let timedOut = false;
|
|
75
|
+
const timer = opts.timeoutMs && opts.timeoutMs > 0 ? setTimeout(() => {
|
|
76
|
+
timedOut = true;
|
|
77
|
+
controller.abort(/* @__PURE__ */ new Error(`Headless run timed out after ${opts.timeoutMs}ms`));
|
|
78
|
+
}, opts.timeoutMs) : void 0;
|
|
79
|
+
let stats;
|
|
80
|
+
let error;
|
|
81
|
+
try {
|
|
82
|
+
stats = await agent.run({
|
|
83
|
+
prompt: opts.prompt,
|
|
84
|
+
signal: controller.signal,
|
|
85
|
+
...opts.model !== void 0 ? { model: opts.model } : {},
|
|
86
|
+
...opts.system !== void 0 ? { system: opts.system } : {},
|
|
87
|
+
...opts.thinking !== void 0 ? { thinking: opts.thinking } : {}
|
|
88
|
+
});
|
|
89
|
+
} catch (err) {
|
|
90
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
91
|
+
error = {
|
|
92
|
+
message: e.message,
|
|
93
|
+
type: e.name
|
|
94
|
+
};
|
|
95
|
+
} finally {
|
|
96
|
+
if (timer) clearTimeout(timer);
|
|
97
|
+
opts.signal?.removeEventListener("abort", onExternalAbort);
|
|
98
|
+
uninstallEvents();
|
|
99
|
+
uninstallSummary();
|
|
100
|
+
await agent.destroy();
|
|
101
|
+
}
|
|
102
|
+
let status;
|
|
103
|
+
if (error) status = timedOut ? "timeout" : controller.signal.aborted ? "aborted" : "error";
|
|
104
|
+
else if (controller.signal.aborted) status = timedOut ? "timeout" : "aborted";
|
|
105
|
+
else status = "completed";
|
|
106
|
+
const rawTranscript = session.turns.slice(runStartIndex);
|
|
107
|
+
const transcript = opts.includeThinking === false ? stripThinking(rawTranscript) : rawTranscript;
|
|
108
|
+
const summary = collector.latest();
|
|
109
|
+
const result = {
|
|
110
|
+
status,
|
|
111
|
+
finalText: extractFinalText(rawTranscript),
|
|
112
|
+
...stats?.output ? { output: stats.output } : {},
|
|
113
|
+
usage: {
|
|
114
|
+
input: stats?.totalIn ?? 0,
|
|
115
|
+
output: stats?.totalOut ?? 0,
|
|
116
|
+
cacheRead: stats?.totalCacheRead ?? 0,
|
|
117
|
+
cacheCreation: stats?.totalCacheCreation ?? 0,
|
|
118
|
+
...typeof stats?.cost === "number" ? { cost: stats.cost } : {}
|
|
119
|
+
},
|
|
120
|
+
turns: stats?.turns ?? 0,
|
|
121
|
+
durationMs: stats?.elapsed ?? Date.now() - startedAt,
|
|
122
|
+
numToolCalls: countToolCalls(rawTranscript),
|
|
123
|
+
...status !== "aborted" && status !== "timeout" && lastFinishReason(stats) ? { finishReason: lastFinishReason(stats) } : {},
|
|
124
|
+
...error ? { error } : {},
|
|
125
|
+
sessionId: session.id,
|
|
126
|
+
...summary ? { summary } : {},
|
|
127
|
+
transcript
|
|
128
|
+
};
|
|
129
|
+
opts.onEvent?.({
|
|
130
|
+
type: "result",
|
|
131
|
+
result
|
|
132
|
+
});
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Convert raw `session.turns` into standard OpenAI chat-completion messages:
|
|
137
|
+
* assistant turns carry `tool_calls`, and each `tool_result` becomes its own
|
|
138
|
+
* `role: 'tool'` message. This is the drop-in shape for an SFT renderer —
|
|
139
|
+
* unlike `toOpenAI` (session/messages.ts), which emits an internal `_tag`
|
|
140
|
+
* envelope meant for re-sending to a provider, not for training data.
|
|
141
|
+
*
|
|
142
|
+
* Fails closed on corrupt raw turns instead of fabricating tool results; silent
|
|
143
|
+
* placeholders would create structurally-valid but semantically-poisoned SFT
|
|
144
|
+
* examples.
|
|
145
|
+
*/
|
|
146
|
+
function transcriptToOpenAIMessages(turns, options = {}) {
|
|
147
|
+
const { strictToolPairing = true } = options;
|
|
148
|
+
const messages = [];
|
|
149
|
+
let chunk = [];
|
|
150
|
+
const flushChunk = () => {
|
|
151
|
+
if (chunk.length === 0) return;
|
|
152
|
+
let paired = chunk;
|
|
153
|
+
if (strictToolPairing) {
|
|
154
|
+
const repairs = [];
|
|
155
|
+
paired = ensureToolResultPairing(chunk, { onRepair: (repair) => repairs.push(repair) });
|
|
156
|
+
if (repairs.length > 0) throw new Error(`Cannot convert transcript to OpenAI messages: tool pairing repair required (${repairs.map((r) => r.mode).join(", ")})`);
|
|
157
|
+
}
|
|
158
|
+
for (const msg of paired) pushOpenAIChatMessage(messages, msg);
|
|
159
|
+
chunk = [];
|
|
160
|
+
};
|
|
161
|
+
for (const turn of turns) {
|
|
162
|
+
if (turn.role === "system") {
|
|
163
|
+
flushChunk();
|
|
164
|
+
messages.push({
|
|
165
|
+
role: "system",
|
|
166
|
+
content: textOf(turn.content)
|
|
167
|
+
});
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
chunk.push({
|
|
171
|
+
role: turn.role,
|
|
172
|
+
content: turn.content
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
flushChunk();
|
|
176
|
+
return messages;
|
|
177
|
+
}
|
|
178
|
+
function pushOpenAIChatMessage(messages, msg) {
|
|
179
|
+
const text = textOf(msg.content);
|
|
180
|
+
if (msg.role === "assistant") {
|
|
181
|
+
const toolCalls = msg.content.filter((b) => b.type === "tool_call");
|
|
182
|
+
const out = {
|
|
183
|
+
role: "assistant",
|
|
184
|
+
content: text || null
|
|
185
|
+
};
|
|
186
|
+
if (toolCalls.length > 0) out.tool_calls = toolCalls.map((b) => ({
|
|
187
|
+
id: b.id,
|
|
188
|
+
type: "function",
|
|
189
|
+
function: {
|
|
190
|
+
name: b.name,
|
|
191
|
+
arguments: JSON.stringify(b.input)
|
|
192
|
+
}
|
|
193
|
+
}));
|
|
194
|
+
messages.push(out);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const userParts = contentPartsFromBlocks(msg.content);
|
|
198
|
+
if (userParts.length > 0) messages.push({
|
|
199
|
+
role: "user",
|
|
200
|
+
content: simplifyOpenAIContent(userParts)
|
|
201
|
+
});
|
|
202
|
+
for (const tr of msg.content.filter((b) => b.type === "tool_result")) {
|
|
203
|
+
const { text, images } = summarizeToolResultForOpenAI(tr.output);
|
|
204
|
+
if (images.length === 0) {
|
|
205
|
+
messages.push({
|
|
206
|
+
role: "tool",
|
|
207
|
+
tool_call_id: tr.callId,
|
|
208
|
+
content: text
|
|
209
|
+
});
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
const noun = images.length === 1 ? "image" : "images";
|
|
213
|
+
const marker = `[${images.length} ${noun} attached — see next user message]`;
|
|
214
|
+
messages.push({
|
|
215
|
+
role: "tool",
|
|
216
|
+
tool_call_id: tr.callId,
|
|
217
|
+
content: text.length > 0 ? `${text}\n\n${marker}` : marker
|
|
218
|
+
});
|
|
219
|
+
messages.push({
|
|
220
|
+
role: "user",
|
|
221
|
+
content: [...images.map(toOpenAIImagePart), {
|
|
222
|
+
type: "text",
|
|
223
|
+
text: `(${noun} returned by tool call ${tr.callId})`
|
|
224
|
+
}]
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
function noop() {}
|
|
229
|
+
function textOf(content) {
|
|
230
|
+
return content.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
231
|
+
}
|
|
232
|
+
function contentPartsFromBlocks(content) {
|
|
233
|
+
const parts = [];
|
|
234
|
+
for (const block of content) if (block.type === "image") {
|
|
235
|
+
assertResolvedMediaBlock(block, "OpenAI transcript messages");
|
|
236
|
+
parts.push(toOpenAIImagePart(block));
|
|
237
|
+
} else if (block.type === "audio") parts.push({
|
|
238
|
+
type: "input_audio",
|
|
239
|
+
input_audio: {
|
|
240
|
+
data: block.data,
|
|
241
|
+
format: audioFormatFromMediaType(block.mediaType)
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
else if (block.type === "video") parts.push({
|
|
245
|
+
type: "video_url",
|
|
246
|
+
video_url: { url: `data:${block.mediaType};base64,${block.data}` }
|
|
247
|
+
});
|
|
248
|
+
else if (block.type === "document") {
|
|
249
|
+
assertResolvedMediaBlock(block, "OpenAI transcript messages");
|
|
250
|
+
parts.push({
|
|
251
|
+
type: "text",
|
|
252
|
+
text: documentMarker(block)
|
|
253
|
+
});
|
|
254
|
+
} else if (block.type === "text" && block.text.length > 0) parts.push({
|
|
255
|
+
type: "text",
|
|
256
|
+
text: block.text
|
|
257
|
+
});
|
|
258
|
+
return parts;
|
|
259
|
+
}
|
|
260
|
+
function simplifyOpenAIContent(parts) {
|
|
261
|
+
if (parts.length === 1 && parts[0].type === "text") return parts[0].text;
|
|
262
|
+
return parts;
|
|
263
|
+
}
|
|
264
|
+
function toOpenAIImagePart(image) {
|
|
265
|
+
return {
|
|
266
|
+
type: "image_url",
|
|
267
|
+
image_url: { url: `data:${image.mediaType};base64,${image.data}` }
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
function summarizeToolResultForOpenAI(output) {
|
|
271
|
+
if (typeof output === "string") return {
|
|
272
|
+
text: output,
|
|
273
|
+
images: []
|
|
274
|
+
};
|
|
275
|
+
const texts = [];
|
|
276
|
+
const images = [];
|
|
277
|
+
for (const block of output) if (block.type === "text") texts.push(block.text);
|
|
278
|
+
else if (block.type === "image") {
|
|
279
|
+
assertResolvedMediaBlock(block, "OpenAI transcript messages");
|
|
280
|
+
images.push({
|
|
281
|
+
mediaType: block.mediaType,
|
|
282
|
+
data: block.data
|
|
283
|
+
});
|
|
284
|
+
} else if (block.type === "audio") texts.push(`[audio: ${block.mediaType}]`);
|
|
285
|
+
else if (block.type === "video") texts.push(`[video: ${block.mediaType}]`);
|
|
286
|
+
else {
|
|
287
|
+
assertResolvedMediaBlock(block, "OpenAI transcript messages");
|
|
288
|
+
texts.push(documentMarker(block));
|
|
289
|
+
}
|
|
290
|
+
return {
|
|
291
|
+
text: texts.join("\n"),
|
|
292
|
+
images
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
function documentMarker(doc) {
|
|
296
|
+
return documentBlockMarker(doc, "document omitted");
|
|
297
|
+
}
|
|
298
|
+
function extractFinalText(turns) {
|
|
299
|
+
for (let i = turns.length - 1; i >= 0; i--) {
|
|
300
|
+
const turn = turns[i];
|
|
301
|
+
if (turn.role !== "assistant") continue;
|
|
302
|
+
const text = textOf(turn.content);
|
|
303
|
+
if (text) return text;
|
|
304
|
+
}
|
|
305
|
+
return "";
|
|
306
|
+
}
|
|
307
|
+
function countToolCalls(turns) {
|
|
308
|
+
let n = 0;
|
|
309
|
+
for (const turn of turns) for (const block of turn.content) if (block.type === "tool_call") n++;
|
|
310
|
+
return n;
|
|
311
|
+
}
|
|
312
|
+
function lastFinishReason(stats) {
|
|
313
|
+
const usages = stats?.turnUsage;
|
|
314
|
+
if (!usages) return void 0;
|
|
315
|
+
for (let i = usages.length - 1; i >= 0; i--) if (usages[i].finishReason) return usages[i].finishReason;
|
|
316
|
+
}
|
|
317
|
+
function stripThinking(turns) {
|
|
318
|
+
return turns.map((turn) => ({
|
|
319
|
+
...turn,
|
|
320
|
+
content: turn.content.filter((b) => b.type !== "thinking" && b.type !== "redacted_thinking")
|
|
321
|
+
}));
|
|
322
|
+
}
|
|
323
|
+
function installHeadlessEventAdapter(hooks, onEvent) {
|
|
324
|
+
const unregs = [];
|
|
325
|
+
const emittedTurnIds = /* @__PURE__ */ new Set();
|
|
326
|
+
const emit = (event) => {
|
|
327
|
+
try {
|
|
328
|
+
onEvent(event);
|
|
329
|
+
} catch {}
|
|
330
|
+
};
|
|
331
|
+
unregs.push(hooks.hook("agent:start", (ctx) => emit({
|
|
332
|
+
type: "start",
|
|
333
|
+
runId: ctx.runId,
|
|
334
|
+
...ctx.providerName ? { provider: ctx.providerName } : {}
|
|
335
|
+
})));
|
|
336
|
+
unregs.push(hooks.hook("stream:text", (ctx) => emit({
|
|
337
|
+
type: "text",
|
|
338
|
+
delta: ctx.delta
|
|
339
|
+
})));
|
|
340
|
+
unregs.push(hooks.hook("stream:thinking", (ctx) => emit({
|
|
341
|
+
type: "thinking",
|
|
342
|
+
delta: ctx.delta
|
|
343
|
+
})));
|
|
344
|
+
unregs.push(hooks.hook("tool:before", (ctx) => emit({
|
|
345
|
+
type: "tool_call",
|
|
346
|
+
callId: ctx.callId,
|
|
347
|
+
name: ctx.name,
|
|
348
|
+
input: ctx.input
|
|
349
|
+
})));
|
|
350
|
+
unregs.push(hooks.hook("tool:after", (ctx) => emit({
|
|
351
|
+
type: "tool_result",
|
|
352
|
+
callId: ctx.callId,
|
|
353
|
+
name: ctx.name,
|
|
354
|
+
output: toolResultToText(ctx.result),
|
|
355
|
+
isError: false
|
|
356
|
+
})));
|
|
357
|
+
unregs.push(hooks.hook("tool:error", (ctx) => emit({
|
|
358
|
+
type: "tool_result",
|
|
359
|
+
callId: ctx.callId,
|
|
360
|
+
name: ctx.name,
|
|
361
|
+
output: ctx.error.message,
|
|
362
|
+
isError: true
|
|
363
|
+
})));
|
|
364
|
+
unregs.push(hooks.hook("session:turns", (ctx) => {
|
|
365
|
+
const startIndex = ctx.count - ctx.turns.length;
|
|
366
|
+
ctx.turns.forEach((turn, i) => {
|
|
367
|
+
if (emittedTurnIds.has(turn.id)) return;
|
|
368
|
+
emittedTurnIds.add(turn.id);
|
|
369
|
+
emit({
|
|
370
|
+
type: "turn",
|
|
371
|
+
index: startIndex + i,
|
|
372
|
+
turn
|
|
373
|
+
});
|
|
374
|
+
});
|
|
375
|
+
}));
|
|
376
|
+
unregs.push(hooks.hook("spawn:before", (ctx) => emit({
|
|
377
|
+
type: "spawn",
|
|
378
|
+
event: "before",
|
|
379
|
+
id: ctx.id
|
|
380
|
+
})));
|
|
381
|
+
unregs.push(hooks.hook("spawn:complete", (ctx) => emit({
|
|
382
|
+
type: "spawn",
|
|
383
|
+
event: "complete",
|
|
384
|
+
id: ctx.id,
|
|
385
|
+
info: { status: ctx.status ?? "completed" }
|
|
386
|
+
})));
|
|
387
|
+
unregs.push(hooks.hook("spawn:error", (ctx) => emit({
|
|
388
|
+
type: "spawn",
|
|
389
|
+
event: "error",
|
|
390
|
+
id: ctx.id,
|
|
391
|
+
info: { message: ctx.error.message }
|
|
392
|
+
})));
|
|
393
|
+
unregs.push(hooks.hook("stream:error", (ctx) => emit({
|
|
394
|
+
type: "error",
|
|
395
|
+
message: ctx.err instanceof Error ? ctx.err.message : String(ctx.err),
|
|
396
|
+
...ctx.err instanceof Error ? { errorType: ctx.err.name } : {}
|
|
397
|
+
})));
|
|
398
|
+
return () => {
|
|
399
|
+
for (const un of unregs) try {
|
|
400
|
+
un();
|
|
401
|
+
} catch {}
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
//#endregion
|
|
2
405
|
export { exitCodeForHeadlessResult, formatHeadlessResult, formatHeadlessTurnEvent, formattedHeadlessTurnEventToJsonl, headlessEventToJsonl, installHeadlessEventAdapter, providerTranscriptFormatForProvider, runHeadless, transcriptToOpenAIMessages, transcriptToProviderMessages };
|
|
406
|
+
|
|
407
|
+
//# sourceMappingURL=headless.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headless.js","names":["basic"],"sources":["../src/headless.ts"],"sourcesContent":["/**\n * Headless mode — a non-interactive, fully-structured way to drive the agent\n * for automation and RL rollouts.\n *\n * `agent.run()` already returns rich {@link AgentStats}, the session captures a\n * lossless transcript (`session.turns`), and the hook bus exposes every\n * streaming/tool/turn event. What this module adds is the *contract* an RL loop\n * needs: one call (`runHeadless`) that runs a prompt to completion in a chosen\n * workdir, bounded by turns + wall-clock, and hands back a single serializable\n * {@link HeadlessResult} — final answer, verifiable structured output, usage,\n * and the complete trajectory — plus an optional live {@link HeadlessEvent}\n * stream (the in-process equivalent of `--output-format stream-json`).\n *\n * It is provider-agnostic: the caller passes a built {@link Provider} (e.g.\n * `local()` pointed at a vLLM server, or any of the named providers). The thin\n * CLI in `src/headless-cli.ts` wraps this with arg parsing, file/stdin I/O, and\n * JSONL transcript writing.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks, AgentOptions } from './agent'\nimport type { ExecutionContext } from './contexts'\nimport type { Provider } from './providers'\nimport type { RunSummary } from './run-summary'\nimport type { Session, SessionStore } from './session'\nimport type { PairingRepair } from './session/messages'\nimport type { ToolDef } from './tools'\nimport type {\n AgentStats,\n McpServerConfig,\n PromptPart,\n SessionContentBlock,\n SessionTurn,\n ThinkingLevel,\n ToolResultContent,\n ToolResultDocumentContent,\n TurnFinishReason,\n} from './types'\nimport { createAgent } from './agent'\nimport { createProcessContext } from './contexts'\nimport { basic } from './presets'\nimport { createRunSummaryCollector } from './run-summary'\nimport { createMemoryStore, createSession, toAnthropic } from './session'\nimport { ensureToolResultPairing } from './session/messages'\nimport { audioFormatFromMediaType } from './tools/media-sniff'\nimport { assertResolvedMediaBlock, documentBlockMarker, toolResultToText } from './types'\n\n// ---------------------------------------------------------------------------\n// Public shapes\n// ---------------------------------------------------------------------------\n\nexport type HeadlessStatus = 'completed' | 'aborted' | 'error' | 'timeout'\n\nexport interface HeadlessUsage {\n input: number\n output: number\n cacheRead: number\n cacheCreation: number\n /** Cumulative USD cost when the provider/registry could price the run. */\n cost?: number\n}\n\nexport interface HeadlessErrorInfo {\n message: string\n /** Typed-error class name (`AgentAbortedError`, `AgentContextExceededError`, …). */\n type: string\n}\n\n/**\n * Strictly JSON-serializable postmortem of one headless run. Everything an RL\n * reward function needs: the final answer (`finalText`), the verifiable\n * structured output (`output`, present iff a `schema` was set), usage/turns,\n * and the lossless `transcript` (the SFT training data).\n */\nexport interface HeadlessResult {\n status: HeadlessStatus\n /** Concatenated text of the last assistant turn that produced any text. */\n finalText: string\n /** Schema-enforced structured output (only when `opts.schema` is set). */\n output?: Record<string, unknown>\n usage: HeadlessUsage\n turns: number\n durationMs: number\n /** Total `tool_call` blocks across the whole transcript. */\n numToolCalls: number\n /** Finish reason of the final turn that reported one. */\n finishReason?: TurnFinishReason\n error?: HeadlessErrorInfo\n sessionId: string\n /** Incident postmortem (errors, gate blocks, budget events) via run-summary. */\n summary?: RunSummary\n /** Lossless transcript — raw `session.turns`. Thinking stripped when `includeThinking: false`. */\n transcript: SessionTurn[]\n}\n\nexport type HeadlessOutputFormat = 'zidane' | 'provider'\n\nexport type ProviderTranscriptFormat = 'anthropic' | 'openai'\n\nexport type FormattedHeadlessResult\n = | HeadlessResult\n | unknown[]\n\nexport type FormattedHeadlessTurnEvent\n = | Extract<HeadlessEvent, { type: 'turn' }>\n | unknown[]\n\nexport function exitCodeForHeadlessResult(result: HeadlessResult): number {\n switch (result.status) {\n case 'completed': return 0\n case 'timeout': return 124\n case 'aborted': return 130\n case 'error':\n default: return 1\n }\n}\n\n/**\n * Live event union — the in-process equivalent of a `stream-json` line. Every\n * member is JSON-serializable; render to JSONL with {@link headlessEventToJsonl}.\n */\nexport type HeadlessEvent\n = | { type: 'start', runId: string, provider?: string }\n | { type: 'text', delta: string }\n | { type: 'thinking', delta: string }\n | { type: 'tool_call', callId: string, name: string, input: Record<string, unknown> }\n | { type: 'tool_result', callId: string, name: string, output: string, isError: boolean }\n | { type: 'turn', index: number, turn: SessionTurn }\n | { type: 'spawn', event: 'before' | 'complete' | 'error', id: string, info?: Record<string, unknown> }\n | { type: 'error', message: string, errorType?: string }\n | { type: 'result', result: HeadlessResult }\n\n/** Serialize one event as a newline-terminated JSON line (stream-json). */\nexport function headlessEventToJsonl(event: HeadlessEvent): string {\n return `${JSON.stringify(event)}\\n`\n}\n\nexport function formattedHeadlessTurnEventToJsonl(event: FormattedHeadlessTurnEvent): string {\n return `${JSON.stringify(event)}\\n`\n}\n\nexport function providerTranscriptFormatForProvider(providerName: string): ProviderTranscriptFormat {\n return providerName === 'anthropic' ? 'anthropic' : 'openai'\n}\n\nexport function transcriptToProviderMessages(\n turns: SessionTurn[],\n providerName: string,\n): unknown[] {\n const format = providerTranscriptFormatForProvider(providerName)\n if (format === 'anthropic') {\n return turns\n .filter((turn): turn is SessionTurn & { role: 'user' | 'assistant' } => turn.role === 'user' || turn.role === 'assistant')\n .map(turn => toAnthropic({ role: turn.role, content: turn.content }))\n }\n return transcriptToOpenAIMessages(turns, { strictToolPairing: false })\n}\n\nexport function formatHeadlessResult(\n result: HeadlessResult,\n options: { format: HeadlessOutputFormat, providerName: string },\n): FormattedHeadlessResult {\n if (options.format === 'zidane')\n return result\n return transcriptToProviderMessages(result.transcript, options.providerName)\n}\n\nexport function formatHeadlessTurnEvent(\n event: Extract<HeadlessEvent, { type: 'turn' }>,\n options: { format: HeadlessOutputFormat, providerName: string },\n): FormattedHeadlessTurnEvent {\n if (options.format === 'zidane')\n return event\n return transcriptToProviderMessages([event.turn], options.providerName)\n}\n\nexport interface HeadlessOptions {\n /** User prompt — plain string or multimodal `PromptPart[]`. */\n prompt: string | PromptPart[]\n /** Built provider (e.g. `local()`, `openaiCompat(...)`, `anthropic(...)`). */\n provider: Provider\n model?: string\n /** Override the preset system prompt for this run. */\n system?: string\n thinking?: ThinkingLevel\n maxTurns?: number\n maxTokens?: number\n /** Wall-clock cap; on expiry the run is aborted and `status` becomes `'timeout'`. */\n timeoutMs?: number\n /** External abort signal — chained with the internal timeout controller. */\n signal?: AbortSignal\n /** JSON Schema for structured-output enforcement → populates `result.output`. */\n schema?: Record<string, unknown>\n /** Agent behavior defaults for this headless run. Top-level shortcuts below override matching fields. */\n behavior?: AgentOptions['behavior']\n /** Tool overrides. Omit to use the basic preset's tools. */\n tools?: Record<string, ToolDef>\n mcpServers?: McpServerConfig[]\n skills?: AgentOptions['skills']\n /** Execution context. Defaults to a process context rooted at `cwd`. */\n execution?: ExecutionContext\n /** Working directory for the default process context (ignored if `execution` is set). */\n cwd?: string\n /** Reuse / resume an existing session. */\n session?: Session\n /** Session store for a fresh session (defaults to an in-memory store). */\n store?: SessionStore\n /** Keep `thinking` blocks in `result.transcript` (default true). */\n includeThinking?: boolean\n /** Live event callback — the in-process stream-json equivalent. */\n onEvent?: (event: HeadlessEvent) => void\n}\n\n// ---------------------------------------------------------------------------\n// runHeadless\n// ---------------------------------------------------------------------------\n\n/**\n * Run a prompt to completion, headless, and return a single serializable\n * {@link HeadlessResult}. Safe to call concurrently for parallel rollouts —\n * each call builds its own agent + session and tears them down in `finally`.\n */\nexport async function runHeadless(opts: HeadlessOptions): Promise<HeadlessResult> {\n const startedAt = Date.now()\n const execution = opts.execution ?? createProcessContext({ cwd: opts.cwd })\n const session = opts.session ?? await createSession({ store: opts.store ?? createMemoryStore() })\n\n const behavior: NonNullable<AgentOptions['behavior']> = { ...(opts.behavior ?? {}) }\n if (opts.maxTurns !== undefined)\n behavior.maxTurns = opts.maxTurns\n if (opts.maxTokens !== undefined)\n behavior.maxTokens = opts.maxTokens\n if (opts.schema !== undefined)\n behavior.schema = opts.schema\n\n const agent = createAgent({\n ...basic,\n provider: opts.provider,\n execution,\n session,\n behavior,\n ...(opts.tools !== undefined ? { tools: opts.tools } : {}),\n ...(opts.mcpServers !== undefined ? { mcpServers: opts.mcpServers } : {}),\n ...(opts.skills !== undefined ? { skills: opts.skills } : {}),\n })\n\n const collector = createRunSummaryCollector()\n const uninstallSummary = collector.install(agent.hooks)\n const uninstallEvents = opts.onEvent ? installHeadlessEventAdapter(agent.hooks, opts.onEvent) : noop\n\n // Resumed sessions carry turns from prior runs — remember where this run\n // starts so transcript/finalText/numToolCalls stay per-run, matching the\n // per-run usage/turns/durationMs stats.\n const runStartIndex = session.turns.length\n\n // Internal controller drives the wall-clock timeout and chains any external\n // signal so a host cancel and a timeout both abort the same run. The\n // listener is removed in `finally` — a long-lived host signal must not\n // accumulate one listener per rollout.\n const controller = new AbortController()\n const onExternalAbort = (): void => controller.abort(opts.signal!.reason)\n if (opts.signal) {\n if (opts.signal.aborted)\n controller.abort(opts.signal.reason)\n else\n opts.signal.addEventListener('abort', onExternalAbort, { once: true })\n }\n let timedOut = false\n const timer = opts.timeoutMs && opts.timeoutMs > 0\n ? setTimeout(() => {\n timedOut = true\n controller.abort(new Error(`Headless run timed out after ${opts.timeoutMs}ms`))\n }, opts.timeoutMs)\n : undefined\n\n let stats: AgentStats | undefined\n let error: HeadlessErrorInfo | undefined\n\n try {\n stats = await agent.run({\n prompt: opts.prompt,\n signal: controller.signal,\n ...(opts.model !== undefined ? { model: opts.model } : {}),\n ...(opts.system !== undefined ? { system: opts.system } : {}),\n ...(opts.thinking !== undefined ? { thinking: opts.thinking } : {}),\n })\n }\n catch (err) {\n // The agent loop throws typed errors (AgentAbortedError,\n // AgentContextExceededError, AgentProviderError, …) — their `name` already\n // classifies the failure, so surface it directly.\n const e = err instanceof Error ? err : new Error(String(err))\n error = { message: e.message, type: e.name }\n }\n finally {\n if (timer)\n clearTimeout(timer)\n opts.signal?.removeEventListener('abort', onExternalAbort)\n uninstallEvents()\n uninstallSummary()\n await agent.destroy()\n }\n\n // Status: a thrown error wins, but an abort/timeout can also surface as a\n // clean resolve (the loop returns partial stats), so check the signal too.\n let status: HeadlessStatus\n if (error)\n status = timedOut ? 'timeout' : controller.signal.aborted ? 'aborted' : 'error'\n else if (controller.signal.aborted)\n status = timedOut ? 'timeout' : 'aborted'\n else\n status = 'completed'\n\n const rawTranscript = session.turns.slice(runStartIndex)\n const transcript = opts.includeThinking === false ? stripThinking(rawTranscript) : rawTranscript\n const summary = collector.latest()\n\n const result: HeadlessResult = {\n status,\n finalText: extractFinalText(rawTranscript),\n ...(stats?.output ? { output: stats.output } : {}),\n usage: {\n input: stats?.totalIn ?? 0,\n output: stats?.totalOut ?? 0,\n cacheRead: stats?.totalCacheRead ?? 0,\n cacheCreation: stats?.totalCacheCreation ?? 0,\n ...(typeof stats?.cost === 'number' ? { cost: stats.cost } : {}),\n },\n turns: stats?.turns ?? 0,\n durationMs: stats?.elapsed ?? (Date.now() - startedAt),\n numToolCalls: countToolCalls(rawTranscript),\n // Suppress `finishReason` on abort/timeout: the last persisted turn can\n // carry `finishReason: 'stop'` (e.g. the model finished a turn, a follow-up\n // continued, then the run was cancelled), which would make a consumer\n // keyed on `finishReason === 'stop'` misread a cancel as \"model finished\".\n // `status` is authoritative for those exits; let it speak alone. The\n // `'pause'` exhaustion exit keeps `status: 'completed'` so it still\n // surfaces its `finishReason: 'pause'` here.\n ...(status !== 'aborted' && status !== 'timeout' && lastFinishReason(stats)\n ? { finishReason: lastFinishReason(stats) }\n : {}),\n ...(error ? { error } : {}),\n sessionId: session.id,\n ...(summary ? { summary } : {}),\n transcript,\n }\n\n opts.onEvent?.({ type: 'result', result })\n return result\n}\n\n// ---------------------------------------------------------------------------\n// Transcript → OpenAI chat messages (SFT-ready)\n// ---------------------------------------------------------------------------\n\nexport interface OpenAIChatMessage {\n role: 'system' | 'user' | 'assistant' | 'tool'\n content: string | null | OpenAIChatContentPart[]\n tool_calls?: Array<{ id: string, type: 'function', function: { name: string, arguments: string } }>\n tool_call_id?: string\n}\n\nexport type OpenAIChatContentPart\n = | { type: 'text', text: string }\n | { type: 'image_url', image_url: { url: string } }\n | { type: 'input_audio', input_audio: { data: string, format: string } }\n | { type: 'video_url', video_url: { url: string } }\n\n/**\n * Convert raw `session.turns` into standard OpenAI chat-completion messages:\n * assistant turns carry `tool_calls`, and each `tool_result` becomes its own\n * `role: 'tool'` message. This is the drop-in shape for an SFT renderer —\n * unlike `toOpenAI` (session/messages.ts), which emits an internal `_tag`\n * envelope meant for re-sending to a provider, not for training data.\n *\n * Fails closed on corrupt raw turns instead of fabricating tool results; silent\n * placeholders would create structurally-valid but semantically-poisoned SFT\n * examples.\n */\nexport function transcriptToOpenAIMessages(\n turns: SessionTurn[],\n options: { strictToolPairing?: boolean } = {},\n): OpenAIChatMessage[] {\n const { strictToolPairing = true } = options\n const messages: OpenAIChatMessage[] = []\n let chunk: Array<{ role: 'user' | 'assistant', content: SessionContentBlock[] }> = []\n const flushChunk = () => {\n if (chunk.length === 0)\n return\n let paired = chunk\n if (strictToolPairing) {\n const repairs: PairingRepair[] = []\n paired = ensureToolResultPairing(chunk, { onRepair: repair => repairs.push(repair) })\n if (repairs.length > 0) {\n throw new Error(\n `Cannot convert transcript to OpenAI messages: tool pairing repair required (${repairs.map(r => r.mode).join(', ')})`,\n )\n }\n }\n for (const msg of paired)\n pushOpenAIChatMessage(messages, msg)\n chunk = []\n }\n\n for (const turn of turns) {\n if (turn.role === 'system') {\n flushChunk()\n messages.push({ role: 'system', content: textOf(turn.content) })\n continue\n }\n chunk.push({ role: turn.role, content: turn.content })\n }\n flushChunk()\n\n return messages\n}\n\nfunction pushOpenAIChatMessage(messages: OpenAIChatMessage[], msg: { role: 'user' | 'assistant', content: SessionContentBlock[] }): void {\n const text = textOf(msg.content)\n\n if (msg.role === 'assistant') {\n const toolCalls = msg.content.filter((b): b is ToolCallBlock => b.type === 'tool_call')\n const out: OpenAIChatMessage = { role: 'assistant', content: text || null }\n if (toolCalls.length > 0) {\n out.tool_calls = toolCalls.map(b => ({\n id: b.id,\n type: 'function' as const,\n function: { name: b.name, arguments: JSON.stringify(b.input) },\n }))\n }\n messages.push(out)\n return\n }\n\n // user turn — may carry prompt text/images and/or tool_result blocks\n const userParts = contentPartsFromBlocks(msg.content)\n if (userParts.length > 0)\n messages.push({ role: 'user', content: simplifyOpenAIContent(userParts) })\n\n for (const tr of msg.content.filter((b): b is ToolResultBlock => b.type === 'tool_result')) {\n const { text, images } = summarizeToolResultForOpenAI(tr.output)\n if (images.length === 0) {\n messages.push({ role: 'tool', tool_call_id: tr.callId, content: text })\n continue\n }\n\n const noun = images.length === 1 ? 'image' : 'images'\n const marker = `[${images.length} ${noun} attached — see next user message]`\n messages.push({\n role: 'tool',\n tool_call_id: tr.callId,\n content: text.length > 0 ? `${text}\\n\\n${marker}` : marker,\n })\n messages.push({\n role: 'user',\n content: [\n ...images.map(toOpenAIImagePart),\n { type: 'text', text: `(${noun} returned by tool call ${tr.callId})` },\n ],\n })\n }\n}\n\n// ---------------------------------------------------------------------------\n// Internals\n// ---------------------------------------------------------------------------\n\ntype TextBlock = Extract<SessionContentBlock, { type: 'text' }>\ntype ToolCallBlock = Extract<SessionContentBlock, { type: 'tool_call' }>\ntype ToolResultBlock = Extract<SessionContentBlock, { type: 'tool_result' }>\n\nfunction noop(): void {}\n\nfunction textOf(content: SessionContentBlock[]): string {\n return content.filter((b): b is TextBlock => b.type === 'text').map(b => b.text).join('')\n}\n\nfunction contentPartsFromBlocks(content: SessionContentBlock[]): OpenAIChatContentPart[] {\n const parts: OpenAIChatContentPart[] = []\n for (const block of content) {\n if (block.type === 'image') {\n assertResolvedMediaBlock(block, 'OpenAI transcript messages')\n parts.push(toOpenAIImagePart(block))\n }\n else if (block.type === 'audio') {\n parts.push({ type: 'input_audio', input_audio: { data: block.data, format: audioFormatFromMediaType(block.mediaType) } })\n }\n else if (block.type === 'video') {\n parts.push({ type: 'video_url', video_url: { url: `data:${block.mediaType};base64,${block.data}` } })\n }\n else if (block.type === 'document') {\n assertResolvedMediaBlock(block, 'OpenAI transcript messages')\n parts.push({ type: 'text', text: documentMarker(block) })\n }\n else if (block.type === 'text' && block.text.length > 0) {\n parts.push({ type: 'text', text: block.text })\n }\n }\n return parts\n}\n\nfunction simplifyOpenAIContent(parts: OpenAIChatContentPart[]): string | OpenAIChatContentPart[] {\n if (parts.length === 1 && parts[0].type === 'text')\n return parts[0].text\n return parts\n}\n\nfunction toOpenAIImagePart(image: { mediaType: string, data: string }): OpenAIChatContentPart {\n return {\n type: 'image_url',\n image_url: { url: `data:${image.mediaType};base64,${image.data}` },\n }\n}\n\nfunction summarizeToolResultForOpenAI(output: string | ToolResultContent[]): {\n text: string\n images: Array<{ mediaType: string, data: string }>\n} {\n if (typeof output === 'string')\n return { text: output, images: [] }\n\n const texts: string[] = []\n const images: Array<{ mediaType: string, data: string }> = []\n for (const block of output) {\n if (block.type === 'text') {\n texts.push(block.text)\n }\n else if (block.type === 'image') {\n assertResolvedMediaBlock(block, 'OpenAI transcript messages')\n images.push({ mediaType: block.mediaType, data: block.data })\n }\n else if (block.type === 'audio') {\n texts.push(`[audio: ${block.mediaType}]`)\n }\n else if (block.type === 'video') {\n texts.push(`[video: ${block.mediaType}]`)\n }\n else {\n assertResolvedMediaBlock(block, 'OpenAI transcript messages')\n texts.push(documentMarker(block))\n }\n }\n return { text: texts.join('\\n'), images }\n}\n\nfunction documentMarker(doc: ToolResultDocumentContent): string {\n return documentBlockMarker(doc, 'document omitted')\n}\n\nfunction extractFinalText(turns: SessionTurn[]): string {\n for (let i = turns.length - 1; i >= 0; i--) {\n const turn = turns[i]\n if (turn.role !== 'assistant')\n continue\n const text = textOf(turn.content)\n if (text)\n return text\n }\n return ''\n}\n\nfunction countToolCalls(turns: SessionTurn[]): number {\n let n = 0\n for (const turn of turns) {\n for (const block of turn.content) {\n if (block.type === 'tool_call')\n n++\n }\n }\n return n\n}\n\nfunction lastFinishReason(stats?: AgentStats): TurnFinishReason | undefined {\n const usages = stats?.turnUsage\n if (!usages)\n return undefined\n for (let i = usages.length - 1; i >= 0; i--) {\n if (usages[i].finishReason)\n return usages[i].finishReason\n }\n return undefined\n}\n\nfunction stripThinking(turns: SessionTurn[]): SessionTurn[] {\n return turns.map(turn => ({\n ...turn,\n content: turn.content.filter(b => b.type !== 'thinking' && b.type !== 'redacted_thinking'),\n }))\n}\n\nexport function installHeadlessEventAdapter(\n hooks: Hookable<AgentHooks>,\n onEvent: (event: HeadlessEvent) => void,\n): () => void {\n const unregs: Array<() => void> = []\n const emittedTurnIds = new Set<string>()\n const emit = (event: HeadlessEvent): void => {\n try {\n onEvent(event)\n }\n catch {\n // A consumer's sink throwing is not the adapter's concern.\n }\n }\n\n unregs.push(hooks.hook('agent:start', ctx => emit({\n type: 'start',\n runId: ctx.runId,\n ...(ctx.providerName ? { provider: ctx.providerName } : {}),\n })))\n unregs.push(hooks.hook('stream:text', ctx => emit({ type: 'text', delta: ctx.delta })))\n unregs.push(hooks.hook('stream:thinking', ctx => emit({ type: 'thinking', delta: ctx.delta })))\n unregs.push(hooks.hook('tool:before', ctx => emit({\n type: 'tool_call',\n callId: ctx.callId,\n name: ctx.name,\n input: ctx.input,\n })))\n unregs.push(hooks.hook('tool:after', ctx => emit({\n type: 'tool_result',\n callId: ctx.callId,\n name: ctx.name,\n output: toolResultToText(ctx.result),\n isError: false,\n })))\n unregs.push(hooks.hook('tool:error', ctx => emit({\n type: 'tool_result',\n callId: ctx.callId,\n name: ctx.name,\n output: ctx.error.message,\n isError: true,\n })))\n unregs.push(hooks.hook('session:turns', (ctx) => {\n const startIndex = ctx.count - ctx.turns.length\n ctx.turns.forEach((turn, i) => {\n if (emittedTurnIds.has(turn.id))\n return\n emittedTurnIds.add(turn.id)\n emit({ type: 'turn', index: startIndex + i, turn })\n })\n }))\n unregs.push(hooks.hook('spawn:before', ctx => emit({ type: 'spawn', event: 'before', id: ctx.id })))\n unregs.push(hooks.hook('spawn:complete', ctx => emit({\n type: 'spawn',\n event: 'complete',\n id: ctx.id,\n info: { status: ctx.status ?? 'completed' },\n })))\n unregs.push(hooks.hook('spawn:error', ctx => emit({\n type: 'spawn',\n event: 'error',\n id: ctx.id,\n info: { message: ctx.error.message },\n })))\n unregs.push(hooks.hook('stream:error', ctx => emit({\n type: 'error',\n message: ctx.err instanceof Error ? ctx.err.message : String(ctx.err),\n ...(ctx.err instanceof Error ? { errorType: ctx.err.name } : {}),\n })))\n\n return () => {\n for (const un of unregs) {\n try {\n un()\n }\n catch {\n // ignore\n }\n }\n }\n}\n"],"mappings":"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"}
|