@tangle-network/agent-runtime 0.85.0 → 0.87.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.
@@ -5,13 +5,13 @@ import {
5
5
  definePersona,
6
6
  runPersonified,
7
7
  worktreeFanout
8
- } from "./chunk-DLAEEF26.js";
8
+ } from "./chunk-VKVNDNG4.js";
9
9
  import {
10
10
  createExecutorRegistry
11
- } from "./chunk-XN5TIJGP.js";
11
+ } from "./chunk-6XCW3M7W.js";
12
12
  import {
13
13
  runAnalystLoop
14
- } from "./chunk-YPA5MLVE.js";
14
+ } from "./chunk-LCXXIL3U.js";
15
15
  import {
16
16
  ConfigError
17
17
  } from "./chunk-YEJR7IXO.js";
@@ -196,4 +196,4 @@ export {
196
196
  runLoopRunnerCli,
197
197
  parseLoopRunnerArgv
198
198
  };
199
- //# sourceMappingURL=chunk-QSYPMMWS.js.map
199
+ //# sourceMappingURL=chunk-FLVVVBWV.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  extractLlmCallEvent
3
- } from "./chunk-4J6RBI3K.js";
3
+ } from "./chunk-QUXZBZCS.js";
4
4
  import {
5
5
  AnalystError
6
6
  } from "./chunk-YEJR7IXO.js";
@@ -579,4 +579,4 @@ export {
579
579
  iterationsToTraceStore,
580
580
  runAnalystLoop
581
581
  };
582
- //# sourceMappingURL=chunk-YPA5MLVE.js.map
582
+ //# sourceMappingURL=chunk-LCXXIL3U.js.map
@@ -8,7 +8,7 @@ import {
8
8
  DELEGATION_STATUS_DESCRIPTION,
9
9
  DELEGATION_STATUS_INPUT_SCHEMA,
10
10
  DELEGATION_STATUS_TOOL_NAME
11
- } from "./chunk-XN5TIJGP.js";
11
+ } from "./chunk-6XCW3M7W.js";
12
12
 
13
13
  // src/mcp/openai-tools.ts
14
14
  function buildTool(name, description, parameters) {
@@ -45,4 +45,4 @@ export {
45
45
  mcpToolsForRuntimeMcp,
46
46
  mcpToolsForRuntimeMcpSubset
47
47
  };
48
- //# sourceMappingURL=chunk-G7HQI6DB.js.map
48
+ //# sourceMappingURL=chunk-MHYF2LIP.js.map
@@ -66,6 +66,83 @@ function pickFiniteNumber(data, keys) {
66
66
  }
67
67
  return void 0;
68
68
  }
69
+ function createSandboxToolPartState() {
70
+ return { statusByCall: /* @__PURE__ */ new Map(), seq: 0 };
71
+ }
72
+ var TERMINAL_TOOL_FAILURE = /^(error|errored|failed|failure|cancelled|canceled|timeout|timed_out)$/i;
73
+ function mapSandboxToolEvent(event, state) {
74
+ if (!event || typeof event !== "object") return [];
75
+ const type = String(event.type ?? "");
76
+ const data = event.data && typeof event.data === "object" ? event.data : {};
77
+ if (type === "message.part.updated") {
78
+ const part = data.part && typeof data.part === "object" ? data.part : {};
79
+ if (String(part.type ?? "") !== "tool") return [];
80
+ return projectToolPart(part, state, typeof event.id === "string" ? event.id : void 0);
81
+ }
82
+ if (type.includes("tool")) {
83
+ const callId = pickString(data, ["toolCallId", "tool_use_id", "id"]) ?? (typeof event.id === "string" ? event.id : void 0) ?? `sandbox-tool-${++state.seq}`;
84
+ const toolName = pickString(data, ["name", "toolName", "tool"]) ?? "sandbox_tool";
85
+ if (type.includes("result")) {
86
+ return [
87
+ {
88
+ type: "tool_result",
89
+ toolName,
90
+ toolCallId: callId,
91
+ result: data.output ?? data.result ?? data.content ?? data
92
+ }
93
+ ];
94
+ }
95
+ return [
96
+ { type: "tool_call", toolName, toolCallId: callId, args: data.input ?? data.args ?? {} }
97
+ ];
98
+ }
99
+ return [];
100
+ }
101
+ function projectToolPart(part, state, eventId) {
102
+ const callId = pickString(part, ["callID", "callId", "toolCallId", "id"]) ?? eventId ?? `sandbox-tool-${++state.seq}`;
103
+ const toolName = pickString(part, ["tool", "toolName", "name"]) ?? "sandbox_tool";
104
+ const toolState = part.state && typeof part.state === "object" ? part.state : {};
105
+ const metadata = toolState.metadata && typeof toolState.metadata === "object" ? toolState.metadata : {};
106
+ const status = pickString(toolState, ["status"]) ?? "updated";
107
+ const previous = state.statusByCall.get(callId);
108
+ const settled = previous === "completed" || previous !== void 0 && TERMINAL_TOOL_FAILURE.test(previous);
109
+ if (settled) return [];
110
+ const out = [];
111
+ if (previous === void 0) {
112
+ out.push({
113
+ type: "tool_call",
114
+ toolName,
115
+ toolCallId: callId,
116
+ args: toolState.input ?? metadata.input ?? {}
117
+ });
118
+ }
119
+ state.statusByCall.set(callId, status);
120
+ if (status === "completed") {
121
+ out.push({
122
+ type: "tool_result",
123
+ toolName,
124
+ toolCallId: callId,
125
+ result: toolState.output ?? metadata.output ?? ""
126
+ });
127
+ } else if (TERMINAL_TOOL_FAILURE.test(status)) {
128
+ const message = pickString(toolState, ["error", "message"]) ?? pickString(metadata, ["error", "message"]) ?? `sandbox tool ended with status ${status}`;
129
+ const output = toolState.output ?? metadata.output;
130
+ out.push({
131
+ type: "tool_result",
132
+ toolName,
133
+ toolCallId: callId,
134
+ result: { error: message, status, ...output !== void 0 ? { output } : {} }
135
+ });
136
+ }
137
+ return out;
138
+ }
139
+ function pickString(data, keys) {
140
+ for (const key of keys) {
141
+ const value = data[key];
142
+ if (typeof value === "string" && value.length > 0) return value;
143
+ }
144
+ return void 0;
145
+ }
69
146
  function mapSandboxEvent(event, opts = {}) {
70
147
  if (!event || typeof event !== "object") return void 0;
71
148
  const type = String(event.type ?? "");
@@ -87,6 +164,8 @@ function mapSandboxEvent(event, opts = {}) {
87
164
  export {
88
165
  extractLlmCallEvent,
89
166
  sumSandboxUsage,
167
+ createSandboxToolPartState,
168
+ mapSandboxToolEvent,
90
169
  mapSandboxEvent
91
170
  };
92
- //# sourceMappingURL=chunk-4J6RBI3K.js.map
171
+ //# sourceMappingURL=chunk-QUXZBZCS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/sandbox-events.ts"],"sourcesContent":["/**\n * Sandbox-event → runtime-event mapping.\n *\n * The sandbox SDK emits a polymorphic `SandboxEvent = { type, data, id? }`\n * whose `type` vocabulary is backend-determined (opencode, etc.) rather than\n * enumerated by the SDK. Two consumers project it:\n * - the loop kernel's cost ledger (`extractLlmCallEvent`) — sums usage off\n * every cost-bearing event, regardless of stream shape;\n * - the `AgentRuntime.act` streaming contract (`mapSandboxEvent`) — projects\n * incremental events to the `RuntimeStreamEvent` chat-UX vocabulary.\n *\n * Both live here so the empirically-observed `type` vocabulary has one home.\n */\n\nimport type { SandboxEvent } from '@tangle-network/sandbox'\nimport type { RuntimeStreamEvent } from '../types'\n\n/**\n * Extract a `RuntimeStreamEvent`-shaped `llm_call` from a sandbox event when\n * the event carries usage/cost data. Returns `undefined` for non-cost events\n * so the kernel can iterate the full stream without branching.\n *\n * Canonical cost-carrying types observed in the wild:\n * - `llm_call` — `data: { model, tokensIn, tokensOut, costUsd, ... }`\n * - `message.completed` / `result` — `data: { usage: { inputTokens,\n * outputTokens, totalCostUsd? } }`\n * - `cost.usage` / `usage` — same shape under a dedicated type\n *\n * Numeric coercion is strict: `Number.isFinite` gates every accumulator write\n * so a sentinel `NaN` from a misbehaving backend cannot poison the ledger.\n */\nexport function extractLlmCallEvent(\n event: SandboxEvent,\n agentRunName: string,\n): (RuntimeStreamEvent & { type: 'llm_call' }) | undefined {\n if (!event || typeof event !== 'object') return undefined\n const type = String(event.type ?? '')\n const data =\n event.data && typeof event.data === 'object'\n ? (event.data as Record<string, unknown>)\n : ({} as Record<string, unknown>)\n\n if (type === 'llm_call' || type === 'cost.usage' || type === 'usage') {\n return buildLlmCall(data, agentRunName)\n }\n if (type === 'message.completed' || type === 'result' || type === 'final') {\n const usage = data.usage as Record<string, unknown> | undefined\n if (!usage || typeof usage !== 'object') return undefined\n return buildLlmCall({ ...usage, model: data.model ?? usage.model }, agentRunName)\n }\n // sandbox 0.4.0 terminal event: `data = { tokenUsage: { inputTokens, outputTokens,\n // reasoningTokens, cacheReadInputTokens }, totalCostUsd }`. Usage lives under\n // `tokenUsage` (not `usage`) and the cost is top-level — neither matched the\n // branches above, so an in-process loopDispatch run reported {0,0} and the\n // backend-integrity guard misread a real run as a stub. Reasoning tokens are\n // billed output (reasoning models), so they fold into the output count.\n if (type === 'done') {\n const usage = data.tokenUsage as Record<string, unknown> | undefined\n if (!usage || typeof usage !== 'object') return undefined\n const out = pickFiniteNumber(usage, ['outputTokens', 'completion_tokens', 'tokensOut'])\n const reasoning = pickFiniteNumber(usage, ['reasoningTokens'])\n const mergedOut =\n out !== undefined || reasoning !== undefined ? (out ?? 0) + (reasoning ?? 0) : undefined\n return buildLlmCall(\n {\n inputTokens: usage.inputTokens,\n outputTokens: mergedOut,\n totalCostUsd: data.totalCostUsd,\n model: data.model ?? usage.model,\n },\n agentRunName,\n )\n }\n return undefined\n}\n\n/**\n * Sum the token usage + USD cost of a sandbox turn's events — the one honest way to meter an\n * `openSandboxRun` cell. Folds `extractLlmCallEvent` over the stream (which reads usage off EVERY backend\n * event shape), so a `runProfileMatrix` dispatch can report it to `ctx.cost`:\n *\n * const turn = await run.start(prompt)\n * const u = sumSandboxUsage(turn.events)\n * if (u.input || u.output) ctx.cost.observeTokens({ input: u.input, output: u.output })\n * if (u.costUsd) ctx.cost.observe(u.costUsd, 'sandbox-cell')\n *\n * Without this a cell reads `{tokens:0, cost:0}` and the backend-integrity guard correctly aborts the\n * matrix as a stub. `agentRunName` is the fallback model label for cost-only events (default `'agent'`).\n */\nexport function sumSandboxUsage(\n events: readonly SandboxEvent[],\n agentRunName = 'agent',\n): { input: number; output: number; costUsd: number } {\n let input = 0\n let output = 0\n let costUsd = 0\n for (const ev of events) {\n const call = extractLlmCallEvent(ev, agentRunName)\n if (!call) continue\n input += call.tokensIn ?? 0\n output += call.tokensOut ?? 0\n costUsd += call.costUsd ?? 0\n }\n return { input, output, costUsd }\n}\n\nfunction buildLlmCall(\n data: Record<string, unknown>,\n agentRunName: string,\n): (RuntimeStreamEvent & { type: 'llm_call' }) | undefined {\n const tokensIn = pickFiniteNumber(data, ['tokensIn', 'inputTokens', 'prompt_tokens'])\n const tokensOut = pickFiniteNumber(data, ['tokensOut', 'outputTokens', 'completion_tokens'])\n const costUsd = pickFiniteNumber(data, ['costUsd', 'totalCostUsd', 'cost_usd', 'cost'])\n if (tokensIn === undefined && tokensOut === undefined && costUsd === undefined) {\n return undefined\n }\n const model = typeof data.model === 'string' && data.model.length > 0 ? data.model : agentRunName\n const event: RuntimeStreamEvent & { type: 'llm_call' } = {\n type: 'llm_call',\n model,\n }\n if (tokensIn !== undefined) event.tokensIn = tokensIn\n if (tokensOut !== undefined) event.tokensOut = tokensOut\n if (costUsd !== undefined) event.costUsd = costUsd\n return event\n}\n\nfunction pickFiniteNumber(data: Record<string, unknown>, keys: string[]): number | undefined {\n for (const key of keys) {\n const value = data[key]\n if (typeof value === 'number' && Number.isFinite(value)) return value\n }\n return undefined\n}\n\n/**\n * Cross-event state for {@link mapSandboxToolEvent}. Sandbox backends emit a\n * tool invocation as MANY `message.part.updated` frames on the same call id\n * (pending → running → completed), so faithful projection needs per-call\n * status memory: one `tool_call` on first sighting, at most one `tool_result`\n * on the terminal transition, nothing on intermediate re-frames. Create one\n * state per turn via {@link createSandboxToolPartState}.\n *\n * @experimental\n */\nexport interface SandboxToolPartState {\n /** Last seen status per tool call id. A terminal status is sticky — later\n * frames on a settled call project to nothing. */\n statusByCall: Map<string, string>\n /** Sequence for synthesized call ids when an event carries none. */\n seq: number\n}\n\n/** @experimental */\nexport function createSandboxToolPartState(): SandboxToolPartState {\n return { statusByCall: new Map(), seq: 0 }\n}\n\n/** Terminal tool statuses that are failures (everything here settles the call). */\nconst TERMINAL_TOOL_FAILURE =\n /^(error|errored|failed|failure|cancelled|canceled|timeout|timed_out)$/i\n\n/**\n * Project one `SandboxEvent` onto the `tool_call` / `tool_result` variants of\n * `RuntimeStreamEvent` — the tool-part projection `mapSandboxEvent`\n * deliberately does NOT perform. Opt-in and additive: `mapSandboxEvent`'s\n * default vocabulary (text/reasoning deltas + `llm_call`) is unchanged;\n * consumers that need the tool surface (chat UIs rendering tool activity)\n * compose this projector alongside it — `streamAgentTurn` does exactly that\n * under its `preserveToolParts` option.\n *\n * Handled shapes (observed on the opencode / claude-code sandbox backends):\n * - `message.part.updated` with `part.type === 'tool'` — stateful: a\n * `tool_call` on the call id's first frame (args from `state.input` or\n * `state.metadata.input`), a `tool_result` when the status transitions to\n * `completed` (result from `state.output` / `metadata.output`) or to a\n * terminal failure (result is `{ error, status, output? }` — the error\n * surfaced in-band, never dropped).\n * - bare `tool*` event types (`tool.call`, `tool_result`, …) — stateless:\n * `*result*` types project to `tool_result`, the rest to `tool_call`.\n *\n * Returns `[]` for every non-tool event.\n *\n * @experimental\n */\nexport function mapSandboxToolEvent(\n event: SandboxEvent,\n state: SandboxToolPartState,\n): (RuntimeStreamEvent & { type: 'tool_call' | 'tool_result' })[] {\n if (!event || typeof event !== 'object') return []\n const type = String(event.type ?? '')\n const data =\n event.data && typeof event.data === 'object'\n ? (event.data as Record<string, unknown>)\n : ({} as Record<string, unknown>)\n\n if (type === 'message.part.updated') {\n const part =\n data.part && typeof data.part === 'object' ? (data.part as Record<string, unknown>) : {}\n if (String(part.type ?? '') !== 'tool') return []\n return projectToolPart(part, state, typeof event.id === 'string' ? event.id : undefined)\n }\n\n if (type.includes('tool')) {\n const callId =\n pickString(data, ['toolCallId', 'tool_use_id', 'id']) ??\n (typeof event.id === 'string' ? event.id : undefined) ??\n `sandbox-tool-${++state.seq}`\n const toolName = pickString(data, ['name', 'toolName', 'tool']) ?? 'sandbox_tool'\n if (type.includes('result')) {\n return [\n {\n type: 'tool_result',\n toolName,\n toolCallId: callId,\n result: data.output ?? data.result ?? data.content ?? data,\n },\n ]\n }\n return [\n { type: 'tool_call', toolName, toolCallId: callId, args: data.input ?? data.args ?? {} },\n ]\n }\n\n return []\n}\n\nfunction projectToolPart(\n part: Record<string, unknown>,\n state: SandboxToolPartState,\n eventId: string | undefined,\n): (RuntimeStreamEvent & { type: 'tool_call' | 'tool_result' })[] {\n const callId =\n pickString(part, ['callID', 'callId', 'toolCallId', 'id']) ??\n eventId ??\n `sandbox-tool-${++state.seq}`\n const toolName = pickString(part, ['tool', 'toolName', 'name']) ?? 'sandbox_tool'\n const toolState =\n part.state && typeof part.state === 'object' ? (part.state as Record<string, unknown>) : {}\n const metadata =\n toolState.metadata && typeof toolState.metadata === 'object'\n ? (toolState.metadata as Record<string, unknown>)\n : {}\n const status = pickString(toolState, ['status']) ?? 'updated'\n\n const previous = state.statusByCall.get(callId)\n const settled =\n previous === 'completed' || (previous !== undefined && TERMINAL_TOOL_FAILURE.test(previous))\n if (settled) return []\n\n const out: (RuntimeStreamEvent & { type: 'tool_call' | 'tool_result' })[] = []\n if (previous === undefined) {\n out.push({\n type: 'tool_call',\n toolName,\n toolCallId: callId,\n args: toolState.input ?? metadata.input ?? {},\n })\n }\n state.statusByCall.set(callId, status)\n\n if (status === 'completed') {\n out.push({\n type: 'tool_result',\n toolName,\n toolCallId: callId,\n result: toolState.output ?? metadata.output ?? '',\n })\n } else if (TERMINAL_TOOL_FAILURE.test(status)) {\n const message =\n pickString(toolState, ['error', 'message']) ??\n pickString(metadata, ['error', 'message']) ??\n `sandbox tool ended with status ${status}`\n const output = toolState.output ?? metadata.output\n out.push({\n type: 'tool_result',\n toolName,\n toolCallId: callId,\n result: { error: message, status, ...(output !== undefined ? { output } : {}) },\n })\n }\n return out\n}\n\nfunction pickString(data: Record<string, unknown>, keys: string[]): string | undefined {\n for (const key of keys) {\n const value = data[key]\n if (typeof value === 'string' && value.length > 0) return value\n }\n return undefined\n}\n\n/**\n * Project one `SandboxEvent` onto the `RuntimeStreamEvent` chat-UX vocabulary,\n * for runtimes that bridge a sandbox `streamPrompt` into the\n * `AgentRuntime.act` streaming contract. Returns `undefined` for events that\n * have no faithful projection — the raw stream is preserved separately for the\n * `OutputAdapter`, so an unmapped event never loses data.\n *\n * Mapped (the task-optional incremental variants — no synthesized task\n * lifecycle, no guessed tool-part shapes):\n * - `message.part.updated` text part → `text_delta`\n * - `message.part.updated` reasoning/thinking part → `reasoning_delta`\n * - cost-bearing events → `llm_call` (shared with the ledger extractor)\n *\n * Tool parts are deliberately NOT mapped here (unchanged default) — compose\n * {@link mapSandboxToolEvent} alongside when a consumer needs them.\n *\n * The opencode backend emits incremental text as\n * `{ type: 'message.part.updated', data: { part: { type, text }, delta } }`;\n * `delta` is the increment, `part.text` the running accumulation.\n */\nexport function mapSandboxEvent(\n event: SandboxEvent,\n opts: { agentRunName?: string } = {},\n): RuntimeStreamEvent | undefined {\n if (!event || typeof event !== 'object') return undefined\n const type = String(event.type ?? '')\n const data =\n event.data && typeof event.data === 'object'\n ? (event.data as Record<string, unknown>)\n : ({} as Record<string, unknown>)\n\n if (type === 'message.part.updated') {\n const part =\n data.part && typeof data.part === 'object' ? (data.part as Record<string, unknown>) : {}\n const partType = String(part.type ?? '')\n const delta = typeof data.delta === 'string' ? data.delta : undefined\n const text = delta ?? (typeof part.text === 'string' ? part.text : undefined)\n if (text === undefined) return undefined\n if (partType === 'text') return { type: 'text_delta', text }\n if (partType === 'reasoning' || partType === 'thinking')\n return { type: 'reasoning_delta', text }\n return undefined\n }\n\n return extractLlmCallEvent(event, opts.agentRunName ?? 'agent')\n}\n"],"mappings":"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","names":[]}
@@ -15,7 +15,7 @@ import {
15
15
  settledToIteration,
16
16
  supervise,
17
17
  withDriverExecutor
18
- } from "./chunk-XN5TIJGP.js";
18
+ } from "./chunk-6XCW3M7W.js";
19
19
  import {
20
20
  addTokenUsage,
21
21
  isAbortError,
@@ -25,8 +25,10 @@ import {
25
25
  zeroTokenUsage
26
26
  } from "./chunk-BZF3KQ6G.js";
27
27
  import {
28
- mapSandboxEvent
29
- } from "./chunk-4J6RBI3K.js";
28
+ createSandboxToolPartState,
29
+ mapSandboxEvent,
30
+ mapSandboxToolEvent
31
+ } from "./chunk-QUXZBZCS.js";
30
32
  import {
31
33
  AnalystError,
32
34
  BackendTransportError,
@@ -977,49 +979,68 @@ function defineLeaderboard(spec) {
977
979
  return p;
978
980
  };
979
981
  let shotNonce = 0;
980
- const dispatch = spec.dispatch ?? loopDispatch({
981
- sandboxClient,
982
- toLoopOptions: (scenario, profile) => {
983
- const axis = harnessAxisOf(profile);
984
- const modelId = bareModel(axis?.model ?? models[0] ?? "");
985
- return {
986
- // naiveDriver = the no-signal retry floor: re-run the same case as
987
- // an independent attempt until one scores (>0) or the shot cap.
988
- driver: naiveDriver({
989
- continuation: "",
990
- applyContinuation: (task) => task,
991
- maxIterations: shots
992
- }),
993
- agentRun: {
994
- profile,
995
- taskToPrompt: (s) => `${promptOf(s)}
982
+ const dispatch = spec.dispatch ?? ((profile, scenario, dispatchCtx) => {
983
+ const cellDispatch = loopDispatch({
984
+ sandboxClient,
985
+ toLoopOptions: (cellScenario, cellProfile) => {
986
+ const axis = harnessAxisOf(cellProfile);
987
+ const modelId = bareModel(axis?.model ?? models[0] ?? "");
988
+ return {
989
+ // naiveDriver = the no-signal retry floor: re-run the same case as
990
+ // an independent attempt until one scores (>0) or the shot cap.
991
+ driver: naiveDriver({
992
+ continuation: "",
993
+ applyContinuation: (task) => task,
994
+ maxIterations: shots
995
+ }),
996
+ agentRun: {
997
+ profile: cellProfile,
998
+ taskToPrompt: (s) => `${promptOf(s)}
996
999
 
997
1000
  <!-- independent-attempt:${shotNonce++} -->`,
998
- ...axis ? {
999
- sandboxOverrides: {
1000
- backend: {
1001
- type: axis.harness,
1002
- model: { ...spec.modelBackend, model: modelId }
1001
+ ...axis ? {
1002
+ sandboxOverrides: {
1003
+ backend: {
1004
+ type: axis.harness,
1005
+ model: { ...spec.modelBackend, model: modelId }
1006
+ }
1003
1007
  }
1008
+ } : {}
1009
+ },
1010
+ output: {
1011
+ parse: (events) => spec.parseOutput ? spec.parseOutput(events, cellScenario.case) : (
1012
+ // The default decode produces string — the TArtifact
1013
+ // default. A structured-TArtifact spec supplies parseOutput
1014
+ // (documented on the field), so this cast never lies.
1015
+ collectAgentResponseText(events) ?? ""
1016
+ )
1017
+ },
1018
+ validator: {
1019
+ validate: async (output) => {
1020
+ const s = normalizeScore(spec.score(output, cellScenario.case));
1021
+ return { valid: s.composite > 0, score: s.composite };
1004
1022
  }
1005
- } : {}
1006
- },
1007
- output: {
1008
- parse: (events) => {
1009
- spec.onCellEvents?.(events, scenario.case);
1010
- return spec.parseOutput ? spec.parseOutput(events, scenario.case) : collectAgentResponseText(events) ?? "";
1011
- }
1012
- },
1013
- validator: {
1014
- validate: async (output) => {
1015
- const s = normalizeScore(spec.score(output, scenario.case));
1016
- return { valid: s.composite > 0, score: s.composite };
1023
+ },
1024
+ task: cellScenario,
1025
+ maxIterations: shots
1026
+ };
1027
+ },
1028
+ toArtifact: (result) => {
1029
+ for (const iter of result.iterations) {
1030
+ spec.onCellEvents?.(iter.events, scenario.case, {
1031
+ index: iter.index,
1032
+ ...iter.error ? { error: iter.error.message } : {},
1033
+ ...iter.verdict ? { verdict: { score: iter.verdict.score } } : {}
1034
+ });
1035
+ if (spec.resolveModel) {
1036
+ const served = spec.resolveModel(iter.events);
1037
+ if (served !== void 0) dispatchCtx.cost.observeModel?.(served);
1017
1038
  }
1018
- },
1019
- task: scenario,
1020
- maxIterations: shots
1021
- };
1022
- }
1039
+ }
1040
+ return result.winner?.output;
1041
+ }
1042
+ });
1043
+ return cellDispatch(profile, scenario, dispatchCtx);
1023
1044
  });
1024
1045
  await spec.setup?.(ctx);
1025
1046
  try {
@@ -1306,7 +1327,7 @@ function isAsyncIterable2(v) {
1306
1327
  return typeof v === "object" && v !== null && Symbol.asyncIterator in v;
1307
1328
  }
1308
1329
  function inProcessSandboxClient(options) {
1309
- const { onPrompt, workdir: workdirPrefix, id: idOption } = options;
1330
+ const { onPrompt, onTask, workdir: workdirPrefix, id: idOption } = options;
1310
1331
  let seq = 0;
1311
1332
  return {
1312
1333
  async create(_options) {
@@ -1345,19 +1366,34 @@ function inProcessSandboxClient(options) {
1345
1366
  }
1346
1367
  }
1347
1368
  } : {};
1369
+ async function* drive(behavior, mode, message, opts) {
1370
+ const prompt = typeof message === "string" ? message : JSON.stringify(message);
1371
+ const { signal: optSignal, ...rest } = opts ?? {};
1372
+ const signal = optSignal ?? new AbortController().signal;
1373
+ const ctx = {
1374
+ round,
1375
+ workdir: boxWorkdir,
1376
+ signal,
1377
+ mode,
1378
+ ...Object.keys(rest).length > 0 ? { options: rest } : {}
1379
+ };
1380
+ round += 1;
1381
+ const produced = await behavior(prompt, ctx);
1382
+ if (isAsyncIterable2(produced)) {
1383
+ for await (const ev of produced) yield ev;
1384
+ } else {
1385
+ for (const ev of produced) yield ev;
1386
+ }
1387
+ }
1348
1388
  const box = {
1349
1389
  id,
1350
- async *streamPrompt(message, opts) {
1351
- const prompt = typeof message === "string" ? message : JSON.stringify(message);
1352
- const signal = opts?.signal ?? new AbortController().signal;
1353
- const ctx = { round, workdir: boxWorkdir, signal };
1354
- round += 1;
1355
- const produced = await onPrompt(prompt, ctx);
1356
- if (isAsyncIterable2(produced)) {
1357
- for await (const ev of produced) yield ev;
1358
- } else {
1359
- for (const ev of produced) yield ev;
1360
- }
1390
+ streamPrompt(message, opts) {
1391
+ return drive(onPrompt, "prompt", message, opts);
1392
+ },
1393
+ // Task-mode verb (`streamAgentTurn`'s `box-task` backend). Drives
1394
+ // `onTask` when configured; otherwise the box's one behavior callback.
1395
+ streamTask(message, opts) {
1396
+ return drive(onTask ?? onPrompt, "task", message, opts);
1361
1397
  },
1362
1398
  ...fsMembers,
1363
1399
  async delete() {
@@ -4301,6 +4337,12 @@ function createOpenAICompatibleBackend(options) {
4301
4337
  if (options.responseFormat !== void 0) {
4302
4338
  bodyPayload.response_format = options.responseFormat;
4303
4339
  }
4340
+ if (options.temperature !== void 0) {
4341
+ bodyPayload.temperature = options.temperature;
4342
+ }
4343
+ if (options.maxTokens !== void 0) {
4344
+ bodyPayload.max_tokens = options.maxTokens;
4345
+ }
4304
4346
  const requestBody = JSON.stringify(bodyPayload);
4305
4347
  let response;
4306
4348
  let lastStatus = 0;
@@ -4781,11 +4823,17 @@ async function* streamAgentTurn(backend, prompt, opts = {}) {
4781
4823
  session = await startTurnSession(backend, task, prompt, deadline.signal, label);
4782
4824
  yield { type: "backend_start", task, session, backend: label, timestamp: nowIso() };
4783
4825
  const inner = backend.kind === "chat" ? driveChatTurn(backend.backend, task, session, prompt, deadline.signal, acc) : driveBoxTurn(
4784
- backend.kind === "box" ? backend.box : await inlineSandboxClient(backend.factory).create(),
4826
+ backend.kind === "executor" ? await inlineSandboxClient(backend.factory).create() : backend.box,
4785
4827
  prompt,
4786
4828
  deadline.signal,
4787
4829
  backend.agentRunName ?? "agent",
4788
- acc
4830
+ acc,
4831
+ {
4832
+ mode: backend.kind === "box-task" ? "task" : "prompt",
4833
+ ...backend.kind !== "executor" && backend.options ? { options: backend.options } : {},
4834
+ preserveToolParts: opts.preserveToolParts === true,
4835
+ ...opts.onRawEvent ? { onRawEvent: opts.onRawEvent } : {}
4836
+ }
4789
4837
  );
4790
4838
  for await (const event of inner) {
4791
4839
  yield event;
@@ -4849,10 +4897,17 @@ async function startTurnSession(backend, task, prompt, signal, label) {
4849
4897
  }
4850
4898
  return newRuntimeSession(label);
4851
4899
  }
4852
- async function* driveBoxTurn(box, prompt, signal, agentRunName, acc) {
4853
- for await (const event of box.streamPrompt(prompt, { signal })) {
4900
+ async function* driveBoxTurn(box, prompt, signal, agentRunName, acc, cfg) {
4901
+ const callOptions = { ...cfg.options ?? {}, signal };
4902
+ const stream = cfg.mode === "task" ? box.streamTask(prompt, callOptions) : box.streamPrompt(prompt, callOptions);
4903
+ const toolParts = cfg.preserveToolParts ? createSandboxToolPartState() : void 0;
4904
+ for await (const event of stream) {
4905
+ if (cfg.onRawEvent) await cfg.onRawEvent(event);
4854
4906
  const terminalText = terminalTextFromSandboxEvent(event);
4855
4907
  if (terminalText !== void 0) acc.terminalText = terminalText;
4908
+ if (toolParts) {
4909
+ for (const toolEvent of mapSandboxToolEvent(event, toolParts)) yield toolEvent;
4910
+ }
4856
4911
  const mapped = mapSandboxEvent(event, { agentRunName });
4857
4912
  if (!mapped) continue;
4858
4913
  foldEvent(mapped, acc, agentRunName);
@@ -5851,4 +5906,4 @@ export {
5851
5906
  computeFindingId,
5852
5907
  makeFinding2 as makeFinding
5853
5908
  };
5854
- //# sourceMappingURL=chunk-DLAEEF26.js.map
5909
+ //# sourceMappingURL=chunk-VKVNDNG4.js.map