@dudousxd/nestjs-agent-core 0.12.0 → 0.14.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.
package/dist/index.cjs CHANGED
@@ -30,6 +30,7 @@ __export(index_exports, {
30
30
  AGENT_DURABLE_RUNNER: () => AGENT_DURABLE_RUNNER,
31
31
  AGENT_EMBEDDING_PROVIDER: () => AGENT_EMBEDDING_PROVIDER,
32
32
  AGENT_GOVERNANCE_QUERIES: () => AGENT_GOVERNANCE_QUERIES,
33
+ AGENT_MEMORY: () => AGENT_MEMORY,
33
34
  AGENT_MODEL: () => AGENT_MODEL,
34
35
  AGENT_OPTIONS: () => AGENT_OPTIONS,
35
36
  AGENT_PRICING_STORE: () => AGENT_PRICING_STORE,
@@ -40,54 +41,132 @@ __export(index_exports, {
40
41
  AGENT_ROLES_POLICY: () => AGENT_ROLES_POLICY,
41
42
  AGENT_RUNNER: () => AGENT_RUNNER,
42
43
  AGENT_SINK: () => AGENT_SINK,
44
+ AGENT_SKILLS: () => AGENT_SKILLS,
45
+ AGENT_SKILL_SOURCES: () => AGENT_SKILL_SOURCES,
43
46
  AGENT_SPAN_EVENTS: () => AGENT_SPAN_EVENTS,
44
47
  AGENT_STORE: () => AGENT_STORE,
45
48
  AGENT_TOOL_REGISTRY: () => AGENT_TOOL_REGISTRY,
49
+ ASK_TOOL_DESCRIPTION: () => ASK_TOOL_DESCRIPTION,
50
+ ASK_TOOL_NAME: () => ASK_TOOL_NAME,
46
51
  AgentRegistry: () => AgentRegistry,
47
52
  AgentStreamError: () => AgentStreamError,
53
+ DEFAULT_HISTORY_SUMMARY_INSTRUCTION: () => DEFAULT_HISTORY_SUMMARY_INSTRUCTION,
54
+ DEFAULT_INCREMENTAL_LOOKBACK_CHARS: () => DEFAULT_INCREMENTAL_LOOKBACK_CHARS,
55
+ DEFAULT_INTAKE_PREAMBLE: () => DEFAULT_INTAKE_PREAMBLE,
56
+ DEFAULT_MAX_FACT_CHARS: () => DEFAULT_MAX_FACT_CHARS,
57
+ DEFAULT_MAX_MEMORIES: () => DEFAULT_MAX_MEMORIES,
58
+ DEFAULT_MAX_SKILLS: () => DEFAULT_MAX_SKILLS,
59
+ DEFAULT_STRUCTURED_OUTPUT_INSTRUCTION: () => DEFAULT_STRUCTURED_OUTPUT_INSTRUCTION,
48
60
  DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS: () => DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS,
49
61
  DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS: () => DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS,
50
62
  DefaultRolesPolicy: () => DefaultRolesPolicy,
63
+ GLOBAL_SCOPE: () => GLOBAL_SCOPE,
64
+ MAX_ASK_QUESTIONS: () => MAX_ASK_QUESTIONS,
65
+ OutputRejectedError: () => OutputRejectedError,
66
+ ProcessorFailedError: () => ProcessorFailedError,
51
67
  QuotaExceededError: () => QuotaExceededError,
68
+ REMEMBER_TOOL_DESCRIPTION: () => REMEMBER_TOOL_DESCRIPTION,
69
+ REMEMBER_TOOL_NAME: () => REMEMBER_TOOL_NAME,
70
+ RunCancelledError: () => RunCancelledError,
71
+ SKILL_TOOL_DESCRIPTION: () => SKILL_TOOL_DESCRIPTION,
72
+ SKILL_TOOL_NAME: () => SKILL_TOOL_NAME,
73
+ StructuredOutputError: () => StructuredOutputError,
52
74
  THREAD_DETAIL_CONTENT_CHARS: () => THREAD_DETAIL_CONTENT_CHARS,
53
75
  ToolDisabledError: () => ToolDisabledError,
54
76
  ToolForbiddenError: () => ToolForbiddenError,
55
77
  ToolInputInvalidError: () => ToolInputInvalidError,
56
78
  ToolNotFoundError: () => ToolNotFoundError,
57
79
  ToolRegistry: () => ToolRegistry,
80
+ actorScope: () => actorScope,
58
81
  agentDiagnosticKey: () => agentDiagnosticKey,
82
+ agentFailureCode: () => agentFailureCode,
83
+ askInputSchema: () => askInputSchema,
84
+ askToolDefinition: () => askToolDefinition,
59
85
  bucketByActor: () => bucketByActor,
60
86
  bucketByModel: () => bucketByModel,
61
87
  bucketByThread: () => bucketByThread,
62
88
  bucketUsageTrend: () => bucketUsageTrend,
89
+ buildMemoryBlock: () => buildMemoryBlock,
90
+ buildSkillsBlock: () => buildSkillsBlock,
63
91
  canActorUseTool: () => canActorUseTool,
92
+ compositeSkillProvider: () => compositeSkillProvider,
93
+ createFrameBuffer: () => createFrameBuffer,
94
+ createIncrementalGate: () => createIncrementalGate,
64
95
  dayBoundsUtc: () => dayBoundsUtc,
96
+ decodeStreamEvent: () => decodeStreamEvent,
97
+ defaultScopeResolver: () => defaultScopeResolver,
98
+ detachedDelivered: () => detachedDelivered,
99
+ detachedStarted: () => detachedStarted,
100
+ detachedUnsettled: () => detachedUnsettled,
65
101
  encodeStreamEvent: () => encodeStreamEvent,
66
102
  estimateCost: () => estimateCost,
103
+ estimateMessageTokens: () => estimateMessageTokens,
104
+ extractJson: () => extractJson,
67
105
  filterToolsByAllowList: () => filterToolsByAllowList,
68
106
  filterToolsByCanUse: () => filterToolsByCanUse,
69
107
  filterToolsByEnabled: () => filterToolsByEnabled,
70
108
  filterToolsByRole: () => filterToolsByRole,
109
+ gateFollowUps: () => gateFollowUps,
110
+ gateTail: () => gateTail,
71
111
  invokeWithTransientRetry: () => invokeWithTransientRetry,
112
+ isControlFlowSignal: () => isControlFlowSignal,
113
+ isReplayIntegrityError: () => isReplayIntegrityError,
72
114
  isToolEnabled: () => isToolEnabled,
73
115
  isTransientToolError: () => isTransientToolError,
116
+ loadSkill: () => loadSkill,
117
+ memoryForgetVerdict: () => memoryForgetVerdict,
118
+ memoryWriteVerdict: () => memoryWriteVerdict,
119
+ normalizeDelegation: () => normalizeDelegation,
120
+ normalizeElicitationReply: () => normalizeElicitationReply,
121
+ offerMemories: () => offerMemories,
122
+ offerSkills: () => offerSkills,
74
123
  publishAgentDelegated: () => publishAgentDelegated,
124
+ publishAgentMemoryResolved: () => publishAgentMemoryResolved,
125
+ publishAgentMemoryWritten: () => publishAgentMemoryWritten,
75
126
  publishAgentMessage: () => publishAgentMessage,
76
127
  publishAgentQuotaExceeded: () => publishAgentQuotaExceeded,
77
128
  publishAgentRetrieved: () => publishAgentRetrieved,
78
129
  publishAgentRunFailed: () => publishAgentRunFailed,
79
130
  publishAgentRunFinished: () => publishAgentRunFinished,
80
131
  publishAgentRunStarted: () => publishAgentRunStarted,
132
+ publishAgentSkillsResolved: () => publishAgentSkillsResolved,
81
133
  publishAgentToolCall: () => publishAgentToolCall,
82
134
  publishAgentToolRetry: () => publishAgentToolRetry,
135
+ releaseGatedFrames: () => releaseGatedFrames,
136
+ rememberInputSchema: () => rememberInputSchema,
137
+ rememberToolDefinition: () => rememberToolDefinition,
138
+ renderElicitationAnswers: () => renderElicitationAnswers,
139
+ repairInstruction: () => repairInstruction,
140
+ resolveElicitation: () => resolveElicitation,
141
+ resolveGateLookback: () => resolveGateLookback,
142
+ resolveMemoryDigest: () => resolveMemoryDigest,
143
+ resolveOutputGateMode: () => resolveOutputGateMode,
144
+ resolveSkillCatalog: () => resolveSkillCatalog,
83
145
  resolveToolTransientRetryNumbers: () => resolveToolTransientRetryNumbers,
84
146
  rollupThreadUsage: () => rollupThreadUsage,
85
147
  runAgentLoop: () => runAgentLoop,
148
+ runInputProcessors: () => runInputProcessors,
149
+ runOutputProcessors: () => runOutputProcessors,
86
150
  seedModelPrices: () => seedModelPrices,
151
+ settleAll: () => settleAll,
152
+ settleElicitation: () => settleElicitation,
153
+ settleUnsettledDelegation: () => settleUnsettledDelegation,
154
+ skillInputSchema: () => skillInputSchema,
155
+ skillToolDefinition: () => skillToolDefinition,
156
+ skillWriteVerdict: () => skillWriteVerdict,
157
+ staticSkillProvider: () => staticSkillProvider,
158
+ summarizeWithModel: () => summarizeWithModel,
159
+ tenantScope: () => tenantScope,
87
160
  traceLlmTurn: () => traceLlmTurn,
88
161
  traceToolExecution: () => traceToolExecution,
89
162
  truncateDetailContent: () => truncateDetailContent,
90
- withToolTimeout: () => withToolTimeout
163
+ validateStructured: () => validateStructured,
164
+ windowHistory: () => windowHistory,
165
+ withAskTool: () => withAskTool,
166
+ withMemoryTool: () => withMemoryTool,
167
+ withSkillTool: () => withSkillTool,
168
+ withToolTimeout: () => withToolTimeout,
169
+ writeMemory: () => writeMemory
91
170
  });
92
171
  module.exports = __toCommonJS(index_exports);
93
172
 
@@ -112,6 +191,9 @@ var AGENT_PROMPT_CONTRIBUTORS = Symbol.for("@dudousxd/nestjs-agent:prompt-contri
112
191
  var AGENT_ACTOR_DIRECTORY = Symbol.for("@dudousxd/nestjs-agent:actor-directory");
113
192
  var AGENT_ATTACHMENT_STAGING = Symbol.for("@dudousxd/nestjs-agent:attachment-staging");
114
193
  var AGENT_APPROVAL_PORT = Symbol.for("@dudousxd/nestjs-agent:approval-port");
194
+ var AGENT_SKILLS = Symbol.for("@dudousxd/nestjs-agent:skills");
195
+ var AGENT_MEMORY = Symbol.for("@dudousxd/nestjs-agent:memory");
196
+ var AGENT_SKILL_SOURCES = Symbol.for("@dudousxd/nestjs-agent:skill-sources");
115
197
 
116
198
  // src/spi/token-stream-sink.ts
117
199
  var AgentStreamError = class extends Error {
@@ -133,6 +215,17 @@ function encodeStreamEvent(event) {
133
215
  `);
134
216
  }
135
217
  __name(encodeStreamEvent, "encodeStreamEvent");
218
+ function decodeStreamEvent(line) {
219
+ try {
220
+ const parsed = JSON.parse(line);
221
+ if (typeof parsed === "object" && parsed !== null && typeof parsed.kind === "string") {
222
+ return parsed;
223
+ }
224
+ } catch {
225
+ }
226
+ return null;
227
+ }
228
+ __name(decodeStreamEvent, "decodeStreamEvent");
136
229
 
137
230
  // src/spi/pricing-store.ts
138
231
  async function seedModelPrices(store, prices) {
@@ -142,6 +235,40 @@ async function seedModelPrices(store, prices) {
142
235
  }
143
236
  __name(seedModelPrices, "seedModelPrices");
144
237
 
238
+ // src/spi/processors.ts
239
+ var DEFAULT_INCREMENTAL_LOOKBACK_CHARS = 64;
240
+ var OutputRejectedError = class extends Error {
241
+ static {
242
+ __name(this, "OutputRejectedError");
243
+ }
244
+ /** {@link OutputProcessor.name} of the processor that refused. */
245
+ processor;
246
+ /** The reason it gave, verbatim. */
247
+ reason;
248
+ constructor(processor, reason) {
249
+ super(`Output rejected by "${processor}": ${reason}`);
250
+ this.name = "OutputRejectedError";
251
+ this.processor = processor;
252
+ this.reason = reason;
253
+ }
254
+ };
255
+ var ProcessorFailedError = class extends Error {
256
+ static {
257
+ __name(this, "ProcessorFailedError");
258
+ }
259
+ /** Which seam it was on, so a reader knows whether the prompt or the answer was in flight. */
260
+ phase;
261
+ /** The processor's `name`. */
262
+ processor;
263
+ constructor(phase, processor, cause) {
264
+ super(`${phase} processor "${processor}" failed: ${cause instanceof Error ? cause.message : String(cause)}`);
265
+ this.name = "ProcessorFailedError";
266
+ this.phase = phase;
267
+ this.processor = processor;
268
+ this.cause = cause;
269
+ }
270
+ };
271
+
145
272
  // src/spi/governance-queries.ts
146
273
  var THREAD_DETAIL_CONTENT_CHARS = 2e3;
147
274
  function truncateDetailContent(content) {
@@ -358,464 +485,2779 @@ function filterToolsByAllowList(tools, allowedTools) {
358
485
  }
359
486
  __name(filterToolsByAllowList, "filterToolsByAllowList");
360
487
 
361
- // src/agent-registry.ts
362
- var AgentRegistry = class {
363
- static {
364
- __name(this, "AgentRegistry");
488
+ // src/history.ts
489
+ function estimateMessageTokens(message) {
490
+ const extras = (message.toolCalls !== void 0 ? JSON.stringify(message.toolCalls).length : 0) + (message.toolResults !== void 0 ? JSON.stringify(message.toolResults).length : 0);
491
+ return Math.ceil((message.content.length + extras) / 4) + 4;
492
+ }
493
+ __name(estimateMessageTokens, "estimateMessageTokens");
494
+ function windowHistory(options) {
495
+ const estimate = options.estimate ?? estimateMessageTokens;
496
+ const policy = {
497
+ // A suffix selection of at most `maxMessages` rows, which is exactly what `HistoryPolicy`'s row
498
+ // hint promises — so the store can bound its read to that many of the thread's newest messages.
499
+ // A token-only window declares nothing: its budget names no row count.
500
+ ...options.maxMessages !== void 0 ? {
501
+ maxMessages: options.maxMessages
502
+ } : {},
503
+ select(messages) {
504
+ let cut = 0;
505
+ if (options.maxMessages !== void 0) {
506
+ cut = Math.max(cut, messages.length - options.maxMessages);
507
+ }
508
+ if (options.maxTokens !== void 0) {
509
+ cut = Math.max(cut, tokenCut(messages, options.maxTokens, estimate));
510
+ }
511
+ cut = Math.min(cut, Math.max(0, messages.length - 1));
512
+ return {
513
+ keep: messages.slice(cut),
514
+ drop: messages.slice(0, cut)
515
+ };
516
+ }
517
+ };
518
+ return options.summarize !== void 0 ? {
519
+ ...policy,
520
+ summarize: options.summarize
521
+ } : policy;
522
+ }
523
+ __name(windowHistory, "windowHistory");
524
+ function tokenCut(messages, maxTokens, estimate) {
525
+ let index = messages.length;
526
+ let total = 0;
527
+ while (index > 0) {
528
+ const message = messages[index - 1];
529
+ if (message === void 0) {
530
+ break;
531
+ }
532
+ const cost = estimate(message);
533
+ if (index < messages.length && total + cost > maxTokens) {
534
+ break;
535
+ }
536
+ total += cost;
537
+ index -= 1;
365
538
  }
366
- definitions = /* @__PURE__ */ new Map();
367
- register(definition) {
368
- this.definitions.set(definition.name, definition);
539
+ return index;
540
+ }
541
+ __name(tokenCut, "tokenCut");
542
+ var DEFAULT_HISTORY_SUMMARY_INSTRUCTION = "Summarize this conversation for an assistant that will continue it without seeing these messages. Preserve decisions made, facts and constraints the user stated, identifiers and names mentioned, and anything left unresolved. Omit pleasantries. Reply with the summary only \u2014 no preamble, no headings.";
543
+ function summarizeWithModel(model, instruction = DEFAULT_HISTORY_SUMMARY_INSTRUCTION) {
544
+ return async (dropped) => {
545
+ const discard = {
546
+ write: /* @__PURE__ */ __name(() => {
547
+ }, "write"),
548
+ end: /* @__PURE__ */ __name(() => {
549
+ }, "end"),
550
+ fail: /* @__PURE__ */ __name(() => {
551
+ }, "fail")
552
+ };
553
+ const turn = await model.runTurn({
554
+ system: instruction,
555
+ messages: dropped,
556
+ tools: [],
557
+ sink: discard
558
+ });
559
+ return {
560
+ text: turn.text,
561
+ usage: turn.usage,
562
+ ...turn.modelId !== void 0 ? {
563
+ modelId: turn.modelId
564
+ } : {}
565
+ };
566
+ };
567
+ }
568
+ __name(summarizeWithModel, "summarizeWithModel");
569
+
570
+ // src/processors.ts
571
+ var decoder = new TextDecoder();
572
+ function createFrameBuffer() {
573
+ const frames = [];
574
+ return {
575
+ writer: {
576
+ write: /* @__PURE__ */ __name((chunk) => {
577
+ for (const line of decoder.decode(chunk).split("\n")) {
578
+ if (line.length > 0) {
579
+ frames.push(line);
580
+ }
581
+ }
582
+ }, "write"),
583
+ end: /* @__PURE__ */ __name(() => {
584
+ }, "end"),
585
+ fail: /* @__PURE__ */ __name(() => {
586
+ }, "fail")
587
+ },
588
+ frames: /* @__PURE__ */ __name(() => frames, "frames")
589
+ };
590
+ }
591
+ __name(createFrameBuffer, "createFrameBuffer");
592
+ function releaseGatedFrames(frames, text) {
593
+ const released = [];
594
+ let emitted = false;
595
+ for (const frame of frames) {
596
+ const event = decodeStreamEvent(frame);
597
+ if (event === null || event.kind === "text") {
598
+ if (!emitted && text.length > 0) {
599
+ released.push(encodeStreamEvent({
600
+ kind: "text",
601
+ text
602
+ }));
603
+ emitted = true;
604
+ }
605
+ continue;
606
+ }
607
+ released.push(encodeStreamEvent(event));
369
608
  }
370
- get(name) {
371
- return this.definitions.get(name);
609
+ if (!emitted && text.length > 0) {
610
+ released.push(encodeStreamEvent({
611
+ kind: "text",
612
+ text
613
+ }));
372
614
  }
373
- has(name) {
374
- return this.definitions.has(name);
615
+ return released;
616
+ }
617
+ __name(releaseGatedFrames, "releaseGatedFrames");
618
+ async function runInputProcessors(processors, prompt, ctx) {
619
+ let current = prompt;
620
+ for (const processor of processors) {
621
+ try {
622
+ current = await processor.process(current, ctx);
623
+ } catch (error) {
624
+ throw new ProcessorFailedError("input", processor.name, error);
625
+ }
375
626
  }
376
- list() {
377
- return [
378
- ...this.definitions.values()
379
- ];
627
+ return current;
628
+ }
629
+ __name(runInputProcessors, "runInputProcessors");
630
+ async function runOutputProcessors(processors, answer, ctx) {
631
+ let text = answer.text;
632
+ for (const processor of processors) {
633
+ let verdict;
634
+ try {
635
+ verdict = await processor.process({
636
+ text,
637
+ toolCalls: answer.toolCalls
638
+ }, ctx);
639
+ } catch (error) {
640
+ throw new ProcessorFailedError("output", processor.name, error);
641
+ }
642
+ if (verdict.action === "reject") {
643
+ return {
644
+ text,
645
+ rejection: {
646
+ processor: processor.name,
647
+ reason: verdict.reason
648
+ }
649
+ };
650
+ }
651
+ if (verdict.action === "replace") {
652
+ text = verdict.text;
653
+ }
380
654
  }
381
- };
382
-
383
- // src/tool-registry.ts
384
- var ToolForbiddenError = class extends Error {
385
- static {
386
- __name(this, "ToolForbiddenError");
655
+ return {
656
+ text
657
+ };
658
+ }
659
+ __name(runOutputProcessors, "runOutputProcessors");
660
+ async function gateFollowUps(processors, followUps, ctx) {
661
+ const kept = [];
662
+ for (const followUp of followUps) {
663
+ const settled = await runOutputProcessors(processors, {
664
+ text: followUp,
665
+ toolCalls: []
666
+ }, ctx);
667
+ if (settled.rejection === void 0 && settled.text.length > 0) {
668
+ kept.push(settled.text);
669
+ }
387
670
  }
388
- toolName;
389
- constructor(toolName) {
390
- super(`Tool "${toolName}" is not allowed for this role`), this.toolName = toolName;
391
- this.name = "ToolForbiddenError";
671
+ return kept;
672
+ }
673
+ __name(gateFollowUps, "gateFollowUps");
674
+ function resolveOutputGateMode(processors) {
675
+ if (processors.length === 0) {
676
+ return "off";
392
677
  }
393
- };
394
- var ToolDisabledError = class extends Error {
395
- static {
396
- __name(this, "ToolDisabledError");
678
+ return processors.every((processor) => processor.incremental !== void 0) ? "incremental" : "whole";
679
+ }
680
+ __name(resolveOutputGateMode, "resolveOutputGateMode");
681
+ function resolveGateLookback(processors) {
682
+ let lookback = 0;
683
+ for (const processor of processors) {
684
+ if (processor.incremental !== void 0) {
685
+ lookback = Math.max(lookback, processor.incremental.lookbackChars ?? DEFAULT_INCREMENTAL_LOOKBACK_CHARS);
686
+ }
397
687
  }
398
- toolName;
399
- constructor(toolName) {
400
- super(`Tool "${toolName}" is disabled in this deployment`), this.toolName = toolName;
401
- this.name = "ToolDisabledError";
688
+ return lookback;
689
+ }
690
+ __name(resolveGateLookback, "resolveGateLookback");
691
+ function createIncrementalGate(options) {
692
+ const { processors, ctx, lookbackChars, writer } = options;
693
+ let raw = "";
694
+ let released = "";
695
+ let rejection;
696
+ let stalled = false;
697
+ const toolCalls = [];
698
+ let queue = Promise.resolve();
699
+ async function advance() {
700
+ if (raw.length === 0) {
701
+ return;
702
+ }
703
+ let settled;
704
+ try {
705
+ settled = await runOutputProcessors(processors, {
706
+ text: raw,
707
+ toolCalls
708
+ }, ctx);
709
+ } catch {
710
+ stalled = true;
711
+ return;
712
+ }
713
+ if (settled.rejection !== void 0) {
714
+ rejection = settled.rejection;
715
+ return;
716
+ }
717
+ const candidate = settled.text.slice(0, Math.max(0, settled.text.length - lookbackChars));
718
+ if (candidate.length <= released.length || !candidate.startsWith(released)) {
719
+ return;
720
+ }
721
+ const delta = candidate.slice(released.length);
722
+ released = candidate;
723
+ await writer.write(encodeStreamEvent({
724
+ kind: "text",
725
+ text: delta
726
+ }));
402
727
  }
403
- };
404
- var ToolNotFoundError = class extends Error {
405
- static {
406
- __name(this, "ToolNotFoundError");
728
+ __name(advance, "advance");
729
+ async function handle(chunk) {
730
+ for (const line of decoder.decode(chunk).split("\n")) {
731
+ if (line.length === 0) {
732
+ continue;
733
+ }
734
+ const event = decodeStreamEvent(line);
735
+ if (event === null || rejection !== void 0) {
736
+ continue;
737
+ }
738
+ if (event.kind === "text") {
739
+ raw += event.text;
740
+ if (!stalled) {
741
+ await advance();
742
+ }
743
+ continue;
744
+ }
745
+ if (event.kind === "tool-input-available") {
746
+ toolCalls.push({
747
+ id: event.id,
748
+ name: event.name,
749
+ input: event.input
750
+ });
751
+ }
752
+ await writer.write(encodeStreamEvent(event));
753
+ }
407
754
  }
408
- toolName;
409
- constructor(toolName) {
410
- super(`Tool "${toolName}" is not registered`), this.toolName = toolName;
411
- this.name = "ToolNotFoundError";
755
+ __name(handle, "handle");
756
+ return {
757
+ writer: {
758
+ write: /* @__PURE__ */ __name((chunk) => {
759
+ queue = queue.then(() => handle(chunk));
760
+ return queue;
761
+ }, "write"),
762
+ end: /* @__PURE__ */ __name(() => {
763
+ }, "end"),
764
+ fail: /* @__PURE__ */ __name(() => {
765
+ }, "fail")
766
+ },
767
+ settled: /* @__PURE__ */ __name(() => queue, "settled"),
768
+ released: /* @__PURE__ */ __name(() => released, "released"),
769
+ rejection: /* @__PURE__ */ __name(() => rejection, "rejection")
770
+ };
771
+ }
772
+ __name(createIncrementalGate, "createIncrementalGate");
773
+ function gateTail(processors, released, text) {
774
+ if (!text.startsWith(released)) {
775
+ throw new ProcessorFailedError("output", processors.map((processor) => processor.name).join(" \u2192 "), new Error(`the gated answer is not an extension of the ${released.length} characters this chain already released \u2014 a processor that declares "incremental" promises its result on a prefix stays a prefix of its result on the whole answer, outside the last lookbackChars`));
412
776
  }
413
- };
414
- var ToolInputInvalidError = class extends Error {
777
+ return text.slice(released.length);
778
+ }
779
+ __name(gateTail, "gateTail");
780
+
781
+ // src/structured-output.ts
782
+ var StructuredOutputError = class extends Error {
415
783
  static {
416
- __name(this, "ToolInputInvalidError");
784
+ __name(this, "StructuredOutputError");
417
785
  }
418
- toolName;
786
+ /** Why it failed the schema. Empty only when the text was not JSON at all. */
419
787
  issues;
420
- constructor(toolName, issues) {
421
- super(`Invalid input for tool "${toolName}": ${issues.map((issue) => issue.message).join("; ")}`), this.toolName = toolName, this.issues = issues;
422
- this.name = "ToolInputInvalidError";
788
+ /** The last text the model produced, verbatim. */
789
+ text;
790
+ /** How many model calls were spent trying (1 = the formatting pass, no repairs). */
791
+ attempts;
792
+ constructor(issues, text, attempts) {
793
+ const detail = issues.length > 0 ? issues.map((issue4) => issue4.message).join("; ") : "the model did not reply with JSON";
794
+ super(`Structured output invalid after ${attempts} attempt(s): ${detail}`);
795
+ this.name = "StructuredOutputError";
796
+ this.issues = issues;
797
+ this.text = text;
798
+ this.attempts = attempts;
423
799
  }
424
800
  };
425
- var ToolRegistry = class {
426
- static {
427
- __name(this, "ToolRegistry");
428
- }
429
- entries = /* @__PURE__ */ new Map();
430
- register(spec, handler) {
431
- this.entries.set(spec.name, {
432
- spec,
433
- handler
434
- });
435
- }
436
- has(name) {
437
- return this.entries.has(name);
438
- }
439
- spec(name) {
440
- return this.entries.get(name)?.spec;
441
- }
442
- allSpecs() {
443
- return [
444
- ...this.entries.values()
445
- ].map((entry) => entry.spec);
446
- }
447
- /**
448
- * The tools to offer the model for this actor+agent, after the four filter layers: what this
449
- * deployment has enabled, what this actor's role allows, what each tool's own `canUse` allows
450
- * this actor, and finally what this agent pinned.
451
- *
452
- * Every layer only ever removes tools, so no arrangement of them can widen what a turn reaches.
453
- */
454
- async definitionsFor(actor, policy, allowedTools) {
455
- const live = await filterToolsByEnabled([
456
- ...this.entries.values()
457
- ]);
458
- const allowedByRole = new Set((await filterToolsByRole(live.map((entry) => entry.spec), actor, policy)).map((spec) => spec.name));
459
- const roleScoped = live.filter((entry) => allowedByRole.has(entry.spec.name));
460
- const actorScoped = await filterToolsByCanUse(roleScoped, actor);
461
- const allowScoped = filterToolsByAllowList(actorScoped.map((entry) => entry.spec), allowedTools);
462
- return allowScoped.map((spec) => ({
463
- name: spec.name,
464
- kind: spec.kind,
465
- description: spec.description,
466
- inputSchema: spec.inputSchema
467
- }));
468
- }
469
- /**
470
- * Run a tool. Re-checks that the tool is enabled and that the role allows it (defense-in-depth —
471
- * a call can reach here from a replayed durable step or an approval granted before the flag
472
- * moved, neither of which went through `definitionsFor` again) and re-parses the input via Zod.
473
- */
474
- async invoke(name, input, ctx, policy) {
475
- const entry = this.entries.get(name);
476
- if (entry === void 0) {
477
- throw new ToolNotFoundError(name);
478
- }
479
- if (!await isToolEnabled(entry.spec, entry.handler)) {
480
- throw new ToolDisabledError(name);
481
- }
482
- if (!await policy.can(ctx.actor, entry.spec)) {
483
- throw new ToolForbiddenError(name);
484
- }
485
- if (!await canActorUseTool(ctx.actor, entry.handler)) {
486
- throw new ToolForbiddenError(name);
801
+ function extractJson(text) {
802
+ const candidates = [
803
+ text,
804
+ text.match(/\{[\s\S]*\}/)?.[0],
805
+ text.match(/\[[\s\S]*\]/)?.[0]
806
+ ];
807
+ for (const candidate of candidates) {
808
+ if (candidate === void 0) {
809
+ continue;
487
810
  }
488
- const validation = await entry.spec.inputSchema["~standard"].validate(input);
489
- if (validation.issues !== void 0) {
490
- throw new ToolInputInvalidError(name, validation.issues);
811
+ try {
812
+ return JSON.parse(candidate);
813
+ } catch {
491
814
  }
492
- return entry.handler.execute(validation.value, ctx);
493
- }
494
- };
495
- var DefaultRolesPolicy = class {
496
- static {
497
- __name(this, "DefaultRolesPolicy");
498
- }
499
- defaultRoles;
500
- constructor(defaultRoles = [
501
- "ADMIN"
502
- ]) {
503
- this.defaultRoles = defaultRoles;
504
815
  }
505
- can(actor, tool) {
506
- const allowed = tool.roles ?? this.defaultRoles;
507
- return (actor.roles ?? []).some((role) => allowed.includes(role));
816
+ return void 0;
817
+ }
818
+ __name(extractJson, "extractJson");
819
+ async function validateStructured(schema, text, reported) {
820
+ const candidate = reported !== void 0 ? reported : extractJson(text);
821
+ if (candidate === void 0) {
822
+ return {
823
+ ok: false,
824
+ issues: []
825
+ };
508
826
  }
509
- };
510
-
511
- // src/agent-loop.ts
512
- var import_node_crypto = require("crypto");
513
- var import_nestjs_diagnostics2 = require("@dudousxd/nestjs-diagnostics");
827
+ const result = await schema["~standard"].validate(candidate);
828
+ return result.issues !== void 0 ? {
829
+ ok: false,
830
+ issues: result.issues
831
+ } : {
832
+ ok: true,
833
+ value: result.value
834
+ };
835
+ }
836
+ __name(validateStructured, "validateStructured");
837
+ var DEFAULT_STRUCTURED_OUTPUT_INSTRUCTION = "Restate the assistant's final answer as a single JSON value matching the required schema. Use only information already present in the conversation \u2014 add nothing, and answer nothing that was not asked. Reply with ONLY the JSON: no prose, no explanation, no code fences.";
838
+ function repairInstruction(instruction, issues) {
839
+ const detail = issues.length > 0 ? issues.map((issue4) => `${(issue4.path ?? []).join(".") || "(root)"}: ${issue4.message}`).join("\n") : "the previous reply was not valid JSON";
840
+ return `${instruction}
514
841
 
515
- // src/diagnostics.ts
516
- var import_nestjs_diagnostics = require("@dudousxd/nestjs-diagnostics");
517
- function publishAgentRunStarted(payload) {
518
- (0, import_nestjs_diagnostics.emit)("agent", "run.started", payload);
842
+ Your previous reply was rejected:
843
+ ${detail}`;
519
844
  }
520
- __name(publishAgentRunStarted, "publishAgentRunStarted");
521
- function publishAgentMessage(payload) {
522
- (0, import_nestjs_diagnostics.emit)("agent", "message", payload);
845
+ __name(repairInstruction, "repairInstruction");
846
+
847
+ // src/elicitation.ts
848
+ function optionValues(question) {
849
+ return new Set(question.options.map((option) => option.value));
523
850
  }
524
- __name(publishAgentMessage, "publishAgentMessage");
525
- function publishAgentToolCall(payload) {
526
- (0, import_nestjs_diagnostics.emit)("agent", "tool-call", payload);
851
+ __name(optionValues, "optionValues");
852
+ function normalizeElicitationReply(reply) {
853
+ if (typeof reply !== "object" || reply === null) {
854
+ return {
855
+ answers: {}
856
+ };
857
+ }
858
+ const candidate = reply;
859
+ if (typeof candidate.answers === "object" && candidate.answers !== null) {
860
+ return reply;
861
+ }
862
+ const answeredByRef = candidate.answeredByRef ?? candidate.executedByRef;
863
+ return {
864
+ answers: {},
865
+ ...candidate.approved === false || candidate.skipped === true ? {
866
+ skipped: true
867
+ } : {},
868
+ ...answeredByRef !== void 0 ? {
869
+ answeredByRef
870
+ } : {}
871
+ };
527
872
  }
528
- __name(publishAgentToolCall, "publishAgentToolCall");
529
- function publishAgentQuotaExceeded(payload) {
530
- (0, import_nestjs_diagnostics.emit)("agent", "quota.exceeded", payload);
873
+ __name(normalizeElicitationReply, "normalizeElicitationReply");
874
+ function resolveElicitation(request, raw) {
875
+ const reply = normalizeElicitationReply(raw);
876
+ const answers = {};
877
+ const defaulted = [];
878
+ for (const question of request.questions) {
879
+ const submitted = reply.skipped === true ? void 0 : reply.answers[question.id];
880
+ if (submitted === void 0) {
881
+ answers[question.id] = [
882
+ ...question.defaults ?? []
883
+ ];
884
+ defaulted.push(question.id);
885
+ continue;
886
+ }
887
+ const allowed = optionValues(question);
888
+ const valid = question.allowFreeText === true ? submitted : submitted.filter((value) => allowed.has(value));
889
+ answers[question.id] = question.multiple === true ? valid : valid.slice(0, 1);
890
+ }
891
+ return {
892
+ answers,
893
+ skipped: reply.skipped === true,
894
+ defaulted
895
+ };
531
896
  }
532
- __name(publishAgentQuotaExceeded, "publishAgentQuotaExceeded");
533
- function publishAgentRunFinished(payload) {
534
- (0, import_nestjs_diagnostics.emit)("agent", "run.finished", payload);
897
+ __name(resolveElicitation, "resolveElicitation");
898
+ function settleElicitation(request, reply) {
899
+ const outcome = resolveElicitation(request, reply);
900
+ return {
901
+ ...outcome,
902
+ summary: renderElicitationAnswers(request, outcome)
903
+ };
535
904
  }
536
- __name(publishAgentRunFinished, "publishAgentRunFinished");
537
- function publishAgentRunFailed(payload) {
538
- (0, import_nestjs_diagnostics.emit)("agent", "run.failed", payload);
905
+ __name(settleElicitation, "settleElicitation");
906
+ function renderElicitationAnswers(request, outcome) {
907
+ const lines = request.questions.map((question) => {
908
+ const chosen = outcome.answers[question.id] ?? [];
909
+ const labels = chosen.map((value) => question.options.find((option) => option.value === value)?.label ?? value);
910
+ return `${question.prompt} \u2192 ${labels.length > 0 ? labels.join(", ") : "(no answer)"}`;
911
+ });
912
+ const preface = outcome.skipped ? "The user declined to answer and asked you to proceed on these assumptions:" : "The user answered:";
913
+ return `${preface}
914
+ ${lines.join("\n")}`;
539
915
  }
540
- __name(publishAgentRunFailed, "publishAgentRunFailed");
541
- function publishAgentDelegated(payload) {
542
- (0, import_nestjs_diagnostics.emit)("agent", "delegated", payload);
543
- }
544
- __name(publishAgentDelegated, "publishAgentDelegated");
545
- function publishAgentRetrieved(payload) {
546
- (0, import_nestjs_diagnostics.emit)("agent", "retrieved", payload);
547
- }
548
- __name(publishAgentRetrieved, "publishAgentRetrieved");
549
- function publishAgentToolRetry(payload) {
550
- (0, import_nestjs_diagnostics.emit)("agent", "tool.retry", payload);
551
- }
552
- __name(publishAgentToolRetry, "publishAgentToolRetry");
553
- var AGENT_SPAN_EVENTS = [
554
- "llm.turn",
555
- "tool.execution",
556
- "retrieval",
557
- "follow-ups"
558
- ];
559
- var AGENT_DIAGNOSTIC_EVENTS = [
560
- "run.started",
561
- "message",
562
- "tool-call",
563
- "quota.exceeded",
564
- "run.finished",
565
- "run.failed",
566
- "delegated",
567
- "retrieved",
568
- "tool.retry"
569
- ];
570
- function agentDiagnosticKey(event) {
571
- return `agent:${event}`;
916
+ __name(renderElicitationAnswers, "renderElicitationAnswers");
917
+ var ASK_TOOL_NAME = "ask";
918
+ var MAX_ASK_QUESTIONS = 5;
919
+ function issue(path, message) {
920
+ return {
921
+ message,
922
+ path
923
+ };
572
924
  }
573
- __name(agentDiagnosticKey, "agentDiagnosticKey");
574
-
575
- // src/tool-retry.ts
576
- function hasTransientShape(error) {
577
- if (typeof error !== "object" || error === null) {
578
- return false;
579
- }
580
- const code = "code" in error ? error.code : void 0;
581
- const errno = "errno" in error ? error.errno : void 0;
582
- const sqlState = "sqlState" in error ? error.sqlState : void 0;
583
- if (code === 1213 || code === 1205 || errno === 1213 || errno === 1205) {
584
- return true;
585
- }
586
- if (code === "ER_LOCK_DEADLOCK" || code === "ER_LOCK_WAIT_TIMEOUT") {
587
- return true;
588
- }
589
- if (code === "40001" || code === "40P01" || sqlState === "40001" || sqlState === "40P01") {
590
- return true;
925
+ __name(issue, "issue");
926
+ function parseOption(raw, path, issues) {
927
+ if (typeof raw !== "object" || raw === null) {
928
+ issues.push(issue(path, "must be an object"));
929
+ return void 0;
930
+ }
931
+ const candidate = raw;
932
+ if (typeof candidate.value !== "string" || candidate.value.length === 0) {
933
+ issues.push(issue([
934
+ ...path,
935
+ "value"
936
+ ], "must be a non-empty string"));
937
+ return void 0;
938
+ }
939
+ if (typeof candidate.label !== "string" || candidate.label.length === 0) {
940
+ issues.push(issue([
941
+ ...path,
942
+ "label"
943
+ ], "must be a non-empty string"));
944
+ return void 0;
591
945
  }
592
- if (code === "SQLITE_BUSY") {
593
- return true;
594
- }
595
- const message = "message" in error ? error.message : void 0;
596
- return typeof message === "string" && /deadlock|lock wait timeout|serialization failure/i.test(message);
946
+ return {
947
+ value: candidate.value,
948
+ label: candidate.label,
949
+ ...typeof candidate.hotkey === "string" ? {
950
+ hotkey: candidate.hotkey
951
+ } : {}
952
+ };
597
953
  }
598
- __name(hasTransientShape, "hasTransientShape");
599
- function isTransientToolError(error) {
600
- if (hasTransientShape(error)) {
601
- return true;
602
- }
603
- if (typeof error === "object" && error !== null && "cause" in error) {
604
- const cause = error.cause;
605
- if (cause !== void 0 && cause !== error && hasTransientShape(cause)) {
606
- return true;
954
+ __name(parseOption, "parseOption");
955
+ function parseQuestion(raw, path, issues) {
956
+ if (typeof raw !== "object" || raw === null) {
957
+ issues.push(issue(path, "must be an object"));
958
+ return void 0;
959
+ }
960
+ const candidate = raw;
961
+ if (typeof candidate.id !== "string" || candidate.id.length === 0) {
962
+ issues.push(issue([
963
+ ...path,
964
+ "id"
965
+ ], "must be a non-empty string"));
966
+ return void 0;
967
+ }
968
+ if (typeof candidate.prompt !== "string" || candidate.prompt.length === 0) {
969
+ issues.push(issue([
970
+ ...path,
971
+ "prompt"
972
+ ], "must be a non-empty string"));
973
+ return void 0;
974
+ }
975
+ if (!Array.isArray(candidate.options) || candidate.options.length === 0) {
976
+ issues.push(issue([
977
+ ...path,
978
+ "options"
979
+ ], "must be a non-empty array"));
980
+ return void 0;
981
+ }
982
+ const options = [];
983
+ for (const [index, rawOption] of candidate.options.entries()) {
984
+ const option = parseOption(rawOption, [
985
+ ...path,
986
+ "options",
987
+ index
988
+ ], issues);
989
+ if (option !== void 0) {
990
+ options.push(option);
607
991
  }
608
992
  }
609
- return false;
610
- }
611
- __name(isTransientToolError, "isTransientToolError");
612
- var DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS = 2;
613
- var DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS = 150;
614
- function resolveToolTransientRetryNumbers(setting) {
615
- if (setting === false) {
616
- return false;
993
+ if (!Array.isArray(candidate.defaults) || candidate.defaults.length === 0) {
994
+ issues.push(issue([
995
+ ...path,
996
+ "defaults"
997
+ ], "must pre-pick at least one option \u2014 say what you would choose so the user can just confirm"));
998
+ return void 0;
999
+ }
1000
+ const offered = new Set(options.map((option) => option.value));
1001
+ const defaults = candidate.defaults.filter((value) => typeof value === "string" && offered.has(value));
1002
+ if (defaults.length === 0) {
1003
+ issues.push(issue([
1004
+ ...path,
1005
+ "defaults"
1006
+ ], "must name values that appear in this question's options"));
1007
+ return void 0;
617
1008
  }
618
1009
  return {
619
- attempts: setting?.attempts ?? DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS,
620
- backoffMs: setting?.backoffMs ?? DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS
1010
+ id: candidate.id,
1011
+ prompt: candidate.prompt,
1012
+ options,
1013
+ defaults,
1014
+ ...candidate.multiple === true ? {
1015
+ multiple: true
1016
+ } : {},
1017
+ ...candidate.allowFreeText === true ? {
1018
+ allowFreeText: true
1019
+ } : {}
621
1020
  };
622
1021
  }
623
- __name(resolveToolTransientRetryNumbers, "resolveToolTransientRetryNumbers");
624
- function delay(ms) {
625
- return new Promise((resolve) => {
626
- setTimeout(resolve, ms);
627
- });
628
- }
629
- __name(delay, "delay");
630
- async function invokeWithTransientRetry(fn, setting, options) {
631
- if (setting === false) {
632
- return fn();
633
- }
634
- const attempts = setting.attempts ?? DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS;
635
- const backoffMs = setting.backoffMs ?? DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS;
636
- const classify = setting.classify ?? isTransientToolError;
637
- let attempt = 1;
638
- for (; ; ) {
639
- try {
640
- return await fn();
641
- } catch (error) {
642
- if (options?.isControlFlowError?.(error) === true) {
643
- throw error;
1022
+ __name(parseQuestion, "parseQuestion");
1023
+ var ASK_JSON_SCHEMA = {
1024
+ type: "object",
1025
+ additionalProperties: false,
1026
+ properties: {
1027
+ preamble: {
1028
+ type: "string",
1029
+ description: 'One sentence shown above the form, e.g. "Three questions before I start. I have pre-picked what I would choose, so confirming is enough."'
1030
+ },
1031
+ questions: {
1032
+ type: "array",
1033
+ minItems: 1,
1034
+ maxItems: MAX_ASK_QUESTIONS,
1035
+ items: {
1036
+ type: "object",
1037
+ additionalProperties: false,
1038
+ required: [
1039
+ "id",
1040
+ "prompt",
1041
+ "options",
1042
+ "defaults"
1043
+ ],
1044
+ properties: {
1045
+ id: {
1046
+ type: "string",
1047
+ description: "Unique within this call; answers come back under it."
1048
+ },
1049
+ prompt: {
1050
+ type: "string"
1051
+ },
1052
+ multiple: {
1053
+ type: "boolean",
1054
+ description: "Allow more than one option to be chosen."
1055
+ },
1056
+ allowFreeText: {
1057
+ type: "boolean",
1058
+ description: "Accept an answer that is not an option."
1059
+ },
1060
+ defaults: {
1061
+ type: "array",
1062
+ minItems: 1,
1063
+ items: {
1064
+ type: "string"
1065
+ },
1066
+ description: "REQUIRED. The option values you would pick yourself, so the user can confirm rather than decide."
1067
+ },
1068
+ options: {
1069
+ type: "array",
1070
+ minItems: 2,
1071
+ items: {
1072
+ type: "object",
1073
+ additionalProperties: false,
1074
+ required: [
1075
+ "value",
1076
+ "label"
1077
+ ],
1078
+ properties: {
1079
+ value: {
1080
+ type: "string"
1081
+ },
1082
+ label: {
1083
+ type: "string"
1084
+ },
1085
+ hotkey: {
1086
+ type: "string",
1087
+ maxLength: 1
1088
+ }
1089
+ }
1090
+ }
1091
+ }
1092
+ }
644
1093
  }
645
- const attemptsRemain = attempt < attempts;
646
- if (!attemptsRemain || !classify(error)) {
647
- throw error;
1094
+ }
1095
+ },
1096
+ required: [
1097
+ "questions"
1098
+ ]
1099
+ };
1100
+ var askInputSchema = {
1101
+ "~standard": {
1102
+ version: 1,
1103
+ vendor: "nestjs-agent",
1104
+ validate: /* @__PURE__ */ __name((value) => {
1105
+ const issues = [];
1106
+ if (typeof value !== "object" || value === null) {
1107
+ return {
1108
+ issues: [
1109
+ issue([], "must be an object")
1110
+ ]
1111
+ };
648
1112
  }
649
- options?.onRetry?.(attempt, error);
650
- await delay(backoffMs * attempt);
651
- attempt += 1;
1113
+ const candidate = value;
1114
+ if (!Array.isArray(candidate.questions) || candidate.questions.length === 0) {
1115
+ return {
1116
+ issues: [
1117
+ issue([
1118
+ "questions"
1119
+ ], "must be a non-empty array")
1120
+ ]
1121
+ };
1122
+ }
1123
+ if (candidate.questions.length > MAX_ASK_QUESTIONS) {
1124
+ return {
1125
+ issues: [
1126
+ issue([
1127
+ "questions"
1128
+ ], `must hold at most ${MAX_ASK_QUESTIONS} questions`)
1129
+ ]
1130
+ };
1131
+ }
1132
+ const questions = [];
1133
+ for (const [index, raw] of candidate.questions.entries()) {
1134
+ const question = parseQuestion(raw, [
1135
+ "questions",
1136
+ index
1137
+ ], issues);
1138
+ if (question !== void 0) {
1139
+ questions.push(question);
1140
+ }
1141
+ }
1142
+ if (issues.length > 0) {
1143
+ return {
1144
+ issues
1145
+ };
1146
+ }
1147
+ return {
1148
+ value: {
1149
+ questions,
1150
+ ...typeof candidate.preamble === "string" ? {
1151
+ preamble: candidate.preamble
1152
+ } : {}
1153
+ }
1154
+ };
1155
+ }, "validate"),
1156
+ jsonSchema: {
1157
+ input: /* @__PURE__ */ __name(() => ASK_JSON_SCHEMA, "input")
652
1158
  }
653
1159
  }
1160
+ };
1161
+ var ASK_TOOL_DESCRIPTION = "Ask the user to settle the scope of the work before you do it. Use it when a reasonable person would produce a materially different result depending on the answer \u2014 not to confirm something the conversation already says. Every question must pre-pick the answer you would choose, so the user can confirm instead of deciding. The user may decline, in which case you proceed on those pre-picked answers.";
1162
+ function askToolDefinition() {
1163
+ return {
1164
+ name: ASK_TOOL_NAME,
1165
+ kind: "ask",
1166
+ description: ASK_TOOL_DESCRIPTION,
1167
+ inputSchema: askInputSchema
1168
+ };
654
1169
  }
655
- __name(invokeWithTransientRetry, "invokeWithTransientRetry");
1170
+ __name(askToolDefinition, "askToolDefinition");
1171
+ var DEFAULT_INTAKE_PREAMBLE = "A few questions before I start. I have pre-picked what I would choose, so confirming is enough.";
656
1172
 
657
- // src/agent-loop.ts
658
- function resolveCostUsd(usage, reportedCostUsd, price) {
659
- if (reportedCostUsd !== void 0) {
660
- return reportedCostUsd;
661
- }
662
- return price === void 0 ? null : estimateCost(usage, price);
1173
+ // src/skills.ts
1174
+ var GLOBAL_SCOPE = "global";
1175
+ function actorScope(actor) {
1176
+ return `actor:${actor.id}`;
663
1177
  }
664
- __name(resolveCostUsd, "resolveCostUsd");
665
- function buildContextBlock(passages) {
666
- const items = passages.map((passage, index) => {
667
- const label = passage.source !== void 0 ? ` (${passage.source})` : "";
668
- return `[${index + 1}]${label} ${passage.text}`;
669
- }).join("\n\n");
670
- return `<retrieved_context>
671
- ${items}
672
- </retrieved_context>
673
- Use the retrieved context above to answer when relevant, and cite sources by their bracket number.`;
1178
+ __name(actorScope, "actorScope");
1179
+ function tenantScope(tenantRef) {
1180
+ return `tenant:${tenantRef}`;
674
1181
  }
675
- __name(buildContextBlock, "buildContextBlock");
676
- var QuotaExceededError = class extends Error {
677
- static {
678
- __name(this, "QuotaExceededError");
679
- }
680
- constructor() {
681
- super("Daily token quota exceeded");
682
- this.name = "QuotaExceededError";
683
- }
1182
+ __name(tenantScope, "tenantScope");
1183
+ var defaultScopeResolver = {
1184
+ resolve: /* @__PURE__ */ __name(({ actor }) => [
1185
+ actorScope(actor),
1186
+ ...actor.tenantRef !== void 0 ? [
1187
+ tenantScope(actor.tenantRef)
1188
+ ] : [],
1189
+ GLOBAL_SCOPE
1190
+ ], "resolve")
684
1191
  };
685
- var MAX_DELEGATION_DEPTH = 5;
686
- async function resolvePrompt(prompt, ctx) {
687
- return typeof prompt === "function" ? prompt(ctx) : prompt;
1192
+ function staticSkillProvider(skills) {
1193
+ return {
1194
+ list: /* @__PURE__ */ __name(({ scopes }) => skills.filter((skill) => scopes.includes(skill.scope)), "list"),
1195
+ load: /* @__PURE__ */ __name(({ name, scope }) => skills.find((skill) => skill.name === name && skill.scope === scope)?.body ?? null, "load")
1196
+ };
688
1197
  }
689
- __name(resolvePrompt, "resolvePrompt");
690
- async function resolveSystemPrompt(deps, input) {
691
- const ctx = {
692
- actor: input.actor,
693
- agentName: input.agentName ?? "default",
694
- ...input.pageContext !== void 0 ? {
695
- pageContext: input.pageContext
696
- } : {}
1198
+ __name(staticSkillProvider, "staticSkillProvider");
1199
+ function compositeSkillProvider(providers) {
1200
+ return {
1201
+ list: /* @__PURE__ */ __name(async ({ scopes, ctx }) => {
1202
+ const seen = /* @__PURE__ */ new Set();
1203
+ const merged = [];
1204
+ for (const provider of providers) {
1205
+ for (const summary of await provider.list({
1206
+ scopes,
1207
+ ctx
1208
+ })) {
1209
+ const key = `${summary.scope}\0${summary.name}`;
1210
+ if (!seen.has(key)) {
1211
+ seen.add(key);
1212
+ merged.push(summary);
1213
+ }
1214
+ }
1215
+ }
1216
+ return merged;
1217
+ }, "list"),
1218
+ load: /* @__PURE__ */ __name(async ({ name, scope, ctx }) => {
1219
+ for (const provider of providers) {
1220
+ const body = await provider.load({
1221
+ name,
1222
+ scope,
1223
+ ctx
1224
+ });
1225
+ if (body !== null) {
1226
+ return body;
1227
+ }
1228
+ }
1229
+ return null;
1230
+ }, "load")
697
1231
  };
698
- const sections = [
699
- await resolvePrompt(deps.systemPrompt, ctx)
700
- ];
701
- for (const contribute of deps.promptContributors ?? []) {
702
- const section = await contribute(ctx);
703
- if (section !== null && section.length > 0) {
704
- sections.push(section);
1232
+ }
1233
+ __name(compositeSkillProvider, "compositeSkillProvider");
1234
+ var DEFAULT_MAX_SKILLS = 20;
1235
+ function resolveSkillCatalog(summaries, scopes, maxSkills = DEFAULT_MAX_SKILLS) {
1236
+ const rank = new Map(scopes.map((scope, index) => [
1237
+ scope,
1238
+ index
1239
+ ]));
1240
+ const byName = /* @__PURE__ */ new Map();
1241
+ for (const summary of summaries) {
1242
+ if (!rank.has(summary.scope)) {
1243
+ continue;
1244
+ }
1245
+ const existing = byName.get(summary.name);
1246
+ if (existing === void 0) {
1247
+ byName.set(summary.name, [
1248
+ summary
1249
+ ]);
1250
+ } else {
1251
+ existing.push(summary);
705
1252
  }
706
1253
  }
707
- return sections.join("\n\n");
708
- }
709
- __name(resolveSystemPrompt, "resolveSystemPrompt");
710
- function extractTask(input) {
711
- if (typeof input === "object" && input !== null && "task" in input) {
712
- const task = input.task;
713
- if (typeof task === "string") {
714
- return task;
1254
+ const resolved = [];
1255
+ for (const candidates of byName.values()) {
1256
+ const ordered = [
1257
+ ...candidates
1258
+ ].sort((a, b) => (rank.get(a.scope) ?? 0) - (rank.get(b.scope) ?? 0));
1259
+ const winner = ordered[0];
1260
+ if (winner === void 0) {
1261
+ continue;
715
1262
  }
1263
+ const shadows = ordered.slice(1).map((candidate) => candidate.scope);
1264
+ resolved.push({
1265
+ name: winner.name,
1266
+ description: winner.description,
1267
+ scope: winner.scope,
1268
+ ...shadows.length > 0 ? {
1269
+ shadows
1270
+ } : {}
1271
+ });
716
1272
  }
717
- return JSON.stringify(input);
1273
+ resolved.sort((a, b) => {
1274
+ const byScope = (rank.get(a.scope) ?? 0) - (rank.get(b.scope) ?? 0);
1275
+ return byScope !== 0 ? byScope : compare(a.name, b.name);
1276
+ });
1277
+ return {
1278
+ entries: resolved.slice(0, maxSkills),
1279
+ omitted: Math.max(0, resolved.length - maxSkills)
1280
+ };
718
1281
  }
719
- __name(extractTask, "extractTask");
720
- function deriveTitle(userText) {
721
- const trimmed = userText.trim().replace(/\s+/g, " ");
722
- return trimmed.length > 60 ? `${trimmed.slice(0, 57)}...` : trimmed || "New chat";
1282
+ __name(resolveSkillCatalog, "resolveSkillCatalog");
1283
+ function compare(a, b) {
1284
+ return a < b ? -1 : a > b ? 1 : 0;
723
1285
  }
724
- __name(deriveTitle, "deriveTitle");
725
- var ToolTimeoutError = class ToolTimeoutError2 extends Error {
726
- static {
727
- __name(this, "ToolTimeoutError");
728
- }
729
- constructor(toolName, ms) {
730
- super(`Tool "${toolName}" exceeded its ${ms}ms timeout`);
731
- this.name = "ToolTimeoutError";
1286
+ __name(compare, "compare");
1287
+ async function offerSkills(config, ctx) {
1288
+ const scopes = await (config.scopes ?? defaultScopeResolver).resolve(ctx);
1289
+ const summaries = await config.provider.list({
1290
+ scopes,
1291
+ ctx
1292
+ });
1293
+ return {
1294
+ scopes,
1295
+ ...resolveSkillCatalog(summaries, scopes, config.maxSkills)
1296
+ };
1297
+ }
1298
+ __name(offerSkills, "offerSkills");
1299
+ function buildSkillsBlock(entries) {
1300
+ const lines = entries.map((entry) => {
1301
+ const shadows = entry.shadows === void 0 ? "" : ` (overrides the one from ${entry.shadows.join(", ")})`;
1302
+ return `- ${entry.name} [${entry.scope}] \u2014 ${entry.description}${shadows}`;
1303
+ });
1304
+ return `<skills>
1305
+ Procedures available to you. Each line is a name, the scope it came from, and what it covers \u2014 not the procedure itself.
1306
+ Call the \`${SKILL_TOOL_NAME}\` tool with a name from this list to read one BEFORE doing the task it covers, and follow what it says; never guess its contents from the description.
1307
+ A skill from a narrower scope overrides a same-named one from a wider scope. When you follow one that overrides another, say which scope it came from, so the user knows their setting differs from the wider default.
1308
+ ${lines.join("\n")}
1309
+ </skills>`;
1310
+ }
1311
+ __name(buildSkillsBlock, "buildSkillsBlock");
1312
+ var SKILL_TOOL_NAME = "skill";
1313
+ var SKILL_JSON_SCHEMA = {
1314
+ type: "object",
1315
+ additionalProperties: false,
1316
+ required: [
1317
+ "name"
1318
+ ],
1319
+ properties: {
1320
+ name: {
1321
+ type: "string",
1322
+ description: "The name of a skill from the <skills> list, exactly as written there."
1323
+ }
732
1324
  }
733
1325
  };
734
- function withToolTimeout(work, ms, toolName) {
735
- return new Promise((resolve, reject) => {
736
- const timer = setTimeout(() => reject(new ToolTimeoutError(toolName, ms)), ms);
737
- work.then((value) => {
738
- clearTimeout(timer);
739
- resolve(value);
740
- }, (error) => {
741
- clearTimeout(timer);
742
- reject(error);
743
- });
744
- });
1326
+ function issue2(path, message) {
1327
+ return {
1328
+ message,
1329
+ path
1330
+ };
745
1331
  }
746
- __name(withToolTimeout, "withToolTimeout");
747
- function parseFollowUps(text, count) {
748
- const source = text.match(/\[[\s\S]*\]/)?.[0] ?? text;
749
- try {
750
- const parsed = JSON.parse(source);
751
- if (Array.isArray(parsed)) {
752
- return parsed.filter((item) => typeof item === "string").slice(0, count);
1332
+ __name(issue2, "issue");
1333
+ var skillInputSchema = {
1334
+ "~standard": {
1335
+ version: 1,
1336
+ vendor: "nestjs-agent",
1337
+ validate: /* @__PURE__ */ __name((value) => {
1338
+ if (typeof value !== "object" || value === null) {
1339
+ return {
1340
+ issues: [
1341
+ issue2([], "must be an object")
1342
+ ]
1343
+ };
1344
+ }
1345
+ const candidate = value;
1346
+ if (typeof candidate.name !== "string" || candidate.name.length === 0) {
1347
+ return {
1348
+ issues: [
1349
+ issue2([
1350
+ "name"
1351
+ ], "must be a non-empty string")
1352
+ ]
1353
+ };
1354
+ }
1355
+ return {
1356
+ value: {
1357
+ name: candidate.name
1358
+ }
1359
+ };
1360
+ }, "validate"),
1361
+ jsonSchema: {
1362
+ input: /* @__PURE__ */ __name(() => SKILL_JSON_SCHEMA, "input")
753
1363
  }
754
- } catch {
755
1364
  }
756
- return [];
1365
+ };
1366
+ var SKILL_TOOL_DESCRIPTION = "Read one of the procedures listed in <skills>. Call it before doing a task a listed skill covers, and follow what it returns. It performs nothing and changes nothing \u2014 it only gives you instructions you do not yet have.";
1367
+ function skillToolDefinition() {
1368
+ return {
1369
+ name: SKILL_TOOL_NAME,
1370
+ kind: "skill",
1371
+ description: SKILL_TOOL_DESCRIPTION,
1372
+ inputSchema: skillInputSchema
1373
+ };
757
1374
  }
758
- __name(parseFollowUps, "parseFollowUps");
759
- async function generateFollowUps(model, messages, count) {
760
- const discard = {
761
- write: /* @__PURE__ */ __name(() => {
762
- }, "write"),
763
- end: /* @__PURE__ */ __name(() => {
764
- }, "end"),
1375
+ __name(skillToolDefinition, "skillToolDefinition");
1376
+ function withSkillTool({ tools, enabled }) {
1377
+ return enabled ? [
1378
+ ...tools,
1379
+ skillToolDefinition()
1380
+ ] : tools;
1381
+ }
1382
+ __name(withSkillTool, "withSkillTool");
1383
+ async function loadSkill(config, offer, name, ctx) {
1384
+ const entry = offer.entries.find((candidate) => candidate.name === name);
1385
+ if (entry === void 0) {
1386
+ const available = offer.entries.map((candidate) => candidate.name).join(", ");
1387
+ return {
1388
+ ok: false,
1389
+ error: available.length === 0 ? `No skill named "${name}" is available to you, and no others are either.` : `No skill named "${name}" is available to you. Available: ${available}.`
1390
+ };
1391
+ }
1392
+ const body = await config.provider.load({
1393
+ name: entry.name,
1394
+ scope: entry.scope,
1395
+ ctx
1396
+ });
1397
+ if (body === null) {
1398
+ return {
1399
+ ok: false,
1400
+ error: `Skill "${name}" is listed but its body could not be read.`
1401
+ };
1402
+ }
1403
+ return {
1404
+ ok: true,
1405
+ skill: {
1406
+ name: entry.name,
1407
+ description: entry.description,
1408
+ scope: entry.scope,
1409
+ body
1410
+ },
1411
+ ...entry.shadows !== void 0 ? {
1412
+ shadows: entry.shadows
1413
+ } : {}
1414
+ };
1415
+ }
1416
+ __name(loadSkill, "loadSkill");
1417
+ function skillWriteVerdict(request) {
1418
+ const { scope, scopes, author, actor } = request;
1419
+ if (!scopes.includes(scope)) {
1420
+ return {
1421
+ allowed: false,
1422
+ reason: `"${scope}" is not a scope this actor belongs to`
1423
+ };
1424
+ }
1425
+ const own = actorScope(actor);
1426
+ if (scope === own) {
1427
+ return {
1428
+ allowed: true
1429
+ };
1430
+ }
1431
+ if (author.kind !== "human") {
1432
+ return {
1433
+ allowed: false,
1434
+ reason: `only a human may author a skill at "${scope}"; an agent may write only at "${own}"`
1435
+ };
1436
+ }
1437
+ return request.elevated === true ? {
1438
+ allowed: true
1439
+ } : {
1440
+ allowed: false,
1441
+ reason: `authoring at "${scope}" requires an elevated human author`
1442
+ };
1443
+ }
1444
+ __name(skillWriteVerdict, "skillWriteVerdict");
1445
+
1446
+ // src/memory.ts
1447
+ var DEFAULT_MAX_MEMORIES = 20;
1448
+ var DEFAULT_MAX_FACT_CHARS = 240;
1449
+ function resolveMemoryDigest({ records, scopes, maxMemories = DEFAULT_MAX_MEMORIES, ranked = false }) {
1450
+ const rank = new Map(scopes.map((scope, index) => [
1451
+ scope,
1452
+ index
1453
+ ]));
1454
+ const byKey = /* @__PURE__ */ new Map();
1455
+ for (const entry of records) {
1456
+ if (!rank.has(entry.scope)) {
1457
+ continue;
1458
+ }
1459
+ const existing = byKey.get(entry.key);
1460
+ if (existing === void 0) {
1461
+ byKey.set(entry.key, [
1462
+ entry
1463
+ ]);
1464
+ } else {
1465
+ existing.push(entry);
1466
+ }
1467
+ }
1468
+ const resolved = [];
1469
+ for (const candidates of byKey.values()) {
1470
+ const ordered = [
1471
+ ...candidates
1472
+ ].sort((a, b) => (rank.get(a.scope) ?? 0) - (rank.get(b.scope) ?? 0));
1473
+ const winner = ordered[0];
1474
+ if (winner === void 0) {
1475
+ continue;
1476
+ }
1477
+ const overrides = ordered.slice(1).map((beaten) => ({
1478
+ scope: beaten.scope,
1479
+ text: beaten.text,
1480
+ author: beaten.origin.author
1481
+ }));
1482
+ const pinned = ordered.some((candidate) => candidate.pinned === true);
1483
+ resolved.push({
1484
+ ...winner,
1485
+ ...pinned ? {
1486
+ pinned: true
1487
+ } : {},
1488
+ ...overrides.length > 0 ? {
1489
+ overrides
1490
+ } : {}
1491
+ });
1492
+ }
1493
+ const byPrecedence = /* @__PURE__ */ __name((a, b) => (rank.get(a.scope) ?? 0) - (rank.get(b.scope) ?? 0) || compare2(b.updatedAt, a.updatedAt) || compare2(a.key, b.key), "byPrecedence");
1494
+ const selected = resolved.map((entry, index) => ({
1495
+ entry,
1496
+ index
1497
+ })).sort((a, b) => pinRank(a.entry) - pinRank(b.entry) || (ranked && a.entry.pinned !== true ? a.index - b.index : byPrecedence(a.entry, b.entry))).slice(0, maxMemories).map((candidate) => candidate.entry);
1498
+ const pinnedOmitted = resolved.filter((entry) => entry.pinned === true).length - selected.filter((entry) => entry.pinned === true).length;
1499
+ selected.sort((a, b) => pinRank(a) - pinRank(b) || (rank.get(a.scope) ?? 0) - (rank.get(b.scope) ?? 0) || compare2(a.key, b.key));
1500
+ return {
1501
+ entries: selected,
1502
+ omitted: Math.max(0, resolved.length - maxMemories),
1503
+ pinnedOmitted
1504
+ };
1505
+ }
1506
+ __name(resolveMemoryDigest, "resolveMemoryDigest");
1507
+ function pinRank(entry) {
1508
+ return entry.pinned === true ? 0 : 1;
1509
+ }
1510
+ __name(pinRank, "pinRank");
1511
+ function compare2(a, b) {
1512
+ return a < b ? -1 : a > b ? 1 : 0;
1513
+ }
1514
+ __name(compare2, "compare");
1515
+ async function offerMemories({ config, ctx, query }) {
1516
+ const scopes = await (config.scopes ?? defaultScopeResolver).resolve(ctx);
1517
+ const maxMemories = config.maxMemories ?? DEFAULT_MAX_MEMORIES;
1518
+ const trimmed = query?.trim() ?? "";
1519
+ const search = trimmed.length > 0 ? config.provider.search : void 0;
1520
+ const records = search !== void 0 ? await search({
1521
+ scopes,
1522
+ query: trimmed,
1523
+ limit: maxMemories,
1524
+ ctx
1525
+ }) : await config.provider.list({
1526
+ scopes,
1527
+ ctx
1528
+ });
1529
+ return {
1530
+ scopes,
1531
+ recalled: search !== void 0,
1532
+ ...resolveMemoryDigest({
1533
+ records,
1534
+ scopes,
1535
+ maxMemories,
1536
+ ranked: search !== void 0
1537
+ })
1538
+ };
1539
+ }
1540
+ __name(offerMemories, "offerMemories");
1541
+ var ASSERTED_FRAMING = "Stated by people. A person wrote each of these deliberately \u2014 the user about themselves, or someone administering their organisation. Treat them as you would any other instruction you were given. If the user says something that contradicts one, say which note it conflicts with and at what scope it is held, rather than quietly setting it aside.";
1542
+ var CONCLUDED_FRAMING = "Concluded by you. These are your own notes from earlier turns, not documents anyone wrote: they may be wrong or out of date, so prefer what the user says now, and say where a note came from if you act on it.";
1543
+ var PARTIAL_FRAMING = "You are being shown a selection, not everything on file. Other notes exist that are not in this list, so never read something\u2019s absence from it as evidence that it was never recorded.";
1544
+ function memorySection(framing, entries) {
1545
+ if (entries.length === 0) {
1546
+ return [];
1547
+ }
1548
+ return [
1549
+ framing,
1550
+ ...entries.flatMap((entry) => [
1551
+ `- [${entry.scope}] ${entry.key}: ${entry.text}`,
1552
+ ...(entry.overrides ?? []).map((beaten) => ` \u21B3 [${beaten.scope}] ${beaten.author === "human" ? "a person stated" : "instead has"}: ${beaten.text}`)
1553
+ ])
1554
+ ];
1555
+ }
1556
+ __name(memorySection, "memorySection");
1557
+ function buildMemoryBlock({ entries, writable, partial }) {
1558
+ const writeLine = writable ? [
1559
+ `When you learn something durable about this user, record it with the \`${REMEMBER_TOOL_NAME}\` tool; when one of these turns out to be wrong, record the corrected fact under the same key. What you record that way is one of your own notes, not something stated by a person.`
1560
+ ] : [];
1561
+ const body = [
1562
+ "What is on file about this user and their organisation, carried over from earlier conversations. Each line is a scope, a key and the fact. A narrower scope overrides a wider one; where the wider value is shown underneath, tell the user their setting differs from it rather than silently choosing one.",
1563
+ ...partial ? [
1564
+ PARTIAL_FRAMING
1565
+ ] : [],
1566
+ ...writeLine,
1567
+ // People before inferences: the model meets what it was told before what it worked out.
1568
+ ...memorySection(ASSERTED_FRAMING, entries.filter((entry) => entry.origin.author === "human")),
1569
+ ...memorySection(CONCLUDED_FRAMING, entries.filter((entry) => entry.origin.author !== "human"))
1570
+ ];
1571
+ return `<memory>
1572
+ ${body.join("\n")}
1573
+ </memory>`;
1574
+ }
1575
+ __name(buildMemoryBlock, "buildMemoryBlock");
1576
+ var REMEMBER_TOOL_NAME = "remember";
1577
+ var REMEMBER_JSON_SCHEMA = {
1578
+ type: "object",
1579
+ additionalProperties: false,
1580
+ required: [
1581
+ "key",
1582
+ "fact"
1583
+ ],
1584
+ properties: {
1585
+ key: {
1586
+ type: "string",
1587
+ description: 'A short, stable handle for what this fact is ABOUT (e.g. "fiscal-year", "preferred-units"). Reusing an existing key replaces that fact rather than adding a second one.'
1588
+ },
1589
+ fact: {
1590
+ type: "string",
1591
+ description: "The fact itself, in one sentence, stated so it still makes sense in a conversation months from now."
1592
+ }
1593
+ }
1594
+ };
1595
+ function issue3(path, message) {
1596
+ return {
1597
+ message,
1598
+ path
1599
+ };
1600
+ }
1601
+ __name(issue3, "issue");
1602
+ var rememberInputSchema = {
1603
+ "~standard": {
1604
+ version: 1,
1605
+ vendor: "nestjs-agent",
1606
+ validate: /* @__PURE__ */ __name((value) => {
1607
+ if (typeof value !== "object" || value === null) {
1608
+ return {
1609
+ issues: [
1610
+ issue3([], "must be an object")
1611
+ ]
1612
+ };
1613
+ }
1614
+ const candidate = value;
1615
+ if (typeof candidate.key !== "string" || candidate.key.length === 0) {
1616
+ return {
1617
+ issues: [
1618
+ issue3([
1619
+ "key"
1620
+ ], "must be a non-empty string")
1621
+ ]
1622
+ };
1623
+ }
1624
+ if (typeof candidate.fact !== "string" || candidate.fact.length === 0) {
1625
+ return {
1626
+ issues: [
1627
+ issue3([
1628
+ "fact"
1629
+ ], "must be a non-empty string")
1630
+ ]
1631
+ };
1632
+ }
1633
+ return {
1634
+ value: {
1635
+ key: candidate.key,
1636
+ fact: candidate.fact
1637
+ }
1638
+ };
1639
+ }, "validate"),
1640
+ jsonSchema: {
1641
+ input: /* @__PURE__ */ __name(() => REMEMBER_JSON_SCHEMA, "input")
1642
+ }
1643
+ }
1644
+ };
1645
+ var REMEMBER_TOOL_DESCRIPTION = "Record one durable fact about this user under a key, so later conversations start knowing it. For things that will still be true another day \u2014 how they work, what their organisation requires, a correction they made. Not for what this conversation is about, and not for anything you were not told or could not reasonably infer. The user can read and delete everything you record here.";
1646
+ function rememberToolDefinition() {
1647
+ return {
1648
+ name: REMEMBER_TOOL_NAME,
1649
+ kind: "memory",
1650
+ description: REMEMBER_TOOL_DESCRIPTION,
1651
+ inputSchema: rememberInputSchema
1652
+ };
1653
+ }
1654
+ __name(rememberToolDefinition, "rememberToolDefinition");
1655
+ function withMemoryTool({ tools, enabled }) {
1656
+ return enabled ? [
1657
+ ...tools,
1658
+ rememberToolDefinition()
1659
+ ] : tools;
1660
+ }
1661
+ __name(withMemoryTool, "withMemoryTool");
1662
+ function memoryWriteVerdict(request) {
1663
+ const { scope, scopes, author, actor } = request;
1664
+ if (!scopes.includes(scope)) {
1665
+ return {
1666
+ allowed: false,
1667
+ reason: `"${scope}" is not a scope this actor belongs to`
1668
+ };
1669
+ }
1670
+ const own = actorScope(actor);
1671
+ if (scope === own) {
1672
+ return {
1673
+ allowed: true
1674
+ };
1675
+ }
1676
+ if (author.kind !== "human") {
1677
+ return {
1678
+ allowed: false,
1679
+ reason: `only a human may write a memory at "${scope}"; an agent may write only at "${own}"`
1680
+ };
1681
+ }
1682
+ return request.elevated === true ? {
1683
+ allowed: true
1684
+ } : {
1685
+ allowed: false,
1686
+ reason: `writing at "${scope}" requires an elevated human author`
1687
+ };
1688
+ }
1689
+ __name(memoryWriteVerdict, "memoryWriteVerdict");
1690
+ function memoryForgetVerdict({ record, actor }) {
1691
+ return record.scope === actorScope(actor) ? {
1692
+ allowed: true
1693
+ } : {
1694
+ allowed: false,
1695
+ reason: `"${record.scope}" is not this actor's own scope; deleting it is an administrative action`
1696
+ };
1697
+ }
1698
+ __name(memoryForgetVerdict, "memoryForgetVerdict");
1699
+ async function writeMemory({ config, digest, call, ctx, runId }) {
1700
+ const write = config.provider.write;
1701
+ if (write === void 0) {
1702
+ return {
1703
+ ok: false,
1704
+ error: "Memory is read-only in this deployment."
1705
+ };
1706
+ }
1707
+ const key = call.key.trim();
1708
+ const text = call.fact.trim();
1709
+ if (key.length === 0 || text.length === 0) {
1710
+ return {
1711
+ ok: false,
1712
+ error: "A memory needs both a key and a fact."
1713
+ };
1714
+ }
1715
+ const maxFactChars = config.maxFactChars ?? DEFAULT_MAX_FACT_CHARS;
1716
+ if (text.length > maxFactChars) {
1717
+ return {
1718
+ ok: false,
1719
+ error: `A memory must be at most ${maxFactChars} characters; that was ${text.length}. State the fact more briefly.`
1720
+ };
1721
+ }
1722
+ const scope = actorScope(ctx.actor);
1723
+ const verdict = memoryWriteVerdict({
1724
+ scope,
1725
+ actor: ctx.actor,
1726
+ scopes: digest.scopes,
1727
+ author: {
1728
+ kind: "agent",
1729
+ actorRef: ctx.actor.id
1730
+ }
1731
+ });
1732
+ if (!verdict.allowed) {
1733
+ return {
1734
+ ok: false,
1735
+ error: verdict.reason
1736
+ };
1737
+ }
1738
+ const record = await write({
1739
+ key,
1740
+ text,
1741
+ scope,
1742
+ origin: {
1743
+ author: "agent",
1744
+ threadId: ctx.threadId,
1745
+ runId,
1746
+ actorRef: ctx.actor.id
1747
+ },
1748
+ ctx
1749
+ });
1750
+ return {
1751
+ ok: true,
1752
+ record
1753
+ };
1754
+ }
1755
+ __name(writeMemory, "writeMemory");
1756
+
1757
+ // src/agent-registry.ts
1758
+ var AgentRegistry = class {
1759
+ static {
1760
+ __name(this, "AgentRegistry");
1761
+ }
1762
+ definitions = /* @__PURE__ */ new Map();
1763
+ register(definition) {
1764
+ this.definitions.set(definition.name, definition);
1765
+ }
1766
+ get(name) {
1767
+ return this.definitions.get(name);
1768
+ }
1769
+ has(name) {
1770
+ return this.definitions.has(name);
1771
+ }
1772
+ list() {
1773
+ return [
1774
+ ...this.definitions.values()
1775
+ ];
1776
+ }
1777
+ };
1778
+
1779
+ // src/replay-integrity.ts
1780
+ function isReplayIntegrityError(error) {
1781
+ return error instanceof Error && error.name.toLowerCase().endsWith("nondeterminismerror");
1782
+ }
1783
+ __name(isReplayIntegrityError, "isReplayIntegrityError");
1784
+
1785
+ // src/control-flow.ts
1786
+ var CONTROL_FLOW_SIGNAL = Symbol.for("aviary:durable:control-flow");
1787
+ function isControlFlowSignal(error) {
1788
+ return typeof error === "object" && error !== null && error[CONTROL_FLOW_SIGNAL] === true;
1789
+ }
1790
+ __name(isControlFlowSignal, "isControlFlowSignal");
1791
+
1792
+ // src/delegation.ts
1793
+ function normalizeDelegation(entry) {
1794
+ return typeof entry === "string" ? {
1795
+ agent: entry,
1796
+ detached: false
1797
+ } : {
1798
+ agent: entry.agent,
1799
+ detached: entry.detached === true
1800
+ };
1801
+ }
1802
+ __name(normalizeDelegation, "normalizeDelegation");
1803
+ function detachedStarted(args) {
1804
+ return {
1805
+ detached: true,
1806
+ status: "started",
1807
+ agent: args.agent,
1808
+ runId: args.runId,
1809
+ note: `The "${args.agent}" agent is now working on this in the background. Its answer is NOT part of this turn and will arrive in this conversation as a separate message when it is ready. Tell the user the work has started; do not state or guess what it will find.`
1810
+ };
1811
+ }
1812
+ __name(detachedStarted, "detachedStarted");
1813
+ function detachedDelivered(args) {
1814
+ return {
1815
+ detached: true,
1816
+ status: "delivered",
1817
+ agent: args.agent,
1818
+ runId: args.runId,
1819
+ text: args.text
1820
+ };
1821
+ }
1822
+ __name(detachedDelivered, "detachedDelivered");
1823
+ function detachedUnsettled(args) {
1824
+ return {
1825
+ detached: true,
1826
+ status: args.status,
1827
+ agent: args.agent,
1828
+ runId: args.runId,
1829
+ ...args.error !== void 0 ? {
1830
+ error: args.error
1831
+ } : {}
1832
+ };
1833
+ }
1834
+ __name(detachedUnsettled, "detachedUnsettled");
1835
+ async function settleUnsettledDelegation(args) {
1836
+ const { store, delivery, agent, runId, status } = args;
1837
+ if (await store.getThread(delivery.threadId) === null) {
1838
+ return;
1839
+ }
1840
+ await store.appendMessage({
1841
+ threadId: delivery.threadId,
1842
+ role: "assistant",
1843
+ content: status === "cancelled" ? `The "${agent}" agent was stopped before it could answer.` : `The "${agent}" agent stopped before it could answer: ${args.error ?? "unknown error"}`,
1844
+ agentName: agent,
1845
+ runId
1846
+ });
1847
+ await store.updateToolCall({
1848
+ toolCallId: delivery.toolCallId,
1849
+ status: "executed",
1850
+ output: detachedUnsettled({
1851
+ agent,
1852
+ runId,
1853
+ status,
1854
+ ...args.error !== void 0 ? {
1855
+ error: args.error
1856
+ } : {}
1857
+ })
1858
+ });
1859
+ }
1860
+ __name(settleUnsettledDelegation, "settleUnsettledDelegation");
1861
+
1862
+ // src/tool-registry.ts
1863
+ var ToolForbiddenError = class extends Error {
1864
+ static {
1865
+ __name(this, "ToolForbiddenError");
1866
+ }
1867
+ toolName;
1868
+ constructor(toolName) {
1869
+ super(`Tool "${toolName}" is not allowed for this role`), this.toolName = toolName;
1870
+ this.name = "ToolForbiddenError";
1871
+ }
1872
+ };
1873
+ var ToolDisabledError = class extends Error {
1874
+ static {
1875
+ __name(this, "ToolDisabledError");
1876
+ }
1877
+ toolName;
1878
+ constructor(toolName) {
1879
+ super(`Tool "${toolName}" is disabled in this deployment`), this.toolName = toolName;
1880
+ this.name = "ToolDisabledError";
1881
+ }
1882
+ };
1883
+ var ToolNotFoundError = class extends Error {
1884
+ static {
1885
+ __name(this, "ToolNotFoundError");
1886
+ }
1887
+ toolName;
1888
+ constructor(toolName) {
1889
+ super(`Tool "${toolName}" is not registered`), this.toolName = toolName;
1890
+ this.name = "ToolNotFoundError";
1891
+ }
1892
+ };
1893
+ var ToolInputInvalidError = class extends Error {
1894
+ static {
1895
+ __name(this, "ToolInputInvalidError");
1896
+ }
1897
+ toolName;
1898
+ issues;
1899
+ constructor(toolName, issues) {
1900
+ super(`Invalid input for tool "${toolName}": ${issues.map((issue4) => issue4.message).join("; ")}`), this.toolName = toolName, this.issues = issues;
1901
+ this.name = "ToolInputInvalidError";
1902
+ }
1903
+ };
1904
+ var ToolRegistry = class {
1905
+ static {
1906
+ __name(this, "ToolRegistry");
1907
+ }
1908
+ entries = /* @__PURE__ */ new Map();
1909
+ register(spec, handler) {
1910
+ this.entries.set(spec.name, {
1911
+ spec,
1912
+ handler
1913
+ });
1914
+ }
1915
+ has(name) {
1916
+ return this.entries.has(name);
1917
+ }
1918
+ spec(name) {
1919
+ return this.entries.get(name)?.spec;
1920
+ }
1921
+ allSpecs() {
1922
+ return [
1923
+ ...this.entries.values()
1924
+ ].map((entry) => entry.spec);
1925
+ }
1926
+ /**
1927
+ * The tools to offer the model for this actor+agent, after the four filter layers: what this
1928
+ * agent pinned, what this deployment has enabled, what this actor's role allows, and what each
1929
+ * tool's own `canUse` allows this actor.
1930
+ *
1931
+ * Every layer only ever removes tools, so no arrangement of them can widen what a turn reaches.
1932
+ * The agent's allow-list therefore goes FIRST, even though it is the narrowest statement: it is a
1933
+ * pure name-set match, while each of the three below it may be a round trip — an authz service, a
1934
+ * feature-flag store, an MCP server — and this runs once per model step. Asking those about a
1935
+ * tool the allow-list has already excluded is a call whose answer nothing reads.
1936
+ */
1937
+ async definitionsFor(actor, policy, allowedTools) {
1938
+ const pinnedNames = new Set(filterToolsByAllowList(this.allSpecs(), allowedTools).map((spec) => spec.name));
1939
+ const pinned = [
1940
+ ...this.entries.values()
1941
+ ].filter((entry) => pinnedNames.has(entry.spec.name));
1942
+ const live = await filterToolsByEnabled(pinned);
1943
+ const allowedByRole = new Set((await filterToolsByRole(live.map((entry) => entry.spec), actor, policy)).map((spec) => spec.name));
1944
+ const roleScoped = live.filter((entry) => allowedByRole.has(entry.spec.name));
1945
+ const actorScoped = await filterToolsByCanUse(roleScoped, actor);
1946
+ return actorScoped.map(({ spec }) => ({
1947
+ name: spec.name,
1948
+ kind: spec.kind,
1949
+ description: spec.description,
1950
+ inputSchema: spec.inputSchema
1951
+ }));
1952
+ }
1953
+ /**
1954
+ * Run a tool. Re-checks that the tool is enabled and that the role allows it (defense-in-depth —
1955
+ * a call can reach here from a replayed durable step or an approval granted before the flag
1956
+ * moved, neither of which went through `definitionsFor` again) and re-parses the input via Zod.
1957
+ */
1958
+ async invoke(name, input, ctx, policy) {
1959
+ const entry = this.entries.get(name);
1960
+ if (entry === void 0) {
1961
+ throw new ToolNotFoundError(name);
1962
+ }
1963
+ if (!await isToolEnabled(entry.spec, entry.handler)) {
1964
+ throw new ToolDisabledError(name);
1965
+ }
1966
+ if (!await policy.can(ctx.actor, entry.spec)) {
1967
+ throw new ToolForbiddenError(name);
1968
+ }
1969
+ if (!await canActorUseTool(ctx.actor, entry.handler)) {
1970
+ throw new ToolForbiddenError(name);
1971
+ }
1972
+ const validation = await entry.spec.inputSchema["~standard"].validate(input);
1973
+ if (validation.issues !== void 0) {
1974
+ throw new ToolInputInvalidError(name, validation.issues);
1975
+ }
1976
+ return entry.handler.execute(validation.value, ctx);
1977
+ }
1978
+ };
1979
+ var DefaultRolesPolicy = class {
1980
+ static {
1981
+ __name(this, "DefaultRolesPolicy");
1982
+ }
1983
+ defaultRoles;
1984
+ constructor(defaultRoles = [
1985
+ "ADMIN"
1986
+ ]) {
1987
+ this.defaultRoles = defaultRoles;
1988
+ }
1989
+ can(actor, tool) {
1990
+ const allowed = tool.roles ?? this.defaultRoles;
1991
+ return (actor.roles ?? []).some((role) => allowed.includes(role));
1992
+ }
1993
+ };
1994
+
1995
+ // src/agent-loop.ts
1996
+ var import_node_crypto = require("crypto");
1997
+ var import_nestjs_diagnostics2 = require("@dudousxd/nestjs-diagnostics");
1998
+
1999
+ // src/diagnostics.ts
2000
+ var import_nestjs_diagnostics = require("@dudousxd/nestjs-diagnostics");
2001
+ function publishAgentRunStarted(payload) {
2002
+ (0, import_nestjs_diagnostics.emit)("agent", "run.started", payload);
2003
+ }
2004
+ __name(publishAgentRunStarted, "publishAgentRunStarted");
2005
+ function publishAgentMessage(payload) {
2006
+ (0, import_nestjs_diagnostics.emit)("agent", "message", payload);
2007
+ }
2008
+ __name(publishAgentMessage, "publishAgentMessage");
2009
+ function publishAgentToolCall(payload) {
2010
+ (0, import_nestjs_diagnostics.emit)("agent", "tool-call", payload);
2011
+ }
2012
+ __name(publishAgentToolCall, "publishAgentToolCall");
2013
+ function publishAgentQuotaExceeded(payload) {
2014
+ (0, import_nestjs_diagnostics.emit)("agent", "quota.exceeded", payload);
2015
+ }
2016
+ __name(publishAgentQuotaExceeded, "publishAgentQuotaExceeded");
2017
+ function publishAgentRunFinished(payload) {
2018
+ (0, import_nestjs_diagnostics.emit)("agent", "run.finished", payload);
2019
+ }
2020
+ __name(publishAgentRunFinished, "publishAgentRunFinished");
2021
+ function publishAgentRunFailed(payload) {
2022
+ (0, import_nestjs_diagnostics.emit)("agent", "run.failed", payload);
2023
+ }
2024
+ __name(publishAgentRunFailed, "publishAgentRunFailed");
2025
+ function publishAgentDelegated(payload) {
2026
+ (0, import_nestjs_diagnostics.emit)("agent", "delegated", payload);
2027
+ }
2028
+ __name(publishAgentDelegated, "publishAgentDelegated");
2029
+ function publishAgentRetrieved(payload) {
2030
+ (0, import_nestjs_diagnostics.emit)("agent", "retrieved", payload);
2031
+ }
2032
+ __name(publishAgentRetrieved, "publishAgentRetrieved");
2033
+ function publishAgentToolRetry(payload) {
2034
+ (0, import_nestjs_diagnostics.emit)("agent", "tool.retry", payload);
2035
+ }
2036
+ __name(publishAgentToolRetry, "publishAgentToolRetry");
2037
+ function publishAgentSkillsResolved(payload) {
2038
+ (0, import_nestjs_diagnostics.emit)("agent", "skills.resolved", payload);
2039
+ }
2040
+ __name(publishAgentSkillsResolved, "publishAgentSkillsResolved");
2041
+ function publishAgentMemoryResolved(payload) {
2042
+ (0, import_nestjs_diagnostics.emit)("agent", "memory.resolved", payload);
2043
+ }
2044
+ __name(publishAgentMemoryResolved, "publishAgentMemoryResolved");
2045
+ function publishAgentMemoryWritten(payload) {
2046
+ (0, import_nestjs_diagnostics.emit)("agent", "memory.written", payload);
2047
+ }
2048
+ __name(publishAgentMemoryWritten, "publishAgentMemoryWritten");
2049
+ var AGENT_SPAN_EVENTS = [
2050
+ "llm.turn",
2051
+ "tool.execution",
2052
+ "retrieval",
2053
+ "follow-ups"
2054
+ ];
2055
+ var AGENT_DIAGNOSTIC_EVENTS = [
2056
+ "run.started",
2057
+ "message",
2058
+ "tool-call",
2059
+ "quota.exceeded",
2060
+ "run.finished",
2061
+ "run.failed",
2062
+ "delegated",
2063
+ "retrieved",
2064
+ "skills.resolved",
2065
+ "memory.resolved",
2066
+ "memory.written",
2067
+ "tool.retry"
2068
+ ];
2069
+ function agentDiagnosticKey(event) {
2070
+ return `agent:${event}`;
2071
+ }
2072
+ __name(agentDiagnosticKey, "agentDiagnosticKey");
2073
+
2074
+ // src/tool-retry.ts
2075
+ function hasTransientShape(error) {
2076
+ if (typeof error !== "object" || error === null) {
2077
+ return false;
2078
+ }
2079
+ const code = "code" in error ? error.code : void 0;
2080
+ const errno = "errno" in error ? error.errno : void 0;
2081
+ const sqlState = "sqlState" in error ? error.sqlState : void 0;
2082
+ if (code === 1213 || code === 1205 || errno === 1213 || errno === 1205) {
2083
+ return true;
2084
+ }
2085
+ if (code === "ER_LOCK_DEADLOCK" || code === "ER_LOCK_WAIT_TIMEOUT") {
2086
+ return true;
2087
+ }
2088
+ if (code === "40001" || code === "40P01" || sqlState === "40001" || sqlState === "40P01") {
2089
+ return true;
2090
+ }
2091
+ if (code === "SQLITE_BUSY") {
2092
+ return true;
2093
+ }
2094
+ const message = "message" in error ? error.message : void 0;
2095
+ return typeof message === "string" && /deadlock|lock wait timeout|serialization failure/i.test(message);
2096
+ }
2097
+ __name(hasTransientShape, "hasTransientShape");
2098
+ function isTransientToolError(error) {
2099
+ if (hasTransientShape(error)) {
2100
+ return true;
2101
+ }
2102
+ if (typeof error === "object" && error !== null && "cause" in error) {
2103
+ const cause = error.cause;
2104
+ if (cause !== void 0 && cause !== error && hasTransientShape(cause)) {
2105
+ return true;
2106
+ }
2107
+ }
2108
+ return false;
2109
+ }
2110
+ __name(isTransientToolError, "isTransientToolError");
2111
+ var DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS = 2;
2112
+ var DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS = 150;
2113
+ function resolveToolTransientRetryNumbers(setting) {
2114
+ if (setting === false) {
2115
+ return false;
2116
+ }
2117
+ return {
2118
+ attempts: setting?.attempts ?? DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS,
2119
+ backoffMs: setting?.backoffMs ?? DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS
2120
+ };
2121
+ }
2122
+ __name(resolveToolTransientRetryNumbers, "resolveToolTransientRetryNumbers");
2123
+ function delay(ms) {
2124
+ return new Promise((resolve) => {
2125
+ setTimeout(resolve, ms);
2126
+ });
2127
+ }
2128
+ __name(delay, "delay");
2129
+ async function invokeWithTransientRetry(fn, setting, options) {
2130
+ if (setting === false) {
2131
+ return fn();
2132
+ }
2133
+ const attempts = setting.attempts ?? DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS;
2134
+ const backoffMs = setting.backoffMs ?? DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS;
2135
+ const classify = setting.classify ?? isTransientToolError;
2136
+ let attempt = 1;
2137
+ for (; ; ) {
2138
+ try {
2139
+ return await fn();
2140
+ } catch (error) {
2141
+ if (isControlFlowSignal(error) || options?.isControlFlowError?.(error) === true) {
2142
+ throw error;
2143
+ }
2144
+ const attemptsRemain = attempt < attempts;
2145
+ if (!attemptsRemain || !classify(error)) {
2146
+ throw error;
2147
+ }
2148
+ options?.onRetry?.(attempt, error);
2149
+ await delay(backoffMs * attempt);
2150
+ attempt += 1;
2151
+ }
2152
+ }
2153
+ }
2154
+ __name(invokeWithTransientRetry, "invokeWithTransientRetry");
2155
+
2156
+ // src/agent-loop.ts
2157
+ function resolveCostUsd(usage, reportedCostUsd, price) {
2158
+ if (reportedCostUsd !== void 0) {
2159
+ return reportedCostUsd;
2160
+ }
2161
+ return price === void 0 ? null : estimateCost(usage, price);
2162
+ }
2163
+ __name(resolveCostUsd, "resolveCostUsd");
2164
+ function buildContextBlock(passages) {
2165
+ const items = passages.map((passage, index) => {
2166
+ const label = passage.source !== void 0 ? ` (${passage.source})` : "";
2167
+ return `[${index + 1}]${label} ${passage.text}`;
2168
+ }).join("\n\n");
2169
+ return `<retrieved_context>
2170
+ ${items}
2171
+ </retrieved_context>
2172
+ Use the retrieved context above to answer when relevant, and cite sources by their bracket number.`;
2173
+ }
2174
+ __name(buildContextBlock, "buildContextBlock");
2175
+ function buildSummaryBlock(summary) {
2176
+ return `<conversation_summary>
2177
+ ${summary}
2178
+ </conversation_summary>
2179
+ Earlier messages in this thread are no longer included verbatim. Treat the summary above as an accurate record of them.`;
2180
+ }
2181
+ __name(buildSummaryBlock, "buildSummaryBlock");
2182
+ function settleAll(tasks) {
2183
+ const started = tasks.map((task) => task());
2184
+ return Promise.all(started.map((work) => work.then((value) => ({
2185
+ ok: true,
2186
+ value
2187
+ }), (error) => ({
2188
+ ok: false,
2189
+ error
2190
+ }))));
2191
+ }
2192
+ __name(settleAll, "settleAll");
2193
+ var QuotaExceededError = class extends Error {
2194
+ static {
2195
+ __name(this, "QuotaExceededError");
2196
+ }
2197
+ constructor() {
2198
+ super("Daily token quota exceeded");
2199
+ this.name = "QuotaExceededError";
2200
+ }
2201
+ };
2202
+ var RunCancelledError = class extends Error {
2203
+ static {
2204
+ __name(this, "RunCancelledError");
2205
+ }
2206
+ constructor() {
2207
+ super("Run cancelled");
2208
+ this.name = "RunCancelledError";
2209
+ }
2210
+ };
2211
+ function agentFailureCode(error) {
2212
+ if (error instanceof RunCancelledError) {
2213
+ return "cancelled";
2214
+ }
2215
+ if (error instanceof QuotaExceededError) {
2216
+ return "quota_exceeded";
2217
+ }
2218
+ if (error instanceof OutputRejectedError) {
2219
+ return "output_rejected";
2220
+ }
2221
+ if (error instanceof StructuredOutputError) {
2222
+ return "structured_output_invalid";
2223
+ }
2224
+ return "run_failed";
2225
+ }
2226
+ __name(agentFailureCode, "agentFailureCode");
2227
+ var MAX_DELEGATION_DEPTH = 5;
2228
+ var DEFAULT_MAX_AGENT_APPEARANCES = 1;
2229
+ function delegationRefusal(args) {
2230
+ const { deps, input, targetAgent } = args;
2231
+ const ancestry = [
2232
+ ...input.delegationPath ?? [],
2233
+ ...input.agentName !== void 0 ? [
2234
+ input.agentName
2235
+ ] : []
2236
+ ];
2237
+ const appearances = ancestry.filter((name) => name === targetAgent).length;
2238
+ const maxAppearances = deps.maxAgentAppearances ?? DEFAULT_MAX_AGENT_APPEARANCES;
2239
+ if (appearances >= maxAppearances) {
2240
+ const chain = [
2241
+ ...ancestry,
2242
+ targetAgent
2243
+ ].join(" \u2192 ");
2244
+ const times = appearances + 1;
2245
+ return `(delegation cycle: ${chain} \u2014 ${targetAgent} ${times} times on one chain)`;
2246
+ }
2247
+ const maxDepth = deps.maxDelegationDepth ?? MAX_DELEGATION_DEPTH;
2248
+ if ((input.delegationDepth ?? 0) >= maxDepth) {
2249
+ return `(delegation depth limit of ${maxDepth} reached)`;
2250
+ }
2251
+ return null;
2252
+ }
2253
+ __name(delegationRefusal, "delegationRefusal");
2254
+ async function resolvePrompt(prompt, ctx) {
2255
+ return typeof prompt === "function" ? prompt(ctx) : prompt;
2256
+ }
2257
+ __name(resolvePrompt, "resolvePrompt");
2258
+ async function resolveSystemPrompt(deps, input) {
2259
+ const ctx = {
2260
+ actor: input.actor,
2261
+ agentName: input.agentName ?? "default",
2262
+ ...input.pageContext !== void 0 ? {
2263
+ pageContext: input.pageContext
2264
+ } : {}
2265
+ };
2266
+ const sections = [
2267
+ await resolvePrompt(deps.systemPrompt, ctx)
2268
+ ];
2269
+ for (const contribute of deps.promptContributors ?? []) {
2270
+ const section = await contribute(ctx);
2271
+ if (section !== null && section.length > 0) {
2272
+ sections.push(section);
2273
+ }
2274
+ }
2275
+ return sections.join("\n\n");
2276
+ }
2277
+ __name(resolveSystemPrompt, "resolveSystemPrompt");
2278
+ function extractTask(input) {
2279
+ if (typeof input === "object" && input !== null && "task" in input) {
2280
+ const task = input.task;
2281
+ if (typeof task === "string") {
2282
+ return task;
2283
+ }
2284
+ }
2285
+ return JSON.stringify(input);
2286
+ }
2287
+ __name(extractTask, "extractTask");
2288
+ function deriveTitle(userText) {
2289
+ const trimmed = userText.trim().replace(/\s+/g, " ");
2290
+ return trimmed.length > 60 ? `${trimmed.slice(0, 57)}...` : trimmed || "New chat";
2291
+ }
2292
+ __name(deriveTitle, "deriveTitle");
2293
+ var ToolTimeoutError = class ToolTimeoutError2 extends Error {
2294
+ static {
2295
+ __name(this, "ToolTimeoutError");
2296
+ }
2297
+ constructor(toolName, ms) {
2298
+ super(`Tool "${toolName}" exceeded its ${ms}ms timeout`);
2299
+ this.name = "ToolTimeoutError";
2300
+ }
2301
+ };
2302
+ function withToolTimeout(work, ms, toolName) {
2303
+ return new Promise((resolve, reject) => {
2304
+ const timer = setTimeout(() => reject(new ToolTimeoutError(toolName, ms)), ms);
2305
+ work.then((value) => {
2306
+ clearTimeout(timer);
2307
+ resolve(value);
2308
+ }, (error) => {
2309
+ clearTimeout(timer);
2310
+ reject(error);
2311
+ });
2312
+ });
2313
+ }
2314
+ __name(withToolTimeout, "withToolTimeout");
2315
+ function parseFollowUps(text, count) {
2316
+ const source = text.match(/\[[\s\S]*\]/)?.[0] ?? text;
2317
+ try {
2318
+ const parsed = JSON.parse(source);
2319
+ if (Array.isArray(parsed)) {
2320
+ return parsed.filter((item) => typeof item === "string").slice(0, count);
2321
+ }
2322
+ } catch {
2323
+ }
2324
+ return [];
2325
+ }
2326
+ __name(parseFollowUps, "parseFollowUps");
2327
+ async function generateFollowUps(model, messages, count) {
2328
+ const discard = {
2329
+ write: /* @__PURE__ */ __name(() => {
2330
+ }, "write"),
2331
+ end: /* @__PURE__ */ __name(() => {
2332
+ }, "end"),
765
2333
  fail: /* @__PURE__ */ __name(() => {
766
2334
  }, "fail")
767
2335
  };
768
- const turn = await model.runTurn({
769
- system: `Based on the conversation so far, propose up to ${count} short, distinct follow-up questions the user is likely to ask next. Respond with ONLY a JSON array of strings \u2014 no prose, no code fences.`,
770
- messages,
771
- tools: [],
772
- sink: discard
2336
+ const turn = await model.runTurn({
2337
+ system: `Based on the conversation so far, propose up to ${count} short, distinct follow-up questions the user is likely to ask next. Respond with ONLY a JSON array of strings \u2014 no prose, no code fences.`,
2338
+ messages,
2339
+ tools: [],
2340
+ sink: discard
2341
+ });
2342
+ return {
2343
+ followUps: parseFollowUps(turn.text, count),
2344
+ usage: turn.usage,
2345
+ ...turn.modelId !== void 0 ? {
2346
+ modelId: turn.modelId
2347
+ } : {}
2348
+ };
2349
+ }
2350
+ __name(generateFollowUps, "generateFollowUps");
2351
+ async function spanned(event, runId, payload, run, summarize) {
2352
+ let value;
2353
+ await (0, import_nestjs_diagnostics2.trace)("agent", event, async () => {
2354
+ value = await run();
2355
+ return summarize(value);
2356
+ }, payload, {
2357
+ traceId: runId
2358
+ });
2359
+ return value;
2360
+ }
2361
+ __name(spanned, "spanned");
2362
+ function traceLlmTurn(runId, step, run) {
2363
+ return spanned("llm.turn", runId, {
2364
+ runId,
2365
+ step
2366
+ }, run, (turn) => ({
2367
+ ...turn.modelId !== void 0 ? {
2368
+ modelId: turn.modelId
2369
+ } : {},
2370
+ inputTokens: turn.usage.inputTokens,
2371
+ outputTokens: turn.usage.outputTokens,
2372
+ textLength: turn.text.length,
2373
+ toolCalls: turn.toolCalls.length
2374
+ }));
2375
+ }
2376
+ __name(traceLlmTurn, "traceLlmTurn");
2377
+ function traceToolExecution(runId, call, run) {
2378
+ return spanned("tool.execution", runId, {
2379
+ runId,
2380
+ ...call
2381
+ }, run, () => ({}));
2382
+ }
2383
+ __name(traceToolExecution, "traceToolExecution");
2384
+ function toModelMessages(messages) {
2385
+ return messages.map((message) => ({
2386
+ role: message.role,
2387
+ content: message.content,
2388
+ ...message.toolCalls !== void 0 ? {
2389
+ toolCalls: message.toolCalls
2390
+ } : {},
2391
+ ...message.toolResults !== void 0 ? {
2392
+ toolResults: message.toolResults
2393
+ } : {},
2394
+ ...message.attachments !== void 0 ? {
2395
+ attachments: message.attachments
2396
+ } : {}
2397
+ }));
2398
+ }
2399
+ __name(toModelMessages, "toModelMessages");
2400
+ function historyContext(input) {
2401
+ return {
2402
+ threadId: input.threadId,
2403
+ actor: input.actor,
2404
+ ...input.agentName !== void 0 ? {
2405
+ agentName: input.agentName
2406
+ } : {}
2407
+ };
2408
+ }
2409
+ __name(historyContext, "historyContext");
2410
+ function splitHistory(policy, input, messages) {
2411
+ return policy === void 0 ? {
2412
+ keep: messages,
2413
+ drop: []
2414
+ } : policy.select(messages, historyContext(input));
2415
+ }
2416
+ __name(splitHistory, "splitHistory");
2417
+ async function loadSelectedHistory(deps, input, hooks) {
2418
+ return hooks.step("load:thread", async () => {
2419
+ const thread = await readThreadForTurn(deps, input.threadId);
2420
+ const { keep, drop } = splitHistory(deps.historyPolicy, input, toModelMessages(thread.messages));
2421
+ return {
2422
+ messages: keep,
2423
+ dropped: deps.historyPolicy?.summarize === void 0 ? [] : drop,
2424
+ title: thread.title,
2425
+ hasAssistantMessage: thread.hasAssistantMessage
2426
+ };
2427
+ });
2428
+ }
2429
+ __name(loadSelectedHistory, "loadSelectedHistory");
2430
+ async function readThreadForTurn(deps, threadId) {
2431
+ const windowing = deps.store;
2432
+ if (typeof windowing.loadThreadForTurn === "function") {
2433
+ const messageLimit = turnMessageLimit(deps.historyPolicy);
2434
+ const page = await windowing.loadThreadForTurn({
2435
+ threadId,
2436
+ ...messageLimit !== void 0 ? {
2437
+ messageLimit
2438
+ } : {}
2439
+ });
2440
+ return page === null ? {
2441
+ messages: [],
2442
+ title: null,
2443
+ hasAssistantMessage: false
2444
+ } : {
2445
+ messages: page.messages,
2446
+ title: page.title,
2447
+ hasAssistantMessage: page.hasAssistantMessage
2448
+ };
2449
+ }
2450
+ const thread = await deps.store.getThread(threadId);
2451
+ const stored = thread?.messages ?? [];
2452
+ return {
2453
+ messages: stored,
2454
+ title: thread?.title ?? null,
2455
+ hasAssistantMessage: stored.some((message) => message.role === "assistant")
2456
+ };
2457
+ }
2458
+ __name(readThreadForTurn, "readThreadForTurn");
2459
+ function turnMessageLimit(policy) {
2460
+ if (policy === void 0 || policy.summarize !== void 0) {
2461
+ return void 0;
2462
+ }
2463
+ return policy.maxMessages;
2464
+ }
2465
+ __name(turnMessageLimit, "turnMessageLimit");
2466
+ async function loadWholeThread(deps, input, hooks) {
2467
+ const thread = await hooks.step("load:thread", () => deps.store.getThread(input.threadId));
2468
+ const stored = thread?.messages ?? [];
2469
+ const { keep, drop } = splitHistory(deps.historyPolicy, input, toModelMessages(stored));
2470
+ return {
2471
+ messages: keep,
2472
+ dropped: drop,
2473
+ title: thread?.title ?? null,
2474
+ hasAssistantMessage: stored.some((message) => message.role === "assistant")
2475
+ };
2476
+ }
2477
+ __name(loadWholeThread, "loadWholeThread");
2478
+ async function foldDroppedHistory(summarize, deps, input, hooks, history) {
2479
+ const summary = await hooks.step("history:summarize", () => summarize(history.dropped, historyContext(input)));
2480
+ if (summary.usage !== void 0) {
2481
+ const usage = summary.usage;
2482
+ await hooks.step("persist:usage:history", () => deps.store.recordUsage({
2483
+ threadId: input.threadId,
2484
+ actorRef: input.actor.id,
2485
+ modelId: summary.modelId ?? deps.modelId ?? "unknown",
2486
+ purpose: "history_summary",
2487
+ usage
2488
+ }));
2489
+ }
2490
+ return [
2491
+ {
2492
+ role: "system",
2493
+ content: buildSummaryBlock(summary.text)
2494
+ },
2495
+ ...history.messages
2496
+ ];
2497
+ }
2498
+ __name(foldDroppedHistory, "foldDroppedHistory");
2499
+ function processorContext(input, step) {
2500
+ return {
2501
+ threadId: input.threadId,
2502
+ actor: input.actor,
2503
+ step,
2504
+ ...input.agentName !== void 0 ? {
2505
+ agentName: input.agentName
2506
+ } : {}
2507
+ };
2508
+ }
2509
+ __name(processorContext, "processorContext");
2510
+ function restatementPrompt(messages, answer, fromTranscript) {
2511
+ const restated = {
2512
+ role: "assistant",
2513
+ content: answer
2514
+ };
2515
+ if (fromTranscript) {
2516
+ return [
2517
+ ...messages,
2518
+ restated
2519
+ ];
2520
+ }
2521
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
2522
+ const message = messages[index];
2523
+ if (message?.role === "user") {
2524
+ return [
2525
+ message,
2526
+ restated
2527
+ ];
2528
+ }
2529
+ }
2530
+ return [
2531
+ restated
2532
+ ];
2533
+ }
2534
+ __name(restatementPrompt, "restatementPrompt");
2535
+ async function structureAnswer(schema, deps, input, hooks, messages, step) {
2536
+ const instruction = deps.outputInstruction ?? DEFAULT_STRUCTURED_OUTPUT_INSTRUCTION;
2537
+ const maxAttempts = 1 + (deps.outputRepairAttempts ?? 1);
2538
+ const outputProcessors = deps.outputProcessors ?? [];
2539
+ let issues = [];
2540
+ let text = "";
2541
+ for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
2542
+ const system = attempt === 0 ? instruction : repairInstruction(instruction, issues);
2543
+ const reply = await hooks.step(`structured:${step}:${attempt}`, () => spanned("structured-output", hooks.runId, {
2544
+ runId: hooks.runId,
2545
+ step,
2546
+ attempt
2547
+ }, async () => {
2548
+ const discard = {
2549
+ write: /* @__PURE__ */ __name(() => {
2550
+ }, "write"),
2551
+ end: /* @__PURE__ */ __name(() => {
2552
+ }, "end"),
2553
+ fail: /* @__PURE__ */ __name(() => {
2554
+ }, "fail")
2555
+ };
2556
+ const turn = await deps.model.runTurn({
2557
+ system,
2558
+ messages,
2559
+ tools: [],
2560
+ sink: discard,
2561
+ outputSchema: schema
2562
+ });
2563
+ return {
2564
+ text: turn.text,
2565
+ usage: turn.usage,
2566
+ ...turn.object !== void 0 ? {
2567
+ object: turn.object
2568
+ } : {},
2569
+ ...turn.modelId !== void 0 ? {
2570
+ modelId: turn.modelId
2571
+ } : {}
2572
+ };
2573
+ }, (result) => ({
2574
+ inputTokens: result.usage.inputTokens,
2575
+ outputTokens: result.usage.outputTokens,
2576
+ textLength: result.text.length
2577
+ })));
2578
+ await hooks.step(`persist:usage:structured:${step}:${attempt}`, () => deps.store.recordUsage({
2579
+ threadId: input.threadId,
2580
+ actorRef: input.actor.id,
2581
+ modelId: reply.modelId ?? deps.modelId ?? "unknown",
2582
+ purpose: "structured_output",
2583
+ usage: reply.usage
2584
+ }));
2585
+ text = reply.text;
2586
+ if (outputProcessors.length > 0) {
2587
+ const gate = await hooks.step(`process:output:structured:${step}:${attempt}`, () => runOutputProcessors(outputProcessors, {
2588
+ text: reply.text,
2589
+ toolCalls: []
2590
+ }, processorContext(input, step)));
2591
+ if (gate.rejection !== void 0) {
2592
+ throw new OutputRejectedError(gate.rejection.processor, gate.rejection.reason);
2593
+ }
2594
+ text = gate.text;
2595
+ }
2596
+ const reported = text === reply.text ? reply.object : void 0;
2597
+ const outcome = await validateStructured(schema, text, reported);
2598
+ if (outcome.ok) {
2599
+ return outcome.value;
2600
+ }
2601
+ issues = outcome.issues;
2602
+ }
2603
+ throw new StructuredOutputError(issues, text, maxAttempts);
2604
+ }
2605
+ __name(structureAnswer, "structureAnswer");
2606
+ function declaredKind(deps, name) {
2607
+ if (deps.ask === true && name === ASK_TOOL_NAME) {
2608
+ return "ask";
2609
+ }
2610
+ if (deps.skills !== void 0 && name === SKILL_TOOL_NAME) {
2611
+ return "skill";
2612
+ }
2613
+ if (memoryIsWritable(deps) && name === REMEMBER_TOOL_NAME) {
2614
+ return "memory";
2615
+ }
2616
+ return deps.registry.spec(name)?.kind ?? "read";
2617
+ }
2618
+ __name(declaredKind, "declaredKind");
2619
+ function memoryIsWritable(deps) {
2620
+ return deps.memory?.provider.write !== void 0;
2621
+ }
2622
+ __name(memoryIsWritable, "memoryIsWritable");
2623
+ function withAskTool({ tools, ask }) {
2624
+ return ask === true ? [
2625
+ ...tools,
2626
+ askToolDefinition()
2627
+ ] : tools;
2628
+ }
2629
+ __name(withAskTool, "withAskTool");
2630
+ async function awaitElicitation(hooks, request, ctx) {
2631
+ if (hooks.awaitAnswers !== void 0) {
2632
+ return normalizeElicitationReply(await hooks.awaitAnswers(request, ctx));
2633
+ }
2634
+ return normalizeElicitationReply(await hooks.awaitApproval({
2635
+ id: request.id,
2636
+ name: ASK_TOOL_NAME,
2637
+ input: request,
2638
+ kind: "ask"
2639
+ }, ctx));
2640
+ }
2641
+ __name(awaitElicitation, "awaitElicitation");
2642
+ function toolContext(deps, input, hooks) {
2643
+ return {
2644
+ actor: input.actor,
2645
+ threadId: input.threadId,
2646
+ runId: hooks.runId,
2647
+ requestId: hooks.runId,
2648
+ ...input.agentName !== void 0 ? {
2649
+ agentName: input.agentName
2650
+ } : {},
2651
+ ...input.pageContext !== void 0 ? {
2652
+ pageContext: input.pageContext
2653
+ } : {},
2654
+ ...deps.host !== void 0 ? {
2655
+ host: deps.host
2656
+ } : {}
2657
+ };
2658
+ }
2659
+ __name(toolContext, "toolContext");
2660
+ function intakeApplies(intake, threadHasAssistant) {
2661
+ return intake.when === "every-turn" || !threadHasAssistant;
2662
+ }
2663
+ __name(intakeApplies, "intakeApplies");
2664
+ async function runIntake(intake, deps, input, hooks, writer, threadHasAssistant) {
2665
+ const preamble = intake.preamble ?? DEFAULT_INTAKE_PREAMBLE;
2666
+ const request = {
2667
+ id: `intake-${hooks.runId}`,
2668
+ source: "intake",
2669
+ preamble,
2670
+ questions: intake.questions
2671
+ };
2672
+ const call = {
2673
+ id: request.id,
2674
+ name: ASK_TOOL_NAME,
2675
+ input: {
2676
+ preamble,
2677
+ questions: intake.questions
2678
+ },
2679
+ kind: "ask"
2680
+ };
2681
+ const asked = await hooks.step("intake:ask", async () => {
2682
+ if (!intakeApplies(intake, threadHasAssistant)) {
2683
+ return null;
2684
+ }
2685
+ const message = await deps.store.appendMessage({
2686
+ threadId: input.threadId,
2687
+ role: "assistant",
2688
+ content: preamble,
2689
+ runId: hooks.runId,
2690
+ toolCalls: [
2691
+ call
2692
+ ],
2693
+ ...input.agentName !== void 0 ? {
2694
+ agentName: input.agentName
2695
+ } : {}
2696
+ });
2697
+ await deps.store.recordToolCall({
2698
+ toolCallId: request.id,
2699
+ messageId: message.id,
2700
+ toolName: ASK_TOOL_NAME,
2701
+ // The store knows read/action only. An unanswered question is work waiting on a human, which
2702
+ // is what `action` + `pending_approval` already mean — so it surfaces in an approvals inbox
2703
+ // rather than needing one of its own.
2704
+ toolType: "action",
2705
+ input: call.input,
2706
+ status: "pending_approval",
2707
+ runId: hooks.runId
2708
+ });
2709
+ await writer.write(encodeStreamEvent({
2710
+ kind: "elicitation",
2711
+ id: request.id,
2712
+ request
2713
+ }));
2714
+ return {
2715
+ messageId: message.id
2716
+ };
2717
+ });
2718
+ if (asked === null) {
2719
+ return null;
2720
+ }
2721
+ const messageId = asked.messageId;
2722
+ const reply = await awaitElicitation(hooks, request, toolContext(deps, input, hooks));
2723
+ const result = settleElicitation(request, reply);
2724
+ await hooks.step("intake:answers", async () => {
2725
+ await deps.store.updateToolCall({
2726
+ toolCallId: request.id,
2727
+ // A skip is not an answer. Both leave the agent holding the same values, but only one of them
2728
+ // is evidence the user chose them, and a reader auditing what the agent was told has to be
2729
+ // able to tell those apart.
2730
+ status: result.skipped ? "rejected" : "executed",
2731
+ output: result,
2732
+ ...result.skipped ? {
2733
+ error: "skipped by the user"
2734
+ } : {},
2735
+ ...reply.answeredByRef !== void 0 ? {
2736
+ executedByRef: reply.answeredByRef
2737
+ } : {}
2738
+ });
2739
+ await deps.store.setMessageToolResults(messageId, [
2740
+ {
2741
+ id: request.id,
2742
+ name: ASK_TOOL_NAME,
2743
+ output: result
2744
+ }
2745
+ ]);
2746
+ await writer.write(encodeStreamEvent({
2747
+ kind: "tool-output",
2748
+ id: request.id,
2749
+ output: result
2750
+ }));
2751
+ });
2752
+ return {
2753
+ role: "assistant",
2754
+ content: preamble,
2755
+ toolCalls: [
2756
+ call
2757
+ ],
2758
+ toolResults: [
2759
+ {
2760
+ id: request.id,
2761
+ name: ASK_TOOL_NAME,
2762
+ output: result
2763
+ }
2764
+ ]
2765
+ };
2766
+ }
2767
+ __name(runIntake, "runIntake");
2768
+ var PARALLEL_TOOLS_PATCH = "agent:parallel-tools";
2769
+ var CANCELLATION_PATCH = "agent:cancellation";
2770
+ var SELECTED_HISTORY_PATCH = "agent:selected-history";
2771
+ var PROMPT_STAGES_PATCH = "agent:prompt-stages";
2772
+ async function resolvePromptStages(deps, hooks) {
2773
+ const configured = {
2774
+ memory: deps.memory !== void 0,
2775
+ retriever: deps.retriever !== void 0,
2776
+ skills: deps.skills !== void 0
2777
+ };
2778
+ return await (hooks.patched?.(PROMPT_STAGES_PATCH) ?? Promise.resolve(true)) ? hooks.step("run:prompt-stages", () => Promise.resolve(configured)) : configured;
2779
+ }
2780
+ __name(resolvePromptStages, "resolvePromptStages");
2781
+ var UNSERVED_MEMORY = {
2782
+ scopes: [],
2783
+ entries: [],
2784
+ omitted: 0,
2785
+ pinnedOmitted: 0
2786
+ };
2787
+ var UNSERVED_SKILLS = {
2788
+ scopes: [],
2789
+ entries: [],
2790
+ omitted: 0
2791
+ };
2792
+ async function haltIfCancelled(hooks, cancellable, name) {
2793
+ const observe = hooks.cancelled;
2794
+ if (!cancellable || observe === void 0) {
2795
+ return;
2796
+ }
2797
+ if (await hooks.step(name, () => observe())) {
2798
+ throw new RunCancelledError();
2799
+ }
2800
+ }
2801
+ __name(haltIfCancelled, "haltIfCancelled");
2802
+ async function claimToolCall(turn, call) {
2803
+ const { deps, input, hooks, messageId } = turn;
2804
+ const persisted = await hooks.step(`persist:toolcall:${call.id}`, async () => {
2805
+ const spec = deps.registry.spec(call.name);
2806
+ const kind = declaredKind(deps, call.name);
2807
+ const awaitsHuman = kind === "action" || kind === "ask";
2808
+ await deps.store.recordToolCall({
2809
+ toolCallId: call.id,
2810
+ messageId,
2811
+ toolName: call.name,
2812
+ toolType: awaitsHuman ? "action" : "read",
2813
+ input: call.input,
2814
+ status: awaitsHuman ? "pending_approval" : "auto_executed",
2815
+ runId: hooks.runId
2816
+ });
2817
+ return {
2818
+ kind,
2819
+ ...spec?.targetAgent !== void 0 ? {
2820
+ targetAgent: spec.targetAgent
2821
+ } : {},
2822
+ // Only an `agent` spec ever carries this, and only when the author declared it — so a
2823
+ // deployment with no detached edge writes the same bytes here it always has.
2824
+ ...spec?.detached === true ? {
2825
+ detached: true
2826
+ } : {}
2827
+ };
2828
+ });
2829
+ const toolType = persisted?.kind ?? call.kind ?? "read";
2830
+ return {
2831
+ call,
2832
+ // What the rest of the turn — the dispatched tool envelope, the stream frames — sees as this
2833
+ // call's kind, so it agrees with the branch actually taken instead of with a second lookup.
2834
+ resolvedCall: call.kind === toolType ? call : {
2835
+ ...call,
2836
+ kind: toolType
2837
+ },
2838
+ toolType,
2839
+ ...persisted?.targetAgent !== void 0 ? {
2840
+ targetAgent: persisted.targetAgent
2841
+ } : {},
2842
+ ...persisted?.detached === true ? {
2843
+ detached: true
2844
+ } : {},
2845
+ ctx: toolContext(deps, input, hooks)
2846
+ };
2847
+ }
2848
+ __name(claimToolCall, "claimToolCall");
2849
+ async function loadSkillIntoTurn(turn, claimed, startedAt) {
2850
+ const { deps, input, hooks } = turn;
2851
+ const { call } = claimed;
2852
+ const config = deps.skills;
2853
+ const offer = turn.skills;
2854
+ const outcome = await hooks.step(`tool:${call.id}`, async () => {
2855
+ if (config === void 0 || offer === void 0) {
2856
+ return {
2857
+ ok: false,
2858
+ error: "Skills are not available in this deployment."
2859
+ };
2860
+ }
2861
+ const parsed = await skillInputSchema["~standard"].validate(call.input);
2862
+ if (parsed.issues !== void 0) {
2863
+ return {
2864
+ ok: false,
2865
+ error: `invalid skill input: ${parsed.issues.map((each) => `${(each.path ?? []).join(".") || "(root)"}: ${each.message}`).join("; ")}`
2866
+ };
2867
+ }
2868
+ const loaded = await loadSkill(config, offer, parsed.value.name, skillContext(input));
2869
+ if (!loaded.ok) {
2870
+ return {
2871
+ ok: false,
2872
+ error: loaded.error
2873
+ };
2874
+ }
2875
+ return {
2876
+ ok: true,
2877
+ output: {
2878
+ name: loaded.skill.name,
2879
+ scope: loaded.skill.scope,
2880
+ body: loaded.skill.body,
2881
+ ...loaded.shadows !== void 0 ? {
2882
+ shadows: loaded.shadows
2883
+ } : {}
2884
+ }
2885
+ };
2886
+ });
2887
+ return outcome.ok ? {
2888
+ status: "executed",
2889
+ output: outcome.output,
2890
+ executionMs: Date.now() - startedAt
2891
+ } : {
2892
+ status: "failed",
2893
+ error: outcome.error,
2894
+ executionMs: Date.now() - startedAt
2895
+ };
2896
+ }
2897
+ __name(loadSkillIntoTurn, "loadSkillIntoTurn");
2898
+ async function rememberIntoTurn(turn, claimed, startedAt) {
2899
+ const { deps, input, hooks } = turn;
2900
+ const { call } = claimed;
2901
+ const config = deps.memory;
2902
+ const digest = turn.memory;
2903
+ const outcome = await hooks.step(`tool:${call.id}`, async () => {
2904
+ if (config === void 0 || digest === void 0) {
2905
+ return {
2906
+ ok: false,
2907
+ error: "Memory is not available in this deployment."
2908
+ };
2909
+ }
2910
+ const parsed = await rememberInputSchema["~standard"].validate(call.input);
2911
+ if (parsed.issues !== void 0) {
2912
+ return {
2913
+ ok: false,
2914
+ error: `invalid remember input: ${parsed.issues.map((each) => `${(each.path ?? []).join(".") || "(root)"}: ${each.message}`).join("; ")}`
2915
+ };
2916
+ }
2917
+ return await writeMemory({
2918
+ config,
2919
+ digest,
2920
+ call: parsed.value,
2921
+ ctx: skillContext(input),
2922
+ runId: hooks.runId
2923
+ });
2924
+ });
2925
+ if (!outcome.ok) {
2926
+ return {
2927
+ status: "failed",
2928
+ error: outcome.error,
2929
+ executionMs: Date.now() - startedAt
2930
+ };
2931
+ }
2932
+ publishAgentMemoryWritten({
2933
+ runId: hooks.runId,
2934
+ scope: outcome.record.scope,
2935
+ chars: outcome.record.text.length
2936
+ });
2937
+ return {
2938
+ status: "executed",
2939
+ output: outcome.record,
2940
+ executionMs: Date.now() - startedAt
2941
+ };
2942
+ }
2943
+ __name(rememberIntoTurn, "rememberIntoTurn");
2944
+ function skillContext(input) {
2945
+ return {
2946
+ actor: input.actor,
2947
+ threadId: input.threadId,
2948
+ ...input.agentName !== void 0 ? {
2949
+ agentName: input.agentName
2950
+ } : {},
2951
+ ...input.pageContext !== void 0 ? {
2952
+ pageContext: input.pageContext
2953
+ } : {}
2954
+ };
2955
+ }
2956
+ __name(skillContext, "skillContext");
2957
+ async function invokeClaimedTool(turn, claimed) {
2958
+ const { deps, input, hooks } = turn;
2959
+ const { call, resolvedCall, ctx } = claimed;
2960
+ const toolType = claimed.toolType === "action" ? "action" : "read";
2961
+ const startedAt = Date.now();
2962
+ try {
2963
+ if (claimed.toolType === "skill") {
2964
+ return await loadSkillIntoTurn(turn, claimed, startedAt);
2965
+ }
2966
+ if (claimed.toolType === "memory") {
2967
+ return await rememberIntoTurn(turn, claimed, startedAt);
2968
+ }
2969
+ let output;
2970
+ if (hooks.dispatchTool) {
2971
+ const stepCtx = {
2972
+ actor: input.actor,
2973
+ threadId: input.threadId,
2974
+ runId: hooks.runId,
2975
+ requestId: hooks.runId,
2976
+ ...input.agentName !== void 0 ? {
2977
+ agentName: input.agentName
2978
+ } : {},
2979
+ ...input.pageContext !== void 0 ? {
2980
+ pageContext: input.pageContext
2981
+ } : {}
2982
+ };
2983
+ const envelope = {
2984
+ toolName: call.name,
2985
+ input: call.input,
2986
+ ctx: stepCtx,
2987
+ ...deps.toolTimeoutMs !== void 0 ? {
2988
+ timeoutMs: deps.toolTimeoutMs
2989
+ } : {},
2990
+ // Numeric-only: the handler applies withToolTimeout AND its own local `classify` — see
2991
+ // ToolStepEnvelope.transientRetry.
2992
+ transientRetry: resolveToolTransientRetryNumbers(deps.toolTransientRetry)
2993
+ };
2994
+ output = await hooks.dispatchTool(resolvedCall, envelope);
2995
+ } else {
2996
+ const invocation = hooks.step(`tool:${call.id}`, () => traceToolExecution(hooks.runId, {
2997
+ toolCallId: call.id,
2998
+ toolName: call.name,
2999
+ toolType
3000
+ }, () => invokeWithTransientRetry(() => deps.registry.invoke(call.name, call.input, ctx, deps.rolesPolicy), deps.toolTransientRetry ?? {}, {
3001
+ ...hooks.isControlFlowError !== void 0 ? {
3002
+ isControlFlowError: hooks.isControlFlowError
3003
+ } : {},
3004
+ onRetry: /* @__PURE__ */ __name((attempt, retryError) => {
3005
+ publishAgentToolRetry({
3006
+ toolName: call.name,
3007
+ toolCallId: call.id,
3008
+ attempt,
3009
+ message: retryError instanceof Error ? retryError.message : String(retryError)
3010
+ });
3011
+ }, "onRetry")
3012
+ })));
3013
+ output = deps.toolTimeoutMs !== void 0 ? await withToolTimeout(invocation, deps.toolTimeoutMs, call.name) : await invocation;
3014
+ }
3015
+ return {
3016
+ status: "executed",
3017
+ output,
3018
+ executionMs: Date.now() - startedAt
3019
+ };
3020
+ } catch (error) {
3021
+ if (hooks.isControlFlowError?.(error) === true || isControlFlowSignal(error) || isReplayIntegrityError(error)) {
3022
+ throw error;
3023
+ }
3024
+ return {
3025
+ status: "failed",
3026
+ error: error instanceof Error ? error.message : String(error),
3027
+ executionMs: Date.now() - startedAt
3028
+ };
3029
+ }
3030
+ }
3031
+ __name(invokeClaimedTool, "invokeClaimedTool");
3032
+ async function recordToolOutcome(turn, claimed, outcome, deciderRef) {
3033
+ const { deps, hooks } = turn;
3034
+ const { call } = claimed;
3035
+ const toolType = claimed.toolType === "action" ? "action" : "read";
3036
+ if (outcome.status === "failed") {
3037
+ await hooks.step(`persist:toolfail:${call.id}`, () => deps.store.updateToolCall({
3038
+ toolCallId: call.id,
3039
+ status: "failed",
3040
+ error: outcome.error,
3041
+ executionMs: outcome.executionMs
3042
+ }));
3043
+ publishAgentToolCall({
3044
+ runId: hooks.runId,
3045
+ toolName: call.name,
3046
+ toolType,
3047
+ status: "failed",
3048
+ durationMs: outcome.executionMs
3049
+ });
3050
+ return {
3051
+ id: call.id,
3052
+ name: call.name,
3053
+ output: null,
3054
+ error: outcome.error
3055
+ };
3056
+ }
3057
+ await hooks.step(`persist:toolexec:${call.id}`, () => deps.store.updateToolCall({
3058
+ toolCallId: call.id,
3059
+ status: "executed",
3060
+ output: outcome.output,
3061
+ executionMs: outcome.executionMs,
3062
+ ...toolType === "action" ? {
3063
+ executedByRef: deciderRef
3064
+ } : {}
3065
+ }));
3066
+ publishAgentToolCall({
3067
+ runId: hooks.runId,
3068
+ toolName: call.name,
3069
+ toolType,
3070
+ status: "executed",
3071
+ durationMs: outcome.executionMs
3072
+ });
3073
+ return {
3074
+ id: call.id,
3075
+ name: call.name,
3076
+ output: outcome.output
3077
+ };
3078
+ }
3079
+ __name(recordToolOutcome, "recordToolOutcome");
3080
+ async function delegateToolCall(turn, claimed) {
3081
+ const { deps, input, hooks } = turn;
3082
+ const { call, targetAgent = call.name } = claimed;
3083
+ const task = extractTask(call.input);
3084
+ const refusal = delegationRefusal({
3085
+ deps,
3086
+ input,
3087
+ targetAgent
773
3088
  });
774
- return {
775
- followUps: parseFollowUps(turn.text, count),
776
- usage: turn.usage,
777
- ...turn.modelId !== void 0 ? {
778
- modelId: turn.modelId
3089
+ const start = claimed.detached === true && refusal === null ? hooks.startAgent : void 0;
3090
+ publishAgentDelegated({
3091
+ runId: hooks.runId,
3092
+ toAgent: targetAgent,
3093
+ ...input.agentName !== void 0 ? {
3094
+ fromAgent: input.agentName
3095
+ } : {},
3096
+ ...start !== void 0 ? {
3097
+ detached: true
779
3098
  } : {}
3099
+ });
3100
+ let sub;
3101
+ if (refusal !== null) {
3102
+ sub = {
3103
+ text: refusal
3104
+ };
3105
+ } else if (start !== void 0) {
3106
+ const started = await start({
3107
+ agentName: targetAgent,
3108
+ task,
3109
+ toolCallId: call.id
3110
+ });
3111
+ sub = detachedStarted({
3112
+ agent: targetAgent,
3113
+ runId: started.runId
3114
+ });
3115
+ } else if (hooks.runAgent) {
3116
+ sub = await hooks.runAgent(targetAgent, task);
3117
+ } else {
3118
+ sub = {
3119
+ text: `(no multi-agent support wired; cannot reach "${targetAgent}")`
3120
+ };
3121
+ }
3122
+ await hooks.step(`persist:toolexec:${call.id}`, () => deps.store.updateToolCall({
3123
+ toolCallId: call.id,
3124
+ status: "executed",
3125
+ output: sub
3126
+ }));
3127
+ return {
3128
+ id: call.id,
3129
+ name: call.name,
3130
+ output: sub
780
3131
  };
781
3132
  }
782
- __name(generateFollowUps, "generateFollowUps");
783
- async function spanned(event, runId, payload, run, summarize) {
784
- let value;
785
- await (0, import_nestjs_diagnostics2.trace)("agent", event, async () => {
786
- value = await run();
787
- return summarize(value);
788
- }, payload, {
789
- traceId: runId
3133
+ __name(delegateToolCall, "delegateToolCall");
3134
+ async function elicitToolCall(turn, claimed) {
3135
+ const { deps, hooks } = turn;
3136
+ const { call, ctx } = claimed;
3137
+ const parsed = await askInputSchema["~standard"].validate(call.input);
3138
+ if (parsed.issues !== void 0) {
3139
+ const error = `invalid ask input: ${parsed.issues.map((each) => `${(each.path ?? []).join(".") || "(root)"}: ${each.message}`).join("; ")}`;
3140
+ await hooks.step(`persist:toolfail:${call.id}`, () => deps.store.updateToolCall({
3141
+ toolCallId: call.id,
3142
+ status: "failed",
3143
+ error
3144
+ }));
3145
+ return {
3146
+ id: call.id,
3147
+ name: call.name,
3148
+ output: null,
3149
+ error
3150
+ };
3151
+ }
3152
+ const request = {
3153
+ id: call.id,
3154
+ source: "ask",
3155
+ questions: parsed.value.questions,
3156
+ ...parsed.value.preamble !== void 0 ? {
3157
+ preamble: parsed.value.preamble
3158
+ } : {}
3159
+ };
3160
+ await hooks.step(`stream:elicitation:${call.id}`, async () => {
3161
+ await turn.writer.write(encodeStreamEvent({
3162
+ kind: "elicitation",
3163
+ id: call.id,
3164
+ request
3165
+ }));
790
3166
  });
791
- return value;
792
- }
793
- __name(spanned, "spanned");
794
- function traceLlmTurn(runId, step, run) {
795
- return spanned("llm.turn", runId, {
796
- runId,
797
- step
798
- }, run, (turn) => ({
799
- ...turn.modelId !== void 0 ? {
800
- modelId: turn.modelId
3167
+ const reply = await awaitElicitation(hooks, request, ctx);
3168
+ const result = settleElicitation(request, reply);
3169
+ await hooks.step(result.skipped ? `persist:toolreject:${call.id}` : `persist:toolexec:${call.id}`, () => deps.store.updateToolCall({
3170
+ toolCallId: call.id,
3171
+ status: result.skipped ? "rejected" : "executed",
3172
+ output: result,
3173
+ ...result.skipped ? {
3174
+ error: "skipped by the user"
801
3175
  } : {},
802
- inputTokens: turn.usage.inputTokens,
803
- outputTokens: turn.usage.outputTokens,
804
- textLength: turn.text.length,
805
- toolCalls: turn.toolCalls.length
3176
+ ...reply.answeredByRef !== void 0 ? {
3177
+ executedByRef: reply.answeredByRef
3178
+ } : {}
806
3179
  }));
3180
+ publishAgentToolCall({
3181
+ runId: hooks.runId,
3182
+ toolName: call.name,
3183
+ toolType: "action",
3184
+ status: result.skipped ? "rejected" : "executed"
3185
+ });
3186
+ return {
3187
+ id: call.id,
3188
+ name: call.name,
3189
+ output: result
3190
+ };
807
3191
  }
808
- __name(traceLlmTurn, "traceLlmTurn");
809
- function traceToolExecution(runId, call, run) {
810
- return spanned("tool.execution", runId, {
811
- runId,
812
- ...call
813
- }, run, () => ({}));
3192
+ __name(elicitToolCall, "elicitToolCall");
3193
+ async function runClaimedToolCall(turn, claimed) {
3194
+ const { deps, input, hooks } = turn;
3195
+ const { call, toolType, ctx } = claimed;
3196
+ if (toolType === "agent") {
3197
+ return delegateToolCall(turn, claimed);
3198
+ }
3199
+ if (toolType === "ask") {
3200
+ return elicitToolCall(turn, claimed);
3201
+ }
3202
+ let deciderRef = input.actor.id;
3203
+ if (toolType === "action") {
3204
+ const decision = await hooks.awaitApproval(call, ctx);
3205
+ deciderRef = decision.executedByRef ?? input.actor.id;
3206
+ if (!decision.approved) {
3207
+ await hooks.step(`persist:toolreject:${call.id}`, () => deps.store.updateToolCall({
3208
+ toolCallId: call.id,
3209
+ status: "rejected",
3210
+ executedByRef: deciderRef,
3211
+ ...decision.reason !== void 0 ? {
3212
+ error: decision.reason
3213
+ } : {}
3214
+ }));
3215
+ publishAgentToolCall({
3216
+ runId: hooks.runId,
3217
+ toolName: call.name,
3218
+ toolType,
3219
+ status: "rejected"
3220
+ });
3221
+ return {
3222
+ id: call.id,
3223
+ name: call.name,
3224
+ output: {
3225
+ rejected: true,
3226
+ reason: decision.reason ?? "rejected by user"
3227
+ },
3228
+ error: "rejected"
3229
+ };
3230
+ }
3231
+ }
3232
+ return recordToolOutcome(turn, claimed, await invokeClaimedTool(turn, claimed), deciderRef);
814
3233
  }
815
- __name(traceToolExecution, "traceToolExecution");
3234
+ __name(runClaimedToolCall, "runClaimedToolCall");
3235
+ async function invokeClaimedToolsTogether(turn, parallel, claimed) {
3236
+ const settled = await parallel(claimed.map((entry) => () => invokeClaimedTool(turn, entry)));
3237
+ for (const outcome of settled) {
3238
+ if (!outcome.ok) {
3239
+ throw outcome.error;
3240
+ }
3241
+ }
3242
+ const results = [];
3243
+ for (const [index, entry] of claimed.entries()) {
3244
+ const outcome = settled[index];
3245
+ if (outcome?.ok === true) {
3246
+ results.push(await recordToolOutcome(turn, entry, outcome.value, turn.input.actor.id));
3247
+ }
3248
+ }
3249
+ return results;
3250
+ }
3251
+ __name(invokeClaimedToolsTogether, "invokeClaimedToolsTogether");
816
3252
  async function runAgentLoop(deps, input, hooks) {
817
3253
  const maxSteps = deps.maxSteps ?? 8;
818
3254
  let system = await resolveSystemPrompt(deps, input);
3255
+ const inputProcessors = deps.inputProcessors ?? [];
3256
+ const outputProcessors = deps.outputProcessors ?? [];
3257
+ const gateMode = resolveOutputGateMode(outputProcessors);
3258
+ const gated = gateMode !== "off";
3259
+ const gateLookback = resolveGateLookback(outputProcessors);
3260
+ let structured;
819
3261
  if (deps.quota !== void 0) {
820
3262
  const quota = deps.quota;
821
3263
  const state = await hooks.step("quota:check", () => quota.check(input.actor.id, deps.day));
@@ -849,25 +3291,18 @@ async function runAgentLoop(deps, input, hooks) {
849
3291
  threadId: input.threadId,
850
3292
  role: "user",
851
3293
  content: input.userText,
3294
+ runId: hooks.runId,
852
3295
  ...input.attachments !== void 0 ? {
853
3296
  attachments: input.attachments
854
3297
  } : {}
855
3298
  }));
856
3299
  }
857
- const thread = await hooks.step("load:thread", () => deps.store.getThread(input.threadId));
858
- const modelMessages = (thread?.messages ?? []).map((message) => ({
859
- role: message.role,
860
- content: message.content,
861
- ...message.toolCalls !== void 0 ? {
862
- toolCalls: message.toolCalls
863
- } : {},
864
- ...message.toolResults !== void 0 ? {
865
- toolResults: message.toolResults
866
- } : {},
867
- ...message.attachments !== void 0 ? {
868
- attachments: message.attachments
869
- } : {}
870
- }));
3300
+ const history = await (hooks.patched?.(SELECTED_HISTORY_PATCH) ?? Promise.resolve(true)) ? await loadSelectedHistory(deps, input, hooks) : await loadWholeThread(deps, input, hooks);
3301
+ let modelMessages = history.messages;
3302
+ const summarize = deps.historyPolicy?.summarize?.bind(deps.historyPolicy);
3303
+ if (summarize !== void 0 && history.dropped.length > 0) {
3304
+ modelMessages = await foldDroppedHistory(summarize, deps, input, hooks, history);
3305
+ }
871
3306
  const writer = await hooks.openSink();
872
3307
  let lastText = "";
873
3308
  let steps = 0;
@@ -881,6 +3316,7 @@ async function runAgentLoop(deps, input, hooks) {
881
3316
  agentName: input.agentName
882
3317
  } : {}
883
3318
  });
3319
+ const stages = await resolvePromptStages(deps, hooks);
884
3320
  const startedAt = await hooks.step("run:started-at", () => Promise.resolve(Date.now()));
885
3321
  await hooks.step("persist:run:start", async () => {
886
3322
  const promptHash = (0, import_node_crypto.createHash)("sha256").update(system).digest("hex");
@@ -891,20 +3327,52 @@ async function runAgentLoop(deps, input, hooks) {
891
3327
  ...input.agentName !== void 0 ? {
892
3328
  agentName: input.agentName
893
3329
  } : {},
3330
+ ...input.parentRunId !== void 0 ? {
3331
+ parentRunId: input.parentRunId
3332
+ } : {},
894
3333
  promptHash
895
3334
  });
896
3335
  });
3336
+ let memoryDigest;
3337
+ if (stages.memory) {
3338
+ const config = deps.memory;
3339
+ memoryDigest = await hooks.step("memory:digest", () => config === void 0 ? Promise.resolve(UNSERVED_MEMORY) : offerMemories({
3340
+ config,
3341
+ ctx: skillContext(input),
3342
+ query: input.userText
3343
+ }));
3344
+ const digest = memoryDigest;
3345
+ const block = digest.entries.length > 0 ? buildMemoryBlock({
3346
+ entries: digest.entries,
3347
+ writable: memoryIsWritable(deps),
3348
+ partial: digest.omitted > 0 || digest.recalled === true
3349
+ }) : "";
3350
+ if (block.length > 0) {
3351
+ system = `${system}
3352
+
3353
+ ${block}`;
3354
+ }
3355
+ publishAgentMemoryResolved({
3356
+ runId: hooks.runId,
3357
+ scopes: digest.scopes.length,
3358
+ offered: digest.entries.length,
3359
+ omitted: digest.omitted,
3360
+ pinnedOmitted: digest.pinnedOmitted,
3361
+ recalled: digest.recalled === true,
3362
+ promptChars: block.length
3363
+ });
3364
+ }
897
3365
  let injectedPassages;
898
- if (deps.retriever !== void 0) {
3366
+ if (stages.retriever) {
899
3367
  const retriever = deps.retriever;
900
3368
  const topK = deps.retrievalTopK ?? 5;
901
3369
  const passages = await hooks.step("retrieve", () => spanned("retrieval", hooks.runId, {
902
3370
  runId: hooks.runId,
903
3371
  queryLength: input.userText.length,
904
3372
  topK
905
- }, () => retriever.retrieve(input.userText, {
3373
+ }, () => retriever?.retrieve(input.userText, {
906
3374
  topK
907
- }), (retrieved) => ({
3375
+ }) ?? Promise.resolve([]), (retrieved) => ({
908
3376
  count: retrieved.length
909
3377
  })));
910
3378
  if (passages.length > 0) {
@@ -919,6 +3387,24 @@ ${buildContextBlock(passages)}`;
919
3387
  count: passages.length
920
3388
  });
921
3389
  }
3390
+ let skillOffer;
3391
+ if (stages.skills) {
3392
+ const config = deps.skills;
3393
+ skillOffer = await hooks.step("skills:catalog", () => config === void 0 ? Promise.resolve(UNSERVED_SKILLS) : offerSkills(config, skillContext(input)));
3394
+ const block = skillOffer.entries.length > 0 ? buildSkillsBlock(skillOffer.entries) : "";
3395
+ if (block.length > 0) {
3396
+ system = `${system}
3397
+
3398
+ ${block}`;
3399
+ }
3400
+ publishAgentSkillsResolved({
3401
+ runId: hooks.runId,
3402
+ scopes: skillOffer.scopes.length,
3403
+ offered: skillOffer.entries.length,
3404
+ omitted: skillOffer.omitted,
3405
+ promptChars: block.length
3406
+ });
3407
+ }
922
3408
  let prices = [];
923
3409
  if (deps.pricingStore !== void 0) {
924
3410
  const pricingStore = deps.pricingStore;
@@ -928,36 +3414,124 @@ ${buildContextBlock(passages)}`;
928
3414
  price.modelId,
929
3415
  price
930
3416
  ]));
3417
+ if (deps.intake !== void 0) {
3418
+ const asked = await runIntake(deps.intake, deps, input, hooks, writer, history.hasAssistantMessage);
3419
+ if (asked !== null) {
3420
+ modelMessages.push(asked);
3421
+ }
3422
+ }
3423
+ const cancellable = hooks.cancelled !== void 0 && await (hooks.patched?.(CANCELLATION_PATCH) ?? Promise.resolve(true));
931
3424
  for (let i = 0; i < maxSteps; i += 1) {
3425
+ await haltIfCancelled(hooks, cancellable, `cancel:check:${i}`);
932
3426
  await hooks.step(`stream:step-start:${i}`, async () => {
933
3427
  await writer.write(encodeStreamEvent({
934
3428
  kind: "step-start"
935
3429
  }));
936
3430
  });
3431
+ let prompt = {
3432
+ system,
3433
+ messages: modelMessages
3434
+ };
3435
+ if (inputProcessors.length > 0) {
3436
+ prompt = await hooks.step(`process:input:${i}`, () => runInputProcessors(inputProcessors, prompt, processorContext(input, i)));
3437
+ }
937
3438
  let turn;
938
3439
  if (hooks.dispatchLlm) {
939
3440
  turn = await hooks.dispatchLlm(i, {
940
3441
  ...input.agentName !== void 0 ? {
941
3442
  agentName: input.agentName
942
3443
  } : {},
943
- system,
944
- messages: modelMessages,
945
- actor: input.actor
3444
+ system: prompt.system,
3445
+ messages: prompt.messages,
3446
+ actor: input.actor,
3447
+ ...gated ? {
3448
+ bufferOutput: true
3449
+ } : {}
946
3450
  });
947
3451
  } else {
948
- const tools = await deps.registry.definitionsFor(input.actor, deps.rolesPolicy, deps.toolAllowList);
949
- turn = await hooks.step(`llm:${i}`, () => traceLlmTurn(hooks.runId, i, () => deps.model.runTurn({
950
- system,
951
- messages: modelMessages,
952
- tools,
953
- sink: writer
954
- })));
3452
+ const tools = withMemoryTool({
3453
+ tools: withSkillTool({
3454
+ tools: withAskTool({
3455
+ tools: await deps.registry.definitionsFor(input.actor, deps.rolesPolicy, deps.toolAllowList),
3456
+ ask: deps.ask
3457
+ }),
3458
+ enabled: deps.skills !== void 0
3459
+ }),
3460
+ enabled: memoryIsWritable(deps)
3461
+ });
3462
+ turn = await hooks.step(`llm:${i}`, async () => {
3463
+ const incremental = gateMode === "incremental" ? createIncrementalGate({
3464
+ processors: outputProcessors,
3465
+ ctx: processorContext(input, i),
3466
+ lookbackChars: gateLookback,
3467
+ writer
3468
+ }) : void 0;
3469
+ const buffer = gateMode === "whole" ? createFrameBuffer() : void 0;
3470
+ const result = await traceLlmTurn(hooks.runId, i, () => deps.model.runTurn({
3471
+ system: prompt.system,
3472
+ messages: prompt.messages,
3473
+ tools,
3474
+ sink: incremental?.writer ?? buffer?.writer ?? writer
3475
+ }));
3476
+ if (incremental !== void 0) {
3477
+ await incremental.settled();
3478
+ const refusal = incremental.rejection();
3479
+ return {
3480
+ ...result,
3481
+ releasedText: incremental.released(),
3482
+ ...refusal !== void 0 ? {
3483
+ gateRejection: refusal
3484
+ } : {}
3485
+ };
3486
+ }
3487
+ return buffer === void 0 ? result : {
3488
+ ...result,
3489
+ bufferedFrames: buffer.frames()
3490
+ };
3491
+ });
3492
+ }
3493
+ let rejection;
3494
+ if (gated) {
3495
+ const gate = await hooks.step(`process:output:${i}`, async () => {
3496
+ const released = turn.releasedText;
3497
+ if (turn.gateRejection !== void 0) {
3498
+ return {
3499
+ text: turn.text,
3500
+ rejection: turn.gateRejection
3501
+ };
3502
+ }
3503
+ const settled = await runOutputProcessors(outputProcessors, {
3504
+ text: turn.text,
3505
+ toolCalls: turn.toolCalls
3506
+ }, processorContext(input, i));
3507
+ if (settled.rejection === void 0) {
3508
+ if (released === void 0) {
3509
+ for (const chunk of releaseGatedFrames(turn.bufferedFrames ?? [], settled.text)) {
3510
+ await writer.write(chunk);
3511
+ }
3512
+ } else {
3513
+ const tail = gateTail(outputProcessors, released, settled.text);
3514
+ if (tail.length > 0) {
3515
+ await writer.write(encodeStreamEvent({
3516
+ kind: "text",
3517
+ text: tail
3518
+ }));
3519
+ }
3520
+ }
3521
+ }
3522
+ return settled;
3523
+ });
3524
+ rejection = gate.rejection;
3525
+ turn = {
3526
+ ...turn,
3527
+ text: gate.text
3528
+ };
955
3529
  }
956
3530
  const resolvedModelId = turn.modelId ?? deps.modelId ?? "unknown";
957
3531
  const costUsd = resolveCostUsd(turn.usage, turn.costUsd, priceByModel.get(resolvedModelId));
958
3532
  const toolCallsWithKind = turn.toolCalls.map((call) => ({
959
3533
  ...call,
960
- kind: deps.registry.spec(call.name)?.kind ?? "read"
3534
+ kind: declaredKind(deps, call.name)
961
3535
  }));
962
3536
  await hooks.step(`persist:usage:${i}`, () => deps.store.recordUsage({
963
3537
  threadId: input.threadId,
@@ -974,6 +3548,9 @@ ${buildContextBlock(passages)}`;
974
3548
  const quota = deps.quota;
975
3549
  await hooks.step(`quota:bump:${i}`, () => quota.bump(input.actor.id, deps.day, turn.usage.inputTokens + turn.usage.outputTokens));
976
3550
  }
3551
+ if (rejection !== void 0) {
3552
+ throw new OutputRejectedError(rejection.processor, rejection.reason);
3553
+ }
977
3554
  steps += 1;
978
3555
  totalInput += turn.usage.inputTokens;
979
3556
  totalOutput += turn.usage.outputTokens;
@@ -985,6 +3562,9 @@ ${buildContextBlock(passages)}`;
985
3562
  textLength: turn.text.length
986
3563
  });
987
3564
  const isFinalTurn = turn.toolCalls.length === 0;
3565
+ if (isFinalTurn && deps.outputSchema !== void 0) {
3566
+ structured = await structureAnswer(deps.outputSchema, deps, input, hooks, restatementPrompt(prompt.messages, turn.text, deps.outputFromTranscript === true), i);
3567
+ }
988
3568
  let followUps;
989
3569
  if (isFinalTurn && deps.followUpsCount !== void 0 && deps.followUpsCount > 0) {
990
3570
  const count = deps.followUpsCount;
@@ -1006,8 +3586,12 @@ ${buildContextBlock(passages)}`;
1006
3586
  modelId: result.modelId
1007
3587
  } : {}
1008
3588
  })));
1009
- if (generated.followUps.length > 0) {
1010
- followUps = generated.followUps;
3589
+ let suggestions = generated.followUps;
3590
+ if (outputProcessors.length > 0) {
3591
+ suggestions = await hooks.step(`process:output:followups:${i}`, () => gateFollowUps(outputProcessors, suggestions, processorContext(input, i)));
3592
+ }
3593
+ if (suggestions.length > 0) {
3594
+ followUps = suggestions;
1011
3595
  }
1012
3596
  await hooks.step(`persist:usage:followups:${i}`, () => deps.store.recordUsage({
1013
3597
  threadId: input.threadId,
@@ -1017,10 +3601,58 @@ ${buildContextBlock(passages)}`;
1017
3601
  usage: generated.usage
1018
3602
  }));
1019
3603
  }
3604
+ const synthetic = [];
3605
+ if (i === 0 && injectedPassages !== void 0) {
3606
+ const call = {
3607
+ id: `retrieve-${hooks.runId}`,
3608
+ name: "retrieve",
3609
+ input: {
3610
+ query: input.userText
3611
+ },
3612
+ kind: "read"
3613
+ };
3614
+ const output = {
3615
+ passages: injectedPassages
3616
+ };
3617
+ synthetic.push({
3618
+ step: "persist:retrieval",
3619
+ call,
3620
+ result: {
3621
+ id: call.id,
3622
+ name: call.name,
3623
+ output
3624
+ }
3625
+ });
3626
+ }
3627
+ if (structured !== void 0) {
3628
+ const call = {
3629
+ id: `structured-${hooks.runId}`,
3630
+ name: "structured_output",
3631
+ input: {},
3632
+ kind: "read"
3633
+ };
3634
+ synthetic.push({
3635
+ step: "persist:structured",
3636
+ call,
3637
+ result: {
3638
+ id: call.id,
3639
+ name: call.name,
3640
+ output: structured
3641
+ }
3642
+ });
3643
+ }
3644
+ const messageCalls = [
3645
+ ...toolCallsWithKind,
3646
+ ...synthetic.map((entry) => entry.call)
3647
+ ];
3648
+ const syntheticResults = synthetic.map((entry) => entry.result);
1020
3649
  const assistant = await hooks.step(`persist:assistant:${i}`, () => deps.store.appendMessage({
1021
3650
  threadId: input.threadId,
1022
3651
  role: "assistant",
1023
3652
  content: turn.text,
3653
+ // Stamps which turn wrote this message, so a reader does not have to infer it from
3654
+ // timestamps — an inference a regenerate breaks, since it re-answers a surviving prompt.
3655
+ runId: hooks.runId,
1024
3656
  usage: {
1025
3657
  ...turn.usage,
1026
3658
  costUsd
@@ -1028,8 +3660,11 @@ ${buildContextBlock(passages)}`;
1028
3660
  ...input.agentName !== void 0 ? {
1029
3661
  agentName: input.agentName
1030
3662
  } : {},
1031
- ...toolCallsWithKind.length > 0 ? {
1032
- toolCalls: toolCallsWithKind
3663
+ ...messageCalls.length > 0 ? {
3664
+ toolCalls: messageCalls
3665
+ } : {},
3666
+ ...syntheticResults.length > 0 ? {
3667
+ toolResults: syntheticResults
1033
3668
  } : {},
1034
3669
  ...followUps !== void 0 ? {
1035
3670
  followUps
@@ -1038,33 +3673,43 @@ ${buildContextBlock(passages)}`;
1038
3673
  const assistantMessage = {
1039
3674
  role: "assistant",
1040
3675
  content: turn.text,
1041
- ...toolCallsWithKind.length > 0 ? {
1042
- toolCalls: toolCallsWithKind
3676
+ ...messageCalls.length > 0 ? {
3677
+ toolCalls: messageCalls
3678
+ } : {},
3679
+ ...syntheticResults.length > 0 ? {
3680
+ toolResults: syntheticResults
1043
3681
  } : {}
1044
3682
  };
1045
3683
  modelMessages.push(assistantMessage);
1046
- if (i === 0 && injectedPassages !== void 0) {
1047
- const passages = injectedPassages;
1048
- const toolCallId = `retrieve-${assistant.id}`;
1049
- await hooks.step(`persist:retrieval:${assistant.id}`, async () => {
3684
+ for (const entry of synthetic) {
3685
+ const { call, result } = entry;
3686
+ await hooks.step(`${entry.step}:${assistant.id}`, async () => {
1050
3687
  await deps.store.recordToolCall({
1051
- toolCallId,
3688
+ toolCallId: call.id,
1052
3689
  messageId: assistant.id,
1053
- toolName: "retrieve",
3690
+ toolName: call.name,
1054
3691
  toolType: "read",
1055
- input: {
1056
- query: input.userText
1057
- },
3692
+ input: call.input,
1058
3693
  status: "auto_executed",
1059
3694
  runId: hooks.runId
1060
3695
  });
1061
3696
  await deps.store.updateToolCall({
1062
- toolCallId,
3697
+ toolCallId: call.id,
1063
3698
  status: "executed",
1064
- output: {
1065
- passages
1066
- }
3699
+ output: result.output
1067
3700
  });
3701
+ await writer.write(encodeStreamEvent({
3702
+ kind: "tool-input-available",
3703
+ id: call.id,
3704
+ name: call.name,
3705
+ input: call.input,
3706
+ toolKind: "read"
3707
+ }));
3708
+ await writer.write(encodeStreamEvent({
3709
+ kind: "tool-output",
3710
+ id: call.id,
3711
+ output: result.output
3712
+ }));
1068
3713
  });
1069
3714
  }
1070
3715
  if (isFinalTurn) {
@@ -1077,218 +3722,46 @@ ${buildContextBlock(passages)}`;
1077
3722
  });
1078
3723
  break;
1079
3724
  }
3725
+ await haltIfCancelled(hooks, cancellable, `cancel:tools:${i}`);
1080
3726
  const results = [];
1081
- for (const call of toolCallsWithKind) {
1082
- const spec = deps.registry.spec(call.name);
1083
- const toolType = call.kind ?? "read";
1084
- const ctx = {
1085
- actor: input.actor,
1086
- threadId: input.threadId,
1087
- runId: hooks.runId,
1088
- requestId: hooks.runId,
1089
- ...input.agentName !== void 0 ? {
1090
- agentName: input.agentName
1091
- } : {},
1092
- ...input.pageContext !== void 0 ? {
1093
- pageContext: input.pageContext
1094
- } : {},
1095
- ...deps.host !== void 0 ? {
1096
- host: deps.host
1097
- } : {}
1098
- };
1099
- if (toolType === "agent") {
1100
- const targetAgent = spec?.targetAgent ?? call.name;
1101
- const task = extractTask(call.input);
1102
- await hooks.step(`persist:toolcall:${call.id}`, () => deps.store.recordToolCall({
1103
- toolCallId: call.id,
1104
- messageId: assistant.id,
1105
- toolName: call.name,
1106
- toolType: "read",
1107
- input: call.input,
1108
- status: "auto_executed",
1109
- runId: hooks.runId
1110
- }));
1111
- const overDepth = (input.delegationDepth ?? 0) >= MAX_DELEGATION_DEPTH;
1112
- publishAgentDelegated({
1113
- runId: hooks.runId,
1114
- toAgent: targetAgent,
1115
- ...input.agentName !== void 0 ? {
1116
- fromAgent: input.agentName
1117
- } : {}
1118
- });
1119
- let sub;
1120
- if (overDepth) {
1121
- sub = {
1122
- text: `(delegation depth limit of ${MAX_DELEGATION_DEPTH} reached)`
1123
- };
1124
- } else if (hooks.runAgent) {
1125
- sub = await hooks.runAgent(targetAgent, task);
1126
- } else {
1127
- sub = {
1128
- text: `(no multi-agent support wired; cannot reach "${targetAgent}")`
1129
- };
1130
- }
1131
- await hooks.step(`persist:toolexec:${call.id}`, () => deps.store.updateToolCall({
1132
- toolCallId: call.id,
1133
- status: "executed",
1134
- output: sub
1135
- }));
1136
- results.push({
1137
- id: call.id,
1138
- name: call.name,
1139
- output: sub
1140
- });
1141
- continue;
3727
+ const turnCalls = {
3728
+ deps,
3729
+ input,
3730
+ hooks,
3731
+ messageId: assistant.id,
3732
+ writer,
3733
+ ...skillOffer !== void 0 ? {
3734
+ skills: skillOffer
3735
+ } : {},
3736
+ ...memoryDigest !== void 0 ? {
3737
+ memory: memoryDigest
3738
+ } : {}
3739
+ };
3740
+ const parallel = hooks.parallel;
3741
+ if (parallel !== void 0 && toolCallsWithKind.length > 1 && await (hooks.patched?.(PARALLEL_TOOLS_PATCH) ?? Promise.resolve(true))) {
3742
+ const claimed = [];
3743
+ for (const call of toolCallsWithKind) {
3744
+ claimed.push(await claimToolCall(turnCalls, call));
1142
3745
  }
1143
- let deciderRef = input.actor.id;
1144
- if (toolType === "action") {
1145
- await hooks.step(`persist:toolcall:${call.id}`, () => deps.store.recordToolCall({
1146
- toolCallId: call.id,
1147
- messageId: assistant.id,
1148
- toolName: call.name,
1149
- toolType: "action",
1150
- input: call.input,
1151
- status: "pending_approval",
1152
- runId: hooks.runId
1153
- }));
1154
- const decision = await hooks.awaitApproval(call, ctx);
1155
- deciderRef = decision.executedByRef ?? input.actor.id;
1156
- if (!decision.approved) {
1157
- await hooks.step(`persist:toolreject:${call.id}`, () => deps.store.updateToolCall({
1158
- toolCallId: call.id,
1159
- status: "rejected",
1160
- executedByRef: deciderRef,
1161
- ...decision.reason !== void 0 ? {
1162
- error: decision.reason
1163
- } : {}
1164
- }));
1165
- results.push({
1166
- id: call.id,
1167
- name: call.name,
1168
- output: {
1169
- rejected: true,
1170
- reason: decision.reason ?? "rejected by user"
1171
- },
1172
- error: "rejected"
1173
- });
1174
- publishAgentToolCall({
1175
- runId: hooks.runId,
1176
- toolName: call.name,
1177
- toolType,
1178
- status: "rejected"
1179
- });
1180
- continue;
1181
- }
3746
+ if (claimed.every((entry) => entry.toolType === "read" || entry.toolType === "skill" || entry.toolType === "memory")) {
3747
+ results.push(...await invokeClaimedToolsTogether(turnCalls, parallel, claimed));
1182
3748
  } else {
1183
- await hooks.step(`persist:toolcall:${call.id}`, () => deps.store.recordToolCall({
1184
- toolCallId: call.id,
1185
- messageId: assistant.id,
1186
- toolName: call.name,
1187
- toolType: "read",
1188
- input: call.input,
1189
- status: "auto_executed",
1190
- runId: hooks.runId
1191
- }));
1192
- }
1193
- const startedAt2 = Date.now();
1194
- try {
1195
- let output;
1196
- if (hooks.dispatchTool) {
1197
- const stepCtx = {
1198
- actor: input.actor,
1199
- threadId: input.threadId,
1200
- runId: hooks.runId,
1201
- requestId: hooks.runId,
1202
- ...input.agentName !== void 0 ? {
1203
- agentName: input.agentName
1204
- } : {},
1205
- ...input.pageContext !== void 0 ? {
1206
- pageContext: input.pageContext
1207
- } : {}
1208
- };
1209
- const envelope = {
1210
- toolName: call.name,
1211
- input: call.input,
1212
- ctx: stepCtx,
1213
- ...deps.toolTimeoutMs !== void 0 ? {
1214
- timeoutMs: deps.toolTimeoutMs
1215
- } : {},
1216
- // Numeric-only: the handler applies withToolTimeout AND its own local `classify` — see
1217
- // ToolStepEnvelope.transientRetry.
1218
- transientRetry: resolveToolTransientRetryNumbers(deps.toolTransientRetry)
1219
- };
1220
- output = await hooks.dispatchTool(call, envelope);
1221
- } else {
1222
- const invocation = hooks.step(`tool:${call.id}`, () => traceToolExecution(hooks.runId, {
1223
- toolCallId: call.id,
1224
- toolName: call.name,
1225
- toolType
1226
- }, () => invokeWithTransientRetry(() => deps.registry.invoke(call.name, call.input, ctx, deps.rolesPolicy), deps.toolTransientRetry ?? {}, {
1227
- ...hooks.isControlFlowError !== void 0 ? {
1228
- isControlFlowError: hooks.isControlFlowError
1229
- } : {},
1230
- onRetry: /* @__PURE__ */ __name((attempt, retryError) => {
1231
- publishAgentToolRetry({
1232
- toolName: call.name,
1233
- toolCallId: call.id,
1234
- attempt,
1235
- message: retryError instanceof Error ? retryError.message : String(retryError)
1236
- });
1237
- }, "onRetry")
1238
- })));
1239
- output = deps.toolTimeoutMs !== void 0 ? await withToolTimeout(invocation, deps.toolTimeoutMs, call.name) : await invocation;
1240
- }
1241
- const executionMs = Date.now() - startedAt2;
1242
- await hooks.step(`persist:toolexec:${call.id}`, () => deps.store.updateToolCall({
1243
- toolCallId: call.id,
1244
- status: "executed",
1245
- output,
1246
- executionMs,
1247
- ...toolType === "action" ? {
1248
- executedByRef: deciderRef
1249
- } : {}
1250
- }));
1251
- results.push({
1252
- id: call.id,
1253
- name: call.name,
1254
- output
1255
- });
1256
- publishAgentToolCall({
1257
- runId: hooks.runId,
1258
- toolName: call.name,
1259
- toolType,
1260
- status: "executed",
1261
- durationMs: executionMs
1262
- });
1263
- } catch (error) {
1264
- if (hooks.isControlFlowError?.(error) === true) {
1265
- throw error;
3749
+ for (const entry of claimed) {
3750
+ results.push(await runClaimedToolCall(turnCalls, entry));
1266
3751
  }
1267
- const executionMs = Date.now() - startedAt2;
1268
- const message = error instanceof Error ? error.message : String(error);
1269
- await hooks.step(`persist:toolfail:${call.id}`, () => deps.store.updateToolCall({
1270
- toolCallId: call.id,
1271
- status: "failed",
1272
- error: message,
1273
- executionMs
1274
- }));
1275
- results.push({
1276
- id: call.id,
1277
- name: call.name,
1278
- output: null,
1279
- error: message
1280
- });
1281
- publishAgentToolCall({
1282
- runId: hooks.runId,
1283
- toolName: call.name,
1284
- toolType,
1285
- status: "failed",
1286
- durationMs: executionMs
1287
- });
3752
+ }
3753
+ } else {
3754
+ for (const call of toolCallsWithKind) {
3755
+ results.push(await runClaimedToolCall(turnCalls, await claimToolCall(turnCalls, call)));
1288
3756
  }
1289
3757
  }
1290
- assistantMessage.toolResults = results;
3758
+ const settledResults = [
3759
+ ...results,
3760
+ ...syntheticResults
3761
+ ];
3762
+ assistantMessage.toolResults = settledResults;
1291
3763
  await hooks.step(`stream:tool-outputs:${i}`, async () => {
3764
+ await deps.store.setMessageToolResults(assistant.id, settledResults);
1292
3765
  for (const result of results) {
1293
3766
  await writer.write(encodeStreamEvent(result.error !== void 0 ? {
1294
3767
  kind: "tool-output-error",
@@ -1309,9 +3782,34 @@ ${buildContextBlock(passages)}`;
1309
3782
  }));
1310
3783
  });
1311
3784
  }
1312
- if (thread !== null && (thread.title === "" || thread.title === "New chat")) {
3785
+ if (history.title === "" || history.title === "New chat") {
1313
3786
  await hooks.step("persist:title", () => deps.store.setTitle(input.threadId, deriveTitle(input.userText)));
1314
3787
  }
3788
+ const delivery = input.deliverTo;
3789
+ if (delivery !== void 0) {
3790
+ await hooks.step("deliver:detached", async () => {
3791
+ if (await deps.store.getThread(delivery.threadId) === null) {
3792
+ return;
3793
+ }
3794
+ const agent = input.agentName ?? "default";
3795
+ await deps.store.appendMessage({
3796
+ threadId: delivery.threadId,
3797
+ role: "assistant",
3798
+ content: lastText,
3799
+ agentName: agent,
3800
+ runId: hooks.runId
3801
+ });
3802
+ await deps.store.updateToolCall({
3803
+ toolCallId: delivery.toolCallId,
3804
+ status: "executed",
3805
+ output: detachedDelivered({
3806
+ agent,
3807
+ runId: hooks.runId,
3808
+ text: lastText
3809
+ })
3810
+ });
3811
+ });
3812
+ }
1315
3813
  await hooks.step("persist:run:end", async () => {
1316
3814
  await deps.store.recordRunEnd?.({
1317
3815
  runId: hooks.runId,
@@ -1328,7 +3826,10 @@ ${buildContextBlock(passages)}`;
1328
3826
  outputTokens: totalOutput
1329
3827
  });
1330
3828
  return {
1331
- text: lastText
3829
+ text: lastText,
3830
+ ...structured !== void 0 ? {
3831
+ object: structured
3832
+ } : {}
1332
3833
  };
1333
3834
  }
1334
3835
  __name(runAgentLoop, "runAgentLoop");
@@ -1343,6 +3844,7 @@ __name(runAgentLoop, "runAgentLoop");
1343
3844
  AGENT_DURABLE_RUNNER,
1344
3845
  AGENT_EMBEDDING_PROVIDER,
1345
3846
  AGENT_GOVERNANCE_QUERIES,
3847
+ AGENT_MEMORY,
1346
3848
  AGENT_MODEL,
1347
3849
  AGENT_OPTIONS,
1348
3850
  AGENT_PRICING_STORE,
@@ -1353,53 +3855,131 @@ __name(runAgentLoop, "runAgentLoop");
1353
3855
  AGENT_ROLES_POLICY,
1354
3856
  AGENT_RUNNER,
1355
3857
  AGENT_SINK,
3858
+ AGENT_SKILLS,
3859
+ AGENT_SKILL_SOURCES,
1356
3860
  AGENT_SPAN_EVENTS,
1357
3861
  AGENT_STORE,
1358
3862
  AGENT_TOOL_REGISTRY,
3863
+ ASK_TOOL_DESCRIPTION,
3864
+ ASK_TOOL_NAME,
1359
3865
  AgentRegistry,
1360
3866
  AgentStreamError,
3867
+ DEFAULT_HISTORY_SUMMARY_INSTRUCTION,
3868
+ DEFAULT_INCREMENTAL_LOOKBACK_CHARS,
3869
+ DEFAULT_INTAKE_PREAMBLE,
3870
+ DEFAULT_MAX_FACT_CHARS,
3871
+ DEFAULT_MAX_MEMORIES,
3872
+ DEFAULT_MAX_SKILLS,
3873
+ DEFAULT_STRUCTURED_OUTPUT_INSTRUCTION,
1361
3874
  DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS,
1362
3875
  DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS,
1363
3876
  DefaultRolesPolicy,
3877
+ GLOBAL_SCOPE,
3878
+ MAX_ASK_QUESTIONS,
3879
+ OutputRejectedError,
3880
+ ProcessorFailedError,
1364
3881
  QuotaExceededError,
3882
+ REMEMBER_TOOL_DESCRIPTION,
3883
+ REMEMBER_TOOL_NAME,
3884
+ RunCancelledError,
3885
+ SKILL_TOOL_DESCRIPTION,
3886
+ SKILL_TOOL_NAME,
3887
+ StructuredOutputError,
1365
3888
  THREAD_DETAIL_CONTENT_CHARS,
1366
3889
  ToolDisabledError,
1367
3890
  ToolForbiddenError,
1368
3891
  ToolInputInvalidError,
1369
3892
  ToolNotFoundError,
1370
3893
  ToolRegistry,
3894
+ actorScope,
1371
3895
  agentDiagnosticKey,
3896
+ agentFailureCode,
3897
+ askInputSchema,
3898
+ askToolDefinition,
1372
3899
  bucketByActor,
1373
3900
  bucketByModel,
1374
3901
  bucketByThread,
1375
3902
  bucketUsageTrend,
3903
+ buildMemoryBlock,
3904
+ buildSkillsBlock,
1376
3905
  canActorUseTool,
3906
+ compositeSkillProvider,
3907
+ createFrameBuffer,
3908
+ createIncrementalGate,
1377
3909
  dayBoundsUtc,
3910
+ decodeStreamEvent,
3911
+ defaultScopeResolver,
3912
+ detachedDelivered,
3913
+ detachedStarted,
3914
+ detachedUnsettled,
1378
3915
  encodeStreamEvent,
1379
3916
  estimateCost,
3917
+ estimateMessageTokens,
3918
+ extractJson,
1380
3919
  filterToolsByAllowList,
1381
3920
  filterToolsByCanUse,
1382
3921
  filterToolsByEnabled,
1383
3922
  filterToolsByRole,
3923
+ gateFollowUps,
3924
+ gateTail,
1384
3925
  invokeWithTransientRetry,
3926
+ isControlFlowSignal,
3927
+ isReplayIntegrityError,
1385
3928
  isToolEnabled,
1386
3929
  isTransientToolError,
3930
+ loadSkill,
3931
+ memoryForgetVerdict,
3932
+ memoryWriteVerdict,
3933
+ normalizeDelegation,
3934
+ normalizeElicitationReply,
3935
+ offerMemories,
3936
+ offerSkills,
1387
3937
  publishAgentDelegated,
3938
+ publishAgentMemoryResolved,
3939
+ publishAgentMemoryWritten,
1388
3940
  publishAgentMessage,
1389
3941
  publishAgentQuotaExceeded,
1390
3942
  publishAgentRetrieved,
1391
3943
  publishAgentRunFailed,
1392
3944
  publishAgentRunFinished,
1393
3945
  publishAgentRunStarted,
3946
+ publishAgentSkillsResolved,
1394
3947
  publishAgentToolCall,
1395
3948
  publishAgentToolRetry,
3949
+ releaseGatedFrames,
3950
+ rememberInputSchema,
3951
+ rememberToolDefinition,
3952
+ renderElicitationAnswers,
3953
+ repairInstruction,
3954
+ resolveElicitation,
3955
+ resolveGateLookback,
3956
+ resolveMemoryDigest,
3957
+ resolveOutputGateMode,
3958
+ resolveSkillCatalog,
1396
3959
  resolveToolTransientRetryNumbers,
1397
3960
  rollupThreadUsage,
1398
3961
  runAgentLoop,
3962
+ runInputProcessors,
3963
+ runOutputProcessors,
1399
3964
  seedModelPrices,
3965
+ settleAll,
3966
+ settleElicitation,
3967
+ settleUnsettledDelegation,
3968
+ skillInputSchema,
3969
+ skillToolDefinition,
3970
+ skillWriteVerdict,
3971
+ staticSkillProvider,
3972
+ summarizeWithModel,
3973
+ tenantScope,
1400
3974
  traceLlmTurn,
1401
3975
  traceToolExecution,
1402
3976
  truncateDetailContent,
1403
- withToolTimeout
3977
+ validateStructured,
3978
+ windowHistory,
3979
+ withAskTool,
3980
+ withMemoryTool,
3981
+ withSkillTool,
3982
+ withToolTimeout,
3983
+ writeMemory
1404
3984
  });
1405
3985
  //# sourceMappingURL=index.cjs.map