@dudousxd/nestjs-agent-core 0.44.1 → 0.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
- import { I as InputProcessor, O as OutputProcessor } from '../processors-BANqZT3O.cjs';
2
- import { a as Actor, b as ToolHandler } from '../stream-events-BfxJAckJ.cjs';
1
+ import { I as InputProcessor, O as OutputProcessor } from '../processors-BhOGaMPY.cjs';
2
+ import { a as Actor, b as ToolHandler } from '../stream-events-qB6NOOvn.cjs';
3
3
  import '@standard-schema/spec';
4
- import '../catalog-G8usJpx5.cjs';
4
+ import '../catalog-BUmTnAqU.cjs';
5
5
 
6
6
  /**
7
7
  * Guardrails: detectors that look at text on its way to or from a model — prompts, answers, tool
@@ -1,7 +1,7 @@
1
- import { I as InputProcessor, O as OutputProcessor } from '../processors-C9mor-73.js';
2
- import { a as Actor, b as ToolHandler } from '../stream-events-DFa2Do42.js';
1
+ import { I as InputProcessor, O as OutputProcessor } from '../processors-DDKKky_6.js';
2
+ import { a as Actor, b as ToolHandler } from '../stream-events-CqCqYjJw.js';
3
3
  import '@standard-schema/spec';
4
- import '../catalog-G8usJpx5.js';
4
+ import '../catalog-BUmTnAqU.js';
5
5
 
6
6
  /**
7
7
  * Guardrails: detectors that look at text on its way to or from a model — prompts, answers, tool
package/dist/index.cjs CHANGED
@@ -68,6 +68,7 @@ __export(src_exports, {
68
68
  DEFAULT_MAX_FACT_CHARS: () => DEFAULT_MAX_FACT_CHARS,
69
69
  DEFAULT_MAX_MEMORIES: () => DEFAULT_MAX_MEMORIES,
70
70
  DEFAULT_MAX_SKILLS: () => DEFAULT_MAX_SKILLS,
71
+ DEFAULT_PREVIEW_THROTTLE_MS: () => DEFAULT_PREVIEW_THROTTLE_MS,
71
72
  DEFAULT_REFUSAL_REASON: () => DEFAULT_REFUSAL_REASON,
72
73
  DEFAULT_STRUCTURED_OUTPUT_INSTRUCTION: () => DEFAULT_STRUCTURED_OUTPUT_INSTRUCTION,
73
74
  DEFAULT_TEXT_ACTION_PROPOSAL_REPLIES: () => DEFAULT_TEXT_ACTION_PROPOSAL_REPLIES,
@@ -186,9 +187,12 @@ __export(src_exports, {
186
187
  observeTurnFrames: () => observeTurnFrames,
187
188
  offerMemories: () => offerMemories,
188
189
  offerSkills: () => offerSkills,
190
+ parsePartialJson: () => parsePartialJson,
189
191
  parseTextActionProposalCommand: () => parseTextActionProposalCommand,
190
192
  personaCatalogEntry: () => personaCatalogEntry,
191
193
  prepareActionProposal: () => prepareActionProposal,
194
+ previewToolInputs: () => previewToolInputs,
195
+ previewUiId: () => previewUiId,
192
196
  ptBrActionProposalText: () => ptBrActionProposalText,
193
197
  publishAgentDelegated: () => publishAgentDelegated,
194
198
  publishAgentMemoryResolved: () => publishAgentMemoryResolved,
@@ -209,6 +213,7 @@ __export(src_exports, {
209
213
  quotaWarning: () => quotaWarning,
210
214
  readElicitationInput: () => readElicitationInput,
211
215
  readElicitationQuestions: () => readElicitationQuestions,
216
+ registryInputPreviews: () => registryInputPreviews,
212
217
  releaseGatedFrames: () => releaseGatedFrames,
213
218
  releaseThreadRun: () => releaseThreadRun,
214
219
  rememberInputSchema: () => rememberInputSchema,
@@ -277,6 +282,7 @@ __export(src_exports, {
277
282
  withSkillTool: () => withSkillTool,
278
283
  withToolTimeout: () => withToolTimeout,
279
284
  withTurnFrames: () => withTurnFrames,
285
+ withdrawPreviewEvent: () => withdrawPreviewEvent,
280
286
  wrapToolPreflightDenied: () => wrapToolPreflightDenied,
281
287
  wrapToolStepOutput: () => wrapToolStepOutput,
282
288
  writeMemory: () => writeMemory
@@ -398,7 +404,7 @@ function observeTurnFrames(writer, now = Date.now) {
398
404
  return;
399
405
  }
400
406
  closeBurst();
401
- if (event.kind === "ui") {
407
+ if (event.kind === "ui" && event.partial !== true) {
402
408
  ui.set(event.id, {
403
409
  id: event.id,
404
410
  component: event.component,
@@ -468,6 +474,423 @@ function withTurnFrames(result2, frames) {
468
474
  }
469
475
  __name(withTurnFrames, "withTurnFrames");
470
476
 
477
+ // src/partial-json.ts
478
+ var Cut = class Cut2 extends Error {
479
+ static {
480
+ __name(this, "Cut");
481
+ }
482
+ };
483
+ function parsePartialJson(text) {
484
+ const open = /* @__PURE__ */ new WeakSet();
485
+ const pending = /* @__PURE__ */ new WeakMap();
486
+ let at = 0;
487
+ const skipSpace = /* @__PURE__ */ __name(() => {
488
+ while (at < text.length) {
489
+ const char = text.charCodeAt(at);
490
+ if (char === 32 || char === 9 || char === 10 || char === 13) at += 1;
491
+ else break;
492
+ }
493
+ }, "skipSpace");
494
+ const fail = /* @__PURE__ */ __name(() => {
495
+ throw new SyntaxError(`unexpected character at ${at}`);
496
+ }, "fail");
497
+ const readString = /* @__PURE__ */ __name(() => {
498
+ at += 1;
499
+ let out = "";
500
+ while (at < text.length) {
501
+ const char = text[at];
502
+ if (char === '"') {
503
+ at += 1;
504
+ return {
505
+ value: out,
506
+ cut: false
507
+ };
508
+ }
509
+ if (char === "\\") {
510
+ const next = text[at + 1];
511
+ if (next === void 0) {
512
+ at = text.length;
513
+ return {
514
+ value: out,
515
+ cut: true
516
+ };
517
+ }
518
+ if (next === "u") {
519
+ const hex = text.slice(at + 2, at + 6);
520
+ if (hex.length < 4) {
521
+ at = text.length;
522
+ return {
523
+ value: out,
524
+ cut: true
525
+ };
526
+ }
527
+ if (!/^[0-9a-fA-F]{4}$/.test(hex)) fail();
528
+ out += String.fromCharCode(Number.parseInt(hex, 16));
529
+ at += 6;
530
+ continue;
531
+ }
532
+ const escapes = {
533
+ '"': '"',
534
+ "\\": "\\",
535
+ "/": "/",
536
+ b: "\b",
537
+ f: "\f",
538
+ n: "\n",
539
+ r: "\r",
540
+ t: " "
541
+ };
542
+ const escaped = escapes[next];
543
+ if (escaped === void 0) fail();
544
+ out += escaped;
545
+ at += 2;
546
+ continue;
547
+ }
548
+ out += char;
549
+ at += 1;
550
+ }
551
+ return {
552
+ value: out,
553
+ cut: true
554
+ };
555
+ }, "readString");
556
+ const readValue = /* @__PURE__ */ __name(() => {
557
+ skipSpace();
558
+ if (at >= text.length) throw new Cut();
559
+ const char = text[at];
560
+ if (char === "{") return readObject();
561
+ if (char === "[") return readArray();
562
+ if (char === '"') return readString();
563
+ const rest = text.slice(at);
564
+ const number = /^-?\d*(?:\.\d*)?(?:[eE][+-]?\d*)?/.exec(rest)?.[0] ?? "";
565
+ if (number.length > 0) {
566
+ if (at + number.length >= text.length) throw new Cut();
567
+ if (!/^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$/.test(number)) fail();
568
+ at += number.length;
569
+ return {
570
+ value: Number(number),
571
+ cut: false
572
+ };
573
+ }
574
+ for (const [word, value] of [
575
+ [
576
+ "true",
577
+ true
578
+ ],
579
+ [
580
+ "false",
581
+ false
582
+ ],
583
+ [
584
+ "null",
585
+ null
586
+ ]
587
+ ]) {
588
+ if (rest.startsWith(word)) {
589
+ at += word.length;
590
+ return {
591
+ value,
592
+ cut: false
593
+ };
594
+ }
595
+ if (word.startsWith(rest)) throw new Cut();
596
+ }
597
+ return fail();
598
+ }, "readValue");
599
+ const readObject = /* @__PURE__ */ __name(() => {
600
+ const object = {};
601
+ open.add(object);
602
+ at += 1;
603
+ skipSpace();
604
+ if (text[at] === "}") {
605
+ at += 1;
606
+ open.delete(object);
607
+ return {
608
+ value: object,
609
+ cut: false
610
+ };
611
+ }
612
+ for (; ; ) {
613
+ skipSpace();
614
+ if (at >= text.length) return {
615
+ value: object,
616
+ cut: true
617
+ };
618
+ if (text[at] !== '"') fail();
619
+ const key = readString();
620
+ if (key.cut) return {
621
+ value: object,
622
+ cut: true
623
+ };
624
+ skipSpace();
625
+ if (at >= text.length) {
626
+ pending.set(object, key.value);
627
+ return {
628
+ value: object,
629
+ cut: true
630
+ };
631
+ }
632
+ if (text[at] !== ":") fail();
633
+ at += 1;
634
+ let member;
635
+ try {
636
+ member = readValue();
637
+ } catch (error) {
638
+ if (!(error instanceof Cut)) throw error;
639
+ pending.set(object, key.value);
640
+ return {
641
+ value: object,
642
+ cut: true
643
+ };
644
+ }
645
+ object[key.value] = member.value;
646
+ if (member.cut) {
647
+ pending.set(object, key.value);
648
+ return {
649
+ value: object,
650
+ cut: true
651
+ };
652
+ }
653
+ skipSpace();
654
+ if (at >= text.length) return {
655
+ value: object,
656
+ cut: true
657
+ };
658
+ if (text[at] === ",") {
659
+ at += 1;
660
+ continue;
661
+ }
662
+ if (text[at] === "}") {
663
+ at += 1;
664
+ open.delete(object);
665
+ return {
666
+ value: object,
667
+ cut: false
668
+ };
669
+ }
670
+ fail();
671
+ }
672
+ }, "readObject");
673
+ const readArray = /* @__PURE__ */ __name(() => {
674
+ const array = [];
675
+ open.add(array);
676
+ at += 1;
677
+ skipSpace();
678
+ if (text[at] === "]") {
679
+ at += 1;
680
+ open.delete(array);
681
+ return {
682
+ value: array,
683
+ cut: false
684
+ };
685
+ }
686
+ for (; ; ) {
687
+ let item;
688
+ try {
689
+ item = readValue();
690
+ } catch (error) {
691
+ if (!(error instanceof Cut)) throw error;
692
+ pending.set(array, array.length);
693
+ return {
694
+ value: array,
695
+ cut: true
696
+ };
697
+ }
698
+ array.push(item.value);
699
+ if (item.cut) {
700
+ pending.set(array, array.length - 1);
701
+ return {
702
+ value: array,
703
+ cut: true
704
+ };
705
+ }
706
+ skipSpace();
707
+ if (at >= text.length) return {
708
+ value: array,
709
+ cut: true
710
+ };
711
+ if (text[at] === ",") {
712
+ at += 1;
713
+ continue;
714
+ }
715
+ if (text[at] === "]") {
716
+ at += 1;
717
+ open.delete(array);
718
+ return {
719
+ value: array,
720
+ cut: false
721
+ };
722
+ }
723
+ fail();
724
+ }
725
+ }, "readArray");
726
+ let root;
727
+ try {
728
+ root = readValue();
729
+ } catch (error) {
730
+ if (error instanceof Cut) root = {
731
+ value: void 0,
732
+ cut: true
733
+ };
734
+ else return void 0;
735
+ }
736
+ skipSpace();
737
+ return {
738
+ value: root.value,
739
+ complete: !root.cut && at >= text.length,
740
+ isOpen: /* @__PURE__ */ __name((container) => open.has(container), "isOpen"),
741
+ pendingMember: /* @__PURE__ */ __name((container) => pending.get(container), "pendingMember")
742
+ };
743
+ }
744
+ __name(parsePartialJson, "parsePartialJson");
745
+
746
+ // src/tool-input-preview.ts
747
+ var DEFAULT_PREVIEW_THROTTLE_MS = 100;
748
+ function previewUiId(toolCallId) {
749
+ return `${toolCallId}:ui:0`;
750
+ }
751
+ __name(previewUiId, "previewUiId");
752
+ function withdrawPreviewEvent(shown) {
753
+ return {
754
+ kind: "ui",
755
+ id: shown.id,
756
+ component: shown.component,
757
+ props: {},
758
+ toolCallId: shown.toolCallId,
759
+ partial: true
760
+ };
761
+ }
762
+ __name(withdrawPreviewEvent, "withdrawPreviewEvent");
763
+ function previewToolInputs(inner, resolve, now = Date.now) {
764
+ const calls = /* @__PURE__ */ new Map();
765
+ const shown = /* @__PURE__ */ new Map();
766
+ const decoder3 = new TextDecoder();
767
+ let pending = "";
768
+ async function emit2(id, state, input, done) {
769
+ let rendered;
770
+ try {
771
+ const parsed = done && input !== void 0 ? {
772
+ value: input,
773
+ complete: true,
774
+ isOpen: /* @__PURE__ */ __name(() => false, "isOpen"),
775
+ pendingMember: /* @__PURE__ */ __name(() => void 0, "pendingMember")
776
+ } : parsePartialJson(state.text);
777
+ if (parsed === void 0) return;
778
+ rendered = state.preview.render({
779
+ value: parsed.value,
780
+ done: done || parsed.complete,
781
+ isOpen: parsed.isOpen,
782
+ pendingMember: parsed.pendingMember
783
+ });
784
+ } catch {
785
+ rendered = null;
786
+ }
787
+ if (rendered === void 0) return;
788
+ const uiId = previewUiId(id);
789
+ if (rendered === null) {
790
+ state.stopped = true;
791
+ const standing = shown.get(uiId);
792
+ if (standing !== void 0) {
793
+ shown.delete(uiId);
794
+ await inner.write(encodeStreamEvent(withdrawPreviewEvent(standing)));
795
+ }
796
+ return;
797
+ }
798
+ const props = JSON.stringify(rendered.props);
799
+ if (props === state.lastProps && rendered.component === state.component) return;
800
+ state.lastProps = props;
801
+ state.component = rendered.component;
802
+ state.lastAt = now();
803
+ shown.set(uiId, {
804
+ id: uiId,
805
+ component: rendered.component,
806
+ toolCallId: id
807
+ });
808
+ await inner.write(encodeStreamEvent({
809
+ kind: "ui",
810
+ id: uiId,
811
+ component: rendered.component,
812
+ props: JSON.parse(props),
813
+ ...rendered.version !== void 0 ? {
814
+ version: rendered.version
815
+ } : {},
816
+ toolCallId: id,
817
+ partial: true
818
+ }));
819
+ }
820
+ __name(emit2, "emit");
821
+ async function observe(event) {
822
+ if (event.kind === "tool-input-start") {
823
+ if (calls.has(event.id)) return;
824
+ let preview;
825
+ try {
826
+ preview = await resolve(event.name, event.id);
827
+ } catch {
828
+ preview = void 0;
829
+ }
830
+ if (preview !== void 0) {
831
+ calls.set(event.id, {
832
+ preview,
833
+ text: "",
834
+ lastAt: void 0,
835
+ lastProps: void 0,
836
+ component: void 0,
837
+ stopped: false
838
+ });
839
+ }
840
+ return;
841
+ }
842
+ if (event.kind === "tool-input-delta") {
843
+ const state = calls.get(event.id);
844
+ if (state === void 0 || state.stopped) return;
845
+ state.text += event.delta;
846
+ const throttle = state.preview.throttleMs ?? DEFAULT_PREVIEW_THROTTLE_MS;
847
+ if (state.lastAt !== void 0 && now() - state.lastAt < throttle) return;
848
+ await emit2(event.id, state, void 0, false);
849
+ return;
850
+ }
851
+ if (event.kind === "tool-input-available") {
852
+ const state = calls.get(event.id);
853
+ if (state === void 0) return;
854
+ calls.delete(event.id);
855
+ if (state.stopped) return;
856
+ await emit2(event.id, state, event.input, true);
857
+ }
858
+ }
859
+ __name(observe, "observe");
860
+ return {
861
+ writer: {
862
+ async write(chunk) {
863
+ await inner.write(chunk);
864
+ pending += decoder3.decode(chunk, {
865
+ stream: true
866
+ });
867
+ let newline = pending.indexOf("\n");
868
+ while (newline !== -1) {
869
+ const line = pending.slice(0, newline);
870
+ pending = pending.slice(newline + 1);
871
+ const event = line.trim().length > 0 ? decodeStreamEvent(line) : null;
872
+ if (event !== null) await observe(event);
873
+ newline = pending.indexOf("\n");
874
+ }
875
+ },
876
+ end: /* @__PURE__ */ __name(() => inner.end(), "end"),
877
+ fail: /* @__PURE__ */ __name((error) => inner.fail(error), "fail")
878
+ },
879
+ shown: /* @__PURE__ */ __name(() => [
880
+ ...shown.values()
881
+ ], "shown")
882
+ };
883
+ }
884
+ __name(previewToolInputs, "previewToolInputs");
885
+ function registryInputPreviews(registry, offered, scope) {
886
+ const names = new Set(offered.map((tool) => tool.name));
887
+ return async (toolName, toolCallId) => names.has(toolName) ? registry.previewInput(toolName, {
888
+ ...scope,
889
+ toolCallId
890
+ }) : void 0;
891
+ }
892
+ __name(registryInputPreviews, "registryInputPreviews");
893
+
471
894
  // src/tool-ui.ts
472
895
  var TOOL_STEP_UI = "@@nestjs-agent/tool-step-ui";
473
896
  function wrapToolStepOutput(output, ui, text) {
@@ -3354,6 +3777,7 @@ function defineComponent(definition) {
3354
3777
  }
3355
3778
  if (definition.version !== void 0 && (!Number.isSafeInteger(definition.version) || definition.version <= 0)) throw new RangeError("genui: component version must be a positive safe integer");
3356
3779
  if (definition.fallbackText !== void 0 && typeof definition.fallbackText !== "function") throw new TypeError("genui: fallbackText must be a function");
3780
+ if (definition.streaming !== void 0 && definition.streaming !== "partial" && definition.streaming !== "complete") throw new TypeError("genui: streaming must be 'partial' or 'complete'");
3357
3781
  return definition;
3358
3782
  }
3359
3783
  __name(defineComponent, "defineComponent");
@@ -4712,6 +5136,19 @@ var ToolRegistry = class {
4712
5136
  unregister(name) {
4713
5137
  return this.entries.delete(name);
4714
5138
  }
5139
+ /**
5140
+ * How a streamed call of `name` is previewed while its input arrives (`ToolHandler.previewInput`),
5141
+ * or `undefined`. A preview that fails to build is no preview: it never fails the turn.
5142
+ */
5143
+ async previewInput(name, scope) {
5144
+ const handler = this.entries.get(name)?.handler;
5145
+ if (handler?.previewInput === void 0) return void 0;
5146
+ try {
5147
+ return await handler.previewInput(scope) ?? void 0;
5148
+ } catch {
5149
+ return void 0;
5150
+ }
5151
+ }
4715
5152
  spec(name) {
4716
5153
  return this.entries.get(name)?.spec;
4717
5154
  }
@@ -4770,6 +5207,9 @@ var ToolRegistry = class {
4770
5207
  * Run a tool. Re-checks that the tool is enabled and that the role allows it (defense-in-depth —
4771
5208
  * a call can reach here from a replayed durable step or an approval granted before the flag
4772
5209
  * moved, neither of which went through `definitionsFor` again) and re-parses the input via Zod.
5210
+ * A tool whose `describe()` answers `available: false` for the call's scope (actor, thread, agent,
5211
+ * `uiCapabilities`) is refused with {@link ToolNotFoundError}, as the unknown tool it was to the
5212
+ * model.
4773
5213
  */
4774
5214
  async invoke(name, input, ctx, policy, options = {}) {
4775
5215
  const { entry, value, ctx: withEmit } = await this.validated(name, input, ctx, policy, options);
@@ -4823,6 +5263,10 @@ var ToolRegistry = class {
4823
5263
  if (options.allowedTools !== void 0 && !options.allowedTools.includes(name)) {
4824
5264
  throw new ToolForbiddenError(name);
4825
5265
  }
5266
+ if (entry.handler.describe !== void 0) {
5267
+ const described = await entry.handler.describe(describeScopeOf(ctx));
5268
+ if (described?.available === false) throw new ToolNotFoundError(name);
5269
+ }
4826
5270
  const validation = await entry.spec.inputSchema["~standard"].validate(input);
4827
5271
  if (validation.issues !== void 0) {
4828
5272
  throw new ToolInputInvalidError(name, validation.issues);
@@ -4838,6 +5282,21 @@ var ToolRegistry = class {
4838
5282
  };
4839
5283
  }
4840
5284
  };
5285
+ function describeScopeOf(ctx) {
5286
+ return {
5287
+ actor: ctx.actor,
5288
+ ...ctx.threadId ? {
5289
+ threadId: ctx.threadId
5290
+ } : {},
5291
+ ...ctx.agentName !== void 0 ? {
5292
+ agentName: ctx.agentName
5293
+ } : {},
5294
+ ...ctx.uiCapabilities !== void 0 ? {
5295
+ uiCapabilities: ctx.uiCapabilities
5296
+ } : {}
5297
+ };
5298
+ }
5299
+ __name(describeScopeOf, "describeScopeOf");
4841
5300
  var DefaultRolesPolicy = class {
4842
5301
  static {
4843
5302
  __name(this, "DefaultRolesPolicy");
@@ -5221,6 +5680,21 @@ var RunCancelledError = class extends Error {
5221
5680
  this.name = "RunCancelledError";
5222
5681
  }
5223
5682
  };
5683
+ async function abortableModelCall(hooks, call) {
5684
+ const signal = hooks.abortSignal;
5685
+ let result2;
5686
+ try {
5687
+ result2 = await call(signal !== void 0 ? {
5688
+ abortSignal: signal
5689
+ } : {});
5690
+ } catch (error) {
5691
+ if (signal?.aborted === true) throw new RunCancelledError();
5692
+ throw error;
5693
+ }
5694
+ if (signal?.aborted === true) throw new RunCancelledError();
5695
+ return result2;
5696
+ }
5697
+ __name(abortableModelCall, "abortableModelCall");
5224
5698
  function agentFailureCode(error) {
5225
5699
  if (error instanceof RunCancelledError) {
5226
5700
  return "cancelled";
@@ -5678,13 +6152,14 @@ async function structureAnswer(schema, deps, input, hooks, messages, step) {
5678
6152
  fail: /* @__PURE__ */ __name(() => {
5679
6153
  }, "fail")
5680
6154
  };
5681
- const turn = await deps.model.runTurn({
6155
+ const turn = await abortableModelCall(hooks, (signal) => deps.model.runTurn({
5682
6156
  system,
5683
6157
  messages,
5684
6158
  tools: [],
5685
6159
  sink: discard,
5686
- outputSchema: schema
5687
- });
6160
+ outputSchema: schema,
6161
+ ...signal
6162
+ }));
5688
6163
  return {
5689
6164
  text: turn.text,
5690
6165
  usage: turn.usage,
@@ -5806,6 +6281,9 @@ function toolContext(deps, input, hooks) {
5806
6281
  ...deps.host !== void 0 ? {
5807
6282
  host: deps.host
5808
6283
  } : {},
6284
+ ...hooks.abortSignal !== void 0 ? {
6285
+ abortSignal: hooks.abortSignal
6286
+ } : {},
5809
6287
  // Replaced per tool call by the call's own collector (see the tool step); this one only serves
5810
6288
  // what runs outside a call — the elicitation wait.
5811
6289
  emitUi: createNoopEmitUi(hooks.runId)
@@ -7173,26 +7651,46 @@ ${block}`;
7173
7651
  writer
7174
7652
  }) : void 0;
7175
7653
  const buffer = gateMode === "whole" ? createFrameBuffer() : void 0;
7176
- const frames = observeTurnFrames(incremental?.writer ?? buffer?.writer ?? writer);
7177
- const result2 = stampToolKinds(withTurnFrames(await traceLlmTurn(hooks.runId, i, () => deps.model.runTurn({
7654
+ const previews = previewToolInputs(incremental?.writer ?? buffer?.writer ?? writer, registryInputPreviews(deps.registry, tools, {
7655
+ actor: input.actor,
7656
+ threadId: input.threadId,
7657
+ ...input.agentName !== void 0 ? {
7658
+ agentName: input.agentName
7659
+ } : {},
7660
+ ...input.uiCapabilities !== void 0 ? {
7661
+ uiCapabilities: input.uiCapabilities
7662
+ } : {}
7663
+ }));
7664
+ const frames = observeTurnFrames(previews.writer);
7665
+ const result2 = stampToolKinds(withTurnFrames(await traceLlmTurn(hooks.runId, i, () => abortableModelCall(hooks, (signal) => deps.model.runTurn({
7178
7666
  system: prompt.system,
7179
7667
  messages: prompt.messages,
7180
7668
  tools,
7181
- sink: frames.writer
7182
- })), frames.summary()), deps);
7669
+ sink: frames.writer,
7670
+ ...signal
7671
+ }))), frames.summary()), deps);
7672
+ const shownPreviews = previews.shown();
7673
+ const previewed = shownPreviews.length > 0 ? {
7674
+ previews: shownPreviews
7675
+ } : {};
7183
7676
  if (incremental !== void 0) {
7184
7677
  await incremental.settled();
7185
7678
  const refusal = incremental.rejection();
7186
7679
  return {
7187
7680
  ...result2,
7681
+ ...previewed,
7188
7682
  releasedText: incremental.released(),
7189
7683
  ...refusal !== void 0 ? {
7190
7684
  gateRejection: refusal
7191
7685
  } : {}
7192
7686
  };
7193
7687
  }
7194
- return buffer === void 0 ? result2 : {
7688
+ return buffer === void 0 ? {
7689
+ ...result2,
7690
+ ...previewed
7691
+ } : {
7195
7692
  ...result2,
7693
+ ...previewed,
7196
7694
  bufferedFrames: buffer.frames()
7197
7695
  };
7198
7696
  });
@@ -7511,6 +8009,12 @@ ${block}`;
7511
8009
  if (toolUi.length > 0) {
7512
8010
  await deps.store.setMessageUi?.(assistant.id, mergeUi(turn.ui, toolUi));
7513
8011
  }
8012
+ for (const preview of turn.previews ?? []) {
8013
+ const pushed = turnCalls.toolUi.get(preview.toolCallId) ?? [];
8014
+ if (!pushed.some((component) => component.id === preview.id)) {
8015
+ await writer.write(encodeStreamEvent(withdrawPreviewEvent(preview)));
8016
+ }
8017
+ }
7514
8018
  for (const result2 of results) {
7515
8019
  await writer.write(encodeStreamEvent(outputFrame(result2)));
7516
8020
  }
@@ -9796,6 +10300,7 @@ __name(createFunctionalTool, "createFunctionalTool");
9796
10300
  DEFAULT_MAX_FACT_CHARS,
9797
10301
  DEFAULT_MAX_MEMORIES,
9798
10302
  DEFAULT_MAX_SKILLS,
10303
+ DEFAULT_PREVIEW_THROTTLE_MS,
9799
10304
  DEFAULT_REFUSAL_REASON,
9800
10305
  DEFAULT_STRUCTURED_OUTPUT_INSTRUCTION,
9801
10306
  DEFAULT_TEXT_ACTION_PROPOSAL_REPLIES,
@@ -9914,9 +10419,12 @@ __name(createFunctionalTool, "createFunctionalTool");
9914
10419
  observeTurnFrames,
9915
10420
  offerMemories,
9916
10421
  offerSkills,
10422
+ parsePartialJson,
9917
10423
  parseTextActionProposalCommand,
9918
10424
  personaCatalogEntry,
9919
10425
  prepareActionProposal,
10426
+ previewToolInputs,
10427
+ previewUiId,
9920
10428
  ptBrActionProposalText,
9921
10429
  publishAgentDelegated,
9922
10430
  publishAgentMemoryResolved,
@@ -9937,6 +10445,7 @@ __name(createFunctionalTool, "createFunctionalTool");
9937
10445
  quotaWarning,
9938
10446
  readElicitationInput,
9939
10447
  readElicitationQuestions,
10448
+ registryInputPreviews,
9940
10449
  releaseGatedFrames,
9941
10450
  releaseThreadRun,
9942
10451
  rememberInputSchema,
@@ -10005,6 +10514,7 @@ __name(createFunctionalTool, "createFunctionalTool");
10005
10514
  withSkillTool,
10006
10515
  withToolTimeout,
10007
10516
  withTurnFrames,
10517
+ withdrawPreviewEvent,
10008
10518
  wrapToolPreflightDenied,
10009
10519
  wrapToolStepOutput,
10010
10520
  writeMemory