@theokit/agents 10.1.0 → 11.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/CHANGELOG.md +356 -0
  2. package/LICENSE +2 -2
  3. package/README.md +6 -5
  4. package/dist/{agent-compiler-CIPQkehU.d.ts → agent-compiler-tetgj6zR.d.ts} +3 -172
  5. package/dist/{agent-handle-Dgi4ZGbg.d.ts → agent-handle-rEWdERuv.d.ts} +113 -2
  6. package/dist/auth.js +1 -1
  7. package/dist/{bridge-entry-emr2PSXC.d.ts → bridge-entry-DPm1C5li.d.ts} +83 -200
  8. package/dist/bridge.d.ts +8 -7
  9. package/dist/bridge.js +4 -3
  10. package/dist/{chunk-CKRM5Q2K.js → chunk-2I6DQUJP.js} +249 -47
  11. package/dist/chunk-2I6DQUJP.js.map +1 -0
  12. package/dist/{chunk-M6HMASZC.js → chunk-7PNUTDBQ.js} +109 -14
  13. package/dist/chunk-7PNUTDBQ.js.map +1 -0
  14. package/dist/{chunk-QXGSF6WX.js → chunk-D2EFYZBV.js} +1 -1
  15. package/dist/{chunk-QXGSF6WX.js.map → chunk-D2EFYZBV.js.map} +1 -1
  16. package/dist/{chunk-4VHCH6IZ.js → chunk-LLIERPF3.js} +14 -1
  17. package/dist/chunk-LLIERPF3.js.map +1 -0
  18. package/dist/chunk-OXNDJSAJ.js +59 -0
  19. package/dist/chunk-OXNDJSAJ.js.map +1 -0
  20. package/dist/{chunk-QJN2LLPF.js → chunk-ZQOKIZCI.js} +284 -164
  21. package/dist/chunk-ZQOKIZCI.js.map +1 -0
  22. package/dist/client-react.d.ts +24 -2
  23. package/dist/client-react.js +2 -1
  24. package/dist/client-react.js.map +1 -1
  25. package/dist/client.d.ts +99 -5
  26. package/dist/client.js +3 -1
  27. package/dist/config.d.ts +2 -2
  28. package/dist/config.js +2 -2
  29. package/dist/{define-agent-BO5QSjV8.d.ts → define-agent-BnH1MBxs.d.ts} +16 -1
  30. package/dist/{delegation-scoring-CDvtrYKd.d.ts → delegation-scoring-CQtF2Zaf.d.ts} +345 -11
  31. package/dist/hooks.js +2 -2
  32. package/dist/hooks.js.map +1 -1
  33. package/dist/index.d.ts +54 -9
  34. package/dist/index.js +17 -3
  35. package/dist/index.js.map +1 -1
  36. package/dist/mcp-health.d.ts +66 -1
  37. package/dist/mcp-health.js +32 -1
  38. package/dist/mcp-health.js.map +1 -1
  39. package/dist/pty.js.map +1 -1
  40. package/dist/session.d.ts +58 -1
  41. package/dist/session.js +34 -1
  42. package/dist/session.js.map +1 -1
  43. package/dist/testing.d.ts +3 -2
  44. package/dist/testing.js +1 -1
  45. package/dist/tools.d.ts +4 -2
  46. package/dist/tools.js +5 -4
  47. package/dist/tools.js.map +1 -1
  48. package/dist/types-C16Wuh9E.d.ts +173 -0
  49. package/dist/usage.d.ts +94 -1
  50. package/dist/usage.js +5 -1
  51. package/dist/usage.js.map +1 -1
  52. package/package.json +23 -10
  53. package/dist/chunk-4VHCH6IZ.js.map +0 -1
  54. package/dist/chunk-CKRM5Q2K.js.map +0 -1
  55. package/dist/chunk-M6HMASZC.js.map +0 -1
  56. package/dist/chunk-QJN2LLPF.js.map +0 -1
@@ -4,7 +4,10 @@ import {
4
4
  } from "./chunk-RKWCXVYG.js";
5
5
  import {
6
6
  compileAgentDefinition
7
- } from "./chunk-4VHCH6IZ.js";
7
+ } from "./chunk-LLIERPF3.js";
8
+ import {
9
+ createRunUsageMeter
10
+ } from "./chunk-OXNDJSAJ.js";
8
11
  import {
9
12
  __name
10
13
  } from "./chunk-Z4QWC7IK.js";
@@ -382,8 +385,8 @@ function createHitlPlugin(wiring) {
382
385
  approved: raw
383
386
  } : raw;
384
387
  if (decision.approved) return void 0;
385
- let message = `Tool '${c.name}' denied by human approver`;
386
- if (decision.reason) message += `: ${decision.reason}`;
388
+ let message = decision.settledBy === "timeout" ? `Tool '${c.name}' was not approved: ${decision.reason ?? "the approval window expired with no decision"}. Decide within the window, or raise 'timeout' on the tool's approval options.` : `Tool '${c.name}' denied by human approver`;
389
+ if (decision.settledBy !== "timeout" && decision.reason) message += `: ${decision.reason}`;
387
390
  if (decision.payload !== void 0) {
388
391
  message += ` (payload: ${JSON.stringify(decision.payload)})`;
389
392
  }
@@ -485,6 +488,14 @@ function buildModelSelection(model, effort) {
485
488
  };
486
489
  }
487
490
  __name(buildModelSelection, "buildModelSelection");
491
+ function modelIdOf(model) {
492
+ return typeof model === "string" ? model : model.id;
493
+ }
494
+ __name(modelIdOf, "modelIdOf");
495
+ function contextWindowOf(model) {
496
+ return typeof model === "string" ? void 0 : model.contextWindow;
497
+ }
498
+ __name(contextWindowOf, "contextWindowOf");
488
499
  function reasoningEffortOf(model) {
489
500
  const params = typeof model === "string" ? void 0 : model.params;
490
501
  return params?.find((p) => p.id === PARAM_THINKING)?.value;
@@ -497,6 +508,16 @@ function asString(value, fallback) {
497
508
  return fallback;
498
509
  }
499
510
  __name(asString, "asString");
511
+ function toolResultExitCode(value) {
512
+ if (typeof value !== "object" || value === null) return void 0;
513
+ const code = value.exitCode;
514
+ return typeof code === "number" ? code : void 0;
515
+ }
516
+ __name(toolResultExitCode, "toolResultExitCode");
517
+ function reportsToolFailure(result) {
518
+ return (toolResultExitCode(result) ?? 0) !== 0;
519
+ }
520
+ __name(reportsToolFailure, "reportsToolFailure");
500
521
  function serializeToolOutput(value, fallback) {
501
522
  if (typeof value === "string") return value;
502
523
  if (value === void 0 || value === null) return fallback;
@@ -559,7 +580,9 @@ function translateToolCallEvent(msg) {
559
580
  toolName,
560
581
  output: serializeToolOutput(msg.result, ""),
561
582
  durationMs: 0,
562
- isError: false
583
+ // #388 — `completed` is the SDK's word for "the call is over", not for "the call worked".
584
+ // The exit code is the part that says which, and it was being thrown away here.
585
+ isError: reportsToolFailure(msg.result)
563
586
  }
564
587
  ];
565
588
  }
@@ -722,7 +745,13 @@ function translateInteractionUpdate(update) {
722
745
  toolName: update.toolCall.name,
723
746
  output: serializeToolOutput(update.toolCall.result, ""),
724
747
  durationMs: 0,
725
- isError: false
748
+ // #388 — the same predicate, and on this shape it answers `false` for a reason rather
749
+ // than by decree: `ToolCall` (`@theokit/sdk/dist/types/updates.d.ts`) declares only
750
+ // `{callId, name, args?, result?}`, and the SDK fills `result` with `renderToolResult()`
751
+ // — a rendered string — so the exit code structurally cannot travel here. The message-
752
+ // shaped report of the same call is the one that carries it, and `dedupeTools` is what
753
+ // lets it contribute (`sdk-timeline.ts`).
754
+ isError: reportsToolFailure(update.toolCall.result)
726
755
  }
727
756
  ];
728
757
  case "shell-output-delta":
@@ -901,10 +930,17 @@ function assembleM8CreateOptions(compiled) {
901
930
  };
902
931
  }
903
932
  __name(assembleM8CreateOptions, "assembleM8CreateOptions");
904
- function realUsageDone(result, t0) {
933
+ function stopReasonOf(result) {
934
+ if (result.stoppedByDoomLoop === true) return "no_progress";
935
+ if (result.stoppedAtIterationLimit === true) return "step_limit";
936
+ return void 0;
937
+ }
938
+ __name(stopReasonOf, "stopReasonOf");
939
+ function realUsageDone(result, t0, model) {
905
940
  const u = result.usage;
906
941
  const inputTokens = u?.inputTokens ?? 0;
907
942
  const outputTokens = u?.outputTokens ?? 0;
943
+ const stopReason = stopReasonOf(result);
908
944
  return {
909
945
  type: "done",
910
946
  result: result.result ?? "",
@@ -919,10 +955,18 @@ function realUsageDone(result, t0) {
919
955
  cacheWriteTokens: u?.cacheWriteTokens ?? 0
920
956
  },
921
957
  durationMs: Date.now() - t0,
922
- cost: result.cost?.amount ?? 0
958
+ cost: result.cost?.amount ?? 0,
959
+ ...terminalExtras(stopReason, model)
923
960
  };
924
961
  }
925
962
  __name(realUsageDone, "realUsageDone");
963
+ function terminalExtras(stopReason, model) {
964
+ const extras = {};
965
+ if (stopReason !== void 0) extras.stopReason = stopReason;
966
+ if (model !== void 0) extras.model = model;
967
+ return extras;
968
+ }
969
+ __name(terminalExtras, "terminalExtras");
926
970
 
927
971
  // src/bridge/sdk-error.ts
928
972
  function sdkErrorEvent(err) {
@@ -954,6 +998,20 @@ function bucketFor(e, seen) {
954
998
  return void 0;
955
999
  }
956
1000
  __name(bucketFor, "bucketFor");
1001
+ function isToolLifecycleEvent(e) {
1002
+ return e.type === "tool_call" || e.type === "tool_result" || e.type === "partial_tool_call";
1003
+ }
1004
+ __name(isToolLifecycleEvent, "isToolLifecycleEvent");
1005
+ function mergeIntoPending(e, ids, seen) {
1006
+ if (e.type !== "tool_result" || !e.isError) return;
1007
+ const held = seen.pending.find((p) => p.ids.some((id) => ids.includes(id)));
1008
+ if (held?.event.type !== "tool_result") return;
1009
+ held.event = {
1010
+ ...held.event,
1011
+ isError: true
1012
+ };
1013
+ }
1014
+ __name(mergeIntoPending, "mergeIntoPending");
957
1015
  function dedupeTools(events, raw, seen) {
958
1016
  return events.filter((e) => {
959
1017
  if (e.type === "thinking") {
@@ -965,16 +1023,39 @@ function dedupeTools(events, raw, seen) {
965
1023
  if (bucket === void 0) return true;
966
1024
  const ids = idsOf(e, raw);
967
1025
  if (ids.length === 0) return true;
968
- if (ids.some((id) => bucket.has(id))) return false;
1026
+ if (ids.some((id) => bucket.has(id))) {
1027
+ mergeIntoPending(e, ids, seen);
1028
+ return false;
1029
+ }
969
1030
  for (const id of ids) bucket.add(id);
1031
+ if (e.type === "tool_result") {
1032
+ seen.pending.push({
1033
+ ids,
1034
+ event: e
1035
+ });
1036
+ return false;
1037
+ }
970
1038
  return true;
971
1039
  });
972
1040
  }
973
1041
  __name(dedupeTools, "dedupeTools");
1042
+ function releasePendingToolResults(translated, seen) {
1043
+ if (seen.pending.length === 0) return [];
1044
+ if (translated.length === 0 || translated.every(isToolLifecycleEvent)) return [];
1045
+ return flushPendingToolResults(seen);
1046
+ }
1047
+ __name(releasePendingToolResults, "releasePendingToolResults");
1048
+ function flushPendingToolResults(seen) {
1049
+ const out = seen.pending.map((p) => p.event);
1050
+ seen.pending = [];
1051
+ return out;
1052
+ }
1053
+ __name(flushPendingToolResults, "flushPendingToolResults");
974
1054
  function createToolSeen() {
975
1055
  return {
976
1056
  started: /* @__PURE__ */ new Set(),
977
1057
  completed: /* @__PURE__ */ new Set(),
1058
+ pending: [],
978
1059
  sawThinkingDelta: false
979
1060
  };
980
1061
  }
@@ -983,15 +1064,37 @@ function translateTimelineEvent(ev, runId, seen) {
983
1064
  if (ev.kind === "delta") {
984
1065
  if (ev.update === void 0) return [];
985
1066
  const events2 = translateInteractionUpdate(ev.update);
986
- return dedupeTools(events2, ev.update, seen);
1067
+ const released2 = releasePendingToolResults(events2, seen);
1068
+ return [
1069
+ ...released2,
1070
+ ...dedupeTools(events2, ev.update, seen)
1071
+ ];
987
1072
  }
988
1073
  if (ev.message === void 0) return [];
989
1074
  const events = translateSdkEvent(ev.message, runId);
990
1075
  const kept = ev.textAlreadyStreamed === true ? events.filter((e) => e.type !== "text_delta") : events;
991
- return dedupeTools(kept, ev.message, seen);
1076
+ const released = releasePendingToolResults(kept, seen);
1077
+ return [
1078
+ ...released,
1079
+ ...dedupeTools(kept, ev.message, seen)
1080
+ ];
992
1081
  }
993
1082
  __name(translateTimelineEvent, "translateTimelineEvent");
994
1083
 
1084
+ // src/bridge/tool-context-injection.ts
1085
+ function withInjectedToolContext(handler, injection) {
1086
+ return (input, ctx) => handler(input, {
1087
+ ...ctx,
1088
+ ...injection.runContext !== void 0 ? {
1089
+ context: injection.runContext.value
1090
+ } : {},
1091
+ ...injection.meter !== void 0 ? {
1092
+ usage: injection.meter.snapshot()
1093
+ } : {}
1094
+ });
1095
+ }
1096
+ __name(withInjectedToolContext, "withInjectedToolContext");
1097
+
995
1098
  // src/bridge/tool-dialect-stripper.ts
996
1099
  var OPEN2 = "<function=";
997
1100
  var CLOSE2 = "</tool_call>";
@@ -1090,6 +1193,61 @@ async function* stripToolDialectStream(source) {
1090
1193
  }
1091
1194
  __name(stripToolDialectStream, "stripToolDialectStream");
1092
1195
 
1196
+ // src/bridge/turn-retry.ts
1197
+ import { TheokitAgentError as TheokitAgentError2 } from "@theokit/sdk/errors";
1198
+ function asText(value) {
1199
+ return typeof value === "string" && value.length > 0 ? value : void 0;
1200
+ }
1201
+ __name(asText, "asText");
1202
+ function startFailure(event, outcome) {
1203
+ if (outcome.failure !== void 0) return outcome.failure;
1204
+ return new TheokitAgentError2(asText(event.message) ?? "The turn failed before producing any output.", {
1205
+ code: asText(event.code) ?? "TURN_START_FAILED",
1206
+ isRetryable: event.retryable === true
1207
+ });
1208
+ }
1209
+ __name(startFailure, "startFailure");
1210
+ async function startTurn(open, retry) {
1211
+ const attempt = /* @__PURE__ */ __name(async () => {
1212
+ const { stream, outcome } = open();
1213
+ const it = stream[Symbol.asyncIterator]();
1214
+ try {
1215
+ const first = await it.next();
1216
+ if (!first.done && first.value.type === "error") throw startFailure(first.value, outcome);
1217
+ return {
1218
+ it,
1219
+ first
1220
+ };
1221
+ } catch (err) {
1222
+ await it.return?.(void 0);
1223
+ throw err;
1224
+ }
1225
+ }, "attempt");
1226
+ const { Retry } = await import("@theokit/sdk/retry");
1227
+ return Retry.create(attempt, retry);
1228
+ }
1229
+ __name(startTurn, "startTurn");
1230
+ async function* withTurnStartRetry(open, retry) {
1231
+ const { it, first } = await startTurn(open, retry);
1232
+ let next = first;
1233
+ while (!next.done) {
1234
+ yield next.value;
1235
+ next = await it.next();
1236
+ }
1237
+ }
1238
+ __name(withTurnStartRetry, "withTurnStartRetry");
1239
+ function runTurnWithRetry(open, retry) {
1240
+ if (retry === void 0) return open();
1241
+ return withTurnStartRetry(() => {
1242
+ const outcome = {};
1243
+ return {
1244
+ stream: open(outcome),
1245
+ outcome
1246
+ };
1247
+ }, retry);
1248
+ }
1249
+ __name(runTurnWithRetry, "runTurnWithRetry");
1250
+
1093
1251
  // src/bridge/sdk-adapter.ts
1094
1252
  function withLeakedDialectRecovery(providers) {
1095
1253
  return {
@@ -1121,6 +1279,10 @@ function buildExtraCreateOptions(overrides, compiled) {
1121
1279
  return extra;
1122
1280
  }
1123
1281
  __name(buildExtraCreateOptions, "buildExtraCreateOptions");
1282
+ function applyStepCeiling(sendOptions, maxIterations) {
1283
+ if (maxIterations !== void 0) sendOptions.maxIterations = maxIterations;
1284
+ }
1285
+ __name(applyStepCeiling, "applyStepCeiling");
1124
1286
  async function loadSdkRuntime() {
1125
1287
  try {
1126
1288
  const sdk = await import("@theokit/sdk");
@@ -1157,15 +1319,19 @@ function hasZodInputSchema(schema) {
1157
1319
  return typeof schema?.parse === "function";
1158
1320
  }
1159
1321
  __name(hasZodInputSchema, "hasZodInputSchema");
1160
- function withRunContext(handler, runContext) {
1161
- return (input, ctx) => handler(input, {
1162
- ...ctx,
1163
- context: runContext
1164
- });
1165
- }
1166
- __name(withRunContext, "withRunContext");
1167
- function buildSdkTools(compiledTools, defineTool, extraSdkTools = [], runContext) {
1168
- const has = runContext !== void 0;
1322
+ function buildSdkTools(compiledTools, defineTool, extraSdkTools = [], runContext, meter) {
1323
+ const injection = {
1324
+ ...runContext !== void 0 ? {
1325
+ runContext: {
1326
+ value: runContext
1327
+ }
1328
+ } : {},
1329
+ ...meter !== void 0 ? {
1330
+ meter
1331
+ } : {}
1332
+ };
1333
+ const has = injection.runContext !== void 0 || injection.meter !== void 0;
1334
+ const inject = /* @__PURE__ */ __name((h) => has ? withInjectedToolContext(h, injection) : h, "inject");
1169
1335
  return [
1170
1336
  ...compiledTools.map((t) => {
1171
1337
  if (hasZodInputSchema(t.inputSchema)) {
@@ -1173,17 +1339,17 @@ function buildSdkTools(compiledTools, defineTool, extraSdkTools = [], runContext
1173
1339
  name: t.name,
1174
1340
  description: t.description,
1175
1341
  inputSchema: t.inputSchema,
1176
- handler: has ? withRunContext(t.handler, runContext) : t.handler
1342
+ handler: inject(t.handler)
1177
1343
  });
1178
1344
  }
1179
1345
  return has ? {
1180
1346
  ...t,
1181
- handler: withRunContext(t.handler, runContext)
1347
+ handler: inject(t.handler)
1182
1348
  } : t;
1183
1349
  }),
1184
1350
  ...extraSdkTools.map((t) => has ? {
1185
1351
  ...t,
1186
- handler: withRunContext(t.handler, runContext)
1352
+ handler: inject(t.handler)
1187
1353
  } : t)
1188
1354
  ];
1189
1355
  }
@@ -1208,7 +1374,11 @@ function createSdkAgentStream(compiled, compiledTools, apiKey, overrides = {}) {
1208
1374
  };
1209
1375
  return;
1210
1376
  }
1211
- const sdkTools = buildSdkTools(compiledTools, rt.defineTool, overrides.sdkTools, runContext);
1377
+ const usageMeter = overrides.exposeUsageToTools === true ? createRunUsageMeter({
1378
+ contextWindowTokens: contextWindowOf(model),
1379
+ delegate: overrides.budgetTracker
1380
+ }) : void 0;
1381
+ const sdkTools = buildSdkTools(compiledTools, rt.defineTool, overrides.sdkTools, runContext, usageMeter);
1212
1382
  const inlineSkills = compiled.skills?.inline;
1213
1383
  if (inlineSkills !== void 0 && inlineSkills.length > 0 && rt.defineSkillReadTool !== void 0 && !compiledTools.some((t) => t.name === "skill_read")) {
1214
1384
  sdkTools.push(rt.defineSkillReadTool(inlineSkills));
@@ -1225,20 +1395,27 @@ function createSdkAgentStream(compiled, compiledTools, apiKey, overrides = {}) {
1225
1395
  source: runContextSource,
1226
1396
  keys: runContext !== void 0 ? Object.keys(runContext) : []
1227
1397
  });
1398
+ const turnOpts = {
1399
+ apiKey: await resolverApiKey(apiKey),
1400
+ model,
1401
+ reasoningEffort,
1402
+ overrides,
1403
+ parseThinkTags,
1404
+ stripToolDialect,
1405
+ sessionId,
1406
+ message,
1407
+ factoryOpts,
1408
+ runId,
1409
+ t0,
1410
+ ...usageMeter !== void 0 ? {
1411
+ usageMeter
1412
+ } : {}
1413
+ };
1228
1414
  try {
1229
- yield* streamSdkAgent(rt, compiled, sdkTools, {
1230
- apiKey: await resolverApiKey(apiKey),
1231
- model,
1232
- reasoningEffort,
1233
- overrides,
1234
- parseThinkTags,
1235
- stripToolDialect,
1236
- sessionId,
1237
- message,
1238
- factoryOpts,
1239
- runId,
1240
- t0
1241
- });
1415
+ yield* runTurnWithRetry((outcome) => streamSdkAgent(rt, compiled, sdkTools, outcome === void 0 ? turnOpts : {
1416
+ ...turnOpts,
1417
+ outcome
1418
+ }), overrides.retry);
1242
1419
  } catch (err) {
1243
1420
  yield sdkErrorEvent(err);
1244
1421
  }
@@ -1262,6 +1439,7 @@ async function* streamSdkAgent(rt, compiled, sdkTools, opts) {
1262
1439
  baseDir: overrides.baseDir
1263
1440
  };
1264
1441
  const extra = buildExtraCreateOptions(overrides, compiled);
1442
+ if (opts.usageMeter !== void 0) extra.budgetTracker = opts.usageMeter.tracker;
1265
1443
  if (applied.length > 0) {
1266
1444
  debugLog("[THEO_AGENT_M8_RUNTIME_APPLIED]", {
1267
1445
  skills: applied.includes("skills"),
@@ -1283,6 +1461,7 @@ async function* streamSdkAgent(rt, compiled, sdkTools, opts) {
1283
1461
  };
1284
1462
  const sendOptions = {};
1285
1463
  if (factoryOpts?.disableTools === true) sendOptions.toolChoice = "none";
1464
+ applyStepCeiling(sendOptions, compiled.maxIterations);
1286
1465
  if (overrides.onRunEvent !== void 0) sendOptions.onRunEvent = overrides.onRunEvent;
1287
1466
  const sendInput = overrides.images && overrides.images.length > 0 ? {
1288
1467
  text: message,
@@ -1292,14 +1471,22 @@ async function* streamSdkAgent(rt, compiled, sdkTools, opts) {
1292
1471
  const timeline = /* @__PURE__ */ __name(async function* () {
1293
1472
  const run = await sendPromise;
1294
1473
  const seen = createToolSeen();
1295
- for await (const ev of run.events()) {
1296
- for (const event of translateTimelineEvent(ev, runId, seen)) {
1474
+ const emit = /* @__PURE__ */ __name(function* (events) {
1475
+ for (const event of events) {
1297
1476
  if (event.type === "error") state.sawError = true;
1298
1477
  if (event.type === "done") continue;
1299
1478
  state.lastEventType = event.type;
1300
1479
  yield event;
1301
1480
  }
1481
+ }, "emit");
1482
+ for await (const ev of run.events()) {
1483
+ const translated = translateTimelineEvent(ev, runId, seen);
1484
+ if (opts.outcome !== void 0 && state.lastEventType === "" && translated.some((e) => e.type === "error")) {
1485
+ opts.outcome.failure = (await (await sendPromise).wait()).error?.cause;
1486
+ }
1487
+ yield* emit(translated);
1302
1488
  }
1489
+ yield* emit(flushPendingToolResults(seen));
1303
1490
  }, "timeline");
1304
1491
  for await (const event of applyTextTransforms(timeline(), {
1305
1492
  parseThinkTags,
@@ -1317,7 +1504,7 @@ async function* streamSdkAgent(rt, compiled, sdkTools, opts) {
1317
1504
  };
1318
1505
  }
1319
1506
  } else {
1320
- yield realUsageDone(await (await sendPromise).wait(), t0);
1507
+ yield realUsageDone(await (await sendPromise).wait(), t0, modelIdOf(model));
1321
1508
  }
1322
1509
  } finally {
1323
1510
  await agent.dispose();
@@ -1356,10 +1543,24 @@ function toAgentFactory(def, opts) {
1356
1543
  ...m8,
1357
1544
  ...extra
1358
1545
  });
1359
- return withGuardrails(agent, compiled.guardrails);
1546
+ return withGuardrails(withStepCeiling(agent, compiled.maxIterations), compiled.guardrails);
1360
1547
  };
1361
1548
  }
1362
1549
  __name(toAgentFactory, "toAgentFactory");
1550
+ function withStepCeiling(handle, maxIterations) {
1551
+ if (maxIterations === void 0) return handle;
1552
+ return {
1553
+ get agentId() {
1554
+ return handle.agentId;
1555
+ },
1556
+ dispose: /* @__PURE__ */ __name(() => handle.dispose(), "dispose"),
1557
+ send: /* @__PURE__ */ __name((msg, sendOpts) => handle.send(msg, {
1558
+ maxIterations,
1559
+ ...sendOpts
1560
+ }), "send")
1561
+ };
1562
+ }
1563
+ __name(withStepCeiling, "withStepCeiling");
1363
1564
  function withGuardrails(handle, guardrails) {
1364
1565
  if (guardrails === void 0 || guardrails.length === 0) return handle;
1365
1566
  return {
@@ -1491,8 +1692,8 @@ var noopReflectionStrategy = {
1491
1692
  };
1492
1693
 
1493
1694
  // src/bridge/delegation-types.ts
1494
- import { TheokitAgentError as TheokitAgentError2 } from "@theokit/sdk/errors";
1495
- var DelegationBudgetExceededError = class extends TheokitAgentError2 {
1695
+ import { TheokitAgentError as TheokitAgentError3 } from "@theokit/sdk/errors";
1696
+ var DelegationBudgetExceededError = class extends TheokitAgentError3 {
1496
1697
  static {
1497
1698
  __name(this, "DelegationBudgetExceededError");
1498
1699
  }
@@ -1509,7 +1710,7 @@ var DelegationBudgetExceededError = class extends TheokitAgentError2 {
1509
1710
  }
1510
1711
  };
1511
1712
  var BudgetExceededError = DelegationBudgetExceededError;
1512
- var DelegationError = class extends TheokitAgentError2 {
1713
+ var DelegationError = class extends TheokitAgentError3 {
1513
1714
  static {
1514
1715
  __name(this, "DelegationError");
1515
1716
  }
@@ -2029,9 +2230,10 @@ __name(formatUnrecognised, "formatUnrecognised");
2029
2230
 
2030
2231
  // src/bridge/agent-orchestrator.ts
2031
2232
  function requireApiKey(opts, agentName) {
2233
+ if (opts.apiKey === null) return "";
2032
2234
  const apiKey = opts.apiKey ?? "";
2033
2235
  if (!apiKey) {
2034
- throw new DelegationError(agentName, "No API key provided. Pass apiKey in DelegateOptions.");
2236
+ throw new DelegationError(agentName, "No API key provided. Pass apiKey in DelegateOptions, or `apiKey: null` when the provider takes no credential (a local model).");
2035
2237
  }
2036
2238
  return apiKey;
2037
2239
  }
@@ -2098,8 +2300,8 @@ async function delegate(spec, message, opts = {}) {
2098
2300
  __name(delegate, "delegate");
2099
2301
 
2100
2302
  // src/bridge/delegation-lifecycle.ts
2101
- import { TheokitAgentError as TheokitAgentError3 } from "@theokit/sdk/errors";
2102
- var DelegationTimeoutError = class extends TheokitAgentError3 {
2303
+ import { TheokitAgentError as TheokitAgentError4 } from "@theokit/sdk/errors";
2304
+ var DelegationTimeoutError = class extends TheokitAgentError4 {
2103
2305
  static {
2104
2306
  __name(this, "DelegationTimeoutError");
2105
2307
  }
@@ -2262,4 +2464,4 @@ export {
2262
2464
  delegateBackground,
2263
2465
  delegateWithScoring
2264
2466
  };
2265
- //# sourceMappingURL=chunk-CKRM5Q2K.js.map
2467
+ //# sourceMappingURL=chunk-2I6DQUJP.js.map