llmz 1.0.1 → 1.0.3

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 (55) 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-MytucGI-.cjs → custom-client-BwRYQ4Oa.cjs} +37 -13
  7. package/dist/{custom-client-BDkgBR2w.js → custom-client-JcdoH-47.js} +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-DLas4V2n.cjs → execute-DJBNrA2H.cjs} +209 -79
  13. package/dist/{execute-BYI_U5sR.js → execute-DoN74Exa.js} +209 -79
  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 +404 -88
  20. package/dist/inspection.d.ts +2 -0
  21. package/dist/{native-DvTH9vFe.js → native-BGW5kBlv.js} +136 -10
  22. package/dist/{native-Bm6L9zOb.cjs → native-sbuzbLbY.cjs} +136 -10
  23. package/dist/prompts/native-examples.d.ts +10 -0
  24. package/dist/prompts/native-examples.test.d.ts +1 -0
  25. package/dist/prompts/reasoning.d.ts +2 -0
  26. package/dist/prompts/reasoning.test.d.ts +1 -0
  27. package/dist/{quickjs-variant-DJwYDSsb.cjs → quickjs-variant-21IO97PF.cjs} +15 -8
  28. package/dist/{quickjs-variant-DlPi9-Sx.js → quickjs-variant-CtuGagsb.js} +10 -9
  29. package/dist/runtime/chat-completion.test.d.ts +1 -0
  30. package/dist/runtime/chat-last-speaker.test.d.ts +1 -0
  31. package/dist/runtime/empty-completion.test.d.ts +1 -0
  32. package/dist/runtime/execution-report.d.ts +3 -0
  33. package/dist/runtime/forced-inspection.d.ts +13 -0
  34. package/dist/runtime/forced-inspection.test.d.ts +1 -0
  35. package/dist/runtime/javascript-api.d.ts +3 -0
  36. package/dist/runtime/think-signal.test.d.ts +1 -0
  37. package/dist/runtime/tool-wrapper.d.ts +4 -2
  38. package/dist/runtime/types.d.ts +8 -0
  39. package/dist/{schema-DBkjo0b7.cjs → schema-CXlnbb3n.cjs} +1 -1
  40. package/dist/{schema-Aer_W7Al.js → schema-GE4ISPCR.js} +1 -1
  41. package/dist/session/messages.d.ts +2 -0
  42. package/dist/session/serialization.d.ts +2 -0
  43. package/dist/session/session.d.ts +4 -0
  44. package/dist/session/speaker.test.d.ts +1 -0
  45. package/dist/{tool--gK91eez.js → tool-DstssiAs.js} +4 -4
  46. package/dist/{tool-Da_F-N-5.cjs → tool-_wK9hQOb.cjs} +4 -4
  47. package/dist/{truncate-BSoH2-nY.js → truncate-BEKbdo3t.js} +1 -1
  48. package/dist/{truncate-nV3Mxr6-.cjs → truncate-uomAMGPs.cjs} +1 -1
  49. package/dist/types.d.ts +6 -0
  50. package/dist/{typings-C1ihexWE.cjs → typings-BA_XxAcY.cjs} +1 -1
  51. package/dist/{typings-D9_aC8aq.js → typings-BEVDvtuk.js} +1 -1
  52. package/dist/vm/types.d.ts +2 -0
  53. package/dist/{vm-8jxt8PTK.js → vm-C7SfutHn.js} +28 -3
  54. package/dist/{vm-XuVPuW3Y.cjs → vm-gmekHc0i.cjs} +28 -2
  55. package/package.json +2 -1
@@ -49,7 +49,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
49
49
  }) : target, mod));
50
50
  //#endregion
51
51
  //#region package.json
52
- var version = "1.0.1";
52
+ var version = "1.0.3";
53
53
  //#endregion
54
54
  //#region src/errors/catalog.ts
55
55
  function validationMessage(subject, issues, expectedInput) {
@@ -68,7 +68,7 @@ function isLLMzError(error, code) {
68
68
  function isCriticalError(error) {
69
69
  return isLLMzError(error) && error.critical;
70
70
  }
71
- var ERROR_BRAND, LLMzError, CodeExecutionError, InvalidCodeError, CodeFormattingError, ToolInputError, ExitInputError, ObjectPropertyError, ComponentInputError, UnknownToolError, UnknownComponentError, UnknownExitError, ReservedIdentifierError, ToolExecutionError, LoopExceededError, TokenOverflowError, MemoryCapacityError, AssignmentError, CognitiveError, CompactionError, InvalidToolError, InvalidObjectError, InvalidExitError, InvalidComponentError, InvalidConfigurationError, InvalidMessageError, InvalidEventError, InvalidSessionError, SessionStateError, MemoryValueError, NativeProtocolError, HostOperationError, DeliveryError, HookError, ExecutionAbortedError, InternalError, errorClasses$1, ERROR_CODES;
71
+ var ERROR_BRAND, LLMzError, CodeExecutionError, InvalidCodeError, CodeFormattingError, ToolInputError, ExitInputError, ObjectPropertyError, ComponentInputError, UnknownToolError, UnknownComponentError, UnknownExitError, ReservedIdentifierError, ToolExecutionError, LoopExceededError, TokenOverflowError, MemoryCapacityError, AssignmentError, CognitiveError, CompactionError, InvalidToolError, InvalidObjectError, InvalidExitError, InvalidComponentError, InvalidConfigurationError, InvalidMessageError, InvalidEventError, InvalidSessionError, SessionStateError, MemoryValueError, NativeProtocolError, HostOperationError, MissingChatResponseError, DeliveryError, HookError, ExecutionAbortedError, InternalError, errorClasses$1, ERROR_CODES;
72
72
  var init_catalog = __esmMin((() => {
73
73
  ERROR_BRAND = Symbol.for("llmz.error.v1");
74
74
  LLMzError = class extends Error {
@@ -358,6 +358,13 @@ var init_catalog = __esmMin((() => {
358
358
  super(message, false, options);
359
359
  }
360
360
  };
361
+ MissingChatResponseError = class extends LLMzError {
362
+ static is = (value) => isLLMzError(value, "MISSING_CHAT_RESPONSE");
363
+ code = "MISSING_CHAT_RESPONSE";
364
+ constructor(message, options) {
365
+ super(message, false, options);
366
+ }
367
+ };
361
368
  DeliveryError = class extends LLMzError {
362
369
  static is = (value) => isLLMzError(value, "DELIVERY_FAILED");
363
370
  code = "DELIVERY_FAILED";
@@ -418,6 +425,7 @@ var init_catalog = __esmMin((() => {
418
425
  NativeProtocolError,
419
426
  HostOperationError,
420
427
  DeliveryError,
428
+ MissingChatResponseError,
421
429
  HookError,
422
430
  ExecutionAbortedError,
423
431
  InternalError
@@ -454,6 +462,7 @@ var init_catalog = __esmMin((() => {
454
462
  "INVALID_NATIVE_CALL",
455
463
  "HOST_OPERATION_FAILED",
456
464
  "DELIVERY_FAILED",
465
+ "MISSING_CHAT_RESPONSE",
457
466
  "HOOK_FAILED",
458
467
  "EXECUTION_ABORTED",
459
468
  "INTERNAL_ERROR"
@@ -6175,7 +6184,7 @@ function createInspector(onInspect) {
6175
6184
  if (onInspect) try {
6176
6185
  const budget = resolveInspectionBudget(value, formatting);
6177
6186
  const output = onInspect(Object.freeze({
6178
- value: snapshot(value),
6187
+ value: snapshotInspectionValue(value),
6179
6188
  purpose: options.purpose,
6180
6189
  maxTokens: budget.tokens,
6181
6190
  preserve: budget.preserve,
@@ -6187,12 +6196,13 @@ function createInspector(onInspect) {
6187
6196
  return inspect(value, void 0, formatting);
6188
6197
  };
6189
6198
  }
6190
- function snapshot(value, copies = /* @__PURE__ */ new WeakMap()) {
6199
+ /** Isolate evidence from subsequent guest mutations without invoking getters. */
6200
+ function snapshotInspectionValue(value, copies = /* @__PURE__ */ new WeakMap()) {
6191
6201
  if (!value || typeof value !== "object") return typeof value === "function" ? "[Function]" : value;
6192
6202
  if (copies.has(value)) return copies.get(value);
6193
6203
  if (isTruncated(value)) {
6194
6204
  copies.set(value, "[Circular]");
6195
- const copy = snapshot(value.value, copies);
6205
+ const copy = snapshotInspectionValue(value.value, copies);
6196
6206
  copies.set(value, copy);
6197
6207
  return copy;
6198
6208
  }
@@ -6203,7 +6213,7 @@ function snapshot(value, copies = /* @__PURE__ */ new WeakMap()) {
6203
6213
  if (Array.isArray(value) && key === "length") continue;
6204
6214
  const descriptor = Object.getOwnPropertyDescriptor(value, key);
6205
6215
  if (descriptor) Object.defineProperty(copy, key, {
6206
- value: "value" in descriptor ? snapshot(descriptor.value, copies) : "[Getter]",
6216
+ value: "value" in descriptor ? snapshotInspectionValue(descriptor.value, copies) : "[Getter]",
6207
6217
  enumerable: descriptor.enumerable
6208
6218
  });
6209
6219
  }
@@ -8464,6 +8474,10 @@ function normalizeMessage(message) {
8464
8474
  validateInputMessage(normalized);
8465
8475
  return normalized;
8466
8476
  }
8477
+ /** Only actual participant content counts as speech, including image/audio-only messages. */
8478
+ function inputSpeaker(message) {
8479
+ return (Array.isArray(message.content) ? message.content.some((part) => part.type !== "text" || Boolean(part.text?.trim())) : Boolean(message.content?.trim())) && (message.role === "user" || message.role === "assistant") ? message.role : null;
8480
+ }
8467
8481
  function createAssistantMessage(response) {
8468
8482
  if (response.assistantMessage) return asSessionMessage(response.assistantMessage);
8469
8483
  const message = {
@@ -8635,6 +8649,7 @@ function validateRestoredHistory(state) {
8635
8649
  if (!Array.isArray(state.groups) || !Array.isArray(state.pendingInputs)) throw new InvalidSessionError("Session history and queued inputs must be arrays.");
8636
8650
  if (!Number.isSafeInteger(state.turn) || state.turn < 0 || !Number.isSafeInteger(state.iteration) || state.iteration < 0) throw new InvalidSessionError("Session turn and iteration counters must be non-negative safe integers");
8637
8651
  if (typeof state.activeTurn !== "boolean" || state.activeTurn && (!state.turn || !state.turnId)) throw new InvalidSessionError("Session processing state must identify an active turn.");
8652
+ if (state.lastSpeaker !== void 0 && state.lastSpeaker !== null && !["user", "assistant"].includes(state.lastSpeaker)) throw new InvalidSessionError("Session last speaker must be user, assistant, or null.");
8638
8653
  const groupIds = /* @__PURE__ */ new Set();
8639
8654
  const callIds = /* @__PURE__ */ new Set();
8640
8655
  let previousIteration = 0;
@@ -8749,6 +8764,7 @@ var init_session = __esmMin((() => {
8749
8764
  #pendingInputs = [];
8750
8765
  #activeTurn = false;
8751
8766
  #locked = false;
8767
+ #lastSpeaker = null;
8752
8768
  constructor(options = {}) {
8753
8769
  this.id = `session_${ulid()}`;
8754
8770
  this.memory = new Memory({
@@ -8773,6 +8789,15 @@ var init_session = __esmMin((() => {
8773
8789
  get transcript() {
8774
8790
  return structuredClone([...this.#allGroups().flatMap((group) => group.source ? [group.source] : group.messages), ...this.#pendingInputs.map((input) => input.source ?? input.message)]);
8775
8791
  }
8792
+ /** Last participant who spoke in the active history. Events and queued inputs do not count. */
8793
+ get lastSpeaker() {
8794
+ return this.#lastSpeaker;
8795
+ }
8796
+ /** Record acknowledged text or component delivery, never generation alone. */
8797
+ recordAssistantDelivery(iterationId) {
8798
+ this.#getActiveIteration(iterationId);
8799
+ this.#lastSpeaker = "assistant";
8800
+ }
8776
8801
  get pendingMessages() {
8777
8802
  return structuredClone(this.#pendingInputs.map((input) => input.message));
8778
8803
  }
@@ -8861,12 +8886,15 @@ var init_session = __esmMin((() => {
8861
8886
  this.#turn++;
8862
8887
  this.#turnId = `turn_${ulid()}`;
8863
8888
  this.#activeTurn = true;
8864
- for (const input of this.#pendingInputs) this.#groups.push({
8865
- id: input.id,
8866
- turn: this.#turn,
8867
- messages: [input.message],
8868
- ...input.source ? { source: input.source } : {}
8869
- });
8889
+ for (const input of this.#pendingInputs) {
8890
+ if (!input.source) this.#lastSpeaker = inputSpeaker(input.message) ?? this.#lastSpeaker;
8891
+ this.#groups.push({
8892
+ id: input.id,
8893
+ turn: this.#turn,
8894
+ messages: [input.message],
8895
+ ...input.source ? { source: input.source } : {}
8896
+ });
8897
+ }
8870
8898
  this.#pendingInputs = [];
8871
8899
  }
8872
8900
  /** Mark the active input batch complete without consuming newly queued input. */
@@ -9167,6 +9195,7 @@ var init_session = __esmMin((() => {
9167
9195
  groups: this.#groups.map(serializeGroup),
9168
9196
  memory: this.memory.serialize(),
9169
9197
  pendingInputs: structuredClone(this.#pendingInputs),
9198
+ lastSpeaker: this.#lastSpeaker,
9170
9199
  activeTurn: this.#activeTurn,
9171
9200
  latestResultId: this.#latestResultId,
9172
9201
  compaction
@@ -9185,6 +9214,7 @@ var init_session = __esmMin((() => {
9185
9214
  session.#groups = state.groups.map(restoreGroup);
9186
9215
  session.#pendingInputs = structuredClone(state.pendingInputs);
9187
9216
  session.#activeTurn = state.activeTurn;
9217
+ session.#lastSpeaker = state.lastSpeaker ?? null;
9188
9218
  session.#latestResultId = state.latestResultId;
9189
9219
  Object.defineProperty(session, "memory", {
9190
9220
  value: Memory.restore(state.memory, () => session.#resultBytes()),
@@ -9622,7 +9652,7 @@ function getRunJavaScriptTool(chat) {
9622
9652
  if (chat) return RUN_JAVASCRIPT_TOOL;
9623
9653
  return {
9624
9654
  ...RUN_JAVASCRIPT_TOOL,
9625
- description: `${WORKER_RESPONSE_INSTRUCTION} See "run_javascript syntax" and the documented functions and memory.`
9655
+ description: `${WORKER_RESPONSE_INSTRUCTION} ${EXECUTION_DESCRIPTION}`
9626
9656
  };
9627
9657
  }
9628
9658
  /** Validate the entire response before any delivery or business action begins. */
@@ -9658,18 +9688,23 @@ function validateNativeToolCalls(calls) {
9658
9688
  }
9659
9689
  };
9660
9690
  }
9661
- var WORKER_RESPONSE_INSTRUCTION, RUN_JAVASCRIPT_TOOL;
9691
+ var WORKER_RESPONSE_INSTRUCTION, EXECUTION_DESCRIPTION, RUN_JAVASCRIPT_TOOL;
9662
9692
  var init_native_tools = __esmMin((() => {
9663
9693
  WORKER_RESPONSE_INSTRUCTION = "You are running in worker mode. Respond only with a run_javascript tool call. Keep assistant text empty: do not send messages, preambles, progress updates, explanations, acknowledgements such as \"Done\", Markdown, or JSON outside the tool call. This applies before and after tools, during recovery, and when completing the task.";
9694
+ EXECUTION_DESCRIPTION = "Execute a JavaScript program in the sandbox. This is the only native tool; business functions are called INSIDE its code, using their documented signatures. It is not a search engine: never submit search terms, user questions, answers, or business tool names as code. Await business calls, then return inspect(value) to read their results, or return exit(name, payload) to select a registered outcome. See \"run_javascript syntax\" and the examples.";
9664
9695
  RUN_JAVASCRIPT_TOOL = {
9665
9696
  name: "run_javascript",
9666
- description: "Run business tools, send requested chat components, or finish a worker task by executing JavaScript. For text plus actions, write the requested text as a preamble to this tool call; do not end with a text-only answer before the actions. Exact requested text needs no separator before this call: do not append a space or newline to the preamble. An ordinary chat reply with no remaining action needs no tool call just to finish the turn. Code displayed in an answer is text, not a program to execute. See \"run_javascript syntax\" and the documented functions and memory.",
9697
+ description: `${EXECUTION_DESCRIPTION} For a requested text message plus an action or component, include the assistant text AND this tool call in the same response. A plain assistant reply needs no tool call when no action remains.`,
9667
9698
  parameters: {
9668
9699
  type: "object",
9669
9700
  properties: { code: {
9670
9701
  type: "string",
9671
- minLength: 1,
9672
- description: "JavaScript source with an explicit return statement. Top-level await is supported."
9702
+ description: [
9703
+ "The body of an async JavaScript program. Top-level await and return are supported. No Markdown fences, XML wrappers, imports, or TypeScript annotations.",
9704
+ "Call business functions using the actual API declarations. A string parameter takes a string; an object parameter takes its documented fields. Do not put a query or reply here instead of a program.",
9705
+ "<example purpose=\"JavaScript syntax only\">const total = 17 + 25; return inspect(total);</example>",
9706
+ "The example tags are documentation only. The code value must contain only executable JavaScript. End with return inspect(value), or return exit(\"registered_name\", payload) with the actual outcome name and required payload. These are JavaScript functions, not separate native tools."
9707
+ ].join("\n\n")
9673
9708
  } },
9674
9709
  required: ["code"],
9675
9710
  additionalProperties: false
@@ -9677,6 +9712,120 @@ var init_native_tools = __esmMin((() => {
9677
9712
  };
9678
9713
  }));
9679
9714
  //#endregion
9715
+ //#region src/prompts/native-examples.ts
9716
+ /** Static examples teach syntax without guessing inputs for arbitrary application schemas. */
9717
+ function getNativeExamples(capabilities) {
9718
+ const examples = [];
9719
+ if (capabilities.chat) examples.push(example("answer_without_actions", `<situation>
9720
+ The user asks for the opening time. The task instructions already say the shop opens at 9 AM. No action is needed.
9721
+ </situation>
9722
+ ${turn(`<assistant_text>
9723
+ We open at 9 AM.
9724
+ </assistant_text>`)}
9725
+ <explanation>
9726
+ This is an ordinary assistant reply, with no native tool call. Its end gives the turn back to the user.
9727
+ </explanation>`));
9728
+ examples.push(example("execute_and_inspect", `<situation>
9729
+ Compute the total of 17 and 25, and inspect the computed value before continuing.
9730
+ </situation>
9731
+ ${turn(call("const total = 17 + 25; return inspect(total);"))}
9732
+ <tool_result>
9733
+ 42
9734
+ </tool_result>
9735
+ <explanation>
9736
+ The code property contains executable JavaScript. Returning inspect(total) makes the result visible in the next response. The variable total is retained; do not recompute it just to read it.
9737
+ </explanation>`));
9738
+ if (capabilities.tools) {
9739
+ examples.push(example("search_then_use_the_result", `<fictional_api>
9740
+ exampleSearch(query: string): Promise<string>
9741
+ </fictional_api>
9742
+ <situation>
9743
+ Find whether blue mugs are available. Availability must come from a search.
9744
+ </situation>
9745
+ ${turn(call("const products = await exampleSearch('blue mugs'); return inspect(products);"))}
9746
+ <tool_result>
9747
+ Blue mugs are available. Price: $12 each.
9748
+ </tool_result>
9749
+ ${capabilities.chat ? turn(`<assistant_text>
9750
+ Blue mugs are available for $12 each.
9751
+ </assistant_text>`) : `<next_step>
9752
+ Use the inspected facts and retained products variable to continue the task. Do not repeat the successful search.
9753
+ </next_step>`}
9754
+ <explanation>
9755
+ The search phrase is a string argument to the business function. It is not executable JavaScript by itself. Await the function, then return inspect with its actual result. Do not write an answer before seeing that result.
9756
+ </explanation>`));
9757
+ examples.push(example("object_arguments_and_independent_calls", `<fictional_api>
9758
+ exampleReadStock(input: { itemId: string }): Promise<{ count: number }>
9759
+ exampleReadPrice(input: { itemId: string }): Promise<{ amount: number }>
9760
+ </fictional_api>
9761
+ <situation>
9762
+ Read stock and price for the same item. Neither read depends on the other.
9763
+ </situation>
9764
+ ${turn(call("const [stock, price] = await Promise.all([exampleReadStock({ itemId: 'MUG-7' }), exampleReadPrice({ itemId: 'MUG-7' })]); return inspect({ stock, price });"))}
9765
+ <explanation>
9766
+ These functions accept objects, unlike exampleSearch which accepts a string. Match the declared arguments. Both calls are awaited inside one program and their results are inspected together.
9767
+ </explanation>`));
9768
+ examples.push(example("repair_a_search_phrase_submitted_as_code", `<fictional_api>
9769
+ exampleSearch(query: string): Promise<string>
9770
+ </fictional_api>
9771
+ <situation>
9772
+ The user asked about red mugs. The previous attempt submitted the words red mugs as JavaScript and failed to parse. No business tool ran.
9773
+ </situation>
9774
+ ${turn(call("const matches = await exampleSearch('red mugs'); return inspect(matches);"))}
9775
+ <explanation>
9776
+ Repair the program by calling the actual business function. Do not resubmit the bare search phrase, quote the phrase as the entire program, or answer without retrieving the facts.
9777
+ </explanation>`));
9778
+ }
9779
+ if (capabilities.exits) examples.push(example("complete_with_a_typed_result", `<fictional_api>
9780
+ exit(name: "example_complete", payload: { total: number }): never
9781
+ </fictional_api>
9782
+ <situation>
9783
+ The required work is complete. The computed total, already inspected, is 42. Complete through the declared example_complete outcome.
9784
+ </situation>
9785
+ ${turn(call("return exit('example_complete', { total: 42 });"))}
9786
+ <explanation>
9787
+ The first argument is the outcome name string. The second argument is its payload, matching the declaration. Do not pass one object containing name and payload. Do not submit the outcome name alone as code or report completion as prose.
9788
+ </explanation>`));
9789
+ if (capabilities.chat && capabilities.components && capabilities.listen) examples.push(example("text_and_buttons_in_the_same_response", `<fictional_api>
9790
+ chat.exampleChoices(props: { options: Array<{ label: string, value: string }> }): void
9791
+ </fictional_api>
9792
+ <situation>
9793
+ The user requests an introduction in a text message, followed by buttons to shop or track an order.
9794
+ </situation>
9795
+ ${turn(`<assistant_text>
9796
+ Hi, I'm your shopping assistant. I can help you shop or track an order.
9797
+ </assistant_text>
9798
+ ${call("chat.exampleChoices({ options: [{ label: 'Shop', value: 'shop' }, { label: 'Track order', value: 'track' }] }); return exit('listen');")}`)}
9799
+ <explanation>
9800
+ Both the assistant text and the native tool call belong to ONE response. The text introduces the assistant; the program sends the buttons. Buttons alone would omit the requested text message. Text alone would omit the buttons. The component returns void and does not need inspection.
9801
+ </explanation>`));
9802
+ return [
9803
+ "<examples>",
9804
+ "These are hypothetical demonstrations, NOT live conversation, task history, or evidence. Do not perform their tasks or copy their facts.",
9805
+ "Names beginning with example are fictional and unavailable. Use the actual names and signatures under JavaScript API for your task.",
9806
+ "The XML tags are documentation boundaries only. NEVER emit these tags, a serialized assistant_turn, or a textual native_tool_call. Use your actual native tool-calling interface.",
9807
+ "Each assistant_turn shows one response. arguments contains the exact JSON shape to send to run_javascript; its code string is JavaScript. tool_result illustrates what the runtime reports afterward; never generate it yourself.",
9808
+ capabilities.chat ? "assistant_text means ordinary user-facing text, outside tool arguments. When text and a call appear in the same assistant_turn, produce both in that response. Follow the real task’s language, style and silence requirements." : "This is worker mode. Every demonstrated assistant_turn contains a native tool call and NO assistant text. Continue using calls after inspection as well.",
9809
+ ...examples,
9810
+ "Apply the demonstrated syntax to your actual task. The real API and task instructions are authoritative; fictional functions and facts are not available.",
9811
+ "</examples>"
9812
+ ].join("\n\n");
9813
+ }
9814
+ var call, turn, example;
9815
+ var init_native_examples = __esmMin((() => {
9816
+ call = (code) => `<native_tool_call name="run_javascript">
9817
+ <arguments>
9818
+ ${JSON.stringify({ code }, null, 2)}
9819
+ </arguments>
9820
+ </native_tool_call>`;
9821
+ turn = (content) => `<assistant_turn>
9822
+ ${content}
9823
+ </assistant_turn>`;
9824
+ example = (name, content) => `<example name="${name}">
9825
+ ${content}
9826
+ </example>`;
9827
+ }));
9828
+ //#endregion
9680
9829
  //#region src/prompts/native.ts
9681
9830
  var native_exports = /* @__PURE__ */ __exportAll({ getNativeSystemMessage: () => getNativeSystemMessage });
9682
9831
  function runtimeRules(props, chat) {
@@ -9703,7 +9852,7 @@ function runtimeRules(props, chat) {
9703
9852
  }
9704
9853
  rules.push("Execution may overlap the remaining response stream. The runtime waits for the stream, code, and queued message deliveries before the next response.", "# Memory", "Declare retained variables at top level with const or let. Bare assignment only updates a variable already declared in this program or listed in Memory. Named variables survive transcript compaction; assignment age records when they were set, not when the underlying data was fetched.", "Object properties are immutable snapshots. Replace a writable property completely, such as account.profile = { ...account.profile, age: 42 }; nested edits are forbidden and replacements are schema-validated.", "$return is the latest successful inspection result. $iterations is read-only retained history, newest first: [0] is the last settled iteration and [1] the preceding one. The current execution is not included. Entries without results still occupy indexes; check hasResult. Compaction prunes automatic results. Assign useful data to named variables to retain it independently.", "# Recovery", "Execution reports identify completed actions, inspected values, memory changes, and errors. Reuse preserved variables and completed actions; retry only failed work. Build completion payloads from those values, not by calling successful tools again. An inspection has already run the recorded calls; it is not a dry run.", "An operational error does not by itself finish the task. Inspect the actual error, repair its cause when safe and authorized, then retry. Unchanged retries do not establish that recovery is exhausted. If another response must diagnose the error, return inspect({ errors, completed }) or let the error reach the runtime. Honor task instructions defining terminal failure outcomes.");
9705
9854
  if (hasExits) rules.push("Use a failure exit only when recovery is unavailable, unsafe, forbidden, its budget is exhausted, or task instructions make the failure terminal. Do not select failure in advance for an unseen error. Do not turn an unexpected exception or rejected Promise.allSettled entry directly into failure completion: first expose it with inspect or let it reach the runtime, then diagnose the actual cause and available recovery tools. Explicit task instructions may define an error as terminal.");
9706
- rules.push("A thinking interruption stops the current program and requests another model response. Statements after the interruption have not run; continue with a new program without repeating completed actions.", "Respect tool-attempt limits separately from the model-response budget. An empty successful inspection result is not a failure.");
9855
+ rules.push("A tool may request forced inspection through ThinkSignal. The tool succeeded and its context is returned to JavaScript. Other calls and assignments continue normally. At the end of the program, forced inspection takes precedence over completion: review the reported results as an inspect() call, then continue from retained values without repeating successful calls.", "Respect tool-attempt limits separately from the model-response budget. An empty successful inspection result is not a failure.");
9707
9856
  return rules.join("\n\n");
9708
9857
  }
9709
9858
  async function describeRuntimeAPI(props, chat) {
@@ -9729,8 +9878,16 @@ async function getNativeSystemMessage(props) {
9729
9878
  const protocol = [
9730
9879
  runJavaScriptSyntax,
9731
9880
  runtimeRules(props, chat),
9732
- ...chat ? ["# Assistant response", (props.response ?? resolveResponse()).instructions] : []
9881
+ ...chat ? ["# Assistant response", (props.response ?? resolveResponse()).instructions] : [],
9882
+ getNativeExamples({
9883
+ chat,
9884
+ tools: declarations.length > 0,
9885
+ components: props.components.size > 0,
9886
+ exits: props.exits.length > 0,
9887
+ listen: props.exits.some((exit) => exit.name === "listen")
9888
+ })
9733
9889
  ].join("\n\n");
9890
+ const delivery = chat ? ["# Assistant text delivery", "When answering, write only the final user-facing answer, once. Do not output private thinking, drafts, or thinking tags. This governs assistant text only: still call required tools, send requested components, and provide requested progress updates. Preserve literal text or code the user explicitly asks you to reproduce."].join("\n\n") : "";
9734
9891
  return {
9735
9892
  message: {
9736
9893
  role: "system",
@@ -9740,13 +9897,14 @@ async function getNativeSystemMessage(props) {
9740
9897
  "These TypeScript declarations describe functions inside run_javascript. Object properties, their types, values, and read/write rules are listed in Memory.",
9741
9898
  tools,
9742
9899
  "# Task instructions",
9743
- instructions
9900
+ instructions,
9901
+ ...delivery ? [delivery] : []
9744
9902
  ].join("\n\n")
9745
9903
  },
9746
9904
  parts: {
9747
9905
  instructions,
9748
9906
  tools,
9749
- protocol
9907
+ protocol: [protocol, delivery].filter(Boolean).join("\n\n")
9750
9908
  }
9751
9909
  };
9752
9910
  }
@@ -9757,6 +9915,7 @@ var init_native = __esmMin((() => {
9757
9915
  init_native_tools();
9758
9916
  init_typings();
9759
9917
  init_utils$1();
9918
+ init_native_examples();
9760
9919
  runJavaScriptSyntax = [
9761
9920
  "# run_javascript syntax",
9762
9921
  "run_javascript is the only native tool. Call it with a JSON object containing exactly one property: \"code\", a non-empty string of JavaScript source.",
@@ -13901,10 +14060,11 @@ var init_errors = __esmMin((() => {
13901
14060
  }));
13902
14061
  //#endregion
13903
14062
  //#region src/vm/types.ts
13904
- var VM_PROGRAM_COMPLETE, VM_TERMINATION, VM_ON_ERROR;
14063
+ var VM_PROGRAM_COMPLETE, VM_TERMINATION, VM_CALL_SITE, VM_ON_ERROR;
13905
14064
  var init_types = __esmMin((() => {
13906
14065
  VM_PROGRAM_COMPLETE = Symbol("llmz.programComplete");
13907
14066
  VM_TERMINATION = Symbol("llmz.termination");
14067
+ VM_CALL_SITE = Symbol("llmz.callSite");
13908
14068
  VM_ON_ERROR = Symbol("llmz.onError");
13909
14069
  }));
13910
14070
  //#endregion
@@ -14043,6 +14203,15 @@ var init_node = __esmMin((() => {
14043
14203
  async execute(ctx) {
14044
14204
  const { transformed, consumer, context, traces, recordTrace, code, lines_executed, variables } = ctx;
14045
14205
  const state = instrumentContext(context, transformed, recordTrace, variables, lines_executed, consumer, findUserCodeStartLine(transformed), ctx.memoryNames);
14206
+ context[VM_CALL_SITE] = () => {
14207
+ const frame = (/* @__PURE__ */ new Error()).stack?.match(/<anonymous>:(\d+):(\d+)/);
14208
+ if (!frame) return;
14209
+ const position = consumer.originalPositionFor({
14210
+ line: Number(frame[1]) - 1,
14211
+ column: Number(frame[2])
14212
+ });
14213
+ return position.line ? Math.max(1, position.line - 3) : void 0;
14214
+ };
14046
14215
  const AsyncFunction = async function() {}.constructor;
14047
14216
  return finalizeMemoryCapture(await (async () => {
14048
14217
  const descriptors = Object.getOwnPropertyDescriptors(context);
@@ -14497,6 +14666,19 @@ var init_quickjs = __esmMin((() => {
14497
14666
  const disposeIfNeeded = (handle) => {
14498
14667
  if (handle !== vm.true && handle !== vm.false && handle !== vm.null && handle !== vm.undefined) handle.dispose();
14499
14668
  };
14669
+ context[VM_CALL_SITE] = () => {
14670
+ const stack = vm.evalCode("new Error().stack");
14671
+ if ("error" in stack) {
14672
+ stack.error?.dispose();
14673
+ return;
14674
+ }
14675
+ try {
14676
+ const frame = vm.getString(stack.value).match(/<quickjs>:(\d+)/);
14677
+ return frame ? Math.max(1, Number(frame[1]) - 9 - userCodeStartLine + 1) : void 0;
14678
+ } finally {
14679
+ stack.value.dispose();
14680
+ }
14681
+ };
14500
14682
  const bridgeFunction = (fn, _fnName = "anonymous") => {
14501
14683
  return (...argHandles) => {
14502
14684
  const args = argHandles.map((h) => vm.dump(h));
@@ -14991,10 +15173,7 @@ var init_execution_activity = __esmMin((() => {
14991
15173
  //#region src/runtime/execution-diagnostics.ts
14992
15174
  /** XML-style boundaries keep diagnostic text separate from recovery instructions. */
14993
15175
  function reportSection(name, content, maxTokens = 2e3, options = {}) {
14994
- const escape = (value) => value.replace(/&/g, "&amp;").replace(/</g, "&lt;");
14995
- const heading = options.heading ? `${escape(options.heading)}\n` : "";
14996
- const body = limitInspectionOutput(content, maxTokens, false, options.preserve ?? "top");
14997
- return `<${name}>\n${heading}${/[<&]|\]\]>/.test(body) ? `<![CDATA[\n${body.replaceAll("]]>", "]]]]><![CDATA[>")}\n]]>` : body}\n</${name}>`;
15176
+ return `<${name}>\n${options.heading ? `${options.heading}\n` : ""}${limitInspectionOutput(content, maxTokens, false, options.preserve ?? "top")}\n</${name}>`;
14998
15177
  }
14999
15178
  /** Show the specific failure and guest source, never the host's implementation stack. */
15000
15179
  function renderExecutionDiagnostics(error, message, inspector, identity) {
@@ -15039,6 +15218,56 @@ var init_execution_diagnostics = __esmMin((() => {
15039
15218
  init_inspect();
15040
15219
  }));
15041
15220
  //#endregion
15221
+ //#region src/runtime/forced-inspection.ts
15222
+ /** Keep attribution and content together, using the same display budgets as inspect(). */
15223
+ function renderForcedInspection(inspections, inspector, identity, maxTokens, policies) {
15224
+ return [
15225
+ "<forced_inspection>",
15226
+ "Forced inspection: the tools listed below completed successfully and requested review of their results.",
15227
+ "This is the equivalent of an inspect() call. Do not repeat these tool calls; use the results below and retained variables.",
15228
+ "No exit was applied. Review the evidence before continuing or completing the task.",
15229
+ "",
15230
+ "Tools requesting inspection (lines refer to the executed JavaScript):",
15231
+ ...inspections.map((entry) => {
15232
+ const entryIdentity = {
15233
+ ...identity,
15234
+ tool: entry.tool
15235
+ };
15236
+ const name = inspector(entry.tool, {
15237
+ purpose: "name",
15238
+ maxTokens: 80,
15239
+ identity: entryIdentity
15240
+ });
15241
+ const reason = inspector(entry.reason, {
15242
+ purpose: "error",
15243
+ maxTokens: 1e3,
15244
+ identity: entryIdentity
15245
+ });
15246
+ const budget = resolveInspectionBudget(entry.value, {
15247
+ tokens: maxTokens,
15248
+ policies
15249
+ });
15250
+ const result = inspector(entry.value, {
15251
+ purpose: "result",
15252
+ maxTokens,
15253
+ policies,
15254
+ identity: entryIdentity
15255
+ });
15256
+ return [
15257
+ `<tool name="${name}" line="${entry.line ?? "unknown"}">`,
15258
+ `<reason>${reason}</reason>`,
15259
+ reportSection("result", result, budget.tokens, { preserve: budget.preserve }),
15260
+ "</tool>"
15261
+ ].join("\n");
15262
+ }),
15263
+ "</forced_inspection>"
15264
+ ].join("\n");
15265
+ }
15266
+ var init_forced_inspection = __esmMin((() => {
15267
+ init_inspect();
15268
+ init_execution_diagnostics();
15269
+ }));
15270
+ //#endregion
15042
15271
  //#region src/runtime/execution-report.ts
15043
15272
  /** Format one settled outcome; execution is responsible for deciding what happened. */
15044
15273
  function renderExecutionReport({ outcome, activity, memory, source, requiresExit = false, iteration, identity = { iteration }, inspector = createInspector(), maxTokens = DEFAULT_TOOL_RESULT_MAX_TOKENS, policies }) {
@@ -15068,6 +15297,13 @@ function renderExecutionReport({ outcome, activity, memory, source, requiresExit
15068
15297
  });
15069
15298
  };
15070
15299
  const sections = [renderStatus(outcome, memory)];
15300
+ if (outcome.type === "inspect" && outcome.forcedInspections?.length) {
15301
+ sections.push(renderForcedInspection(outcome.forcedInspections, inspector, identity, maxTokens, policies));
15302
+ if (outcome.downstreamError) {
15303
+ sections.push(...renderExecutionDiagnostics(outcome.downstreamError, getErrorMessage(outcome.downstreamError), inspector, identity));
15304
+ 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."));
15305
+ }
15306
+ }
15071
15307
  if (outcome.type === "error") {
15072
15308
  sections.push(...renderExecutionDiagnostics(outcome.error, outcome.message, inspector, identity));
15073
15309
  sections.push(reportSection("recovery", [
@@ -15100,7 +15336,7 @@ function renderExecutionReport({ outcome, activity, memory, source, requiresExit
15100
15336
  if (memory.unavailable.length > failures.length) entries.push(`- ${memory.unavailable.length - failures.length} additional values could not be retained.`);
15101
15337
  sections.push(reportSection("memory_errors", `Memory errors\n${entries.join("\n")}`));
15102
15338
  }
15103
- if (outcome.type === "inspect") {
15339
+ if (outcome.type === "inspect" && outcome.forcedInspections?.length && (!outcome.explicit || outcome.forcedInspections.some((entry) => isEqual(entry.value, outcome.value)))) {} else if (outcome.type === "inspect") {
15104
15340
  const heading = outcome.explicit ? "inspect() result" : "Result";
15105
15341
  sections.push(outcome.available ? resultSection("result", heading, outcome.value) : reportSection("result", "Unavailable; see memory errors above.", maxTokens, { heading }));
15106
15342
  } else if (outcome.type === "exit") sections.push(resultSection("completion", `Completion\nExit "${outcome.name}" completed.`, outcome.value === void 0 ? "" : outcome.value));
@@ -15149,16 +15385,26 @@ function renderChanges(label, changes, name) {
15149
15385
  }
15150
15386
  var MAX_REPORTED_CHANGES, MAX_OVERRIDE_SOURCE_LENGTH;
15151
15387
  var init_execution_report = __esmMin((() => {
15388
+ init_lodash();
15152
15389
  init_errors$1();
15153
15390
  init_inspect();
15154
15391
  init_inspection();
15155
15392
  init_truncate();
15393
+ init_utils$1();
15156
15394
  init_execution_activity();
15157
15395
  init_execution_diagnostics();
15396
+ init_forced_inspection();
15158
15397
  MAX_REPORTED_CHANGES = 40;
15159
15398
  MAX_OVERRIDE_SOURCE_LENGTH = 3e3;
15160
15399
  }));
15161
15400
  //#endregion
15401
+ //#region src/prompts/reasoning.ts
15402
+ /** Supplement explicit reasoning disablement consistently across providers and fallbacks. */
15403
+ function getReasoningHint(reasoningEffort) {
15404
+ return reasoningEffort === "none" ? "/no_think" : void 0;
15405
+ }
15406
+ var init_reasoning = __esmMin((() => {}));
15407
+ //#endregion
15162
15408
  //#region src/runtime/generate.ts
15163
15409
  function assertSuccessfulGeneration(metadata) {
15164
15410
  if (!metadata || metadata.provider === "unknown") throw new CognitiveError("LLM generation failed: missing successful provider metadata");
@@ -15242,7 +15488,13 @@ async function prepareNativeRequest({ iteration, ctx, cognitive, controller, met
15242
15488
  const model = models[0];
15243
15489
  const { limit, output: reserve } = resolveTokenBudget(models, ctx.maxTokens);
15244
15490
  const tools = [getRunJavaScriptTool(!!ctx.chat)];
15245
- const system = [iteration.systemMessage];
15491
+ const systemMessage = structuredClone(iteration.systemMessage);
15492
+ const reasoningHint = getReasoningHint(iteration.reasoningEffort);
15493
+ if (reasoningHint) systemMessage.content = typeof systemMessage.content === "string" ? `${systemMessage.content}\n\n${reasoningHint}` : [...systemMessage.content ?? [], {
15494
+ type: "text",
15495
+ text: reasoningHint
15496
+ }];
15497
+ const system = [systemMessage];
15246
15498
  const budgetInstruction = getBudgetInstruction(ctx, iteration);
15247
15499
  const budget = `\n\nExecution budget: response ${ctx.iterations.length} of ${ctx.loop}. ${budgetInstruction}`;
15248
15500
  const buildMessages = (retainedIds, summary) => {
@@ -15551,6 +15803,7 @@ var init_generate = __esmMin((() => {
15551
15803
  init_abort_signal();
15552
15804
  init_hooks();
15553
15805
  init_errors$1();
15806
+ init_reasoning();
15554
15807
  init_compactor();
15555
15808
  init_json();
15556
15809
  init_utils$1();
@@ -15650,6 +15903,7 @@ var init_inspection_values = __esmMin((() => {
15650
15903
  function createJavaScriptApi({ iteration, components, exits, deliver, signal, onError }) {
15651
15904
  const decisions = /* @__PURE__ */ new Map();
15652
15905
  const pending = /* @__PURE__ */ new Set();
15906
+ const inspections = [];
15653
15907
  let open = true;
15654
15908
  let outstanding = [];
15655
15909
  let delivery;
@@ -15785,6 +16039,10 @@ function createJavaScriptApi({ iteration, components, exits, deliver, signal, on
15785
16039
  isReceipt: (value) => resolve(value) !== void 0,
15786
16040
  getTerminalOutcome: () => terminalOutcome,
15787
16041
  getInterruption: () => interruption,
16042
+ requestInspection: (inspection) => {
16043
+ inspections.push(inspection);
16044
+ },
16045
+ getForcedInspections: () => inspections,
15788
16046
  throwIfTerminated,
15789
16047
  track,
15790
16048
  assertOpen,
@@ -15824,8 +16082,8 @@ var init_utils = __esmMin((() => {
15824
16082
  }));
15825
16083
  //#endregion
15826
16084
  //#region src/runtime/tool-wrapper.ts
15827
- function wrapTool({ tool, object, iteration, beforeHook, afterHook, onTruncation, onResult, controller }) {
15828
- return async function(input) {
16085
+ function wrapTool({ tool, object, iteration, beforeHook, afterHook, onTruncation, onResult, controller, onThink }) {
16086
+ return async function(input, line) {
15829
16087
  controller.signal.throwIfAborted();
15830
16088
  const toolCallId = `tcall_${ulid()}`;
15831
16089
  const originalInput = input;
@@ -15844,7 +16102,7 @@ function wrapTool({ tool, object, iteration, beforeHook, afterHook, onTruncation
15844
16102
  let output;
15845
16103
  let error;
15846
16104
  let success = true;
15847
- let signalToThrow;
16105
+ const inspections = [];
15848
16106
  const pushToolCallTrace = () => {
15849
16107
  iteration.recordTrace({
15850
16108
  type: "tool_call",
@@ -15860,32 +16118,21 @@ function wrapTool({ tool, object, iteration, beforeHook, afterHook, onTruncation
15860
16118
  success
15861
16119
  });
15862
16120
  };
15863
- const handleSignals = async (err) => {
15864
- if (output === err) return true;
15865
- if (ThinkSignal.is(err)) {
15866
- signalToThrow = err;
15867
- iteration.recordTrace({
15868
- type: "think_signal",
15869
- started_at: Date.now(),
15870
- line: 0,
15871
- ended_at: Date.now()
15872
- });
15873
- success = true;
15874
- output = err;
15875
- const afterRes = await callHook(() => afterHook?.({
15876
- iteration,
15877
- tool,
15878
- input: originalInput,
15879
- output,
15880
- controller,
15881
- object,
15882
- toolCallId,
15883
- nativeCallId: iteration.nativeCallId
15884
- }));
15885
- if (typeof afterRes?.output !== "undefined") output = afterRes.output;
15886
- return true;
15887
- }
15888
- return false;
16121
+ const unwrapSignal = (value) => {
16122
+ if (!ThinkSignal.is(value)) return value;
16123
+ const context = value.context;
16124
+ const output = unwrapTruncated(context);
16125
+ if (isTruncated(context)) onTruncation?.(output, context.$$truncate);
16126
+ const inspection = {
16127
+ tool: object ? `${object}.${tool.name}` : tool.name,
16128
+ toolCallId,
16129
+ line,
16130
+ reason: value.reason,
16131
+ value: output,
16132
+ metadata: value.metadata
16133
+ };
16134
+ inspections.push(inspection);
16135
+ return output;
15889
16136
  };
15890
16137
  try {
15891
16138
  const beforeRes = await callHook(() => beforeHook?.({
@@ -15897,18 +16144,25 @@ function wrapTool({ tool, object, iteration, beforeHook, afterHook, onTruncation
15897
16144
  toolCallId,
15898
16145
  nativeCallId: iteration.nativeCallId
15899
16146
  }));
16147
+ if (ThinkSignal.is(beforeRes)) throw new HookError("Tool hooks cannot request inspection with ThinkSignal. Return it from the tool handler instead.");
15900
16148
  if (typeof beforeRes?.input !== "undefined") effectiveInput = beforeRes.input;
15901
16149
  controller.signal.throwIfAborted();
15902
- output = await tool.execute(effectiveInput, {
15903
- callId: toolCallId,
15904
- iterationId: iteration.id,
15905
- nativeCallId: iteration.nativeCallId,
15906
- onTruncation,
15907
- onInput: (parsed) => {
15908
- controller.signal.throwIfAborted();
15909
- if (effectiveInput === originalInput) reportedInput = parsed;
15910
- }
15911
- });
16150
+ try {
16151
+ output = await tool.execute(effectiveInput, {
16152
+ callId: toolCallId,
16153
+ iterationId: iteration.id,
16154
+ nativeCallId: iteration.nativeCallId,
16155
+ onTruncation,
16156
+ onInput: (parsed) => {
16157
+ controller.signal.throwIfAborted();
16158
+ if (effectiveInput === originalInput) reportedInput = parsed;
16159
+ }
16160
+ });
16161
+ } catch (error) {
16162
+ if (!ThinkSignal.is(error)) throw error;
16163
+ output = error;
16164
+ }
16165
+ output = unwrapSignal(output);
15912
16166
  const afterRes = await callHook(() => afterHook?.({
15913
16167
  iteration,
15914
16168
  tool,
@@ -15919,19 +16173,39 @@ function wrapTool({ tool, object, iteration, beforeHook, afterHook, onTruncation
15919
16173
  toolCallId,
15920
16174
  nativeCallId: iteration.nativeCallId
15921
16175
  }));
16176
+ if (ThinkSignal.is(afterRes) || ThinkSignal.is(afterRes?.output)) throw new HookError("Tool hooks cannot request inspection with ThinkSignal. Return it from the tool handler instead.");
15922
16177
  if (typeof afterRes?.output !== "undefined") output = afterRes.output;
16178
+ controller.signal.throwIfAborted();
15923
16179
  } catch (err) {
15924
- if (!await handleSignals(err)) {
15925
- success = false;
15926
- error = isLLMzError(err) ? err : new ToolExecutionError(tool.name, err);
15927
- iteration.recordError(error);
15928
- }
16180
+ success = false;
16181
+ output = void 0;
16182
+ if (ThinkSignal.is(err)) error = new HookError("Tool hooks cannot request inspection with ThinkSignal. Return it from the tool handler instead.");
16183
+ else error = isLLMzError(err) ? err : new ToolExecutionError(tool.name, err);
16184
+ iteration.recordError(error);
15929
16185
  } finally {
15930
16186
  clearTimeout(alertSlowTool);
16187
+ for (const inspection of success ? inspections : []) {
16188
+ const value = snapshotInspectionValue(output);
16189
+ onThink?.({
16190
+ ...inspection,
16191
+ value
16192
+ });
16193
+ iteration.recordTrace({
16194
+ type: "think_signal",
16195
+ started_at: Date.now(),
16196
+ ended_at: Date.now(),
16197
+ line: line ?? 0,
16198
+ tool_name: tool.name,
16199
+ tool_call_id: toolCallId,
16200
+ object,
16201
+ reason: inspection.reason,
16202
+ context: value,
16203
+ metadata: inspection.metadata
16204
+ });
16205
+ }
15931
16206
  pushToolCallTrace();
15932
16207
  }
15933
16208
  if (!success) throw error;
15934
- if (signalToThrow) throw signalToThrow;
15935
16209
  onResult?.(output);
15936
16210
  return output;
15937
16211
  };
@@ -15940,6 +16214,8 @@ var SLOW_TOOL_WARNING;
15940
16214
  var init_tool_wrapper = __esmMin((() => {
15941
16215
  init_hooks();
15942
16216
  init_errors$1();
16217
+ init_inspection();
16218
+ init_truncate();
15943
16219
  SLOW_TOOL_WARNING = ms("15s");
15944
16220
  }));
15945
16221
  //#endregion
@@ -16046,9 +16322,13 @@ var init_vm_context = __esmMin((() => {
16046
16322
  afterHook: onAfterTool,
16047
16323
  onTruncation,
16048
16324
  onResult: onToolResult,
16049
- controller
16325
+ controller,
16326
+ onThink: javascriptApi?.requestInspection
16050
16327
  });
16051
- instance[tool.name] = javascriptApi ? (input) => javascriptApi.track(() => wrapped(input)) : wrapped;
16328
+ instance[tool.name] = javascriptApi ? (input) => {
16329
+ const line = vmContext[VM_CALL_SITE]?.();
16330
+ return javascriptApi.track(() => wrapped(input, line));
16331
+ } : wrapped;
16052
16332
  }
16053
16333
  vmContext[obj.name] = withMissingMember(instance, (name) => {
16054
16334
  const error = new UnknownToolError(`${obj.name}.${name}`, (obj.tools ?? []).map((tool) => `${obj.name}.${tool.name}`));
@@ -16064,9 +16344,13 @@ var init_vm_context = __esmMin((() => {
16064
16344
  afterHook: onAfterTool,
16065
16345
  onTruncation,
16066
16346
  onResult: onToolResult,
16067
- controller
16347
+ controller,
16348
+ onThink: javascriptApi?.requestInspection
16068
16349
  });
16069
- const callable = javascriptApi ? (input) => javascriptApi.track(() => wrapped(input)) : wrapped;
16350
+ const callable = javascriptApi ? (input) => {
16351
+ const line = vmContext[VM_CALL_SITE]?.();
16352
+ return javascriptApi.track(() => wrapped(input, line));
16353
+ } : wrapped;
16070
16354
  for (const key of [tool.name, ...tool.aliases ?? []]) vmContext[key] = callable;
16071
16355
  }
16072
16356
  return vmContext;
@@ -16100,6 +16384,7 @@ async function executeContextInternal(props) {
16100
16384
  try {
16101
16385
  if ("snapshot" in props) throw new InvalidConfigurationError("Snapshots and external pause/resume are no longer supported. Use a session for conversation history and memory.");
16102
16386
  if ("messages" in props) throw new InvalidConfigurationError("Append input with session.append(message) before calling execute(). execute.messages is no longer supported.");
16387
+ if (props.options?.requireChatResponse !== void 0 && typeof props.options.requireChatResponse !== "boolean") throw new InvalidConfigurationError("Invalid requireChatResponse. Expected a boolean.");
16103
16388
  release = ctx.session.acquire();
16104
16389
  prepareSession(ctx);
16105
16390
  const client = props.client ?? new Client();
@@ -16270,18 +16555,19 @@ async function rejectNativeBatch({ ctx, iteration }, generated, errors) {
16270
16555
  }
16271
16556
  async function deliverAssistantText(state, generated) {
16272
16557
  const { ctx, iteration } = state;
16273
- if (!generated.output.trim() || !ctx.chat) return;
16558
+ if (!generated.output.trim() || !ctx.chat || !iteration.response?.handler) return;
16274
16559
  const startedAt = Date.now();
16275
16560
  const message = {
16276
16561
  type: "text",
16277
16562
  text: generated.output
16278
16563
  };
16279
16564
  try {
16280
- await iteration.response?.handler?.(generated.output.trim(), generated.messageMetadata);
16565
+ await iteration.response.handler(generated.output.trim(), generated.messageMetadata);
16281
16566
  } catch (cause) {
16282
16567
  if (isCriticalError(cause)) throw cause;
16283
16568
  throw new DeliveryError(`Assistant response delivery failed: ${getErrorMessage(cause)}`, { cause });
16284
16569
  }
16570
+ ctx.session.recordAssistantDelivery(iteration.id);
16285
16571
  iteration.recordTrace({
16286
16572
  type: "message_delivery",
16287
16573
  value: message,
@@ -16319,6 +16605,31 @@ async function settleJavaScriptCall(state, execution) {
16319
16605
  inspected: outcome?.type === "inspect"
16320
16606
  };
16321
16607
  if (outcome?.type === "inspect" && result.success) result.return_value = outcome.value;
16608
+ const forcedInspections = api.getForcedInspections();
16609
+ if (forcedInspections.length && !controller.signal.aborted && !isCriticalError(result.error)) {
16610
+ if (!result.success && result.error) {
16611
+ iteration.recordError(result.error);
16612
+ state.capture.downstreamError = result.error;
16613
+ }
16614
+ state.capture.forcedInspections = forcedInspections;
16615
+ let value = forcedInspections.length === 1 ? forcedInspections[0].value : forcedInspections.map((entry) => entry.value);
16616
+ if (outcome?.type === "inspect") value = outcome.value;
16617
+ state.capture.result = {
16618
+ ...result,
16619
+ success: true,
16620
+ signal: void 0,
16621
+ return_value: value
16622
+ };
16623
+ iteration.end({
16624
+ type: "thinking_requested",
16625
+ thinking_requested: {
16626
+ reason: "Tools completed successfully and requested forced inspection.",
16627
+ variables: value,
16628
+ metadata: forcedInspections.length === 1 ? forcedInspections[0].metadata : void 0
16629
+ }
16630
+ });
16631
+ return;
16632
+ }
16322
16633
  if (outcome?.type === "exit") {
16323
16634
  await completeJavaScriptExit(state, result, outcome);
16324
16635
  return;
@@ -16378,11 +16689,11 @@ function containsDecision(value, api, seen = /* @__PURE__ */ new Set()) {
16378
16689
  return Object.values(value).some((nested) => containsDecision(nested, api, seen));
16379
16690
  }
16380
16691
  async function completeJavaScriptExit(state, result, outcome) {
16381
- const { iteration, controller, props } = state;
16692
+ const { iteration, controller } = state;
16382
16693
  state.memory = commitMemory(state, result, false);
16383
16694
  try {
16384
16695
  controller.signal.throwIfAborted();
16385
- await applyNativeExit(iteration, outcome.exit, outcome.value, controller, props.onExit);
16696
+ await applyNativeExit(state, outcome.exit, outcome.value);
16386
16697
  } catch (error) {
16387
16698
  endFailedIteration(iteration, controller, error);
16388
16699
  }
@@ -16414,6 +16725,7 @@ async function deliverJavaScriptMessages({ ctx, iteration, controller }, message
16414
16725
  });
16415
16726
  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 });
16416
16727
  }
16728
+ ctx.session.recordAssistantDelivery(iteration.id);
16417
16729
  iteration.recordTrace({
16418
16730
  type: "message_delivery",
16419
16731
  value: message.component,
@@ -16426,9 +16738,9 @@ async function deliverJavaScriptMessages({ ctx, iteration, controller }, message
16426
16738
  }
16427
16739
  }
16428
16740
  async function finishNativeResponse(state, generated) {
16429
- const { ctx, iteration, controller, props } = state;
16430
- if (!generated.toolCalls.length && generated.output.trim() && ctx.chat) {
16431
- await applyNativeExit(iteration, ListenExit, {}, controller, props.onExit);
16741
+ const { ctx, iteration } = state;
16742
+ if (!generated.toolCalls.length && ctx.chat && (generated.output.trim() || generated.metadata.stopReason === "stop")) {
16743
+ await applyNativeExit(state, ListenExit, {});
16432
16744
  if (!iteration.hasExited()) ctx.session.appendContext(ctx.inspector(iteration.error ?? "Completion rejected.", {
16433
16745
  purpose: "error",
16434
16746
  maxTokens: 200
@@ -16524,7 +16836,9 @@ function getExecutionOutcome(state, memory) {
16524
16836
  type: "inspect",
16525
16837
  value: capture?.result.success ? capture.result.return_value : void 0,
16526
16838
  available: memory.resultAvailable,
16527
- explicit: capture?.inspected ?? false
16839
+ explicit: capture?.inspected ?? false,
16840
+ forcedInspections: capture?.forcedInspections,
16841
+ downstreamError: capture?.downstreamError
16528
16842
  };
16529
16843
  }
16530
16844
  return {
@@ -16615,9 +16929,11 @@ function getIterationResult(state) {
16615
16929
  }
16616
16930
  if (iteration.status.type === "aborted") return new ErrorExecutionResult(ctx, iteration.error);
16617
16931
  }
16618
- async function applyNativeExit(iteration, exit, value, controller, onExit) {
16932
+ async function applyNativeExit(state, exit, value) {
16933
+ const { ctx, iteration, controller, props } = state;
16619
16934
  try {
16620
- await callHook(() => onExit?.({
16935
+ if (ctx.chat && exit === ListenExit && props.options?.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.");
16936
+ await callHook(() => props.onExit?.({
16621
16937
  exit,
16622
16938
  result: value
16623
16939
  }, controller));
@@ -16875,4 +17191,4 @@ const init = async () => {
16875
17191
  await Promise.resolve().then(() => (init_native(), native_exports));
16876
17192
  };
16877
17193
  //#endregion
16878
- export { AssignmentError, Chat, CitationsManager, CodeExecutionError, CodeFormattingError, CognitiveError, CompactionError, Component, ComponentInputError, DefaultComponents, DefaultExit, DeliveryError, ErrorExecutionResult, ExecutionAbortedError, ExecutionResult, Exit, ExitInputError, HookError, HostOperationError, InternalError, InvalidCodeError, InvalidComponentError, InvalidConfigurationError, InvalidEventError, InvalidExitError, InvalidMessageError, InvalidObjectError, InvalidSessionError, InvalidToolError, LLMzError, ListenExit, LoopExceededError, Memory, MemoryCapacityError, MemoryValueError, NativeProtocolError, ObjectInstance, ObjectPropertyError, ReservedIdentifierError, Session, SessionStateError, SuccessExecutionResult, ThinkSignal, TokenOverflowError, Tool, ToolExecutionError, ToolInputError, UnknownComponentError, UnknownExitError, UnknownToolError, _CustomModelClient, assertValidComponent, configureQuickJS, configureTokenizer, createInspector, execute, getValue, init, inspect, isAnyComponent, isComponent, isCriticalError, isLLMzError, truncate, utils, version };
17194
+ export { AssignmentError, Chat, CitationsManager, CodeExecutionError, CodeFormattingError, CognitiveError, CompactionError, Component, ComponentInputError, DefaultComponents, DefaultExit, DeliveryError, ErrorExecutionResult, ExecutionAbortedError, ExecutionResult, Exit, ExitInputError, HookError, HostOperationError, InternalError, InvalidCodeError, InvalidComponentError, InvalidConfigurationError, InvalidEventError, InvalidExitError, InvalidMessageError, InvalidObjectError, InvalidSessionError, InvalidToolError, LLMzError, ListenExit, LoopExceededError, Memory, MemoryCapacityError, MemoryValueError, MissingChatResponseError, NativeProtocolError, ObjectInstance, ObjectPropertyError, ReservedIdentifierError, Session, SessionStateError, SuccessExecutionResult, ThinkSignal, TokenOverflowError, Tool, ToolExecutionError, ToolInputError, UnknownComponentError, UnknownExitError, UnknownToolError, _CustomModelClient, assertValidComponent, configureQuickJS, configureTokenizer, createInspector, execute, getValue, init, inspect, isAnyComponent, isComponent, isCriticalError, isLLMzError, truncate, utils, version };