@dudousxd/nestjs-agent-core 0.44.1 → 0.45.1

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.
package/dist/index.js CHANGED
@@ -116,7 +116,7 @@ function observeTurnFrames(writer, now = Date.now) {
116
116
  return;
117
117
  }
118
118
  closeBurst();
119
- if (event.kind === "ui") {
119
+ if (event.kind === "ui" && event.partial !== true) {
120
120
  ui.set(event.id, {
121
121
  id: event.id,
122
122
  component: event.component,
@@ -186,6 +186,423 @@ function withTurnFrames(result2, frames) {
186
186
  }
187
187
  __name(withTurnFrames, "withTurnFrames");
188
188
 
189
+ // src/partial-json.ts
190
+ var Cut = class Cut2 extends Error {
191
+ static {
192
+ __name(this, "Cut");
193
+ }
194
+ };
195
+ function parsePartialJson(text) {
196
+ const open = /* @__PURE__ */ new WeakSet();
197
+ const pending = /* @__PURE__ */ new WeakMap();
198
+ let at = 0;
199
+ const skipSpace = /* @__PURE__ */ __name(() => {
200
+ while (at < text.length) {
201
+ const char = text.charCodeAt(at);
202
+ if (char === 32 || char === 9 || char === 10 || char === 13) at += 1;
203
+ else break;
204
+ }
205
+ }, "skipSpace");
206
+ const fail = /* @__PURE__ */ __name(() => {
207
+ throw new SyntaxError(`unexpected character at ${at}`);
208
+ }, "fail");
209
+ const readString = /* @__PURE__ */ __name(() => {
210
+ at += 1;
211
+ let out = "";
212
+ while (at < text.length) {
213
+ const char = text[at];
214
+ if (char === '"') {
215
+ at += 1;
216
+ return {
217
+ value: out,
218
+ cut: false
219
+ };
220
+ }
221
+ if (char === "\\") {
222
+ const next = text[at + 1];
223
+ if (next === void 0) {
224
+ at = text.length;
225
+ return {
226
+ value: out,
227
+ cut: true
228
+ };
229
+ }
230
+ if (next === "u") {
231
+ const hex = text.slice(at + 2, at + 6);
232
+ if (hex.length < 4) {
233
+ at = text.length;
234
+ return {
235
+ value: out,
236
+ cut: true
237
+ };
238
+ }
239
+ if (!/^[0-9a-fA-F]{4}$/.test(hex)) fail();
240
+ out += String.fromCharCode(Number.parseInt(hex, 16));
241
+ at += 6;
242
+ continue;
243
+ }
244
+ const escapes = {
245
+ '"': '"',
246
+ "\\": "\\",
247
+ "/": "/",
248
+ b: "\b",
249
+ f: "\f",
250
+ n: "\n",
251
+ r: "\r",
252
+ t: " "
253
+ };
254
+ const escaped = escapes[next];
255
+ if (escaped === void 0) fail();
256
+ out += escaped;
257
+ at += 2;
258
+ continue;
259
+ }
260
+ out += char;
261
+ at += 1;
262
+ }
263
+ return {
264
+ value: out,
265
+ cut: true
266
+ };
267
+ }, "readString");
268
+ const readValue = /* @__PURE__ */ __name(() => {
269
+ skipSpace();
270
+ if (at >= text.length) throw new Cut();
271
+ const char = text[at];
272
+ if (char === "{") return readObject();
273
+ if (char === "[") return readArray();
274
+ if (char === '"') return readString();
275
+ const rest = text.slice(at);
276
+ const number = /^-?\d*(?:\.\d*)?(?:[eE][+-]?\d*)?/.exec(rest)?.[0] ?? "";
277
+ if (number.length > 0) {
278
+ if (at + number.length >= text.length) throw new Cut();
279
+ if (!/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(number)) fail();
280
+ at += number.length;
281
+ return {
282
+ value: Number(number),
283
+ cut: false
284
+ };
285
+ }
286
+ for (const [word, value] of [
287
+ [
288
+ "true",
289
+ true
290
+ ],
291
+ [
292
+ "false",
293
+ false
294
+ ],
295
+ [
296
+ "null",
297
+ null
298
+ ]
299
+ ]) {
300
+ if (rest.startsWith(word)) {
301
+ at += word.length;
302
+ return {
303
+ value,
304
+ cut: false
305
+ };
306
+ }
307
+ if (word.startsWith(rest)) throw new Cut();
308
+ }
309
+ return fail();
310
+ }, "readValue");
311
+ const readObject = /* @__PURE__ */ __name(() => {
312
+ const object = {};
313
+ open.add(object);
314
+ at += 1;
315
+ skipSpace();
316
+ if (text[at] === "}") {
317
+ at += 1;
318
+ open.delete(object);
319
+ return {
320
+ value: object,
321
+ cut: false
322
+ };
323
+ }
324
+ for (; ; ) {
325
+ skipSpace();
326
+ if (at >= text.length) return {
327
+ value: object,
328
+ cut: true
329
+ };
330
+ if (text[at] !== '"') fail();
331
+ const key = readString();
332
+ if (key.cut) return {
333
+ value: object,
334
+ cut: true
335
+ };
336
+ skipSpace();
337
+ if (at >= text.length) {
338
+ pending.set(object, key.value);
339
+ return {
340
+ value: object,
341
+ cut: true
342
+ };
343
+ }
344
+ if (text[at] !== ":") fail();
345
+ at += 1;
346
+ let member;
347
+ try {
348
+ member = readValue();
349
+ } catch (error) {
350
+ if (!(error instanceof Cut)) throw error;
351
+ pending.set(object, key.value);
352
+ return {
353
+ value: object,
354
+ cut: true
355
+ };
356
+ }
357
+ object[key.value] = member.value;
358
+ if (member.cut) {
359
+ pending.set(object, key.value);
360
+ return {
361
+ value: object,
362
+ cut: true
363
+ };
364
+ }
365
+ skipSpace();
366
+ if (at >= text.length) return {
367
+ value: object,
368
+ cut: true
369
+ };
370
+ if (text[at] === ",") {
371
+ at += 1;
372
+ continue;
373
+ }
374
+ if (text[at] === "}") {
375
+ at += 1;
376
+ open.delete(object);
377
+ return {
378
+ value: object,
379
+ cut: false
380
+ };
381
+ }
382
+ fail();
383
+ }
384
+ }, "readObject");
385
+ const readArray = /* @__PURE__ */ __name(() => {
386
+ const array = [];
387
+ open.add(array);
388
+ at += 1;
389
+ skipSpace();
390
+ if (text[at] === "]") {
391
+ at += 1;
392
+ open.delete(array);
393
+ return {
394
+ value: array,
395
+ cut: false
396
+ };
397
+ }
398
+ for (; ; ) {
399
+ let item;
400
+ try {
401
+ item = readValue();
402
+ } catch (error) {
403
+ if (!(error instanceof Cut)) throw error;
404
+ pending.set(array, array.length);
405
+ return {
406
+ value: array,
407
+ cut: true
408
+ };
409
+ }
410
+ array.push(item.value);
411
+ if (item.cut) {
412
+ pending.set(array, array.length - 1);
413
+ return {
414
+ value: array,
415
+ cut: true
416
+ };
417
+ }
418
+ skipSpace();
419
+ if (at >= text.length) return {
420
+ value: array,
421
+ cut: true
422
+ };
423
+ if (text[at] === ",") {
424
+ at += 1;
425
+ continue;
426
+ }
427
+ if (text[at] === "]") {
428
+ at += 1;
429
+ open.delete(array);
430
+ return {
431
+ value: array,
432
+ cut: false
433
+ };
434
+ }
435
+ fail();
436
+ }
437
+ }, "readArray");
438
+ let root;
439
+ try {
440
+ root = readValue();
441
+ } catch (error) {
442
+ if (error instanceof Cut) root = {
443
+ value: void 0,
444
+ cut: true
445
+ };
446
+ else return void 0;
447
+ }
448
+ skipSpace();
449
+ return {
450
+ value: root.value,
451
+ complete: !root.cut && at >= text.length,
452
+ isOpen: /* @__PURE__ */ __name((container) => open.has(container), "isOpen"),
453
+ pendingMember: /* @__PURE__ */ __name((container) => pending.get(container), "pendingMember")
454
+ };
455
+ }
456
+ __name(parsePartialJson, "parsePartialJson");
457
+
458
+ // src/tool-input-preview.ts
459
+ var DEFAULT_PREVIEW_THROTTLE_MS = 100;
460
+ function previewUiId(toolCallId) {
461
+ return `${toolCallId}:ui:0`;
462
+ }
463
+ __name(previewUiId, "previewUiId");
464
+ function withdrawPreviewEvent(shown) {
465
+ return {
466
+ kind: "ui",
467
+ id: shown.id,
468
+ component: shown.component,
469
+ props: {},
470
+ toolCallId: shown.toolCallId,
471
+ partial: true
472
+ };
473
+ }
474
+ __name(withdrawPreviewEvent, "withdrawPreviewEvent");
475
+ function previewToolInputs(inner, resolve, now = Date.now) {
476
+ const calls = /* @__PURE__ */ new Map();
477
+ const shown = /* @__PURE__ */ new Map();
478
+ const decoder3 = new TextDecoder();
479
+ let pending = "";
480
+ async function emit2(id, state, input, done) {
481
+ let rendered;
482
+ try {
483
+ const parsed = done && input !== void 0 ? {
484
+ value: input,
485
+ complete: true,
486
+ isOpen: /* @__PURE__ */ __name(() => false, "isOpen"),
487
+ pendingMember: /* @__PURE__ */ __name(() => void 0, "pendingMember")
488
+ } : parsePartialJson(state.text);
489
+ if (parsed === void 0) return;
490
+ rendered = state.preview.render({
491
+ value: parsed.value,
492
+ done: done || parsed.complete,
493
+ isOpen: parsed.isOpen,
494
+ pendingMember: parsed.pendingMember
495
+ });
496
+ } catch {
497
+ rendered = null;
498
+ }
499
+ if (rendered === void 0) return;
500
+ const uiId = previewUiId(id);
501
+ if (rendered === null) {
502
+ state.stopped = true;
503
+ const standing = shown.get(uiId);
504
+ if (standing !== void 0) {
505
+ shown.delete(uiId);
506
+ await inner.write(encodeStreamEvent(withdrawPreviewEvent(standing)));
507
+ }
508
+ return;
509
+ }
510
+ const props = JSON.stringify(rendered.props);
511
+ if (props === state.lastProps && rendered.component === state.component) return;
512
+ state.lastProps = props;
513
+ state.component = rendered.component;
514
+ state.lastAt = now();
515
+ shown.set(uiId, {
516
+ id: uiId,
517
+ component: rendered.component,
518
+ toolCallId: id
519
+ });
520
+ await inner.write(encodeStreamEvent({
521
+ kind: "ui",
522
+ id: uiId,
523
+ component: rendered.component,
524
+ props: JSON.parse(props),
525
+ ...rendered.version !== void 0 ? {
526
+ version: rendered.version
527
+ } : {},
528
+ toolCallId: id,
529
+ partial: true
530
+ }));
531
+ }
532
+ __name(emit2, "emit");
533
+ async function observe(event) {
534
+ if (event.kind === "tool-input-start") {
535
+ if (calls.has(event.id)) return;
536
+ let preview;
537
+ try {
538
+ preview = await resolve(event.name, event.id);
539
+ } catch {
540
+ preview = void 0;
541
+ }
542
+ if (preview !== void 0) {
543
+ calls.set(event.id, {
544
+ preview,
545
+ text: "",
546
+ lastAt: void 0,
547
+ lastProps: void 0,
548
+ component: void 0,
549
+ stopped: false
550
+ });
551
+ }
552
+ return;
553
+ }
554
+ if (event.kind === "tool-input-delta") {
555
+ const state = calls.get(event.id);
556
+ if (state === void 0 || state.stopped) return;
557
+ state.text += event.delta;
558
+ const throttle = state.preview.throttleMs ?? DEFAULT_PREVIEW_THROTTLE_MS;
559
+ if (state.lastAt !== void 0 && now() - state.lastAt < throttle) return;
560
+ await emit2(event.id, state, void 0, false);
561
+ return;
562
+ }
563
+ if (event.kind === "tool-input-available") {
564
+ const state = calls.get(event.id);
565
+ if (state === void 0) return;
566
+ calls.delete(event.id);
567
+ if (state.stopped) return;
568
+ await emit2(event.id, state, event.input, true);
569
+ }
570
+ }
571
+ __name(observe, "observe");
572
+ return {
573
+ writer: {
574
+ async write(chunk) {
575
+ await inner.write(chunk);
576
+ pending += decoder3.decode(chunk, {
577
+ stream: true
578
+ });
579
+ let newline = pending.indexOf("\n");
580
+ while (newline !== -1) {
581
+ const line = pending.slice(0, newline);
582
+ pending = pending.slice(newline + 1);
583
+ const event = line.trim().length > 0 ? decodeStreamEvent(line) : null;
584
+ if (event !== null) await observe(event);
585
+ newline = pending.indexOf("\n");
586
+ }
587
+ },
588
+ end: /* @__PURE__ */ __name(() => inner.end(), "end"),
589
+ fail: /* @__PURE__ */ __name((error) => inner.fail(error), "fail")
590
+ },
591
+ shown: /* @__PURE__ */ __name(() => [
592
+ ...shown.values()
593
+ ], "shown")
594
+ };
595
+ }
596
+ __name(previewToolInputs, "previewToolInputs");
597
+ function registryInputPreviews(registry, offered, scope) {
598
+ const names = new Set(offered.map((tool) => tool.name));
599
+ return async (toolName, toolCallId) => names.has(toolName) ? registry.previewInput(toolName, {
600
+ ...scope,
601
+ toolCallId
602
+ }) : void 0;
603
+ }
604
+ __name(registryInputPreviews, "registryInputPreviews");
605
+
189
606
  // src/tool-ui.ts
190
607
  var TOOL_STEP_UI = "@@nestjs-agent/tool-step-ui";
191
608
  function wrapToolStepOutput(output, ui, text) {
@@ -3072,6 +3489,7 @@ function defineComponent(definition) {
3072
3489
  }
3073
3490
  if (definition.version !== void 0 && (!Number.isSafeInteger(definition.version) || definition.version <= 0)) throw new RangeError("genui: component version must be a positive safe integer");
3074
3491
  if (definition.fallbackText !== void 0 && typeof definition.fallbackText !== "function") throw new TypeError("genui: fallbackText must be a function");
3492
+ if (definition.streaming !== void 0 && definition.streaming !== "partial" && definition.streaming !== "complete") throw new TypeError("genui: streaming must be 'partial' or 'complete'");
3075
3493
  return definition;
3076
3494
  }
3077
3495
  __name(defineComponent, "defineComponent");
@@ -4430,6 +4848,19 @@ var ToolRegistry = class {
4430
4848
  unregister(name) {
4431
4849
  return this.entries.delete(name);
4432
4850
  }
4851
+ /**
4852
+ * How a streamed call of `name` is previewed while its input arrives (`ToolHandler.previewInput`),
4853
+ * or `undefined`. A preview that fails to build is no preview: it never fails the turn.
4854
+ */
4855
+ async previewInput(name, scope) {
4856
+ const handler = this.entries.get(name)?.handler;
4857
+ if (handler?.previewInput === void 0) return void 0;
4858
+ try {
4859
+ return await handler.previewInput(scope) ?? void 0;
4860
+ } catch {
4861
+ return void 0;
4862
+ }
4863
+ }
4433
4864
  spec(name) {
4434
4865
  return this.entries.get(name)?.spec;
4435
4866
  }
@@ -4488,6 +4919,9 @@ var ToolRegistry = class {
4488
4919
  * Run a tool. Re-checks that the tool is enabled and that the role allows it (defense-in-depth —
4489
4920
  * a call can reach here from a replayed durable step or an approval granted before the flag
4490
4921
  * moved, neither of which went through `definitionsFor` again) and re-parses the input via Zod.
4922
+ * A tool whose `describe()` answers `available: false` for the call's scope (actor, thread, agent,
4923
+ * `uiCapabilities`) is refused with {@link ToolNotFoundError}, as the unknown tool it was to the
4924
+ * model.
4491
4925
  */
4492
4926
  async invoke(name, input, ctx, policy, options = {}) {
4493
4927
  const { entry, value, ctx: withEmit } = await this.validated(name, input, ctx, policy, options);
@@ -4541,6 +4975,10 @@ var ToolRegistry = class {
4541
4975
  if (options.allowedTools !== void 0 && !options.allowedTools.includes(name)) {
4542
4976
  throw new ToolForbiddenError(name);
4543
4977
  }
4978
+ if (entry.handler.describe !== void 0) {
4979
+ const described = await entry.handler.describe(describeScopeOf(ctx));
4980
+ if (described?.available === false) throw new ToolNotFoundError(name);
4981
+ }
4544
4982
  const validation = await entry.spec.inputSchema["~standard"].validate(input);
4545
4983
  if (validation.issues !== void 0) {
4546
4984
  throw new ToolInputInvalidError(name, validation.issues);
@@ -4556,6 +4994,21 @@ var ToolRegistry = class {
4556
4994
  };
4557
4995
  }
4558
4996
  };
4997
+ function describeScopeOf(ctx) {
4998
+ return {
4999
+ actor: ctx.actor,
5000
+ ...ctx.threadId ? {
5001
+ threadId: ctx.threadId
5002
+ } : {},
5003
+ ...ctx.agentName !== void 0 ? {
5004
+ agentName: ctx.agentName
5005
+ } : {},
5006
+ ...ctx.uiCapabilities !== void 0 ? {
5007
+ uiCapabilities: ctx.uiCapabilities
5008
+ } : {}
5009
+ };
5010
+ }
5011
+ __name(describeScopeOf, "describeScopeOf");
4559
5012
  var DefaultRolesPolicy = class {
4560
5013
  static {
4561
5014
  __name(this, "DefaultRolesPolicy");
@@ -4939,6 +5392,21 @@ var RunCancelledError = class extends Error {
4939
5392
  this.name = "RunCancelledError";
4940
5393
  }
4941
5394
  };
5395
+ async function abortableModelCall(hooks, call) {
5396
+ const signal = hooks.abortSignal;
5397
+ let result2;
5398
+ try {
5399
+ result2 = await call(signal !== void 0 ? {
5400
+ abortSignal: signal
5401
+ } : {});
5402
+ } catch (error) {
5403
+ if (signal?.aborted === true) throw new RunCancelledError();
5404
+ throw error;
5405
+ }
5406
+ if (signal?.aborted === true) throw new RunCancelledError();
5407
+ return result2;
5408
+ }
5409
+ __name(abortableModelCall, "abortableModelCall");
4942
5410
  function agentFailureCode(error) {
4943
5411
  if (error instanceof RunCancelledError) {
4944
5412
  return "cancelled";
@@ -5396,13 +5864,14 @@ async function structureAnswer(schema, deps, input, hooks, messages, step) {
5396
5864
  fail: /* @__PURE__ */ __name(() => {
5397
5865
  }, "fail")
5398
5866
  };
5399
- const turn = await deps.model.runTurn({
5867
+ const turn = await abortableModelCall(hooks, (signal) => deps.model.runTurn({
5400
5868
  system,
5401
5869
  messages,
5402
5870
  tools: [],
5403
5871
  sink: discard,
5404
- outputSchema: schema
5405
- });
5872
+ outputSchema: schema,
5873
+ ...signal
5874
+ }));
5406
5875
  return {
5407
5876
  text: turn.text,
5408
5877
  usage: turn.usage,
@@ -5524,6 +5993,9 @@ function toolContext(deps, input, hooks) {
5524
5993
  ...deps.host !== void 0 ? {
5525
5994
  host: deps.host
5526
5995
  } : {},
5996
+ ...hooks.abortSignal !== void 0 ? {
5997
+ abortSignal: hooks.abortSignal
5998
+ } : {},
5527
5999
  // Replaced per tool call by the call's own collector (see the tool step); this one only serves
5528
6000
  // what runs outside a call — the elicitation wait.
5529
6001
  emitUi: createNoopEmitUi(hooks.runId)
@@ -6891,26 +7363,46 @@ ${block}`;
6891
7363
  writer
6892
7364
  }) : void 0;
6893
7365
  const buffer = gateMode === "whole" ? createFrameBuffer() : void 0;
6894
- const frames = observeTurnFrames(incremental?.writer ?? buffer?.writer ?? writer);
6895
- const result2 = stampToolKinds(withTurnFrames(await traceLlmTurn(hooks.runId, i, () => deps.model.runTurn({
7366
+ const previews = previewToolInputs(incremental?.writer ?? buffer?.writer ?? writer, registryInputPreviews(deps.registry, tools, {
7367
+ actor: input.actor,
7368
+ threadId: input.threadId,
7369
+ ...input.agentName !== void 0 ? {
7370
+ agentName: input.agentName
7371
+ } : {},
7372
+ ...input.uiCapabilities !== void 0 ? {
7373
+ uiCapabilities: input.uiCapabilities
7374
+ } : {}
7375
+ }));
7376
+ const frames = observeTurnFrames(previews.writer);
7377
+ const result2 = stampToolKinds(withTurnFrames(await traceLlmTurn(hooks.runId, i, () => abortableModelCall(hooks, (signal) => deps.model.runTurn({
6896
7378
  system: prompt.system,
6897
7379
  messages: prompt.messages,
6898
7380
  tools,
6899
- sink: frames.writer
6900
- })), frames.summary()), deps);
7381
+ sink: frames.writer,
7382
+ ...signal
7383
+ }))), frames.summary()), deps);
7384
+ const shownPreviews = previews.shown();
7385
+ const previewed = shownPreviews.length > 0 ? {
7386
+ previews: shownPreviews
7387
+ } : {};
6901
7388
  if (incremental !== void 0) {
6902
7389
  await incremental.settled();
6903
7390
  const refusal = incremental.rejection();
6904
7391
  return {
6905
7392
  ...result2,
7393
+ ...previewed,
6906
7394
  releasedText: incremental.released(),
6907
7395
  ...refusal !== void 0 ? {
6908
7396
  gateRejection: refusal
6909
7397
  } : {}
6910
7398
  };
6911
7399
  }
6912
- return buffer === void 0 ? result2 : {
7400
+ return buffer === void 0 ? {
7401
+ ...result2,
7402
+ ...previewed
7403
+ } : {
6913
7404
  ...result2,
7405
+ ...previewed,
6914
7406
  bufferedFrames: buffer.frames()
6915
7407
  };
6916
7408
  });
@@ -7229,6 +7721,12 @@ ${block}`;
7229
7721
  if (toolUi.length > 0) {
7230
7722
  await deps.store.setMessageUi?.(assistant.id, mergeUi(turn.ui, toolUi));
7231
7723
  }
7724
+ for (const preview of turn.previews ?? []) {
7725
+ const pushed = turnCalls.toolUi.get(preview.toolCallId) ?? [];
7726
+ if (!pushed.some((component) => component.id === preview.id)) {
7727
+ await writer.write(encodeStreamEvent(withdrawPreviewEvent(preview)));
7728
+ }
7729
+ }
7232
7730
  for (const result2 of results) {
7233
7731
  await writer.write(encodeStreamEvent(outputFrame(result2)));
7234
7732
  }
@@ -7310,6 +7808,98 @@ ${toolText}`;
7310
7808
  }
7311
7809
  __name(runAgentLoop, "runAgentLoop");
7312
7810
 
7811
+ // src/action-proposal-tool-call.ts
7812
+ function toolCallUpdateForProposal(proposal) {
7813
+ const audit = proposal.decisionAudit;
7814
+ const toolCallId = proposal.originToolCallId;
7815
+ const decidedBy = {
7816
+ ...audit?.actorRef !== void 0 ? {
7817
+ executedByRef: audit.actorRef
7818
+ } : {},
7819
+ ...audit?.via !== void 0 ? {
7820
+ decidedVia: audit.via
7821
+ } : {}
7822
+ };
7823
+ switch (proposal.decision) {
7824
+ case "rejected":
7825
+ return {
7826
+ toolCallId,
7827
+ status: "rejected",
7828
+ ...decidedBy,
7829
+ ...audit?.reason !== void 0 ? {
7830
+ error: storableText2(audit.reason)
7831
+ } : {}
7832
+ };
7833
+ case "expired":
7834
+ return {
7835
+ toolCallId,
7836
+ status: "expired",
7837
+ ...audit?.via !== void 0 ? {
7838
+ decidedVia: audit.via
7839
+ } : {}
7840
+ };
7841
+ case "superseded":
7842
+ return {
7843
+ toolCallId,
7844
+ status: "expired",
7845
+ decidedVia: audit?.via ?? "supersession",
7846
+ error: proposal.supersededBy !== void 0 ? `superseded by proposal ${proposal.supersededBy}` : "superseded by a newer proposal"
7847
+ };
7848
+ case "approved": {
7849
+ const execution = proposal.execution;
7850
+ const remember = audit?.remember !== void 0 ? {
7851
+ remember: audit.remember
7852
+ } : {};
7853
+ if (execution?.status === "succeeded") {
7854
+ return {
7855
+ toolCallId,
7856
+ status: "executed",
7857
+ ...storableOutput(execution.result) ? {
7858
+ output: execution.result
7859
+ } : {},
7860
+ ...decidedBy,
7861
+ ...remember
7862
+ };
7863
+ }
7864
+ if (execution?.status === "failed") {
7865
+ return {
7866
+ toolCallId,
7867
+ status: "failed",
7868
+ error: storableText2(execution.error ?? "the approved action failed"),
7869
+ ...decidedBy,
7870
+ ...remember
7871
+ };
7872
+ }
7873
+ return null;
7874
+ }
7875
+ default:
7876
+ return null;
7877
+ }
7878
+ }
7879
+ __name(toolCallUpdateForProposal, "toolCallUpdateForProposal");
7880
+ function toolCallUpdateForTransition(previous, next) {
7881
+ const update = toolCallUpdateForProposal(next);
7882
+ if (update === null) return null;
7883
+ const before = previous === void 0 ? null : toolCallUpdateForProposal(previous);
7884
+ return before?.status === update.status ? null : update;
7885
+ }
7886
+ __name(toolCallUpdateForTransition, "toolCallUpdateForTransition");
7887
+ function storableOutput(result2) {
7888
+ if (result2 === void 0) return false;
7889
+ let json;
7890
+ try {
7891
+ json = JSON.stringify(result2);
7892
+ } catch {
7893
+ return false;
7894
+ }
7895
+ return json !== void 0 && !/\\u0000|\\ud[89ab][0-9a-f]{2}(?!\\ud[c-f])|(?<!\\ud[89ab][0-9a-f]{2})\\ud[c-f][0-9a-f]{2}/i.test(json);
7896
+ }
7897
+ __name(storableOutput, "storableOutput");
7898
+ function storableText2(text) {
7899
+ return text.replaceAll("\0", "");
7900
+ }
7901
+ __name(storableText2, "storableText");
7902
+
7313
7903
  // src/in-memory-action-proposal-store.ts
7314
7904
  import { randomUUID } from "crypto";
7315
7905
  var InMemoryActionProposalStore = class {
@@ -7356,9 +7946,19 @@ var InMemoryActionProposalStore = class {
7356
7946
  status: "not_found"
7357
7947
  };
7358
7948
  const result2 = transition(row2, this.clock());
7359
- if (result2.proposal) this.rows.set(id, snapshotActionProposal(result2.proposal));
7949
+ if (result2.proposal) {
7950
+ this.rows.set(id, snapshotActionProposal(result2.proposal));
7951
+ this.proposalChanged(row2, result2.proposal);
7952
+ }
7360
7953
  return result2;
7361
7954
  }
7955
+ /**
7956
+ * Called after every proposal transition, with the row before and after — synchronously, so no
7957
+ * reader sees one without the other. {@link InMemoryAgentStore} settles the proposal's tool-call
7958
+ * record here (see `toolCallUpdateForTransition`).
7959
+ */
7960
+ proposalChanged(_previous, _next) {
7961
+ }
7362
7962
  async decideActionProposal(scope, id, command) {
7363
7963
  return this.mutate(scope, id, (row2, now) => transitionActionProposalDecision(row2, command, now));
7364
7964
  }
@@ -7439,7 +8039,11 @@ var InMemoryActionProposalStore = class {
7439
8039
  if (result2.proposal) replacements.push(result2.proposal);
7440
8040
  }
7441
8041
  this.rows.set(proposal.id, proposal);
7442
- for (const row2 of replacements) this.rows.set(row2.id, row2);
8042
+ for (const row2 of replacements) {
8043
+ const previous = this.rows.get(row2.id);
8044
+ this.rows.set(row2.id, row2);
8045
+ if (previous) this.proposalChanged(previous, row2);
8046
+ }
7443
8047
  return {
7444
8048
  status: "created",
7445
8049
  proposal: snapshotActionProposal(proposal)
@@ -8160,6 +8764,15 @@ var InMemoryAgentStore = class extends InMemoryActionProposalStore {
8160
8764
  return settled;
8161
8765
  }
8162
8766
  async updateToolCall(input) {
8767
+ this.applyToolCallUpdate(input);
8768
+ }
8769
+ /** An independent proposal moved: its `proposed` tool-call record follows it. */
8770
+ proposalChanged(previous, next) {
8771
+ const update = toolCallUpdateForTransition(previous, next);
8772
+ if (update === null || this.toolCalls.get(update.toolCallId)?.proposalId !== next.id) return;
8773
+ this.applyToolCallUpdate(update);
8774
+ }
8775
+ applyToolCallUpdate(input) {
8163
8776
  const row2 = this.toolCalls.get(input.toolCallId);
8164
8777
  if (row2 === void 0) {
8165
8778
  return;
@@ -9513,6 +10126,7 @@ export {
9513
10126
  DEFAULT_MAX_FACT_CHARS,
9514
10127
  DEFAULT_MAX_MEMORIES,
9515
10128
  DEFAULT_MAX_SKILLS,
10129
+ DEFAULT_PREVIEW_THROTTLE_MS,
9516
10130
  DEFAULT_REFUSAL_REASON,
9517
10131
  DEFAULT_STRUCTURED_OUTPUT_INSTRUCTION,
9518
10132
  DEFAULT_TEXT_ACTION_PROPOSAL_REPLIES,
@@ -9631,9 +10245,12 @@ export {
9631
10245
  observeTurnFrames,
9632
10246
  offerMemories,
9633
10247
  offerSkills,
10248
+ parsePartialJson,
9634
10249
  parseTextActionProposalCommand,
9635
10250
  personaCatalogEntry,
9636
10251
  prepareActionProposal,
10252
+ previewToolInputs,
10253
+ previewUiId,
9637
10254
  ptBrActionProposalText,
9638
10255
  publishAgentDelegated,
9639
10256
  publishAgentMemoryResolved,
@@ -9654,6 +10271,7 @@ export {
9654
10271
  quotaWarning,
9655
10272
  readElicitationInput,
9656
10273
  readElicitationQuestions,
10274
+ registryInputPreviews,
9657
10275
  releaseGatedFrames,
9658
10276
  releaseThreadRun,
9659
10277
  rememberInputSchema,
@@ -9696,6 +10314,8 @@ export {
9696
10314
  toActionProposalView,
9697
10315
  toolCallApprovalFromRow,
9698
10316
  toolCallContext,
10317
+ toolCallUpdateForProposal,
10318
+ toolCallUpdateForTransition,
9699
10319
  traceLlmTurn,
9700
10320
  traceToolExecution,
9701
10321
  transitionActionProposalClaim,
@@ -9722,6 +10342,7 @@ export {
9722
10342
  withSkillTool,
9723
10343
  withToolTimeout,
9724
10344
  withTurnFrames,
10345
+ withdrawPreviewEvent,
9725
10346
  wrapToolPreflightDenied,
9726
10347
  wrapToolStepOutput,
9727
10348
  writeMemory