llmz 1.0.1 → 1.0.2

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 (51) hide show
  1. package/DOCS.md +8 -4
  2. package/ERRORS.md +5 -2
  3. package/dist/{component-BpMVZYOa.cjs → component-CMFoCHyu.cjs} +3 -3
  4. package/dist/{component-C27qu6Zv.js → component-DncqP4fB.js} +3 -3
  5. package/dist/context.d.ts +1 -1
  6. package/dist/{custom-client-BDkgBR2w.js → custom-client-C-WXvLD9.js} +37 -13
  7. package/dist/{custom-client-MytucGI-.cjs → custom-client-Cgt9_0r1.cjs} +37 -13
  8. package/dist/errors/catalog.d.ts +7 -0
  9. package/dist/{errors-IhnTKUp7.cjs → errors-C6ppQUZX.cjs} +22 -0
  10. package/dist/{errors-H4JJFH3S.js → errors-Crk5P8jo.js} +17 -1
  11. package/dist/errors.d.ts +6 -0
  12. package/dist/{execute-BYI_U5sR.js → execute-CiYvPs5Q.js} +196 -78
  13. package/dist/{execute-DLas4V2n.cjs → execute-DTTfacsi.cjs} +196 -78
  14. package/dist/{exit-BUgJ5qi5.cjs → exit-BOtKWPuT.cjs} +2 -2
  15. package/dist/{exit-CPNk3vbz.js → exit-DMPwCSba.js} +2 -2
  16. package/dist/index.cjs +18 -17
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.js +18 -18
  19. package/dist/index.workerd.js +252 -79
  20. package/dist/inspection.d.ts +2 -0
  21. package/dist/{native-Bm6L9zOb.cjs → native-0bq5ATZM.cjs} +3 -3
  22. package/dist/{native-DvTH9vFe.js → native-n_718Z-T.js} +3 -3
  23. package/dist/{quickjs-variant-DJwYDSsb.cjs → quickjs-variant-21IO97PF.cjs} +15 -8
  24. package/dist/{quickjs-variant-DlPi9-Sx.js → quickjs-variant-CtuGagsb.js} +10 -9
  25. package/dist/runtime/chat-completion.test.d.ts +1 -0
  26. package/dist/runtime/chat-last-speaker.test.d.ts +1 -0
  27. package/dist/runtime/empty-completion.test.d.ts +1 -0
  28. package/dist/runtime/execution-report.d.ts +3 -0
  29. package/dist/runtime/forced-inspection.d.ts +13 -0
  30. package/dist/runtime/forced-inspection.test.d.ts +1 -0
  31. package/dist/runtime/javascript-api.d.ts +3 -0
  32. package/dist/runtime/think-signal.test.d.ts +1 -0
  33. package/dist/runtime/tool-wrapper.d.ts +4 -2
  34. package/dist/runtime/types.d.ts +8 -0
  35. package/dist/{schema-DBkjo0b7.cjs → schema-CXlnbb3n.cjs} +1 -1
  36. package/dist/{schema-Aer_W7Al.js → schema-GE4ISPCR.js} +1 -1
  37. package/dist/session/messages.d.ts +2 -0
  38. package/dist/session/serialization.d.ts +2 -0
  39. package/dist/session/session.d.ts +4 -0
  40. package/dist/session/speaker.test.d.ts +1 -0
  41. package/dist/{tool--gK91eez.js → tool-DstssiAs.js} +4 -4
  42. package/dist/{tool-Da_F-N-5.cjs → tool-_wK9hQOb.cjs} +4 -4
  43. package/dist/{truncate-BSoH2-nY.js → truncate-BEKbdo3t.js} +1 -1
  44. package/dist/{truncate-nV3Mxr6-.cjs → truncate-uomAMGPs.cjs} +1 -1
  45. package/dist/types.d.ts +6 -0
  46. package/dist/{typings-C1ihexWE.cjs → typings-BA_XxAcY.cjs} +1 -1
  47. package/dist/{typings-D9_aC8aq.js → typings-BEVDvtuk.js} +1 -1
  48. package/dist/vm/types.d.ts +2 -0
  49. package/dist/{vm-8jxt8PTK.js → vm-C7SfutHn.js} +28 -3
  50. package/dist/{vm-XuVPuW3Y.cjs → vm-gmekHc0i.cjs} +28 -2
  51. package/package.json +1 -1
@@ -1,13 +1,13 @@
1
1
  import { g as baseIsEqual, o as init, r as getErrorMessage, u as stripInvalidIdentifiers } from "./utils-BOFzb8Ok.js";
2
- import { A as MemoryValueError, B as UnknownToolError, F as TokenOverflowError, H as isLLMzError, I as ToolExecutionError, M as ObjectPropertyError, O as LoopExceededError, P as SessionStateError, R as UnknownComponentError, V as isCriticalError, a as cleanStackTrace, b as InvalidConfigurationError, f as DeliveryError, g as HostOperationError, h as HookError, j as NativeProtocolError, k as MemoryCapacityError, l as CognitiveError, m as ExitInputError, n as ThinkSignal, o as AssignmentError, p as ExecutionAbortedError, r as VMSignal, s as CodeExecutionError, t as Signals, u as CompactionError, v as InvalidCodeError, z as UnknownExitError } from "./errors-H4JJFH3S.js";
3
- import { a as isAnyComponent } from "./component-C27qu6Zv.js";
4
- import { n as parseSchemaSync } from "./schema-Aer_W7Al.js";
5
- import { t as DEFAULT_TOOL_RESULT_MAX_TOKENS } from "./truncate-BSoH2-nY.js";
6
- import { a as cloneMemoryValue, f as createInspector, h as resolveInspectionBudget, m as limitInspectionOutput } from "./quickjs-variant-DlPi9-Sx.js";
7
- import { n as schemaToTypeScript } from "./typings-D9_aC8aq.js";
8
- import { a as Context, d as prepareAutoCompaction, f as countNativeRequestTokens, i as SuccessExecutionResult, n as ErrorExecutionResult, p as resolveTokenBudget, s as ListenExit, t as _CustomModelClient, u as stableJSON } from "./custom-client-BDkgBR2w.js";
9
- import { a as validateNativeToolCalls, i as getRunJavaScriptTool, r as WORKER_RESPONSE_INSTRUCTION } from "./native-DvTH9vFe.js";
10
- import { a as compile, i as VM_TERMINATION, n as VM_ON_ERROR, r as VM_PROGRAM_COMPLETE, runAsyncFunction, t as withMissingMember } from "./vm-8jxt8PTK.js";
2
+ import { A as MemoryValueError, B as UnknownExitError, F as SessionStateError, H as isCriticalError, I as TokenOverflowError, L as ToolExecutionError, M as NativeProtocolError, N as ObjectPropertyError, O as LoopExceededError, U as isLLMzError, V as UnknownToolError, a as cleanStackTrace, b as InvalidConfigurationError, f as DeliveryError, g as HostOperationError, h as HookError, j as MissingChatResponseError, k as MemoryCapacityError, l as CognitiveError, m as ExitInputError, n as ThinkSignal, o as AssignmentError, p as ExecutionAbortedError, r as VMSignal, s as CodeExecutionError, t as Signals, u as CompactionError, v as InvalidCodeError, z as UnknownComponentError } from "./errors-Crk5P8jo.js";
3
+ import { a as isAnyComponent } from "./component-DncqP4fB.js";
4
+ import { n as parseSchemaSync } from "./schema-GE4ISPCR.js";
5
+ import { i as unwrapTruncated, n as isTruncated, t as DEFAULT_TOOL_RESULT_MAX_TOKENS } from "./truncate-BEKbdo3t.js";
6
+ import { a as cloneMemoryValue, f as createInspector, g as resolveInspectionBudget, h as limitInspectionOutput, p as snapshotInspectionValue } from "./quickjs-variant-CtuGagsb.js";
7
+ import { n as schemaToTypeScript } from "./typings-BEVDvtuk.js";
8
+ import { a as Context, d as prepareAutoCompaction, f as countNativeRequestTokens, i as SuccessExecutionResult, n as ErrorExecutionResult, p as resolveTokenBudget, s as ListenExit, t as _CustomModelClient, u as stableJSON } from "./custom-client-C-WXvLD9.js";
9
+ import { a as validateNativeToolCalls, i as getRunJavaScriptTool, r as WORKER_RESPONSE_INSTRUCTION } from "./native-n_718Z-T.js";
10
+ import { a as VM_TERMINATION, i as VM_PROGRAM_COMPLETE, n as VM_CALL_SITE, o as compile, r as VM_ON_ERROR, runAsyncFunction, t as withMissingMember } from "./vm-C7SfutHn.js";
11
11
  import { z } from "@bpinternal/zui";
12
12
  import { ulid } from "ulid";
13
13
  import { Cognitive } from "@botpress/cognitive";
@@ -208,10 +208,7 @@ function errorPreview(value, inspector, identity) {
208
208
  //#region src/runtime/execution-diagnostics.ts
209
209
  /** XML-style boundaries keep diagnostic text separate from recovery instructions. */
210
210
  function reportSection(name, content, maxTokens = 2e3, options = {}) {
211
- const escape = (value) => value.replace(/&/g, "&amp;").replace(/</g, "&lt;");
212
- const heading = options.heading ? `${escape(options.heading)}\n` : "";
213
- const body = limitInspectionOutput(content, maxTokens, false, options.preserve ?? "top");
214
- return `<${name}>\n${heading}${/[<&]|\]\]>/.test(body) ? `<![CDATA[\n${body.replaceAll("]]>", "]]]]><![CDATA[>")}\n]]>` : body}\n</${name}>`;
211
+ return `<${name}>\n${options.heading ? `${options.heading}\n` : ""}${limitInspectionOutput(content, maxTokens, false, options.preserve ?? "top")}\n</${name}>`;
215
212
  }
216
213
  /** Show the specific failure and guest source, never the host's implementation stack. */
217
214
  function renderExecutionDiagnostics(error, message, inspector, identity) {
@@ -252,11 +249,58 @@ function renderSourceTrace(stack, inspector, identity) {
252
249
  }), 1e3);
253
250
  }
254
251
  //#endregion
252
+ //#region src/runtime/forced-inspection.ts
253
+ /** Keep attribution and content together, using the same display budgets as inspect(). */
254
+ function renderForcedInspection(inspections, inspector, identity, maxTokens, policies) {
255
+ return [
256
+ "<forced_inspection>",
257
+ "Forced inspection: the tools listed below completed successfully and requested review of their results.",
258
+ "This is the equivalent of an inspect() call. Do not repeat these tool calls; use the results below and retained variables.",
259
+ "No exit was applied. Review the evidence before continuing or completing the task.",
260
+ "",
261
+ "Tools requesting inspection (lines refer to the executed JavaScript):",
262
+ ...inspections.map((entry) => {
263
+ const entryIdentity = {
264
+ ...identity,
265
+ tool: entry.tool
266
+ };
267
+ const name = inspector(entry.tool, {
268
+ purpose: "name",
269
+ maxTokens: 80,
270
+ identity: entryIdentity
271
+ });
272
+ const reason = inspector(entry.reason, {
273
+ purpose: "error",
274
+ maxTokens: 1e3,
275
+ identity: entryIdentity
276
+ });
277
+ const budget = resolveInspectionBudget(entry.value, {
278
+ tokens: maxTokens,
279
+ policies
280
+ });
281
+ const result = inspector(entry.value, {
282
+ purpose: "result",
283
+ maxTokens,
284
+ policies,
285
+ identity: entryIdentity
286
+ });
287
+ return [
288
+ `<tool name="${name}" line="${entry.line ?? "unknown"}">`,
289
+ `<reason>${reason}</reason>`,
290
+ reportSection("result", result, budget.tokens, { preserve: budget.preserve }),
291
+ "</tool>"
292
+ ].join("\n");
293
+ }),
294
+ "</forced_inspection>"
295
+ ].join("\n");
296
+ }
297
+ //#endregion
255
298
  //#region src/runtime/execution-report.ts
256
299
  const MAX_REPORTED_CHANGES = 40;
257
300
  const MAX_OVERRIDE_SOURCE_LENGTH = 3e3;
258
301
  /** Format one settled outcome; execution is responsible for deciding what happened. */
259
302
  function renderExecutionReport({ outcome, activity, memory, source, requiresExit = false, iteration, identity = { iteration }, inspector = createInspector(), maxTokens = DEFAULT_TOOL_RESULT_MAX_TOKENS, policies }) {
303
+ var _outcome$forcedInspec, _outcome$forcedInspec2;
260
304
  const detail = (value) => inspector(value, {
261
305
  purpose: "error",
262
306
  maxTokens: 1e3,
@@ -283,6 +327,13 @@ function renderExecutionReport({ outcome, activity, memory, source, requiresExit
283
327
  });
284
328
  };
285
329
  const sections = [renderStatus(outcome, memory)];
330
+ if (outcome.type === "inspect" && ((_outcome$forcedInspec = outcome.forcedInspections) === null || _outcome$forcedInspec === void 0 ? void 0 : _outcome$forcedInspec.length)) {
331
+ sections.push(renderForcedInspection(outcome.forcedInspections, inspector, identity, maxTokens, policies));
332
+ if (outcome.downstreamError) {
333
+ sections.push(...renderExecutionDiagnostics(outcome.downstreamError, getErrorMessage(outcome.downstreamError), inspector, identity));
334
+ sections.push(reportSection("recovery", "A later operation failed. The tool results above were successfully retrieved; inspect them and repair only the failed work. Do not repeat successful calls."));
335
+ }
336
+ }
286
337
  if (outcome.type === "error") {
287
338
  sections.push(...renderExecutionDiagnostics(outcome.error, outcome.message, inspector, identity));
288
339
  sections.push(reportSection("recovery", [
@@ -315,7 +366,7 @@ function renderExecutionReport({ outcome, activity, memory, source, requiresExit
315
366
  if (memory.unavailable.length > failures.length) entries.push(`- ${memory.unavailable.length - failures.length} additional values could not be retained.`);
316
367
  sections.push(reportSection("memory_errors", `Memory errors\n${entries.join("\n")}`));
317
368
  }
318
- if (outcome.type === "inspect") {
369
+ if (outcome.type === "inspect" && ((_outcome$forcedInspec2 = outcome.forcedInspections) === null || _outcome$forcedInspec2 === void 0 ? void 0 : _outcome$forcedInspec2.length) && (!outcome.explicit || outcome.forcedInspections.some((entry) => isEqual(entry.value, outcome.value)))) {} else if (outcome.type === "inspect") {
319
370
  const heading = outcome.explicit ? "inspect() result" : "Result";
320
371
  sections.push(outcome.available ? resultSection("result", heading, outcome.value) : reportSection("result", "Unavailable; see memory errors above.", maxTokens, { heading }));
321
372
  } else if (outcome.type === "exit") sections.push(resultSection("completion", `Completion\nExit "${outcome.name}" completed.`, outcome.value === void 0 ? "" : outcome.value));
@@ -851,6 +902,7 @@ const isRecord = (value) => value !== null && typeof value === "object" && !Arra
851
902
  function createJavaScriptApi({ iteration, components, exits, deliver, signal, onError }) {
852
903
  const decisions = /* @__PURE__ */ new Map();
853
904
  const pending = /* @__PURE__ */ new Set();
905
+ const inspections = [];
854
906
  let open = true;
855
907
  let outstanding = [];
856
908
  let delivery;
@@ -987,6 +1039,10 @@ function createJavaScriptApi({ iteration, components, exits, deliver, signal, on
987
1039
  isReceipt: (value) => resolve(value) !== void 0,
988
1040
  getTerminalOutcome: () => terminalOutcome,
989
1041
  getInterruption: () => interruption,
1042
+ requestInspection: (inspection) => {
1043
+ inspections.push(inspection);
1044
+ },
1045
+ getForcedInspections: () => inspections,
990
1046
  throwIfTerminated,
991
1047
  track,
992
1048
  assertOpen,
@@ -1014,8 +1070,8 @@ const finalizeIteration = async ({ iteration, status, controller, onIterationEnd
1014
1070
  //#endregion
1015
1071
  //#region src/runtime/tool-wrapper.ts
1016
1072
  const SLOW_TOOL_WARNING = ms("15s");
1017
- function wrapTool({ tool, object, iteration, beforeHook, afterHook, onTruncation, onResult, controller }) {
1018
- return async function(input) {
1073
+ function wrapTool({ tool, object, iteration, beforeHook, afterHook, onTruncation, onResult, controller, onThink }) {
1074
+ return async function(input, line) {
1019
1075
  controller.signal.throwIfAborted();
1020
1076
  const toolCallId = `tcall_${ulid()}`;
1021
1077
  const originalInput = input;
@@ -1034,7 +1090,7 @@ function wrapTool({ tool, object, iteration, beforeHook, afterHook, onTruncation
1034
1090
  let output;
1035
1091
  let error;
1036
1092
  let success = true;
1037
- let signalToThrow;
1093
+ const inspections = [];
1038
1094
  const pushToolCallTrace = () => {
1039
1095
  iteration.recordTrace({
1040
1096
  type: "tool_call",
@@ -1050,32 +1106,21 @@ function wrapTool({ tool, object, iteration, beforeHook, afterHook, onTruncation
1050
1106
  success
1051
1107
  });
1052
1108
  };
1053
- const handleSignals = async (err) => {
1054
- if (output === err) return true;
1055
- if (ThinkSignal.is(err)) {
1056
- signalToThrow = err;
1057
- iteration.recordTrace({
1058
- type: "think_signal",
1059
- started_at: Date.now(),
1060
- line: 0,
1061
- ended_at: Date.now()
1062
- });
1063
- success = true;
1064
- output = err;
1065
- const afterRes = await callHook(() => afterHook === null || afterHook === void 0 ? void 0 : afterHook({
1066
- iteration,
1067
- tool,
1068
- input: originalInput,
1069
- output,
1070
- controller,
1071
- object,
1072
- toolCallId,
1073
- nativeCallId: iteration.nativeCallId
1074
- }));
1075
- if (typeof (afterRes === null || afterRes === void 0 ? void 0 : afterRes.output) !== "undefined") output = afterRes.output;
1076
- return true;
1077
- }
1078
- return false;
1109
+ const unwrapSignal = (value) => {
1110
+ if (!ThinkSignal.is(value)) return value;
1111
+ const context = value.context;
1112
+ const output = unwrapTruncated(context);
1113
+ if (isTruncated(context)) onTruncation === null || onTruncation === void 0 || onTruncation(output, context.$$truncate);
1114
+ const inspection = {
1115
+ tool: object ? `${object}.${tool.name}` : tool.name,
1116
+ toolCallId,
1117
+ line,
1118
+ reason: value.reason,
1119
+ value: output,
1120
+ metadata: value.metadata
1121
+ };
1122
+ inspections.push(inspection);
1123
+ return output;
1079
1124
  };
1080
1125
  try {
1081
1126
  const beforeRes = await callHook(() => beforeHook === null || beforeHook === void 0 ? void 0 : beforeHook({
@@ -1087,18 +1132,25 @@ function wrapTool({ tool, object, iteration, beforeHook, afterHook, onTruncation
1087
1132
  toolCallId,
1088
1133
  nativeCallId: iteration.nativeCallId
1089
1134
  }));
1135
+ if (ThinkSignal.is(beforeRes)) throw new HookError("Tool hooks cannot request inspection with ThinkSignal. Return it from the tool handler instead.");
1090
1136
  if (typeof (beforeRes === null || beforeRes === void 0 ? void 0 : beforeRes.input) !== "undefined") effectiveInput = beforeRes.input;
1091
1137
  controller.signal.throwIfAborted();
1092
- output = await tool.execute(effectiveInput, {
1093
- callId: toolCallId,
1094
- iterationId: iteration.id,
1095
- nativeCallId: iteration.nativeCallId,
1096
- onTruncation,
1097
- onInput: (parsed) => {
1098
- controller.signal.throwIfAborted();
1099
- if (effectiveInput === originalInput) reportedInput = parsed;
1100
- }
1101
- });
1138
+ try {
1139
+ output = await tool.execute(effectiveInput, {
1140
+ callId: toolCallId,
1141
+ iterationId: iteration.id,
1142
+ nativeCallId: iteration.nativeCallId,
1143
+ onTruncation,
1144
+ onInput: (parsed) => {
1145
+ controller.signal.throwIfAborted();
1146
+ if (effectiveInput === originalInput) reportedInput = parsed;
1147
+ }
1148
+ });
1149
+ } catch (error) {
1150
+ if (!ThinkSignal.is(error)) throw error;
1151
+ output = error;
1152
+ }
1153
+ output = unwrapSignal(output);
1102
1154
  const afterRes = await callHook(() => afterHook === null || afterHook === void 0 ? void 0 : afterHook({
1103
1155
  iteration,
1104
1156
  tool,
@@ -1109,19 +1161,39 @@ function wrapTool({ tool, object, iteration, beforeHook, afterHook, onTruncation
1109
1161
  toolCallId,
1110
1162
  nativeCallId: iteration.nativeCallId
1111
1163
  }));
1164
+ if (ThinkSignal.is(afterRes) || ThinkSignal.is(afterRes === null || afterRes === void 0 ? void 0 : afterRes.output)) throw new HookError("Tool hooks cannot request inspection with ThinkSignal. Return it from the tool handler instead.");
1112
1165
  if (typeof (afterRes === null || afterRes === void 0 ? void 0 : afterRes.output) !== "undefined") output = afterRes.output;
1166
+ controller.signal.throwIfAborted();
1113
1167
  } catch (err) {
1114
- if (!await handleSignals(err)) {
1115
- success = false;
1116
- error = isLLMzError(err) ? err : new ToolExecutionError(tool.name, err);
1117
- iteration.recordError(error);
1118
- }
1168
+ success = false;
1169
+ output = void 0;
1170
+ if (ThinkSignal.is(err)) error = new HookError("Tool hooks cannot request inspection with ThinkSignal. Return it from the tool handler instead.");
1171
+ else error = isLLMzError(err) ? err : new ToolExecutionError(tool.name, err);
1172
+ iteration.recordError(error);
1119
1173
  } finally {
1120
1174
  clearTimeout(alertSlowTool);
1175
+ for (const inspection of success ? inspections : []) {
1176
+ const value = snapshotInspectionValue(output);
1177
+ onThink === null || onThink === void 0 || onThink({
1178
+ ...inspection,
1179
+ value
1180
+ });
1181
+ iteration.recordTrace({
1182
+ type: "think_signal",
1183
+ started_at: Date.now(),
1184
+ ended_at: Date.now(),
1185
+ line: line ?? 0,
1186
+ tool_name: tool.name,
1187
+ tool_call_id: toolCallId,
1188
+ object,
1189
+ reason: inspection.reason,
1190
+ context: value,
1191
+ metadata: inspection.metadata
1192
+ });
1193
+ }
1121
1194
  pushToolCallTrace();
1122
1195
  }
1123
1196
  if (!success) throw error;
1124
- if (signalToThrow) throw signalToThrow;
1125
1197
  onResult === null || onResult === void 0 || onResult(output);
1126
1198
  return output;
1127
1199
  };
@@ -1212,9 +1284,14 @@ const buildVMContext = ({ ctx, iteration, controller, onBeforeTool, onAfterTool,
1212
1284
  afterHook: onAfterTool,
1213
1285
  onTruncation,
1214
1286
  onResult: onToolResult,
1215
- controller
1287
+ controller,
1288
+ onThink: javascriptApi === null || javascriptApi === void 0 ? void 0 : javascriptApi.requestInspection
1216
1289
  });
1217
- instance[tool.name] = javascriptApi ? (input) => javascriptApi.track(() => wrapped(input)) : wrapped;
1290
+ instance[tool.name] = javascriptApi ? (input) => {
1291
+ var _vmContext$VM_CALL_SI;
1292
+ const line = (_vmContext$VM_CALL_SI = vmContext[VM_CALL_SITE]) === null || _vmContext$VM_CALL_SI === void 0 ? void 0 : _vmContext$VM_CALL_SI.call(vmContext);
1293
+ return javascriptApi.track(() => wrapped(input, line));
1294
+ } : wrapped;
1218
1295
  }
1219
1296
  vmContext[obj.name] = withMissingMember(instance, (name) => {
1220
1297
  const error = new UnknownToolError(`${obj.name}.${name}`, (obj.tools ?? []).map((tool) => `${obj.name}.${tool.name}`));
@@ -1230,9 +1307,14 @@ const buildVMContext = ({ ctx, iteration, controller, onBeforeTool, onAfterTool,
1230
1307
  afterHook: onAfterTool,
1231
1308
  onTruncation,
1232
1309
  onResult: onToolResult,
1233
- controller
1310
+ controller,
1311
+ onThink: javascriptApi === null || javascriptApi === void 0 ? void 0 : javascriptApi.requestInspection
1234
1312
  });
1235
- const callable = javascriptApi ? (input) => javascriptApi.track(() => wrapped(input)) : wrapped;
1313
+ const callable = javascriptApi ? (input) => {
1314
+ var _vmContext$VM_CALL_SI2;
1315
+ const line = (_vmContext$VM_CALL_SI2 = vmContext[VM_CALL_SITE]) === null || _vmContext$VM_CALL_SI2 === void 0 ? void 0 : _vmContext$VM_CALL_SI2.call(vmContext);
1316
+ return javascriptApi.track(() => wrapped(input, line));
1317
+ } : wrapped;
1236
1318
  for (const key of [tool.name, ...tool.aliases ?? []]) vmContext[key] = callable;
1237
1319
  }
1238
1320
  return vmContext;
@@ -1272,9 +1354,10 @@ async function executeContextInternal(props) {
1272
1354
  });
1273
1355
  let release;
1274
1356
  try {
1275
- var _ctx$iterations$at;
1357
+ var _props$options8, _ctx$iterations$at;
1276
1358
  if ("snapshot" in props) throw new InvalidConfigurationError("Snapshots and external pause/resume are no longer supported. Use a session for conversation history and memory.");
1277
1359
  if ("messages" in props) throw new InvalidConfigurationError("Append input with session.append(message) before calling execute(). execute.messages is no longer supported.");
1360
+ if (((_props$options8 = props.options) === null || _props$options8 === void 0 ? void 0 : _props$options8.requireChatResponse) !== void 0 && typeof props.options.requireChatResponse !== "boolean") throw new InvalidConfigurationError("Invalid requireChatResponse. Expected a boolean.");
1278
1361
  release = ctx.session.acquire();
1279
1362
  prepareSession(ctx);
1280
1363
  const client = props.client ?? new Client();
@@ -1457,20 +1540,21 @@ async function rejectNativeBatch({ ctx, iteration }, generated, errors) {
1457
1540
  }, generated.toolCalls.some((call) => call.name !== "run_javascript") ? new UnknownToolError(generated.toolCalls.find((call) => call.name !== "run_javascript").name, ["run_javascript"], message) : new NativeProtocolError(message));
1458
1541
  }
1459
1542
  async function deliverAssistantText(state, generated) {
1543
+ var _iteration$response4;
1460
1544
  const { ctx, iteration } = state;
1461
- if (!generated.output.trim() || !ctx.chat) return;
1545
+ if (!generated.output.trim() || !ctx.chat || !((_iteration$response4 = iteration.response) === null || _iteration$response4 === void 0 ? void 0 : _iteration$response4.handler)) return;
1462
1546
  const startedAt = Date.now();
1463
1547
  const message = {
1464
1548
  type: "text",
1465
1549
  text: generated.output
1466
1550
  };
1467
1551
  try {
1468
- var _iteration$response4, _iteration$response4$;
1469
- await ((_iteration$response4 = iteration.response) === null || _iteration$response4 === void 0 || (_iteration$response4$ = _iteration$response4.handler) === null || _iteration$response4$ === void 0 ? void 0 : _iteration$response4$.call(_iteration$response4, generated.output.trim(), generated.messageMetadata));
1552
+ await iteration.response.handler(generated.output.trim(), generated.messageMetadata);
1470
1553
  } catch (cause) {
1471
1554
  if (isCriticalError(cause)) throw cause;
1472
1555
  throw new DeliveryError(`Assistant response delivery failed: ${getErrorMessage(cause)}`, { cause });
1473
1556
  }
1557
+ ctx.session.recordAssistantDelivery(iteration.id);
1474
1558
  iteration.recordTrace({
1475
1559
  type: "message_delivery",
1476
1560
  value: message,
@@ -1508,6 +1592,31 @@ async function settleJavaScriptCall(state, execution) {
1508
1592
  inspected: (outcome === null || outcome === void 0 ? void 0 : outcome.type) === "inspect"
1509
1593
  };
1510
1594
  if ((outcome === null || outcome === void 0 ? void 0 : outcome.type) === "inspect" && result.success) result.return_value = outcome.value;
1595
+ const forcedInspections = api.getForcedInspections();
1596
+ if (forcedInspections.length && !controller.signal.aborted && !isCriticalError(result.error)) {
1597
+ if (!result.success && result.error) {
1598
+ iteration.recordError(result.error);
1599
+ state.capture.downstreamError = result.error;
1600
+ }
1601
+ state.capture.forcedInspections = forcedInspections;
1602
+ let value = forcedInspections.length === 1 ? forcedInspections[0].value : forcedInspections.map((entry) => entry.value);
1603
+ if ((outcome === null || outcome === void 0 ? void 0 : outcome.type) === "inspect") value = outcome.value;
1604
+ state.capture.result = {
1605
+ ...result,
1606
+ success: true,
1607
+ signal: void 0,
1608
+ return_value: value
1609
+ };
1610
+ iteration.end({
1611
+ type: "thinking_requested",
1612
+ thinking_requested: {
1613
+ reason: "Tools completed successfully and requested forced inspection.",
1614
+ variables: value,
1615
+ metadata: forcedInspections.length === 1 ? forcedInspections[0].metadata : void 0
1616
+ }
1617
+ });
1618
+ return;
1619
+ }
1511
1620
  if ((outcome === null || outcome === void 0 ? void 0 : outcome.type) === "exit") {
1512
1621
  await completeJavaScriptExit(state, result, outcome);
1513
1622
  return;
@@ -1567,11 +1676,11 @@ function containsDecision(value, api, seen = /* @__PURE__ */ new Set()) {
1567
1676
  return Object.values(value).some((nested) => containsDecision(nested, api, seen));
1568
1677
  }
1569
1678
  async function completeJavaScriptExit(state, result, outcome) {
1570
- const { iteration, controller, props } = state;
1679
+ const { iteration, controller } = state;
1571
1680
  state.memory = commitMemory(state, result, false);
1572
1681
  try {
1573
1682
  controller.signal.throwIfAborted();
1574
- await applyNativeExit(iteration, outcome.exit, outcome.value, controller, props.onExit);
1683
+ await applyNativeExit(state, outcome.exit, outcome.value);
1575
1684
  } catch (error) {
1576
1685
  endFailedIteration(iteration, controller, error);
1577
1686
  }
@@ -1603,6 +1712,7 @@ async function deliverJavaScriptMessages({ ctx, iteration, controller }, message
1603
1712
  });
1604
1713
  throw isCriticalError(error) ? error : new DeliveryError(`Delivery ${message.id} failed: ${getErrorMessage(error)}. Its external outcome is uncertain. Later messages were skipped; earlier acknowledged messages remain delivered.`, { cause: error });
1605
1714
  }
1715
+ ctx.session.recordAssistantDelivery(iteration.id);
1606
1716
  iteration.recordTrace({
1607
1717
  type: "message_delivery",
1608
1718
  value: message.component,
@@ -1615,9 +1725,9 @@ async function deliverJavaScriptMessages({ ctx, iteration, controller }, message
1615
1725
  }
1616
1726
  }
1617
1727
  async function finishNativeResponse(state, generated) {
1618
- const { ctx, iteration, controller, props } = state;
1619
- if (!generated.toolCalls.length && generated.output.trim() && ctx.chat) {
1620
- await applyNativeExit(iteration, ListenExit, {}, controller, props.onExit);
1728
+ const { ctx, iteration } = state;
1729
+ if (!generated.toolCalls.length && ctx.chat && (generated.output.trim() || generated.metadata.stopReason === "stop")) {
1730
+ await applyNativeExit(state, ListenExit, {});
1621
1731
  if (!iteration.hasExited()) ctx.session.appendContext(ctx.inspector(iteration.error ?? "Completion rejected.", {
1622
1732
  purpose: "error",
1623
1733
  maxTokens: 200
@@ -1716,7 +1826,9 @@ function getExecutionOutcome(state, memory) {
1716
1826
  type: "inspect",
1717
1827
  value: (capture === null || capture === void 0 ? void 0 : capture.result.success) ? capture.result.return_value : void 0,
1718
1828
  available: memory.resultAvailable,
1719
- explicit: (capture === null || capture === void 0 ? void 0 : capture.inspected) ?? false
1829
+ explicit: (capture === null || capture === void 0 ? void 0 : capture.inspected) ?? false,
1830
+ forcedInspections: capture === null || capture === void 0 ? void 0 : capture.forcedInspections,
1831
+ downstreamError: capture === null || capture === void 0 ? void 0 : capture.downstreamError
1720
1832
  };
1721
1833
  }
1722
1834
  return {
@@ -1808,12 +1920,18 @@ function getIterationResult(state) {
1808
1920
  }
1809
1921
  if (iteration.status.type === "aborted") return new ErrorExecutionResult(ctx, iteration.error);
1810
1922
  }
1811
- async function applyNativeExit(iteration, exit, value, controller, onExit) {
1923
+ async function applyNativeExit(state, exit, value) {
1924
+ const { ctx, iteration, controller, props } = state;
1812
1925
  try {
1813
- await callHook(() => onExit === null || onExit === void 0 ? void 0 : onExit({
1814
- exit,
1815
- result: value
1816
- }, controller));
1926
+ var _props$options9;
1927
+ if (ctx.chat && exit === ListenExit && ((_props$options9 = props.options) === null || _props$options9 === void 0 ? void 0 : _props$options9.requireChatResponse) !== false && ctx.session.lastSpeaker !== "assistant") throw new MissingChatResponseError("The assistant has not delivered a message since the last user message. Send a response using the inspected results before waiting for the user. Do not repeat completed tool calls.");
1928
+ await callHook(() => {
1929
+ var _props$onExit;
1930
+ return (_props$onExit = props.onExit) === null || _props$onExit === void 0 ? void 0 : _props$onExit.call(props, {
1931
+ exit,
1932
+ result: value
1933
+ }, controller);
1934
+ });
1817
1935
  controller.signal.throwIfAborted();
1818
1936
  iteration.end({
1819
1937
  type: "exit_success",