@ai-sdk/harness 1.0.101 → 1.0.103

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.
@@ -42,9 +42,11 @@ var HarnessCapabilityUnsupportedError = class extends (_b2 = HarnessError, _a2 =
42
42
  import {
43
43
  asArray as asArray2,
44
44
  asSchema,
45
- generateId as generateId5,
45
+ generateId as generateId3,
46
+ normalizeHeaders,
46
47
  validateTypes
47
48
  } from "@ai-sdk/provider-utils";
49
+ import { mergeCallbacks } from "ai/internal";
48
50
 
49
51
  // src/agent/internal/lifecycle-state-validation.ts
50
52
  import { safeValidateTypes } from "@ai-sdk/provider-utils";
@@ -155,19 +157,18 @@ async function toHarnessStream(options) {
155
157
  // src/agent/internal/run-prompt.ts
156
158
  import {
157
159
  executeTool,
158
- generateId as generateId4,
160
+ generateId as generateId2,
159
161
  isExecutableTool,
160
162
  safeParseJSON as safeParseJSON2
161
163
  } from "@ai-sdk/provider-utils";
162
164
  import {
163
165
  getErrorMessage
164
166
  } from "@ai-sdk/provider";
165
- import { parseToolCall } from "ai/internal";
167
+ import { asLanguageModelUsage as asLanguageModelUsage2, parseToolCall } from "ai/internal";
166
168
 
167
169
  // src/agent/internal/harness-stream-text-result.ts
168
170
  import {
169
- DelayedPromise,
170
- generateId
171
+ DelayedPromise
171
172
  } from "@ai-sdk/provider-utils";
172
173
  import {
173
174
  addLanguageModelUsage,
@@ -224,7 +225,8 @@ var HarnessStreamTextResult = class {
224
225
  this.runtimeContext = options.runtimeContext;
225
226
  this.toolsContext = options.toolsContext;
226
227
  this.providerName = `harness:${options.harnessId}`;
227
- this.modelId = options.sessionId;
228
+ this.callId = options.callId;
229
+ this.modelId = options.modelId;
228
230
  this.outputSpecification = options.output;
229
231
  let controllerRef;
230
232
  const baseStream = new ReadableStream({
@@ -252,6 +254,11 @@ var HarnessStreamTextResult = class {
252
254
  this.fullStreamController.enqueue(part);
253
255
  this.appendToCurrentStepContent(part);
254
256
  }
257
+ setModelId(modelId) {
258
+ if (this.stepsBuffer.length === 0) {
259
+ this.modelId = modelId;
260
+ }
261
+ }
255
262
  /**
256
263
  * Push a continuation input into the consumer stream without attributing it
257
264
  * to the next model step. Approval responses and client tool results arrive
@@ -281,7 +288,7 @@ var HarnessStreamTextResult = class {
281
288
  const finishReason = input.finishReason.unified;
282
289
  const rawFinishReason = input.finishReason.raw;
283
290
  const step = new DefaultStepResult({
284
- callId: generateId(),
291
+ callId: this.callId,
285
292
  stepNumber: this.stepNumber,
286
293
  provider: this.providerName,
287
294
  modelId: this.modelId,
@@ -295,7 +302,7 @@ var HarnessStreamTextResult = class {
295
302
  warnings: input.warnings.length > 0 ? input.warnings : void 0,
296
303
  request: {},
297
304
  response: {
298
- id: generateId(),
305
+ id: `${this.callId}-${this.stepNumber}`,
299
306
  timestamp: /* @__PURE__ */ new Date(),
300
307
  modelId: this.modelId,
301
308
  messages: []
@@ -357,7 +364,7 @@ var HarnessStreamTextResult = class {
357
364
  }
358
365
  this.settled = true;
359
366
  const finalStep = this.stepsBuffer.length > 0 ? this.stepsBuffer[this.stepsBuffer.length - 1] : new DefaultStepResult({
360
- callId: generateId(),
367
+ callId: this.callId,
361
368
  stepNumber: 0,
362
369
  provider: this.providerName,
363
370
  modelId: this.modelId,
@@ -371,7 +378,7 @@ var HarnessStreamTextResult = class {
371
378
  warnings: void 0,
372
379
  request: {},
373
380
  response: {
374
- id: generateId(),
381
+ id: `${this.callId}-0`,
375
382
  timestamp: /* @__PURE__ */ new Date(),
376
383
  modelId: this.modelId,
377
384
  messages: []
@@ -733,6 +740,18 @@ var HarnessStreamTextResult = class {
733
740
  }
734
741
  return;
735
742
  }
743
+ case "reasoning-delta": {
744
+ const last = this.currentStepContent[this.currentStepContent.length - 1];
745
+ if (last && last.type === "reasoning") {
746
+ last.text += part.text;
747
+ } else {
748
+ this.currentStepContent.push({
749
+ type: "reasoning",
750
+ text: part.text
751
+ });
752
+ }
753
+ return;
754
+ }
736
755
  case "tool-call":
737
756
  case "tool-approval-request":
738
757
  case "tool-approval-response":
@@ -833,7 +852,7 @@ function notSupportedYet(feature) {
833
852
  }
834
853
 
835
854
  // src/agent/internal/translate-stream-part.ts
836
- import { generateId as generateId2 } from "@ai-sdk/provider-utils";
855
+ import { generateId } from "@ai-sdk/provider-utils";
837
856
  function translateStreamPart(event, options = {}) {
838
857
  var _a4, _b4;
839
858
  switch (event.type) {
@@ -925,7 +944,7 @@ function translateStreamPart(event, options = {}) {
925
944
  }
926
945
  ];
927
946
  case "file-change": {
928
- const toolCallId = `harness-file-change-${generateId2()}`;
947
+ const toolCallId = `harness-file-change-${generateId()}`;
929
948
  const payload = { event: event.event, path: event.path };
930
949
  return [
931
950
  {
@@ -950,7 +969,7 @@ function translateStreamPart(event, options = {}) {
950
969
  ];
951
970
  }
952
971
  case "compaction": {
953
- const toolCallId = `harness-compaction-${generateId2()}`;
972
+ const toolCallId = `harness-compaction-${generateId()}`;
954
973
  const output = {
955
974
  trigger: event.trigger,
956
975
  summary: event.summary,
@@ -1097,371 +1116,255 @@ function stripDeep(value, workDir) {
1097
1116
  }
1098
1117
 
1099
1118
  // src/agent/internal/turn-telemetry.ts
1100
- import {
1101
- generateId as generateId3
1102
- } from "@ai-sdk/provider-utils";
1103
1119
  import { createTelemetryDispatcher } from "ai/internal";
1104
- var NOOP = {
1105
- async start() {
1106
- },
1107
- async ensureStepOpen() {
1108
- },
1109
- async stepFinish() {
1110
- },
1111
- async toolStart() {
1112
- },
1113
- async executeTool({ execute }) {
1114
- return await execute();
1115
- },
1116
- async toolEnd() {
1117
- },
1118
- async end() {
1119
- },
1120
- async error() {
1121
- }
1122
- };
1123
- function normalizeFinishReason(finishReason) {
1124
- if (finishReason != null && typeof finishReason === "object" && "unified" in finishReason) {
1125
- return finishReason.unified;
1126
- }
1127
- return finishReason;
1128
- }
1129
- function addTokenCounts(tokenCount1, tokenCount2) {
1130
- return tokenCount1 == null && tokenCount2 == null ? void 0 : (tokenCount1 != null ? tokenCount1 : 0) + (tokenCount2 != null ? tokenCount2 : 0);
1131
- }
1132
- function normalizeUsage(usage) {
1133
- if (usage == null || typeof usage !== "object" || !("inputTokens" in usage) || !("outputTokens" in usage)) {
1134
- return usage;
1135
- }
1136
- const inputTokens = usage.inputTokens;
1137
- const outputTokens = usage.outputTokens;
1138
- if (inputTokens == null || typeof inputTokens !== "object" || outputTokens == null || typeof outputTokens !== "object") {
1139
- return usage;
1140
- }
1141
- const input = inputTokens;
1142
- const output = outputTokens;
1143
- return {
1144
- inputTokens: input.total,
1145
- inputTokenDetails: {
1146
- noCacheTokens: input.noCache,
1147
- cacheReadTokens: input.cacheRead,
1148
- cacheWriteTokens: input.cacheWrite
1149
- },
1150
- outputTokens: output.total,
1151
- outputTokenDetails: {
1152
- textTokens: output.text,
1153
- reasoningTokens: output.reasoning
1154
- },
1155
- totalTokens: addTokenCounts(input.total, output.total),
1156
- raw: usage.raw
1157
- };
1120
+ async function notify(event, ...callbacks) {
1121
+ await Promise.allSettled(
1122
+ callbacks.map(async (callback) => {
1123
+ await (callback == null ? void 0 : callback(event));
1124
+ })
1125
+ );
1158
1126
  }
1159
- function createTurnTelemetry(opts) {
1127
+ function createTurnLifecycle(options) {
1160
1128
  var _a4;
1161
- if (opts.telemetry == null) return NOOP;
1162
- const dispatcher = createTelemetryDispatcher({ telemetry: opts.telemetry });
1163
- const callId = generateId3();
1164
- const provider = opts.harnessId;
1165
- let modelId = (_a4 = opts.modelId) != null ? _a4 : "";
1166
- const runtimeContext = opts.runtimeContext;
1167
- const inputMessages = [
1168
- { role: "user", content: opts.promptText }
1169
- ];
1170
- const languageModelTools = opts.toolSpecs.length === 0 ? void 0 : opts.toolSpecs.map((tool) => ({
1171
- type: "function",
1172
- name: tool.name,
1173
- ...tool.description != null ? { description: tool.description } : {},
1174
- ...tool.inputSchema != null ? { inputSchema: tool.inputSchema } : {}
1175
- }));
1129
+ const telemetry = options.telemetry == null ? {} : createTelemetryDispatcher({ telemetry: options.telemetry });
1130
+ const provider = `harness:${options.harnessId}`;
1131
+ let modelId = (_a4 = options.modelId) != null ? _a4 : "";
1176
1132
  let started = false;
1177
1133
  let stepOpen = false;
1178
1134
  let stepNumber = 0;
1179
1135
  let ended = false;
1180
- let finalStepText = "";
1181
- let finalStepReasoning = [];
1182
- let finalStepProviderMetadata;
1183
- let outputToolCalls = [];
1184
- const openTools = /* @__PURE__ */ new Map();
1185
- const cast = (event) => event;
1186
- const fireStart = async () => {
1187
- var _a5;
1188
- if (started) return;
1189
- started = true;
1190
- await ((_a5 = dispatcher.onStart) == null ? void 0 : _a5.call(
1191
- dispatcher,
1192
- cast({
1193
- callId,
1194
- operationId: "ai.harness",
1195
- provider,
1196
- modelId,
1197
- tools: opts.tools,
1198
- toolChoice: void 0,
1199
- activeTools: opts.activeToolNames,
1200
- maxRetries: 0,
1201
- timeout: void 0,
1202
- headers: void 0,
1203
- providerOptions: void 0,
1204
- output: void 0,
1205
- toolsContext: void 0,
1206
- runtimeContext,
1207
- instructions: opts.instructions,
1208
- messages: inputMessages
1209
- })
1210
- ));
1211
- };
1136
+ let modelCallStartedAt = 0;
1137
+ const completedSteps = [];
1138
+ const languageModelTools = options.toolSpecs.length === 0 ? void 0 : options.toolSpecs.map((tool) => ({
1139
+ type: "function",
1140
+ name: tool.name,
1141
+ ...tool.description == null ? {} : { description: tool.description },
1142
+ ...tool.inputSchema == null ? {} : { inputSchema: tool.inputSchema }
1143
+ }));
1212
1144
  const start = async (overrideModelId) => {
1213
1145
  if (started) return;
1214
- if (overrideModelId) modelId = overrideModelId;
1215
- await fireStart();
1146
+ if (overrideModelId != null) modelId = overrideModelId;
1147
+ started = true;
1148
+ const event = {
1149
+ callId: options.callId,
1150
+ operationId: "ai.harness",
1151
+ provider,
1152
+ modelId,
1153
+ tools: options.tools,
1154
+ toolChoice: void 0,
1155
+ activeTools: options.activeToolNames,
1156
+ toolOrder: [],
1157
+ maxRetries: 0,
1158
+ timeout: void 0,
1159
+ headers: void 0,
1160
+ providerOptions: void 0,
1161
+ output: options.output,
1162
+ toolsContext: options.toolsContext,
1163
+ runtimeContext: options.runtimeContext,
1164
+ instructions: options.instructions,
1165
+ messages: options.messages
1166
+ };
1167
+ await notify(
1168
+ event,
1169
+ options.callbacks.onStart,
1170
+ telemetry.onStart
1171
+ );
1216
1172
  };
1217
1173
  const ensureStepOpen = async () => {
1218
- var _a5, _b4;
1219
- if (!started) await fireStart();
1174
+ if (!started) await start();
1220
1175
  if (stepOpen || ended) return;
1221
1176
  stepOpen = true;
1222
- await ((_a5 = dispatcher.onStepStart) == null ? void 0 : _a5.call(
1223
- dispatcher,
1224
- cast({
1225
- callId,
1226
- provider,
1227
- modelId,
1228
- stepNumber,
1229
- tools: opts.tools,
1230
- toolChoice: void 0,
1231
- activeTools: opts.activeToolNames,
1232
- steps: new Array(stepNumber),
1233
- providerOptions: void 0,
1234
- output: void 0,
1235
- runtimeContext,
1236
- instructions: opts.instructions,
1237
- messages: inputMessages
1238
- })
1239
- ));
1240
- await ((_b4 = dispatcher.onLanguageModelCallStart) == null ? void 0 : _b4.call(
1241
- dispatcher,
1242
- cast({
1243
- callId,
1244
- provider,
1245
- modelId,
1246
- instructions: opts.instructions,
1247
- messages: inputMessages,
1248
- tools: languageModelTools
1249
- })
1250
- ));
1177
+ const stepStartEvent = {
1178
+ callId: options.callId,
1179
+ provider,
1180
+ modelId,
1181
+ stepNumber,
1182
+ tools: options.tools,
1183
+ toolChoice: void 0,
1184
+ activeTools: options.activeToolNames,
1185
+ toolOrder: [],
1186
+ steps: [...completedSteps],
1187
+ providerOptions: void 0,
1188
+ output: options.output,
1189
+ runtimeContext: options.runtimeContext,
1190
+ toolsContext: options.toolsContext,
1191
+ instructions: options.instructions,
1192
+ messages: options.messages
1193
+ };
1194
+ await notify(
1195
+ stepStartEvent,
1196
+ options.callbacks.onStepStart,
1197
+ telemetry.onStepStart
1198
+ );
1199
+ const modelStartEvent = {
1200
+ callId: options.callId,
1201
+ provider,
1202
+ modelId,
1203
+ instructions: options.instructions,
1204
+ messages: options.messages,
1205
+ tools: languageModelTools
1206
+ };
1207
+ modelCallStartedAt = Date.now();
1208
+ await notify(
1209
+ modelStartEvent,
1210
+ options.callbacks.onLanguageModelCallStart,
1211
+ telemetry.onLanguageModelCallStart
1212
+ );
1251
1213
  };
1252
- const inferenceEnd = async (info) => {
1253
- var _a5;
1254
- const finishReason = normalizeFinishReason(info.finishReason);
1255
- const usage = normalizeUsage(info.usage);
1256
- await ((_a5 = dispatcher.onLanguageModelCallEnd) == null ? void 0 : _a5.call(
1257
- dispatcher,
1258
- cast({
1259
- callId,
1214
+ return {
1215
+ start,
1216
+ ensureStepOpen,
1217
+ async languageModelCallEnd(input) {
1218
+ await ensureStepOpen();
1219
+ const event = {
1220
+ callId: options.callId,
1260
1221
  provider,
1261
1222
  modelId,
1262
- finishReason,
1263
- responseId: callId,
1264
- usage,
1265
- content: info.content,
1266
- ...info.providerMetadata != null ? { providerMetadata: info.providerMetadata } : {},
1223
+ finishReason: input.finishReason,
1224
+ usage: input.usage,
1225
+ content: input.content,
1226
+ responseId: `${options.callId}-${stepNumber}`,
1227
+ providerMetadata: input.providerMetadata,
1267
1228
  performance: {
1268
- responseTimeMs: void 0,
1229
+ responseTimeMs: Math.max(0, Date.now() - modelCallStartedAt),
1230
+ effectiveOutputTokensPerSecond: 0,
1231
+ outputTokensPerSecond: void 0,
1232
+ inputTokensPerSecond: void 0,
1233
+ effectiveTotalTokensPerSecond: 0,
1269
1234
  timeToFirstOutputMs: void 0,
1270
1235
  timeBetweenOutputChunksMs: void 0
1271
1236
  }
1272
- })
1273
- ));
1274
- };
1275
- const recordOutputContent = (content) => {
1276
- finalStepText = "";
1277
- finalStepReasoning = [];
1278
- for (const part of content) {
1279
- if (part.type === "text") {
1280
- finalStepText += part.text;
1281
- } else if (part.type === "reasoning") {
1282
- finalStepReasoning.push({ text: part.text });
1283
- } else if (part.type === "tool-call") {
1284
- outputToolCalls.push(part);
1285
- }
1286
- }
1287
- };
1288
- const closeOpenTools = async () => {
1289
- var _a5;
1290
- for (const call of openTools.values()) {
1291
- await ((_a5 = dispatcher.onToolExecutionEnd) == null ? void 0 : _a5.call(
1292
- dispatcher,
1293
- cast({
1294
- callId,
1295
- toolExecutionMs: 0,
1296
- messages: [],
1297
- toolCall: {
1298
- type: "tool-call",
1299
- toolCallId: call.toolCallId,
1300
- toolName: call.toolName,
1301
- input: call.input,
1302
- dynamic: true
1303
- },
1304
- toolContext: void 0,
1305
- toolOutput: { type: "error", error: new Error("tool span unclosed") }
1306
- })
1307
- ));
1308
- }
1309
- openTools.clear();
1310
- };
1311
- return {
1312
- start,
1313
- ensureStepOpen,
1314
- async stepFinish(info) {
1315
- var _a5, _b4;
1237
+ };
1238
+ await notify(
1239
+ event,
1240
+ options.callbacks.onLanguageModelCallEnd,
1241
+ telemetry.onLanguageModelCallEnd
1242
+ );
1243
+ },
1244
+ async toolExecutionStart({ toolCall }) {
1245
+ const event = {
1246
+ callId: options.callId,
1247
+ messages: options.messages,
1248
+ toolCall,
1249
+ toolContext: void 0
1250
+ };
1251
+ await notify(
1252
+ event,
1253
+ options.callbacks.onToolExecutionStart,
1254
+ telemetry.onToolExecutionStart
1255
+ );
1256
+ },
1257
+ async toolExecutionEnd({ toolCall, toolOutput, toolExecutionMs }) {
1258
+ const event = {
1259
+ callId: options.callId,
1260
+ messages: options.messages,
1261
+ toolCall,
1262
+ toolContext: void 0,
1263
+ toolOutput,
1264
+ toolExecutionMs
1265
+ };
1266
+ await notify(
1267
+ event,
1268
+ options.callbacks.onToolExecutionEnd,
1269
+ telemetry.onToolExecutionEnd
1270
+ );
1271
+ },
1272
+ async stepEnd(step) {
1273
+ var _a5, _b4, _c;
1316
1274
  if (!stepOpen) return;
1317
- const content = (_a5 = info.content) != null ? _a5 : [];
1318
- const finishReason = normalizeFinishReason(info.finishReason);
1319
- const usage = normalizeUsage(info.usage);
1320
- recordOutputContent(content);
1321
- finalStepProviderMetadata = info.providerMetadata;
1322
- await closeOpenTools();
1323
- await inferenceEnd({
1324
- finishReason,
1325
- usage,
1326
- content,
1327
- providerMetadata: info.providerMetadata
1275
+ completedSteps.push(step);
1276
+ const telemetryStepEndEvent = Object.assign(/* @__PURE__ */ Object.create(null), {
1277
+ callId: step.callId,
1278
+ stepNumber: step.stepNumber,
1279
+ model: step.model,
1280
+ toolsContext: step.toolsContext,
1281
+ runtimeContext: step.runtimeContext,
1282
+ content: step.content,
1283
+ finishReason: step.finishReason,
1284
+ rawFinishReason: step.rawFinishReason,
1285
+ usage: step.usage,
1286
+ performance: step.performance,
1287
+ warnings: step.warnings,
1288
+ request: step.request,
1289
+ response: step.response,
1290
+ providerMetadata: step.providerMetadata,
1291
+ text: step.text,
1292
+ reasoning: step.reasoning,
1293
+ reasoningText: step.reasoningText,
1294
+ files: step.files,
1295
+ sources: step.sources,
1296
+ toolCalls: step.toolCalls,
1297
+ staticToolCalls: step.staticToolCalls,
1298
+ dynamicToolCalls: step.dynamicToolCalls,
1299
+ toolResults: step.toolResults,
1300
+ staticToolResults: step.staticToolResults,
1301
+ dynamicToolResults: step.dynamicToolResults
1328
1302
  });
1329
- await ((_b4 = dispatcher.onStepEnd) == null ? void 0 : _b4.call(
1330
- dispatcher,
1331
- cast({
1332
- callId,
1333
- stepNumber,
1334
- finishReason,
1335
- usage,
1336
- providerMetadata: info.providerMetadata,
1337
- content,
1338
- response: {
1339
- id: callId,
1340
- modelId,
1341
- timestamp: /* @__PURE__ */ new Date(0),
1342
- messages: []
1343
- }
1344
- })
1345
- ));
1303
+ await Promise.allSettled([
1304
+ (_b4 = (_a5 = options.callbacks).onStepEnd) == null ? void 0 : _b4.call(_a5, step),
1305
+ (_c = telemetry.onStepEnd) == null ? void 0 : _c.call(telemetry, telemetryStepEndEvent)
1306
+ ]);
1346
1307
  stepOpen = false;
1347
1308
  stepNumber += 1;
1348
1309
  },
1349
- async toolStart(call) {
1350
- var _a5;
1351
- await ensureStepOpen();
1352
- if (openTools.has(call.toolCallId)) return;
1353
- openTools.set(call.toolCallId, call);
1354
- await ((_a5 = dispatcher.onToolExecutionStart) == null ? void 0 : _a5.call(
1355
- dispatcher,
1356
- cast({
1357
- callId,
1358
- messages: [],
1359
- toolCall: {
1360
- type: "tool-call",
1361
- toolCallId: call.toolCallId,
1362
- toolName: call.toolName,
1363
- input: call.input,
1364
- dynamic: true
1365
- },
1366
- toolContext: void 0
1367
- })
1368
- ));
1310
+ async end({ steps, usage }) {
1311
+ if (!started) await start();
1312
+ if (ended || steps.length === 0) return;
1313
+ ended = true;
1314
+ const finalStep = steps[steps.length - 1];
1315
+ const event = {
1316
+ callId: options.callId,
1317
+ stepNumber: finalStep.stepNumber,
1318
+ model: finalStep.model,
1319
+ toolsContext: finalStep.toolsContext,
1320
+ runtimeContext: finalStep.runtimeContext,
1321
+ content: steps.flatMap((step) => step.content),
1322
+ text: finalStep.text,
1323
+ reasoning: finalStep.reasoning,
1324
+ reasoningText: finalStep.reasoningText,
1325
+ files: steps.flatMap((step) => step.files),
1326
+ sources: steps.flatMap((step) => step.sources),
1327
+ toolCalls: steps.flatMap((step) => step.toolCalls),
1328
+ staticToolCalls: steps.flatMap((step) => step.staticToolCalls),
1329
+ dynamicToolCalls: steps.flatMap((step) => step.dynamicToolCalls),
1330
+ toolResults: steps.flatMap((step) => step.toolResults),
1331
+ staticToolResults: steps.flatMap((step) => step.staticToolResults),
1332
+ dynamicToolResults: steps.flatMap((step) => step.dynamicToolResults),
1333
+ finishReason: finalStep.finishReason,
1334
+ rawFinishReason: finalStep.rawFinishReason,
1335
+ usage,
1336
+ totalUsage: usage,
1337
+ warnings: steps.flatMap((step) => {
1338
+ var _a5;
1339
+ return (_a5 = step.warnings) != null ? _a5 : [];
1340
+ }),
1341
+ request: finalStep.request,
1342
+ response: finalStep.response,
1343
+ providerMetadata: finalStep.providerMetadata,
1344
+ responseMessages: steps.flatMap((step) => step.response.messages),
1345
+ steps,
1346
+ finalStep
1347
+ };
1348
+ await notify(
1349
+ event,
1350
+ options.callbacks.onEnd,
1351
+ telemetry.onEnd
1352
+ );
1369
1353
  },
1370
1354
  async executeTool({ toolCallId, execute }) {
1371
- if (dispatcher.executeTool == null) return await execute();
1372
- return await dispatcher.executeTool({ callId, toolCallId, execute });
1373
- },
1374
- async toolEnd(toolCallId, output) {
1375
- var _a5;
1376
- const call = openTools.get(toolCallId);
1377
- const normalizedOutput = output.ok ? { type: "tool-result", output: output.output } : { type: "error", error: output.error };
1378
- if (call == null) return;
1379
- openTools.delete(toolCallId);
1380
- await ((_a5 = dispatcher.onToolExecutionEnd) == null ? void 0 : _a5.call(
1381
- dispatcher,
1382
- cast({
1383
- callId,
1384
- toolExecutionMs: 0,
1385
- messages: [],
1386
- toolCall: {
1387
- type: "tool-call",
1388
- toolCallId: call.toolCallId,
1389
- toolName: call.toolName,
1390
- input: call.input,
1391
- dynamic: true
1392
- },
1393
- toolContext: void 0,
1394
- toolOutput: normalizedOutput
1395
- })
1396
- ));
1397
- },
1398
- async end(info) {
1399
- var _a5, _b4;
1400
- if (ended) return;
1401
- const finishReason = normalizeFinishReason(info.finishReason);
1402
- const usage = normalizeUsage(info.usage);
1403
- if (!started) await fireStart();
1404
- if (stepOpen) {
1405
- await closeOpenTools();
1406
- await inferenceEnd({
1407
- finishReason,
1408
- usage,
1409
- content: []
1410
- });
1411
- await ((_a5 = dispatcher.onStepEnd) == null ? void 0 : _a5.call(
1412
- dispatcher,
1413
- cast({
1414
- callId,
1415
- stepNumber,
1416
- finishReason,
1417
- usage,
1418
- providerMetadata: void 0,
1419
- content: [],
1420
- response: {
1421
- id: callId,
1422
- modelId,
1423
- timestamp: /* @__PURE__ */ new Date(0),
1424
- messages: []
1425
- }
1426
- })
1427
- ));
1428
- stepOpen = false;
1429
- }
1430
- ended = true;
1431
- await ((_b4 = dispatcher.onEnd) == null ? void 0 : _b4.call(
1432
- dispatcher,
1433
- cast({
1434
- callId,
1435
- operationId: "ai.harness",
1436
- finishReason,
1437
- usage,
1438
- totalUsage: usage,
1439
- content: [],
1440
- text: finalStepText,
1441
- finalStep: {
1442
- reasoning: finalStepReasoning,
1443
- providerMetadata: finalStepProviderMetadata
1444
- },
1445
- toolCalls: outputToolCalls,
1446
- files: [],
1447
- steps: new Array(stepNumber),
1448
- response: {
1449
- id: callId,
1450
- modelId,
1451
- timestamp: /* @__PURE__ */ new Date(0),
1452
- messages: []
1453
- },
1454
- runtimeContext
1455
- })
1456
- ));
1355
+ if (telemetry.executeTool == null) return await execute();
1356
+ return await telemetry.executeTool({
1357
+ callId: options.callId,
1358
+ toolCallId,
1359
+ execute
1360
+ });
1457
1361
  },
1458
- async error(err) {
1362
+ async error(error) {
1459
1363
  var _a5;
1460
1364
  if (ended) return;
1461
- if (!started) await fireStart();
1462
- await closeOpenTools();
1365
+ if (!started) await start();
1463
1366
  ended = true;
1464
- await ((_a5 = dispatcher.onError) == null ? void 0 : _a5.call(dispatcher, err));
1367
+ await ((_a5 = telemetry.onError) == null ? void 0 : _a5.call(telemetry, error));
1465
1368
  }
1466
1369
  };
1467
1370
  }
@@ -1576,27 +1479,29 @@ function unwrapToolResultOutput(toolResult) {
1576
1479
  }
1577
1480
  }
1578
1481
  function runPrompt(input) {
1579
- var _a4, _b4, _c, _d, _e, _f, _g;
1482
+ var _a4, _b4, _c, _d, _e, _f, _g, _h, _i;
1483
+ const callId = generateId2();
1484
+ const toolsContext = {};
1580
1485
  const result = new HarnessStreamTextResult({
1581
1486
  tools: input.tools,
1582
1487
  runtimeContext: input.runtimeContext,
1583
- // toolsContext is not configurable for harnesses; pass undefined cast.
1584
- toolsContext: void 0,
1488
+ toolsContext,
1585
1489
  harnessId: input.harness.harnessId,
1586
- sessionId: input.session.sessionId,
1490
+ callId,
1491
+ modelId: (_a4 = input.model) != null ? _a4 : "",
1587
1492
  output: input.output
1588
1493
  });
1589
- const pendingToolApprovals = (_a4 = input.pendingToolApprovals) != null ? _a4 : [];
1590
- const pendingToolResults = (_b4 = input.pendingToolResults) != null ? _b4 : [];
1591
- const onPendingToolApproval = (_c = input.onPendingToolApproval) != null ? _c : (() => {
1494
+ const pendingToolApprovals = (_b4 = input.pendingToolApprovals) != null ? _b4 : [];
1495
+ const pendingToolResults = (_c = input.pendingToolResults) != null ? _c : [];
1496
+ const onPendingToolApproval = (_d = input.onPendingToolApproval) != null ? _d : (() => {
1592
1497
  });
1593
- const onToolApprovalSettled = (_d = input.onToolApprovalSettled) != null ? _d : (() => {
1498
+ const onToolApprovalSettled = (_e = input.onToolApprovalSettled) != null ? _e : (() => {
1594
1499
  });
1595
- const onPendingToolResult = (_e = input.onPendingToolResult) != null ? _e : (() => {
1500
+ const onPendingToolResult = (_f = input.onPendingToolResult) != null ? _f : (() => {
1596
1501
  });
1597
- const onToolResultSettled = (_f = input.onToolResultSettled) != null ? _f : (() => {
1502
+ const onToolResultSettled = (_g = input.onToolResultSettled) != null ? _g : (() => {
1598
1503
  });
1599
- const activeTools = (_g = input.activeTools) != null ? _g : input.tools;
1504
+ const activeTools = (_h = input.activeTools) != null ? _h : input.tools;
1600
1505
  const activeToolNames = Object.keys(input.tools).filter(
1601
1506
  (toolName) => Object.prototype.hasOwnProperty.call(activeTools, toolName) || Object.prototype.hasOwnProperty.call(
1602
1507
  input.harness.builtinTools,
@@ -1606,16 +1511,20 @@ function runPrompt(input) {
1606
1511
  toolFiltering: input.builtinToolFiltering
1607
1512
  })
1608
1513
  );
1609
- const telemetry = createTurnTelemetry({
1514
+ const lifecycle = createTurnLifecycle({
1515
+ callId,
1610
1516
  telemetry: input.telemetry,
1517
+ callbacks: (_i = input.callbacks) != null ? _i : {},
1611
1518
  harnessId: input.harness.harnessId,
1612
1519
  modelId: input.model,
1613
1520
  instructions: input.instructions,
1614
1521
  tools: input.tools,
1615
1522
  activeToolNames,
1616
1523
  toolSpecs: input.toolSpecs,
1617
- promptText: input.prompt != null ? promptToText(input.prompt) : "",
1618
- runtimeContext: input.runtimeContext
1524
+ messages: input.prompt == null ? [] : [{ role: "user", content: promptToText(input.prompt) }],
1525
+ runtimeContext: input.runtimeContext,
1526
+ toolsContext,
1527
+ output: input.output
1619
1528
  });
1620
1529
  const settleFailure = (err) => {
1621
1530
  var _a5, _b5, _c2;
@@ -1632,7 +1541,7 @@ function runPrompt(input) {
1632
1541
  result.fail(err);
1633
1542
  };
1634
1543
  const done = (async () => {
1635
- var _a5, _b5, _c2, _d2, _e2, _f2, _g2, _h, _i, _j, _k, _l, _m, _n;
1544
+ var _a5, _b5, _c2, _d2, _e2, _f2, _g2, _h2, _i2, _j, _k, _l, _m, _n, _o;
1636
1545
  let bridge;
1637
1546
  try {
1638
1547
  bridge = await toHarnessStream({
@@ -1667,7 +1576,7 @@ function runPrompt(input) {
1667
1576
  }
1668
1577
  });
1669
1578
  } catch (err) {
1670
- await telemetry.error(err);
1579
+ await lifecycle.error(err);
1671
1580
  logBridgeError({
1672
1581
  harnessId: input.harness.harnessId,
1673
1582
  sessionId: input.session.sessionId,
@@ -1746,20 +1655,47 @@ function runPrompt(input) {
1746
1655
  let stepText = "";
1747
1656
  let stepReasoning = "";
1748
1657
  let stepToolCalls = [];
1658
+ let stepProviderToolResults = [];
1659
+ let stepApprovalRequests = [];
1660
+ let bufferedToolOutcomes = [];
1661
+ const toolExecutions = /* @__PURE__ */ new Map();
1662
+ const publishToolExecutions = async () => {
1663
+ var _a6;
1664
+ for (const execution of toolExecutions.values()) {
1665
+ if (execution.toolOutput == null) continue;
1666
+ await lifecycle.toolExecutionStart({
1667
+ toolCall: execution.toolCall
1668
+ });
1669
+ await lifecycle.toolExecutionEnd({
1670
+ toolCall: execution.toolCall,
1671
+ toolOutput: execution.toolOutput,
1672
+ toolExecutionMs: (_a6 = execution.toolExecutionMs) != null ? _a6 : 0
1673
+ });
1674
+ }
1675
+ for (const publish of bufferedToolOutcomes) publish();
1676
+ toolExecutions.clear();
1677
+ bufferedToolOutcomes = [];
1678
+ };
1749
1679
  let expectedStepToolCallCount;
1750
1680
  let observedStepToolCallCount = 0;
1751
1681
  let pauseAfterStepToolCalls = false;
1752
- const buildStepContent = () => {
1682
+ const buildModelCallContent = () => {
1753
1683
  const parts = [];
1754
1684
  if (stepText) parts.push({ type: "text", text: stepText });
1755
1685
  if (stepReasoning) parts.push({ type: "reasoning", text: stepReasoning });
1756
1686
  parts.push(...stepToolCalls);
1687
+ parts.push(...stepApprovalRequests);
1688
+ parts.push(...stepProviderToolResults);
1757
1689
  return parts;
1758
1690
  };
1759
1691
  const resetStepContent = () => {
1760
1692
  stepText = "";
1761
1693
  stepReasoning = "";
1762
1694
  stepToolCalls = [];
1695
+ stepProviderToolResults = [];
1696
+ stepApprovalRequests = [];
1697
+ bufferedToolOutcomes = [];
1698
+ toolExecutions.clear();
1763
1699
  expectedStepToolCallCount = void 0;
1764
1700
  observedStepToolCallCount = 0;
1765
1701
  pauseAfterStepToolCalls = false;
@@ -1782,13 +1718,13 @@ function runPrompt(input) {
1782
1718
  raw: void 0
1783
1719
  };
1784
1720
  const completeStep = async (input2) => {
1785
- await telemetry.stepFinish({
1786
- finishReason: input2.finishReason,
1787
- usage: input2.usage,
1721
+ await lifecycle.languageModelCallEnd({
1722
+ finishReason: input2.finishReason.unified,
1723
+ usage: asLanguageModelUsage2(input2.usage),
1788
1724
  providerMetadata: input2.providerMetadata,
1789
- content: buildStepContent()
1725
+ content: buildModelCallContent()
1790
1726
  });
1791
- resetStepContent();
1727
+ await publishToolExecutions();
1792
1728
  const step = result.finishStep({
1793
1729
  finishReason: input2.finishReason,
1794
1730
  usage: input2.usage,
@@ -1796,6 +1732,8 @@ function runPrompt(input) {
1796
1732
  warnings: []
1797
1733
  });
1798
1734
  completedSteps.push(step);
1735
+ await lifecycle.stepEnd(step);
1736
+ resetStepContent();
1799
1737
  return step;
1800
1738
  };
1801
1739
  const finishForHostInputPause = async (options) => {
@@ -1806,20 +1744,24 @@ function runPrompt(input) {
1806
1744
  usage: zeroUsage,
1807
1745
  providerMetadata: void 0
1808
1746
  });
1747
+ } else {
1748
+ await publishToolExecutions();
1809
1749
  }
1810
- await telemetry.end({
1811
- finishReason: toolCallsFinishReason,
1812
- usage: zeroUsage
1750
+ await lifecycle.end({
1751
+ steps: completedSteps,
1752
+ usage: asLanguageModelUsage2(zeroUsage)
1813
1753
  });
1814
1754
  await result.finish();
1815
1755
  };
1816
1756
  const enqueueApprovalRequest = (approval) => {
1817
- result.enqueue({
1757
+ const part = {
1818
1758
  type: "tool-approval-request",
1819
1759
  approvalId: approval.approvalId,
1820
1760
  toolCall: approval.toolCall,
1821
1761
  ...approval.isAutomatic !== void 0 ? { isAutomatic: approval.isAutomatic } : {}
1822
- });
1762
+ };
1763
+ result.enqueue(part);
1764
+ stepApprovalRequests.push(part);
1823
1765
  };
1824
1766
  const enqueueAutomaticApprovalResponse = (input2) => {
1825
1767
  result.enqueue({
@@ -1944,16 +1886,15 @@ function runPrompt(input) {
1944
1886
  });
1945
1887
  return "continued";
1946
1888
  }
1947
- await telemetry.start(input.model);
1948
- await telemetry.toolStart({
1949
- toolCallId: rawToolCall.toolCallId,
1950
- toolName: rawToolCall.toolName,
1951
- input: rawToolCall.input
1889
+ await lifecycle.start(input.model);
1890
+ toolExecutions.set(rawToolCall.toolCallId, {
1891
+ toolCall
1952
1892
  });
1893
+ const executionStartedAt = Date.now();
1953
1894
  const execution = await maybeExecuteHostTool({
1954
1895
  event: rawToolCall,
1955
1896
  tools: activeTools,
1956
- wrappedExecuteTool: telemetry.executeTool,
1897
+ wrappedExecuteTool: lifecycle.executeTool,
1957
1898
  sandboxSession: input.sandboxSession,
1958
1899
  abortSignal: input.abortSignal,
1959
1900
  control,
@@ -1967,13 +1908,15 @@ function runPrompt(input) {
1967
1908
  },
1968
1909
  input.sessionWorkDir
1969
1910
  );
1970
- result.enqueue({
1971
- type: "tool-result",
1972
- toolCallId: rawToolCall.toolCallId,
1973
- toolName: rawToolCall.toolName,
1974
- input: void 0,
1975
- output: stripped.result,
1976
- preliminary: true
1911
+ bufferedToolOutcomes.push(() => {
1912
+ result.enqueue({
1913
+ type: "tool-result",
1914
+ toolCallId: rawToolCall.toolCallId,
1915
+ toolName: rawToolCall.toolName,
1916
+ input: void 0,
1917
+ output: stripped.result,
1918
+ preliminary: true
1919
+ });
1977
1920
  });
1978
1921
  }
1979
1922
  });
@@ -1982,11 +1925,19 @@ function runPrompt(input) {
1982
1925
  await finishForHostInputPause({ completeCurrentStep: false });
1983
1926
  return "awaiting-tool-result";
1984
1927
  }
1985
- enqueueHostToolOutcome({
1928
+ const toolExecution = toolExecutions.get(rawToolCall.toolCallId);
1929
+ toolExecution.toolOutput = toToolOutput({
1986
1930
  toolCall,
1987
1931
  outcome: execution.outcome
1988
1932
  });
1989
- await telemetry.toolEnd(rawToolCall.toolCallId, execution.outcome);
1933
+ toolExecution.toolExecutionMs = Date.now() - executionStartedAt;
1934
+ bufferedToolOutcomes.push(() => {
1935
+ enqueueHostToolOutcome({
1936
+ toolCall,
1937
+ outcome: execution.outcome
1938
+ });
1939
+ });
1940
+ await publishToolExecutions();
1990
1941
  return "continued";
1991
1942
  };
1992
1943
  try {
@@ -2033,9 +1984,12 @@ function runPrompt(input) {
2033
1984
  )
2034
1985
  )).some(Boolean)) {
2035
1986
  await ((_d2 = input.onStopConditionMet) == null ? void 0 : _d2.call(input));
2036
- const { finishReason, usage } = pendingStopBoundary;
1987
+ const { usage } = pendingStopBoundary;
2037
1988
  releasePendingStopBoundary();
2038
- await telemetry.end({ finishReason, usage });
1989
+ await lifecycle.end({
1990
+ steps: completedSteps,
1991
+ usage: asLanguageModelUsage2(usage)
1992
+ });
2039
1993
  await result.finish();
2040
1994
  return;
2041
1995
  } else {
@@ -2043,10 +1997,12 @@ function runPrompt(input) {
2043
1997
  }
2044
1998
  }
2045
1999
  if (value.type === "stream-start") {
2046
- await telemetry.start((_e2 = value.modelId) != null ? _e2 : input.model);
2000
+ const modelId = (_e2 = value.modelId) != null ? _e2 : input.model;
2001
+ if (modelId != null) result.setModelId(modelId);
2002
+ await lifecycle.start(modelId);
2047
2003
  }
2048
2004
  if (value.type !== "stream-start" && value.type !== "finish-step" && value.type !== "finish" && value.type !== "error") {
2049
- await telemetry.ensureStepOpen();
2005
+ await lifecycle.ensureStepOpen();
2050
2006
  }
2051
2007
  if (value.type === "tool-input-start" || value.type === "tool-input-delta" || value.type === "tool-input-end") {
2052
2008
  if (settledHostToolCallIds.has(value.id) || settledBuiltinApprovalToolCallIds.has(value.id)) {
@@ -2070,6 +2026,7 @@ function runPrompt(input) {
2070
2026
  }
2071
2027
  if (displayValue.type === "finish-step" && closingResumedStep) {
2072
2028
  closingResumedStep = false;
2029
+ await publishToolExecutions();
2073
2030
  resetStepContent();
2074
2031
  result.discardCurrentStepContent();
2075
2032
  continue;
@@ -2106,7 +2063,7 @@ function runPrompt(input) {
2106
2063
  }
2107
2064
  if (value.type === "error" && displayValue.type === "error") {
2108
2065
  await waitForOutstandingHostToolExecutions();
2109
- await telemetry.error(value.error);
2066
+ await lifecycle.error(value.error);
2110
2067
  if (!((_g2 = input.abortSignal) == null ? void 0 : _g2.aborted)) {
2111
2068
  logBridgeError({
2112
2069
  harnessId: input.harness.harnessId,
@@ -2118,11 +2075,16 @@ function runPrompt(input) {
2118
2075
  settleFailure(displayValue.error);
2119
2076
  return;
2120
2077
  }
2121
- for (const part of translateStreamPart(
2078
+ const translatedParts = translateStreamPart(
2122
2079
  displayValue,
2123
2080
  translateOptions
2124
- )) {
2125
- result.enqueue(part);
2081
+ );
2082
+ if (value.type === "tool-result") {
2083
+ bufferedToolOutcomes.push(() => {
2084
+ for (const part of translatedParts) result.enqueue(part);
2085
+ });
2086
+ } else {
2087
+ for (const part of translatedParts) result.enqueue(part);
2126
2088
  }
2127
2089
  if (displayValue.type === "tool-call") {
2128
2090
  const parsed = await validateToolCall({
@@ -2142,23 +2104,32 @@ function runPrompt(input) {
2142
2104
  if (value.type === "tool-call") {
2143
2105
  observedStepToolCallCount += 1;
2144
2106
  expectedStepToolCallCount != null ? expectedStepToolCallCount : expectedStepToolCallCount = value.stepToolCallCount;
2145
- stepToolCalls.push({
2146
- type: "tool-call",
2147
- toolCallId: value.toolCallId,
2148
- toolName: value.toolName,
2149
- input: value.input
2150
- });
2151
- await telemetry.toolStart({
2152
- toolCallId: value.toolCallId,
2153
- toolName: value.toolName,
2154
- input: value.input
2155
- });
2107
+ const toolCall = toolCallsByToolCallId.get(value.toolCallId);
2108
+ if (toolCall != null) {
2109
+ stepToolCalls.push(toolCall);
2110
+ toolExecutions.set(value.toolCallId, {
2111
+ toolCall
2112
+ });
2113
+ }
2156
2114
  }
2157
2115
  if (value.type === "tool-result") {
2158
- await telemetry.toolEnd(
2159
- value.toolCallId,
2160
- value.isError ? { ok: false, error: value.result } : { ok: true, output: value.result }
2161
- );
2116
+ const execution = toolExecutions.get(value.toolCallId);
2117
+ if (execution != null && execution.toolOutput == null) {
2118
+ execution.toolOutput = value.isError ? {
2119
+ ...execution.toolCall,
2120
+ type: "tool-error",
2121
+ error: value.result
2122
+ } : {
2123
+ ...execution.toolCall,
2124
+ type: "tool-result",
2125
+ output: value.result
2126
+ };
2127
+ }
2128
+ if (((_h2 = rawToolCallsByToolCallId.get(value.toolCallId)) == null ? void 0 : _h2.providerExecuted) === true && (execution == null ? void 0 : execution.toolOutput) != null) {
2129
+ stepProviderToolResults.push(
2130
+ execution.toolOutput
2131
+ );
2132
+ }
2162
2133
  }
2163
2134
  if (value.type === "tool-approval-request") {
2164
2135
  const toolCall = toolCallsByToolCallId.get(value.toolCallId);
@@ -2168,13 +2139,13 @@ function runPrompt(input) {
2168
2139
  );
2169
2140
  }
2170
2141
  const rawToolCall = rawToolCallsByToolCallId.get(value.toolCallId);
2171
- const pendingApproval = (_j = pendingApprovalsByApprovalId.get(value.approvalId)) != null ? _j : {
2142
+ const pendingApproval = (_k = pendingApprovalsByApprovalId.get(value.approvalId)) != null ? _k : {
2172
2143
  approvalId: value.approvalId,
2173
2144
  toolCallId: value.toolCallId,
2174
2145
  toolName: toolCall.toolName,
2175
- input: (_h = rawToolCall == null ? void 0 : rawToolCall.input) != null ? _h : JSON.stringify(toolCall.input),
2146
+ input: (_i2 = rawToolCall == null ? void 0 : rawToolCall.input) != null ? _i2 : JSON.stringify(toolCall.input),
2176
2147
  kind: "builtin",
2177
- providerExecuted: (_i = rawToolCall == null ? void 0 : rawToolCall.providerExecuted) != null ? _i : true,
2148
+ providerExecuted: (_j = rawToolCall == null ? void 0 : rawToolCall.providerExecuted) != null ? _j : true,
2178
2149
  ...(rawToolCall == null ? void 0 : rawToolCall.nativeName) !== void 0 ? { nativeName: rawToolCall.nativeName } : {}
2179
2150
  };
2180
2151
  pendingApprovalsByApprovalId.set(
@@ -2223,9 +2194,9 @@ function runPrompt(input) {
2223
2194
  if (value.type === "finish") {
2224
2195
  await waitForOutstandingHostToolExecutions();
2225
2196
  finalFinish = value;
2226
- await telemetry.end({
2227
- finishReason: value.finishReason,
2228
- usage: value.totalUsage
2197
+ await lifecycle.end({
2198
+ steps: completedSteps,
2199
+ usage: asLanguageModelUsage2(value.totalUsage)
2229
2200
  });
2230
2201
  }
2231
2202
  if (value.type === "tool-call" && !value.providerExecuted) {
@@ -2251,7 +2222,13 @@ function runPrompt(input) {
2251
2222
  toolCallId: toolCall.toolCallId,
2252
2223
  output
2253
2224
  });
2254
- await telemetry.toolEnd(toolCall.toolCallId, { ok: true, output });
2225
+ const execution = toolExecutions.get(toolCall.toolCallId);
2226
+ if (execution != null) {
2227
+ execution.toolOutput = toToolOutput({
2228
+ toolCall: parsedToolCall,
2229
+ outcome: { ok: true, output }
2230
+ });
2231
+ }
2255
2232
  continue;
2256
2233
  }
2257
2234
  if (isClientExecutedBuiltin) {
@@ -2268,7 +2245,7 @@ function runPrompt(input) {
2268
2245
  toolApproval: input.toolApproval
2269
2246
  });
2270
2247
  if (customToolApprovalDecision.type === "deny") {
2271
- const approvalId = generateId4();
2248
+ const approvalId = generateId2();
2272
2249
  enqueueApprovalRequest({
2273
2250
  approvalId,
2274
2251
  toolCall: parsedToolCall,
@@ -2289,11 +2266,17 @@ function runPrompt(input) {
2289
2266
  toolCallId: toolCall.toolCallId,
2290
2267
  output
2291
2268
  });
2292
- await telemetry.toolEnd(toolCall.toolCallId, { ok: true, output });
2269
+ const execution = toolExecutions.get(toolCall.toolCallId);
2270
+ if (execution != null) {
2271
+ execution.toolOutput = toToolOutput({
2272
+ toolCall: parsedToolCall,
2273
+ outcome: { ok: true, output }
2274
+ });
2275
+ }
2293
2276
  continue;
2294
2277
  }
2295
- const pendingApproval = (_k = pendingApprovalsByToolCallId.get(toolCall.toolCallId)) != null ? _k : customToolApprovalDecision.type === "request" ? {
2296
- approvalId: generateId4(),
2278
+ const pendingApproval = (_l = pendingApprovalsByToolCallId.get(toolCall.toolCallId)) != null ? _l : customToolApprovalDecision.type === "request" ? {
2279
+ approvalId: generateId2(),
2297
2280
  toolCallId: toolCall.toolCallId,
2298
2281
  toolName: toolCall.toolName,
2299
2282
  input: toolCall.input,
@@ -2353,10 +2336,11 @@ function runPrompt(input) {
2353
2336
  }
2354
2337
  startHostToolExecution(
2355
2338
  (async () => {
2339
+ const executionStartedAt = Date.now();
2356
2340
  const execution = await maybeExecuteHostTool({
2357
2341
  event: toolCall,
2358
2342
  tools: activeTools,
2359
- wrappedExecuteTool: telemetry.executeTool,
2343
+ wrappedExecuteTool: lifecycle.executeTool,
2360
2344
  sandboxSession: input.sandboxSession,
2361
2345
  abortSignal: input.abortSignal,
2362
2346
  control,
@@ -2370,13 +2354,15 @@ function runPrompt(input) {
2370
2354
  },
2371
2355
  input.sessionWorkDir
2372
2356
  );
2373
- result.enqueue({
2374
- type: "tool-result",
2375
- toolCallId: toolCall.toolCallId,
2376
- toolName: toolCall.toolName,
2377
- input: void 0,
2378
- output: stripped.result,
2379
- preliminary: true
2357
+ bufferedToolOutcomes.push(() => {
2358
+ result.enqueue({
2359
+ type: "tool-result",
2360
+ toolCallId: toolCall.toolCallId,
2361
+ toolName: toolCall.toolName,
2362
+ input: void 0,
2363
+ output: stripped.result,
2364
+ preliminary: true
2365
+ });
2380
2366
  });
2381
2367
  }
2382
2368
  });
@@ -2385,21 +2371,28 @@ function runPrompt(input) {
2385
2371
  `Harness '${input.harness.harnessId}' could not execute host tool '${toolCall.toolName}'.`
2386
2372
  );
2387
2373
  }
2388
- await telemetry.toolEnd(toolCall.toolCallId, execution.outcome);
2374
+ const toolExecution = toolExecutions.get(toolCall.toolCallId);
2375
+ if (toolExecution != null) {
2376
+ toolExecution.toolOutput = toToolOutput({
2377
+ toolCall: parsedToolCall,
2378
+ outcome: execution.outcome
2379
+ });
2380
+ toolExecution.toolExecutionMs = Date.now() - executionStartedAt;
2381
+ }
2389
2382
  })()
2390
2383
  );
2391
2384
  }
2392
2385
  }
2393
2386
  await waitForOutstandingHostToolExecutions();
2394
- const isTurnSuspending = ((_l = input.isTurnSuspending) == null ? void 0 : _l.call(input)) === true;
2387
+ const isTurnSuspending = ((_m = input.isTurnSuspending) == null ? void 0 : _m.call(input)) === true;
2395
2388
  if (isTurnSuspending) {
2396
2389
  if (finalFinish == null) {
2397
2390
  result.discardCurrentStepContent();
2398
2391
  }
2399
2392
  } else if (finalFinish != null) {
2400
- (_m = input.onTurnFinished) == null ? void 0 : _m.call(input);
2393
+ (_n = input.onTurnFinished) == null ? void 0 : _n.call(input);
2401
2394
  } else {
2402
- (_n = input.onTurnFailed) == null ? void 0 : _n.call(input);
2395
+ (_o = input.onTurnFailed) == null ? void 0 : _o.call(input);
2403
2396
  }
2404
2397
  await result.finish(
2405
2398
  finalFinish ? {
@@ -2413,7 +2406,7 @@ function runPrompt(input) {
2413
2406
  await waitForOutstandingHostToolExecutions();
2414
2407
  } catch (e) {
2415
2408
  }
2416
- await telemetry.error(err);
2409
+ await lifecycle.error(err);
2417
2410
  logBridgeError({
2418
2411
  harnessId: input.harness.harnessId,
2419
2412
  sessionId: input.session.sessionId,
@@ -2430,6 +2423,17 @@ function runPrompt(input) {
2430
2423
  });
2431
2424
  return { result, done };
2432
2425
  }
2426
+ function toToolOutput(input) {
2427
+ return input.outcome.ok ? {
2428
+ ...input.toolCall,
2429
+ type: "tool-result",
2430
+ output: input.outcome.output
2431
+ } : {
2432
+ ...input.toolCall,
2433
+ type: "tool-error",
2434
+ error: input.outcome.error
2435
+ };
2436
+ }
2433
2437
  function asToolCallTextStreamPart(input) {
2434
2438
  if (input.part.type !== "tool-call") {
2435
2439
  throw new Error(
@@ -2611,6 +2615,7 @@ var HarnessAgentSession = class {
2611
2615
  responseFormat: options.responseFormat,
2612
2616
  output: options.output,
2613
2617
  telemetry: options.telemetry,
2618
+ callbacks: options.callbacks,
2614
2619
  stopConditions: options.stopConditions,
2615
2620
  toolApproval: this.toolApproval,
2616
2621
  pendingToolApprovals: this.getPendingToolApprovals(),
@@ -2683,6 +2688,7 @@ var HarnessAgentSession = class {
2683
2688
  responseFormat: options.responseFormat,
2684
2689
  output: options.output,
2685
2690
  telemetry: options.telemetry,
2691
+ callbacks: options.callbacks,
2686
2692
  stopConditions: options.stopConditions,
2687
2693
  toolApproval: this.toolApproval,
2688
2694
  pendingToolApprovals: this.getPendingToolApprovals(),
@@ -3578,14 +3584,28 @@ function filterToolSet(input) {
3578
3584
  var HarnessAgent = class {
3579
3585
  constructor(settings) {
3580
3586
  this.version = "agent-v1";
3581
- var _a4;
3587
+ var _a4, _b4;
3582
3588
  const sandboxConfig = resolveSandboxConfig(settings);
3583
3589
  validateSandboxBootstrapSettings(sandboxConfig);
3584
3590
  this.settings = settings;
3585
3591
  this.stopConditions = settings.stopWhen == null ? [] : asArray2(settings.stopWhen);
3586
3592
  this.sandboxConfig = sandboxConfig;
3593
+ const forbiddenHeaders = /* @__PURE__ */ new Set([
3594
+ "authorization",
3595
+ "x-api-key",
3596
+ "user-agent",
3597
+ "x-client-app"
3598
+ ]);
3599
+ const forbiddenHeader = Object.keys((_a4 = settings.headers) != null ? _a4 : {}).map((name4) => name4.toLowerCase()).find((name4) => forbiddenHeaders.has(name4));
3600
+ if (forbiddenHeader != null) {
3601
+ throw new Error(
3602
+ `HarnessAgent: \`headers\` must not include the managed header \`${forbiddenHeader}\`.`
3603
+ );
3604
+ }
3605
+ const headers = normalizeHeaders(settings.headers);
3606
+ this.headers = Object.keys(headers).length === 0 ? void 0 : headers;
3587
3607
  this.id = settings.id;
3588
- const userTools = (_a4 = settings.tools) != null ? _a4 : {};
3608
+ const userTools = (_b4 = settings.tools) != null ? _b4 : {};
3589
3609
  assertNoReservedQuestionTool({
3590
3610
  harness: settings.harness,
3591
3611
  userTools
@@ -3628,7 +3648,7 @@ var HarnessAgent = class {
3628
3648
  */
3629
3649
  async createSession(options) {
3630
3650
  var _a4, _b4, _c;
3631
- const sessionId = (_a4 = options == null ? void 0 : options.sessionId) != null ? _a4 : generateId5();
3651
+ const sessionId = (_a4 = options == null ? void 0 : options.sessionId) != null ? _a4 : generateId3();
3632
3652
  const resumeFrom = options == null ? void 0 : options.resumeFrom;
3633
3653
  const continueFrom = options == null ? void 0 : options.continueFrom;
3634
3654
  const providedSandboxSession = options == null ? void 0 : options.sandboxSession;
@@ -3796,6 +3816,7 @@ var HarnessAgent = class {
3796
3816
  try {
3797
3817
  const baseStartOptions = {
3798
3818
  sessionId,
3819
+ ...this.headers == null ? {} : { headers: this.headers },
3799
3820
  resumeFrom: validatedResumeFrom,
3800
3821
  continueFrom: effectiveContinueFrom,
3801
3822
  permissionMode: this.permissionMode,
@@ -3915,7 +3936,8 @@ var HarnessAgent = class {
3915
3936
  turnSettings: turnInput,
3916
3937
  runtimeContext: input.runtimeContext,
3917
3938
  abortSignal: input.options.abortSignal,
3918
- responseFormat
3939
+ responseFormat,
3940
+ callbacks: this._resolveLifecycleCallbacks(input.options)
3919
3941
  }),
3920
3942
  prompt: turnInput.prompt
3921
3943
  });
@@ -3928,7 +3950,8 @@ var HarnessAgent = class {
3928
3950
  turnSettings: turnInput,
3929
3951
  runtimeContext: input.runtimeContext,
3930
3952
  abortSignal: input.abortSignal,
3931
- responseFormat
3953
+ responseFormat,
3954
+ callbacks: this._resolveLifecycleCallbacks()
3932
3955
  }),
3933
3956
  toolApprovalContinuations: turnInput.toolApprovalContinuations,
3934
3957
  toolResultContinuations: turnInput.toolResultContinuations
@@ -3948,9 +3971,38 @@ var HarnessAgent = class {
3948
3971
  responseFormat: input.responseFormat,
3949
3972
  output: this.settings.output,
3950
3973
  telemetry: this.settings.telemetry,
3974
+ callbacks: input.callbacks,
3951
3975
  stopConditions: this.stopConditions
3952
3976
  };
3953
3977
  }
3978
+ _resolveLifecycleCallbacks(call) {
3979
+ var _a4, _b4, _c, _d, _e, _f;
3980
+ return {
3981
+ onStart: mergeCallbacks(
3982
+ this.settings.onStart,
3983
+ (_a4 = call == null ? void 0 : call.onStart) != null ? _a4 : call == null ? void 0 : call.experimental_onStart
3984
+ ),
3985
+ onStepStart: mergeCallbacks(
3986
+ this.settings.onStepStart,
3987
+ (_b4 = call == null ? void 0 : call.onStepStart) != null ? _b4 : call == null ? void 0 : call.experimental_onStepStart
3988
+ ),
3989
+ onLanguageModelCallStart: this.settings.onLanguageModelCallStart,
3990
+ onLanguageModelCallEnd: this.settings.onLanguageModelCallEnd,
3991
+ onToolExecutionStart: mergeCallbacks(
3992
+ this.settings.onToolExecutionStart,
3993
+ (_c = call == null ? void 0 : call.onToolExecutionStart) != null ? _c : call == null ? void 0 : call.experimental_onToolCallStart
3994
+ ),
3995
+ onToolExecutionEnd: mergeCallbacks(
3996
+ this.settings.onToolExecutionEnd,
3997
+ (_d = call == null ? void 0 : call.onToolExecutionEnd) != null ? _d : call == null ? void 0 : call.experimental_onToolCallFinish
3998
+ ),
3999
+ onStepEnd: mergeCallbacks(
4000
+ this.settings.onStepEnd,
4001
+ (_e = call == null ? void 0 : call.onStepEnd) != null ? _e : call == null ? void 0 : call.onStepFinish
4002
+ ),
4003
+ onEnd: mergeCallbacks(this.settings.onEnd, (_f = call == null ? void 0 : call.onEnd) != null ? _f : call == null ? void 0 : call.onFinish)
4004
+ };
4005
+ }
3954
4006
  _resolveContinueTurnInput(options) {
3955
4007
  if (typeof options.prompt === "string") {
3956
4008
  return void 0;