@dudousxd/nestjs-agent-core 0.12.0 → 0.13.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/README.md +16 -2
- package/dist/index.cjs +3190 -637
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2350 -38
- package/dist/index.d.ts +2350 -38
- package/dist/index.js +3105 -631
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
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
|
-
|
|
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,2753 @@ function filterToolsByAllowList(tools, allowedTools) {
|
|
|
358
485
|
}
|
|
359
486
|
__name(filterToolsByAllowList, "filterToolsByAllowList");
|
|
360
487
|
|
|
361
|
-
// src/
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
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
|
-
|
|
367
|
-
|
|
368
|
-
|
|
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
|
-
|
|
371
|
-
|
|
609
|
+
if (!emitted && text.length > 0) {
|
|
610
|
+
released.push(encodeStreamEvent({
|
|
611
|
+
kind: "text",
|
|
612
|
+
text
|
|
613
|
+
}));
|
|
372
614
|
}
|
|
373
|
-
|
|
374
|
-
|
|
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
|
-
|
|
377
|
-
|
|
378
|
-
|
|
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
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
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
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
671
|
+
return kept;
|
|
672
|
+
}
|
|
673
|
+
__name(gateFollowUps, "gateFollowUps");
|
|
674
|
+
function resolveOutputGateMode(processors) {
|
|
675
|
+
if (processors.length === 0) {
|
|
676
|
+
return "off";
|
|
392
677
|
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
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
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
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
|
-
|
|
405
|
-
|
|
406
|
-
|
|
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
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
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
|
-
|
|
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, "
|
|
784
|
+
__name(this, "StructuredOutputError");
|
|
417
785
|
}
|
|
418
|
-
|
|
786
|
+
/** Why it failed the schema. Empty only when the text was not JSON at all. */
|
|
419
787
|
issues;
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
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
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
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
|
-
|
|
489
|
-
|
|
490
|
-
|
|
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
|
-
|
|
506
|
-
|
|
507
|
-
|
|
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
|
-
|
|
512
|
-
|
|
513
|
-
|
|
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
|
-
|
|
516
|
-
|
|
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(
|
|
521
|
-
|
|
522
|
-
|
|
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(
|
|
525
|
-
function
|
|
526
|
-
|
|
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(
|
|
529
|
-
function
|
|
530
|
-
|
|
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(
|
|
533
|
-
function
|
|
534
|
-
|
|
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(
|
|
537
|
-
function
|
|
538
|
-
|
|
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(
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
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(
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
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
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
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(
|
|
599
|
-
function
|
|
600
|
-
if (
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
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
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
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
|
-
|
|
620
|
-
|
|
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(
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
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
|
-
|
|
646
|
-
|
|
647
|
-
|
|
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
|
-
|
|
650
|
-
|
|
651
|
-
|
|
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(
|
|
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/
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
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(
|
|
665
|
-
function
|
|
666
|
-
|
|
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(
|
|
676
|
-
var
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
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
|
-
|
|
686
|
-
|
|
687
|
-
|
|
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(
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
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
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
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
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
const
|
|
713
|
-
if (
|
|
714
|
-
|
|
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
|
-
|
|
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(
|
|
720
|
-
function
|
|
721
|
-
|
|
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(
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
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
|
|
735
|
-
return
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
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(
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
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
|
-
|
|
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(
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
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 = input.delegationPath ?? [];
|
|
2232
|
+
const appearances = ancestry.filter((name) => name === targetAgent).length;
|
|
2233
|
+
const maxAppearances = deps.maxAgentAppearances ?? DEFAULT_MAX_AGENT_APPEARANCES;
|
|
2234
|
+
if (appearances >= maxAppearances) {
|
|
2235
|
+
const chain = [
|
|
2236
|
+
...ancestry,
|
|
2237
|
+
targetAgent
|
|
2238
|
+
].join(" \u2192 ");
|
|
2239
|
+
const times = appearances + 1;
|
|
2240
|
+
return `(delegation cycle: ${chain} \u2014 ${targetAgent} ${times} times on one chain)`;
|
|
2241
|
+
}
|
|
2242
|
+
const maxDepth = deps.maxDelegationDepth ?? MAX_DELEGATION_DEPTH;
|
|
2243
|
+
if ((input.delegationDepth ?? 0) >= maxDepth) {
|
|
2244
|
+
return `(delegation depth limit of ${maxDepth} reached)`;
|
|
2245
|
+
}
|
|
2246
|
+
return null;
|
|
2247
|
+
}
|
|
2248
|
+
__name(delegationRefusal, "delegationRefusal");
|
|
2249
|
+
async function resolvePrompt(prompt, ctx) {
|
|
2250
|
+
return typeof prompt === "function" ? prompt(ctx) : prompt;
|
|
2251
|
+
}
|
|
2252
|
+
__name(resolvePrompt, "resolvePrompt");
|
|
2253
|
+
async function resolveSystemPrompt(deps, input) {
|
|
2254
|
+
const ctx = {
|
|
2255
|
+
actor: input.actor,
|
|
2256
|
+
agentName: input.agentName ?? "default",
|
|
2257
|
+
...input.pageContext !== void 0 ? {
|
|
2258
|
+
pageContext: input.pageContext
|
|
2259
|
+
} : {}
|
|
2260
|
+
};
|
|
2261
|
+
const sections = [
|
|
2262
|
+
await resolvePrompt(deps.systemPrompt, ctx)
|
|
2263
|
+
];
|
|
2264
|
+
for (const contribute of deps.promptContributors ?? []) {
|
|
2265
|
+
const section = await contribute(ctx);
|
|
2266
|
+
if (section !== null && section.length > 0) {
|
|
2267
|
+
sections.push(section);
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
return sections.join("\n\n");
|
|
2271
|
+
}
|
|
2272
|
+
__name(resolveSystemPrompt, "resolveSystemPrompt");
|
|
2273
|
+
function extractTask(input) {
|
|
2274
|
+
if (typeof input === "object" && input !== null && "task" in input) {
|
|
2275
|
+
const task = input.task;
|
|
2276
|
+
if (typeof task === "string") {
|
|
2277
|
+
return task;
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
return JSON.stringify(input);
|
|
2281
|
+
}
|
|
2282
|
+
__name(extractTask, "extractTask");
|
|
2283
|
+
function deriveTitle(userText) {
|
|
2284
|
+
const trimmed = userText.trim().replace(/\s+/g, " ");
|
|
2285
|
+
return trimmed.length > 60 ? `${trimmed.slice(0, 57)}...` : trimmed || "New chat";
|
|
2286
|
+
}
|
|
2287
|
+
__name(deriveTitle, "deriveTitle");
|
|
2288
|
+
var ToolTimeoutError = class ToolTimeoutError2 extends Error {
|
|
2289
|
+
static {
|
|
2290
|
+
__name(this, "ToolTimeoutError");
|
|
2291
|
+
}
|
|
2292
|
+
constructor(toolName, ms) {
|
|
2293
|
+
super(`Tool "${toolName}" exceeded its ${ms}ms timeout`);
|
|
2294
|
+
this.name = "ToolTimeoutError";
|
|
2295
|
+
}
|
|
2296
|
+
};
|
|
2297
|
+
function withToolTimeout(work, ms, toolName) {
|
|
2298
|
+
return new Promise((resolve, reject) => {
|
|
2299
|
+
const timer = setTimeout(() => reject(new ToolTimeoutError(toolName, ms)), ms);
|
|
2300
|
+
work.then((value) => {
|
|
2301
|
+
clearTimeout(timer);
|
|
2302
|
+
resolve(value);
|
|
2303
|
+
}, (error) => {
|
|
2304
|
+
clearTimeout(timer);
|
|
2305
|
+
reject(error);
|
|
2306
|
+
});
|
|
2307
|
+
});
|
|
2308
|
+
}
|
|
2309
|
+
__name(withToolTimeout, "withToolTimeout");
|
|
2310
|
+
function parseFollowUps(text, count) {
|
|
2311
|
+
const source = text.match(/\[[\s\S]*\]/)?.[0] ?? text;
|
|
2312
|
+
try {
|
|
2313
|
+
const parsed = JSON.parse(source);
|
|
2314
|
+
if (Array.isArray(parsed)) {
|
|
2315
|
+
return parsed.filter((item) => typeof item === "string").slice(0, count);
|
|
2316
|
+
}
|
|
2317
|
+
} catch {
|
|
2318
|
+
}
|
|
2319
|
+
return [];
|
|
2320
|
+
}
|
|
2321
|
+
__name(parseFollowUps, "parseFollowUps");
|
|
2322
|
+
async function generateFollowUps(model, messages, count) {
|
|
2323
|
+
const discard = {
|
|
2324
|
+
write: /* @__PURE__ */ __name(() => {
|
|
2325
|
+
}, "write"),
|
|
2326
|
+
end: /* @__PURE__ */ __name(() => {
|
|
2327
|
+
}, "end"),
|
|
765
2328
|
fail: /* @__PURE__ */ __name(() => {
|
|
766
2329
|
}, "fail")
|
|
767
2330
|
};
|
|
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
|
|
2331
|
+
const turn = await model.runTurn({
|
|
2332
|
+
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.`,
|
|
2333
|
+
messages,
|
|
2334
|
+
tools: [],
|
|
2335
|
+
sink: discard
|
|
2336
|
+
});
|
|
2337
|
+
return {
|
|
2338
|
+
followUps: parseFollowUps(turn.text, count),
|
|
2339
|
+
usage: turn.usage,
|
|
2340
|
+
...turn.modelId !== void 0 ? {
|
|
2341
|
+
modelId: turn.modelId
|
|
2342
|
+
} : {}
|
|
2343
|
+
};
|
|
2344
|
+
}
|
|
2345
|
+
__name(generateFollowUps, "generateFollowUps");
|
|
2346
|
+
async function spanned(event, runId, payload, run, summarize) {
|
|
2347
|
+
let value;
|
|
2348
|
+
await (0, import_nestjs_diagnostics2.trace)("agent", event, async () => {
|
|
2349
|
+
value = await run();
|
|
2350
|
+
return summarize(value);
|
|
2351
|
+
}, payload, {
|
|
2352
|
+
traceId: runId
|
|
2353
|
+
});
|
|
2354
|
+
return value;
|
|
2355
|
+
}
|
|
2356
|
+
__name(spanned, "spanned");
|
|
2357
|
+
function traceLlmTurn(runId, step, run) {
|
|
2358
|
+
return spanned("llm.turn", runId, {
|
|
2359
|
+
runId,
|
|
2360
|
+
step
|
|
2361
|
+
}, run, (turn) => ({
|
|
2362
|
+
...turn.modelId !== void 0 ? {
|
|
2363
|
+
modelId: turn.modelId
|
|
2364
|
+
} : {},
|
|
2365
|
+
inputTokens: turn.usage.inputTokens,
|
|
2366
|
+
outputTokens: turn.usage.outputTokens,
|
|
2367
|
+
textLength: turn.text.length,
|
|
2368
|
+
toolCalls: turn.toolCalls.length
|
|
2369
|
+
}));
|
|
2370
|
+
}
|
|
2371
|
+
__name(traceLlmTurn, "traceLlmTurn");
|
|
2372
|
+
function traceToolExecution(runId, call, run) {
|
|
2373
|
+
return spanned("tool.execution", runId, {
|
|
2374
|
+
runId,
|
|
2375
|
+
...call
|
|
2376
|
+
}, run, () => ({}));
|
|
2377
|
+
}
|
|
2378
|
+
__name(traceToolExecution, "traceToolExecution");
|
|
2379
|
+
function toModelMessages(messages) {
|
|
2380
|
+
return messages.map((message) => ({
|
|
2381
|
+
role: message.role,
|
|
2382
|
+
content: message.content,
|
|
2383
|
+
...message.toolCalls !== void 0 ? {
|
|
2384
|
+
toolCalls: message.toolCalls
|
|
2385
|
+
} : {},
|
|
2386
|
+
...message.toolResults !== void 0 ? {
|
|
2387
|
+
toolResults: message.toolResults
|
|
2388
|
+
} : {},
|
|
2389
|
+
...message.attachments !== void 0 ? {
|
|
2390
|
+
attachments: message.attachments
|
|
2391
|
+
} : {}
|
|
2392
|
+
}));
|
|
2393
|
+
}
|
|
2394
|
+
__name(toModelMessages, "toModelMessages");
|
|
2395
|
+
function historyContext(input) {
|
|
2396
|
+
return {
|
|
2397
|
+
threadId: input.threadId,
|
|
2398
|
+
actor: input.actor,
|
|
2399
|
+
...input.agentName !== void 0 ? {
|
|
2400
|
+
agentName: input.agentName
|
|
2401
|
+
} : {}
|
|
2402
|
+
};
|
|
2403
|
+
}
|
|
2404
|
+
__name(historyContext, "historyContext");
|
|
2405
|
+
function splitHistory(policy, input, messages) {
|
|
2406
|
+
return policy === void 0 ? {
|
|
2407
|
+
keep: messages,
|
|
2408
|
+
drop: []
|
|
2409
|
+
} : policy.select(messages, historyContext(input));
|
|
2410
|
+
}
|
|
2411
|
+
__name(splitHistory, "splitHistory");
|
|
2412
|
+
async function loadSelectedHistory(deps, input, hooks) {
|
|
2413
|
+
return hooks.step("load:thread", async () => {
|
|
2414
|
+
const thread = await readThreadForTurn(deps, input.threadId);
|
|
2415
|
+
const { keep, drop } = splitHistory(deps.historyPolicy, input, toModelMessages(thread.messages));
|
|
2416
|
+
return {
|
|
2417
|
+
messages: keep,
|
|
2418
|
+
dropped: deps.historyPolicy?.summarize === void 0 ? [] : drop,
|
|
2419
|
+
title: thread.title,
|
|
2420
|
+
hasAssistantMessage: thread.hasAssistantMessage
|
|
2421
|
+
};
|
|
2422
|
+
});
|
|
2423
|
+
}
|
|
2424
|
+
__name(loadSelectedHistory, "loadSelectedHistory");
|
|
2425
|
+
async function readThreadForTurn(deps, threadId) {
|
|
2426
|
+
const windowing = deps.store;
|
|
2427
|
+
if (typeof windowing.loadThreadForTurn === "function") {
|
|
2428
|
+
const messageLimit = turnMessageLimit(deps.historyPolicy);
|
|
2429
|
+
const page = await windowing.loadThreadForTurn({
|
|
2430
|
+
threadId,
|
|
2431
|
+
...messageLimit !== void 0 ? {
|
|
2432
|
+
messageLimit
|
|
2433
|
+
} : {}
|
|
2434
|
+
});
|
|
2435
|
+
return page === null ? {
|
|
2436
|
+
messages: [],
|
|
2437
|
+
title: null,
|
|
2438
|
+
hasAssistantMessage: false
|
|
2439
|
+
} : {
|
|
2440
|
+
messages: page.messages,
|
|
2441
|
+
title: page.title,
|
|
2442
|
+
hasAssistantMessage: page.hasAssistantMessage
|
|
2443
|
+
};
|
|
2444
|
+
}
|
|
2445
|
+
const thread = await deps.store.getThread(threadId);
|
|
2446
|
+
const stored = thread?.messages ?? [];
|
|
2447
|
+
return {
|
|
2448
|
+
messages: stored,
|
|
2449
|
+
title: thread?.title ?? null,
|
|
2450
|
+
hasAssistantMessage: stored.some((message) => message.role === "assistant")
|
|
2451
|
+
};
|
|
2452
|
+
}
|
|
2453
|
+
__name(readThreadForTurn, "readThreadForTurn");
|
|
2454
|
+
function turnMessageLimit(policy) {
|
|
2455
|
+
if (policy === void 0 || policy.summarize !== void 0) {
|
|
2456
|
+
return void 0;
|
|
2457
|
+
}
|
|
2458
|
+
return policy.maxMessages;
|
|
2459
|
+
}
|
|
2460
|
+
__name(turnMessageLimit, "turnMessageLimit");
|
|
2461
|
+
async function loadWholeThread(deps, input, hooks) {
|
|
2462
|
+
const thread = await hooks.step("load:thread", () => deps.store.getThread(input.threadId));
|
|
2463
|
+
const stored = thread?.messages ?? [];
|
|
2464
|
+
const { keep, drop } = splitHistory(deps.historyPolicy, input, toModelMessages(stored));
|
|
2465
|
+
return {
|
|
2466
|
+
messages: keep,
|
|
2467
|
+
dropped: drop,
|
|
2468
|
+
title: thread?.title ?? null,
|
|
2469
|
+
hasAssistantMessage: stored.some((message) => message.role === "assistant")
|
|
2470
|
+
};
|
|
2471
|
+
}
|
|
2472
|
+
__name(loadWholeThread, "loadWholeThread");
|
|
2473
|
+
async function foldDroppedHistory(summarize, deps, input, hooks, history) {
|
|
2474
|
+
const summary = await hooks.step("history:summarize", () => summarize(history.dropped, historyContext(input)));
|
|
2475
|
+
if (summary.usage !== void 0) {
|
|
2476
|
+
const usage = summary.usage;
|
|
2477
|
+
await hooks.step("persist:usage:history", () => deps.store.recordUsage({
|
|
2478
|
+
threadId: input.threadId,
|
|
2479
|
+
actorRef: input.actor.id,
|
|
2480
|
+
modelId: summary.modelId ?? deps.modelId ?? "unknown",
|
|
2481
|
+
purpose: "history_summary",
|
|
2482
|
+
usage
|
|
2483
|
+
}));
|
|
2484
|
+
}
|
|
2485
|
+
return [
|
|
2486
|
+
{
|
|
2487
|
+
role: "system",
|
|
2488
|
+
content: buildSummaryBlock(summary.text)
|
|
2489
|
+
},
|
|
2490
|
+
...history.messages
|
|
2491
|
+
];
|
|
2492
|
+
}
|
|
2493
|
+
__name(foldDroppedHistory, "foldDroppedHistory");
|
|
2494
|
+
function processorContext(input, step) {
|
|
2495
|
+
return {
|
|
2496
|
+
threadId: input.threadId,
|
|
2497
|
+
actor: input.actor,
|
|
2498
|
+
step,
|
|
2499
|
+
...input.agentName !== void 0 ? {
|
|
2500
|
+
agentName: input.agentName
|
|
2501
|
+
} : {}
|
|
2502
|
+
};
|
|
2503
|
+
}
|
|
2504
|
+
__name(processorContext, "processorContext");
|
|
2505
|
+
function restatementPrompt(messages, answer, fromTranscript) {
|
|
2506
|
+
const restated = {
|
|
2507
|
+
role: "assistant",
|
|
2508
|
+
content: answer
|
|
2509
|
+
};
|
|
2510
|
+
if (fromTranscript) {
|
|
2511
|
+
return [
|
|
2512
|
+
...messages,
|
|
2513
|
+
restated
|
|
2514
|
+
];
|
|
2515
|
+
}
|
|
2516
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
2517
|
+
const message = messages[index];
|
|
2518
|
+
if (message?.role === "user") {
|
|
2519
|
+
return [
|
|
2520
|
+
message,
|
|
2521
|
+
restated
|
|
2522
|
+
];
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
return [
|
|
2526
|
+
restated
|
|
2527
|
+
];
|
|
2528
|
+
}
|
|
2529
|
+
__name(restatementPrompt, "restatementPrompt");
|
|
2530
|
+
async function structureAnswer(schema, deps, input, hooks, messages, step) {
|
|
2531
|
+
const instruction = deps.outputInstruction ?? DEFAULT_STRUCTURED_OUTPUT_INSTRUCTION;
|
|
2532
|
+
const maxAttempts = 1 + (deps.outputRepairAttempts ?? 1);
|
|
2533
|
+
const outputProcessors = deps.outputProcessors ?? [];
|
|
2534
|
+
let issues = [];
|
|
2535
|
+
let text = "";
|
|
2536
|
+
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
2537
|
+
const system = attempt === 0 ? instruction : repairInstruction(instruction, issues);
|
|
2538
|
+
const reply = await hooks.step(`structured:${step}:${attempt}`, () => spanned("structured-output", hooks.runId, {
|
|
2539
|
+
runId: hooks.runId,
|
|
2540
|
+
step,
|
|
2541
|
+
attempt
|
|
2542
|
+
}, async () => {
|
|
2543
|
+
const discard = {
|
|
2544
|
+
write: /* @__PURE__ */ __name(() => {
|
|
2545
|
+
}, "write"),
|
|
2546
|
+
end: /* @__PURE__ */ __name(() => {
|
|
2547
|
+
}, "end"),
|
|
2548
|
+
fail: /* @__PURE__ */ __name(() => {
|
|
2549
|
+
}, "fail")
|
|
2550
|
+
};
|
|
2551
|
+
const turn = await deps.model.runTurn({
|
|
2552
|
+
system,
|
|
2553
|
+
messages,
|
|
2554
|
+
tools: [],
|
|
2555
|
+
sink: discard,
|
|
2556
|
+
outputSchema: schema
|
|
2557
|
+
});
|
|
2558
|
+
return {
|
|
2559
|
+
text: turn.text,
|
|
2560
|
+
usage: turn.usage,
|
|
2561
|
+
...turn.object !== void 0 ? {
|
|
2562
|
+
object: turn.object
|
|
2563
|
+
} : {},
|
|
2564
|
+
...turn.modelId !== void 0 ? {
|
|
2565
|
+
modelId: turn.modelId
|
|
2566
|
+
} : {}
|
|
2567
|
+
};
|
|
2568
|
+
}, (result) => ({
|
|
2569
|
+
inputTokens: result.usage.inputTokens,
|
|
2570
|
+
outputTokens: result.usage.outputTokens,
|
|
2571
|
+
textLength: result.text.length
|
|
2572
|
+
})));
|
|
2573
|
+
await hooks.step(`persist:usage:structured:${step}:${attempt}`, () => deps.store.recordUsage({
|
|
2574
|
+
threadId: input.threadId,
|
|
2575
|
+
actorRef: input.actor.id,
|
|
2576
|
+
modelId: reply.modelId ?? deps.modelId ?? "unknown",
|
|
2577
|
+
purpose: "structured_output",
|
|
2578
|
+
usage: reply.usage
|
|
2579
|
+
}));
|
|
2580
|
+
text = reply.text;
|
|
2581
|
+
if (outputProcessors.length > 0) {
|
|
2582
|
+
const gate = await hooks.step(`process:output:structured:${step}:${attempt}`, () => runOutputProcessors(outputProcessors, {
|
|
2583
|
+
text: reply.text,
|
|
2584
|
+
toolCalls: []
|
|
2585
|
+
}, processorContext(input, step)));
|
|
2586
|
+
if (gate.rejection !== void 0) {
|
|
2587
|
+
throw new OutputRejectedError(gate.rejection.processor, gate.rejection.reason);
|
|
2588
|
+
}
|
|
2589
|
+
text = gate.text;
|
|
2590
|
+
}
|
|
2591
|
+
const reported = text === reply.text ? reply.object : void 0;
|
|
2592
|
+
const outcome = await validateStructured(schema, text, reported);
|
|
2593
|
+
if (outcome.ok) {
|
|
2594
|
+
return outcome.value;
|
|
2595
|
+
}
|
|
2596
|
+
issues = outcome.issues;
|
|
2597
|
+
}
|
|
2598
|
+
throw new StructuredOutputError(issues, text, maxAttempts);
|
|
2599
|
+
}
|
|
2600
|
+
__name(structureAnswer, "structureAnswer");
|
|
2601
|
+
function declaredKind(deps, name) {
|
|
2602
|
+
if (deps.ask === true && name === ASK_TOOL_NAME) {
|
|
2603
|
+
return "ask";
|
|
2604
|
+
}
|
|
2605
|
+
if (deps.skills !== void 0 && name === SKILL_TOOL_NAME) {
|
|
2606
|
+
return "skill";
|
|
2607
|
+
}
|
|
2608
|
+
if (memoryIsWritable(deps) && name === REMEMBER_TOOL_NAME) {
|
|
2609
|
+
return "memory";
|
|
2610
|
+
}
|
|
2611
|
+
return deps.registry.spec(name)?.kind ?? "read";
|
|
2612
|
+
}
|
|
2613
|
+
__name(declaredKind, "declaredKind");
|
|
2614
|
+
function memoryIsWritable(deps) {
|
|
2615
|
+
return deps.memory?.provider.write !== void 0;
|
|
2616
|
+
}
|
|
2617
|
+
__name(memoryIsWritable, "memoryIsWritable");
|
|
2618
|
+
function withAskTool({ tools, ask }) {
|
|
2619
|
+
return ask === true ? [
|
|
2620
|
+
...tools,
|
|
2621
|
+
askToolDefinition()
|
|
2622
|
+
] : tools;
|
|
2623
|
+
}
|
|
2624
|
+
__name(withAskTool, "withAskTool");
|
|
2625
|
+
async function awaitElicitation(hooks, request, ctx) {
|
|
2626
|
+
if (hooks.awaitAnswers !== void 0) {
|
|
2627
|
+
return normalizeElicitationReply(await hooks.awaitAnswers(request, ctx));
|
|
2628
|
+
}
|
|
2629
|
+
return normalizeElicitationReply(await hooks.awaitApproval({
|
|
2630
|
+
id: request.id,
|
|
2631
|
+
name: ASK_TOOL_NAME,
|
|
2632
|
+
input: request,
|
|
2633
|
+
kind: "ask"
|
|
2634
|
+
}, ctx));
|
|
2635
|
+
}
|
|
2636
|
+
__name(awaitElicitation, "awaitElicitation");
|
|
2637
|
+
function toolContext(deps, input, hooks) {
|
|
2638
|
+
return {
|
|
2639
|
+
actor: input.actor,
|
|
2640
|
+
threadId: input.threadId,
|
|
2641
|
+
runId: hooks.runId,
|
|
2642
|
+
requestId: hooks.runId,
|
|
2643
|
+
...input.agentName !== void 0 ? {
|
|
2644
|
+
agentName: input.agentName
|
|
2645
|
+
} : {},
|
|
2646
|
+
...input.pageContext !== void 0 ? {
|
|
2647
|
+
pageContext: input.pageContext
|
|
2648
|
+
} : {},
|
|
2649
|
+
...deps.host !== void 0 ? {
|
|
2650
|
+
host: deps.host
|
|
2651
|
+
} : {}
|
|
2652
|
+
};
|
|
2653
|
+
}
|
|
2654
|
+
__name(toolContext, "toolContext");
|
|
2655
|
+
function intakeApplies(intake, threadHasAssistant) {
|
|
2656
|
+
return intake.when === "every-turn" || !threadHasAssistant;
|
|
2657
|
+
}
|
|
2658
|
+
__name(intakeApplies, "intakeApplies");
|
|
2659
|
+
async function runIntake(intake, deps, input, hooks, writer, threadHasAssistant) {
|
|
2660
|
+
const preamble = intake.preamble ?? DEFAULT_INTAKE_PREAMBLE;
|
|
2661
|
+
const request = {
|
|
2662
|
+
id: `intake-${hooks.runId}`,
|
|
2663
|
+
source: "intake",
|
|
2664
|
+
preamble,
|
|
2665
|
+
questions: intake.questions
|
|
2666
|
+
};
|
|
2667
|
+
const call = {
|
|
2668
|
+
id: request.id,
|
|
2669
|
+
name: ASK_TOOL_NAME,
|
|
2670
|
+
input: {
|
|
2671
|
+
preamble,
|
|
2672
|
+
questions: intake.questions
|
|
2673
|
+
},
|
|
2674
|
+
kind: "ask"
|
|
2675
|
+
};
|
|
2676
|
+
const asked = await hooks.step("intake:ask", async () => {
|
|
2677
|
+
if (!intakeApplies(intake, threadHasAssistant)) {
|
|
2678
|
+
return null;
|
|
2679
|
+
}
|
|
2680
|
+
const message = await deps.store.appendMessage({
|
|
2681
|
+
threadId: input.threadId,
|
|
2682
|
+
role: "assistant",
|
|
2683
|
+
content: preamble,
|
|
2684
|
+
runId: hooks.runId,
|
|
2685
|
+
toolCalls: [
|
|
2686
|
+
call
|
|
2687
|
+
],
|
|
2688
|
+
...input.agentName !== void 0 ? {
|
|
2689
|
+
agentName: input.agentName
|
|
2690
|
+
} : {}
|
|
2691
|
+
});
|
|
2692
|
+
await deps.store.recordToolCall({
|
|
2693
|
+
toolCallId: request.id,
|
|
2694
|
+
messageId: message.id,
|
|
2695
|
+
toolName: ASK_TOOL_NAME,
|
|
2696
|
+
// The store knows read/action only. An unanswered question is work waiting on a human, which
|
|
2697
|
+
// is what `action` + `pending_approval` already mean — so it surfaces in an approvals inbox
|
|
2698
|
+
// rather than needing one of its own.
|
|
2699
|
+
toolType: "action",
|
|
2700
|
+
input: call.input,
|
|
2701
|
+
status: "pending_approval",
|
|
2702
|
+
runId: hooks.runId
|
|
2703
|
+
});
|
|
2704
|
+
await writer.write(encodeStreamEvent({
|
|
2705
|
+
kind: "elicitation",
|
|
2706
|
+
id: request.id,
|
|
2707
|
+
request
|
|
2708
|
+
}));
|
|
2709
|
+
return {
|
|
2710
|
+
messageId: message.id
|
|
2711
|
+
};
|
|
2712
|
+
});
|
|
2713
|
+
if (asked === null) {
|
|
2714
|
+
return null;
|
|
2715
|
+
}
|
|
2716
|
+
const messageId = asked.messageId;
|
|
2717
|
+
const reply = await awaitElicitation(hooks, request, toolContext(deps, input, hooks));
|
|
2718
|
+
const result = settleElicitation(request, reply);
|
|
2719
|
+
await hooks.step("intake:answers", async () => {
|
|
2720
|
+
await deps.store.updateToolCall({
|
|
2721
|
+
toolCallId: request.id,
|
|
2722
|
+
// A skip is not an answer. Both leave the agent holding the same values, but only one of them
|
|
2723
|
+
// is evidence the user chose them, and a reader auditing what the agent was told has to be
|
|
2724
|
+
// able to tell those apart.
|
|
2725
|
+
status: result.skipped ? "rejected" : "executed",
|
|
2726
|
+
output: result,
|
|
2727
|
+
...result.skipped ? {
|
|
2728
|
+
error: "skipped by the user"
|
|
2729
|
+
} : {},
|
|
2730
|
+
...reply.answeredByRef !== void 0 ? {
|
|
2731
|
+
executedByRef: reply.answeredByRef
|
|
2732
|
+
} : {}
|
|
2733
|
+
});
|
|
2734
|
+
await deps.store.setMessageToolResults(messageId, [
|
|
2735
|
+
{
|
|
2736
|
+
id: request.id,
|
|
2737
|
+
name: ASK_TOOL_NAME,
|
|
2738
|
+
output: result
|
|
2739
|
+
}
|
|
2740
|
+
]);
|
|
2741
|
+
await writer.write(encodeStreamEvent({
|
|
2742
|
+
kind: "tool-output",
|
|
2743
|
+
id: request.id,
|
|
2744
|
+
output: result
|
|
2745
|
+
}));
|
|
2746
|
+
});
|
|
2747
|
+
return {
|
|
2748
|
+
role: "assistant",
|
|
2749
|
+
content: preamble,
|
|
2750
|
+
toolCalls: [
|
|
2751
|
+
call
|
|
2752
|
+
],
|
|
2753
|
+
toolResults: [
|
|
2754
|
+
{
|
|
2755
|
+
id: request.id,
|
|
2756
|
+
name: ASK_TOOL_NAME,
|
|
2757
|
+
output: result
|
|
2758
|
+
}
|
|
2759
|
+
]
|
|
2760
|
+
};
|
|
2761
|
+
}
|
|
2762
|
+
__name(runIntake, "runIntake");
|
|
2763
|
+
var PARALLEL_TOOLS_PATCH = "agent:parallel-tools";
|
|
2764
|
+
var CANCELLATION_PATCH = "agent:cancellation";
|
|
2765
|
+
var SELECTED_HISTORY_PATCH = "agent:selected-history";
|
|
2766
|
+
async function haltIfCancelled(hooks, cancellable, name) {
|
|
2767
|
+
const observe = hooks.cancelled;
|
|
2768
|
+
if (!cancellable || observe === void 0) {
|
|
2769
|
+
return;
|
|
2770
|
+
}
|
|
2771
|
+
if (await hooks.step(name, () => observe())) {
|
|
2772
|
+
throw new RunCancelledError();
|
|
2773
|
+
}
|
|
2774
|
+
}
|
|
2775
|
+
__name(haltIfCancelled, "haltIfCancelled");
|
|
2776
|
+
async function claimToolCall(turn, call) {
|
|
2777
|
+
const { deps, input, hooks, messageId } = turn;
|
|
2778
|
+
const persisted = await hooks.step(`persist:toolcall:${call.id}`, async () => {
|
|
2779
|
+
const spec = deps.registry.spec(call.name);
|
|
2780
|
+
const kind = declaredKind(deps, call.name);
|
|
2781
|
+
const awaitsHuman = kind === "action" || kind === "ask";
|
|
2782
|
+
await deps.store.recordToolCall({
|
|
2783
|
+
toolCallId: call.id,
|
|
2784
|
+
messageId,
|
|
2785
|
+
toolName: call.name,
|
|
2786
|
+
toolType: awaitsHuman ? "action" : "read",
|
|
2787
|
+
input: call.input,
|
|
2788
|
+
status: awaitsHuman ? "pending_approval" : "auto_executed",
|
|
2789
|
+
runId: hooks.runId
|
|
2790
|
+
});
|
|
2791
|
+
return {
|
|
2792
|
+
kind,
|
|
2793
|
+
...spec?.targetAgent !== void 0 ? {
|
|
2794
|
+
targetAgent: spec.targetAgent
|
|
2795
|
+
} : {},
|
|
2796
|
+
// Only an `agent` spec ever carries this, and only when the author declared it — so a
|
|
2797
|
+
// deployment with no detached edge writes the same bytes here it always has.
|
|
2798
|
+
...spec?.detached === true ? {
|
|
2799
|
+
detached: true
|
|
2800
|
+
} : {}
|
|
2801
|
+
};
|
|
2802
|
+
});
|
|
2803
|
+
const toolType = persisted?.kind ?? call.kind ?? "read";
|
|
2804
|
+
return {
|
|
2805
|
+
call,
|
|
2806
|
+
// What the rest of the turn — the dispatched tool envelope, the stream frames — sees as this
|
|
2807
|
+
// call's kind, so it agrees with the branch actually taken instead of with a second lookup.
|
|
2808
|
+
resolvedCall: call.kind === toolType ? call : {
|
|
2809
|
+
...call,
|
|
2810
|
+
kind: toolType
|
|
2811
|
+
},
|
|
2812
|
+
toolType,
|
|
2813
|
+
...persisted?.targetAgent !== void 0 ? {
|
|
2814
|
+
targetAgent: persisted.targetAgent
|
|
2815
|
+
} : {},
|
|
2816
|
+
...persisted?.detached === true ? {
|
|
2817
|
+
detached: true
|
|
2818
|
+
} : {},
|
|
2819
|
+
ctx: toolContext(deps, input, hooks)
|
|
2820
|
+
};
|
|
2821
|
+
}
|
|
2822
|
+
__name(claimToolCall, "claimToolCall");
|
|
2823
|
+
async function loadSkillIntoTurn(turn, claimed, startedAt) {
|
|
2824
|
+
const { deps, input, hooks } = turn;
|
|
2825
|
+
const { call } = claimed;
|
|
2826
|
+
const config = deps.skills;
|
|
2827
|
+
const offer = turn.skills;
|
|
2828
|
+
const outcome = await hooks.step(`tool:${call.id}`, async () => {
|
|
2829
|
+
if (config === void 0 || offer === void 0) {
|
|
2830
|
+
return {
|
|
2831
|
+
ok: false,
|
|
2832
|
+
error: "Skills are not available in this deployment."
|
|
2833
|
+
};
|
|
2834
|
+
}
|
|
2835
|
+
const parsed = await skillInputSchema["~standard"].validate(call.input);
|
|
2836
|
+
if (parsed.issues !== void 0) {
|
|
2837
|
+
return {
|
|
2838
|
+
ok: false,
|
|
2839
|
+
error: `invalid skill input: ${parsed.issues.map((each) => `${(each.path ?? []).join(".") || "(root)"}: ${each.message}`).join("; ")}`
|
|
2840
|
+
};
|
|
2841
|
+
}
|
|
2842
|
+
const loaded = await loadSkill(config, offer, parsed.value.name, skillContext(input));
|
|
2843
|
+
if (!loaded.ok) {
|
|
2844
|
+
return {
|
|
2845
|
+
ok: false,
|
|
2846
|
+
error: loaded.error
|
|
2847
|
+
};
|
|
2848
|
+
}
|
|
2849
|
+
return {
|
|
2850
|
+
ok: true,
|
|
2851
|
+
output: {
|
|
2852
|
+
name: loaded.skill.name,
|
|
2853
|
+
scope: loaded.skill.scope,
|
|
2854
|
+
body: loaded.skill.body,
|
|
2855
|
+
...loaded.shadows !== void 0 ? {
|
|
2856
|
+
shadows: loaded.shadows
|
|
2857
|
+
} : {}
|
|
2858
|
+
}
|
|
2859
|
+
};
|
|
2860
|
+
});
|
|
2861
|
+
return outcome.ok ? {
|
|
2862
|
+
status: "executed",
|
|
2863
|
+
output: outcome.output,
|
|
2864
|
+
executionMs: Date.now() - startedAt
|
|
2865
|
+
} : {
|
|
2866
|
+
status: "failed",
|
|
2867
|
+
error: outcome.error,
|
|
2868
|
+
executionMs: Date.now() - startedAt
|
|
2869
|
+
};
|
|
2870
|
+
}
|
|
2871
|
+
__name(loadSkillIntoTurn, "loadSkillIntoTurn");
|
|
2872
|
+
async function rememberIntoTurn(turn, claimed, startedAt) {
|
|
2873
|
+
const { deps, input, hooks } = turn;
|
|
2874
|
+
const { call } = claimed;
|
|
2875
|
+
const config = deps.memory;
|
|
2876
|
+
const digest = turn.memory;
|
|
2877
|
+
const outcome = await hooks.step(`tool:${call.id}`, async () => {
|
|
2878
|
+
if (config === void 0 || digest === void 0) {
|
|
2879
|
+
return {
|
|
2880
|
+
ok: false,
|
|
2881
|
+
error: "Memory is not available in this deployment."
|
|
2882
|
+
};
|
|
2883
|
+
}
|
|
2884
|
+
const parsed = await rememberInputSchema["~standard"].validate(call.input);
|
|
2885
|
+
if (parsed.issues !== void 0) {
|
|
2886
|
+
return {
|
|
2887
|
+
ok: false,
|
|
2888
|
+
error: `invalid remember input: ${parsed.issues.map((each) => `${(each.path ?? []).join(".") || "(root)"}: ${each.message}`).join("; ")}`
|
|
2889
|
+
};
|
|
2890
|
+
}
|
|
2891
|
+
return await writeMemory({
|
|
2892
|
+
config,
|
|
2893
|
+
digest,
|
|
2894
|
+
call: parsed.value,
|
|
2895
|
+
ctx: skillContext(input),
|
|
2896
|
+
runId: hooks.runId
|
|
2897
|
+
});
|
|
2898
|
+
});
|
|
2899
|
+
if (!outcome.ok) {
|
|
2900
|
+
return {
|
|
2901
|
+
status: "failed",
|
|
2902
|
+
error: outcome.error,
|
|
2903
|
+
executionMs: Date.now() - startedAt
|
|
2904
|
+
};
|
|
2905
|
+
}
|
|
2906
|
+
publishAgentMemoryWritten({
|
|
2907
|
+
runId: hooks.runId,
|
|
2908
|
+
scope: outcome.record.scope,
|
|
2909
|
+
chars: outcome.record.text.length
|
|
2910
|
+
});
|
|
2911
|
+
return {
|
|
2912
|
+
status: "executed",
|
|
2913
|
+
output: outcome.record,
|
|
2914
|
+
executionMs: Date.now() - startedAt
|
|
2915
|
+
};
|
|
2916
|
+
}
|
|
2917
|
+
__name(rememberIntoTurn, "rememberIntoTurn");
|
|
2918
|
+
function skillContext(input) {
|
|
2919
|
+
return {
|
|
2920
|
+
actor: input.actor,
|
|
2921
|
+
threadId: input.threadId,
|
|
2922
|
+
...input.agentName !== void 0 ? {
|
|
2923
|
+
agentName: input.agentName
|
|
2924
|
+
} : {},
|
|
2925
|
+
...input.pageContext !== void 0 ? {
|
|
2926
|
+
pageContext: input.pageContext
|
|
2927
|
+
} : {}
|
|
2928
|
+
};
|
|
2929
|
+
}
|
|
2930
|
+
__name(skillContext, "skillContext");
|
|
2931
|
+
async function invokeClaimedTool(turn, claimed) {
|
|
2932
|
+
const { deps, input, hooks } = turn;
|
|
2933
|
+
const { call, resolvedCall, ctx } = claimed;
|
|
2934
|
+
const toolType = claimed.toolType === "action" ? "action" : "read";
|
|
2935
|
+
const startedAt = Date.now();
|
|
2936
|
+
try {
|
|
2937
|
+
if (claimed.toolType === "skill") {
|
|
2938
|
+
return await loadSkillIntoTurn(turn, claimed, startedAt);
|
|
2939
|
+
}
|
|
2940
|
+
if (claimed.toolType === "memory") {
|
|
2941
|
+
return await rememberIntoTurn(turn, claimed, startedAt);
|
|
2942
|
+
}
|
|
2943
|
+
let output;
|
|
2944
|
+
if (hooks.dispatchTool) {
|
|
2945
|
+
const stepCtx = {
|
|
2946
|
+
actor: input.actor,
|
|
2947
|
+
threadId: input.threadId,
|
|
2948
|
+
runId: hooks.runId,
|
|
2949
|
+
requestId: hooks.runId,
|
|
2950
|
+
...input.agentName !== void 0 ? {
|
|
2951
|
+
agentName: input.agentName
|
|
2952
|
+
} : {},
|
|
2953
|
+
...input.pageContext !== void 0 ? {
|
|
2954
|
+
pageContext: input.pageContext
|
|
2955
|
+
} : {}
|
|
2956
|
+
};
|
|
2957
|
+
const envelope = {
|
|
2958
|
+
toolName: call.name,
|
|
2959
|
+
input: call.input,
|
|
2960
|
+
ctx: stepCtx,
|
|
2961
|
+
...deps.toolTimeoutMs !== void 0 ? {
|
|
2962
|
+
timeoutMs: deps.toolTimeoutMs
|
|
2963
|
+
} : {},
|
|
2964
|
+
// Numeric-only: the handler applies withToolTimeout AND its own local `classify` — see
|
|
2965
|
+
// ToolStepEnvelope.transientRetry.
|
|
2966
|
+
transientRetry: resolveToolTransientRetryNumbers(deps.toolTransientRetry)
|
|
2967
|
+
};
|
|
2968
|
+
output = await hooks.dispatchTool(resolvedCall, envelope);
|
|
2969
|
+
} else {
|
|
2970
|
+
const invocation = hooks.step(`tool:${call.id}`, () => traceToolExecution(hooks.runId, {
|
|
2971
|
+
toolCallId: call.id,
|
|
2972
|
+
toolName: call.name,
|
|
2973
|
+
toolType
|
|
2974
|
+
}, () => invokeWithTransientRetry(() => deps.registry.invoke(call.name, call.input, ctx, deps.rolesPolicy), deps.toolTransientRetry ?? {}, {
|
|
2975
|
+
...hooks.isControlFlowError !== void 0 ? {
|
|
2976
|
+
isControlFlowError: hooks.isControlFlowError
|
|
2977
|
+
} : {},
|
|
2978
|
+
onRetry: /* @__PURE__ */ __name((attempt, retryError) => {
|
|
2979
|
+
publishAgentToolRetry({
|
|
2980
|
+
toolName: call.name,
|
|
2981
|
+
toolCallId: call.id,
|
|
2982
|
+
attempt,
|
|
2983
|
+
message: retryError instanceof Error ? retryError.message : String(retryError)
|
|
2984
|
+
});
|
|
2985
|
+
}, "onRetry")
|
|
2986
|
+
})));
|
|
2987
|
+
output = deps.toolTimeoutMs !== void 0 ? await withToolTimeout(invocation, deps.toolTimeoutMs, call.name) : await invocation;
|
|
2988
|
+
}
|
|
2989
|
+
return {
|
|
2990
|
+
status: "executed",
|
|
2991
|
+
output,
|
|
2992
|
+
executionMs: Date.now() - startedAt
|
|
2993
|
+
};
|
|
2994
|
+
} catch (error) {
|
|
2995
|
+
if (hooks.isControlFlowError?.(error) === true || isControlFlowSignal(error) || isReplayIntegrityError(error)) {
|
|
2996
|
+
throw error;
|
|
2997
|
+
}
|
|
2998
|
+
return {
|
|
2999
|
+
status: "failed",
|
|
3000
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3001
|
+
executionMs: Date.now() - startedAt
|
|
3002
|
+
};
|
|
3003
|
+
}
|
|
3004
|
+
}
|
|
3005
|
+
__name(invokeClaimedTool, "invokeClaimedTool");
|
|
3006
|
+
async function recordToolOutcome(turn, claimed, outcome, deciderRef) {
|
|
3007
|
+
const { deps, hooks } = turn;
|
|
3008
|
+
const { call } = claimed;
|
|
3009
|
+
const toolType = claimed.toolType === "action" ? "action" : "read";
|
|
3010
|
+
if (outcome.status === "failed") {
|
|
3011
|
+
await hooks.step(`persist:toolfail:${call.id}`, () => deps.store.updateToolCall({
|
|
3012
|
+
toolCallId: call.id,
|
|
3013
|
+
status: "failed",
|
|
3014
|
+
error: outcome.error,
|
|
3015
|
+
executionMs: outcome.executionMs
|
|
3016
|
+
}));
|
|
3017
|
+
publishAgentToolCall({
|
|
3018
|
+
runId: hooks.runId,
|
|
3019
|
+
toolName: call.name,
|
|
3020
|
+
toolType,
|
|
3021
|
+
status: "failed",
|
|
3022
|
+
durationMs: outcome.executionMs
|
|
3023
|
+
});
|
|
3024
|
+
return {
|
|
3025
|
+
id: call.id,
|
|
3026
|
+
name: call.name,
|
|
3027
|
+
output: null,
|
|
3028
|
+
error: outcome.error
|
|
3029
|
+
};
|
|
3030
|
+
}
|
|
3031
|
+
await hooks.step(`persist:toolexec:${call.id}`, () => deps.store.updateToolCall({
|
|
3032
|
+
toolCallId: call.id,
|
|
3033
|
+
status: "executed",
|
|
3034
|
+
output: outcome.output,
|
|
3035
|
+
executionMs: outcome.executionMs,
|
|
3036
|
+
...toolType === "action" ? {
|
|
3037
|
+
executedByRef: deciderRef
|
|
3038
|
+
} : {}
|
|
3039
|
+
}));
|
|
3040
|
+
publishAgentToolCall({
|
|
3041
|
+
runId: hooks.runId,
|
|
3042
|
+
toolName: call.name,
|
|
3043
|
+
toolType,
|
|
3044
|
+
status: "executed",
|
|
3045
|
+
durationMs: outcome.executionMs
|
|
3046
|
+
});
|
|
3047
|
+
return {
|
|
3048
|
+
id: call.id,
|
|
3049
|
+
name: call.name,
|
|
3050
|
+
output: outcome.output
|
|
3051
|
+
};
|
|
3052
|
+
}
|
|
3053
|
+
__name(recordToolOutcome, "recordToolOutcome");
|
|
3054
|
+
async function delegateToolCall(turn, claimed) {
|
|
3055
|
+
const { deps, input, hooks } = turn;
|
|
3056
|
+
const { call, targetAgent = call.name } = claimed;
|
|
3057
|
+
const task = extractTask(call.input);
|
|
3058
|
+
const refusal = delegationRefusal({
|
|
3059
|
+
deps,
|
|
3060
|
+
input,
|
|
3061
|
+
targetAgent
|
|
773
3062
|
});
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
3063
|
+
const start = claimed.detached === true && refusal === null ? hooks.startAgent : void 0;
|
|
3064
|
+
publishAgentDelegated({
|
|
3065
|
+
runId: hooks.runId,
|
|
3066
|
+
toAgent: targetAgent,
|
|
3067
|
+
...input.agentName !== void 0 ? {
|
|
3068
|
+
fromAgent: input.agentName
|
|
3069
|
+
} : {},
|
|
3070
|
+
...start !== void 0 ? {
|
|
3071
|
+
detached: true
|
|
779
3072
|
} : {}
|
|
3073
|
+
});
|
|
3074
|
+
let sub;
|
|
3075
|
+
if (refusal !== null) {
|
|
3076
|
+
sub = {
|
|
3077
|
+
text: refusal
|
|
3078
|
+
};
|
|
3079
|
+
} else if (start !== void 0) {
|
|
3080
|
+
const started = await start({
|
|
3081
|
+
agentName: targetAgent,
|
|
3082
|
+
task,
|
|
3083
|
+
toolCallId: call.id
|
|
3084
|
+
});
|
|
3085
|
+
sub = detachedStarted({
|
|
3086
|
+
agent: targetAgent,
|
|
3087
|
+
runId: started.runId
|
|
3088
|
+
});
|
|
3089
|
+
} else if (hooks.runAgent) {
|
|
3090
|
+
sub = await hooks.runAgent(targetAgent, task);
|
|
3091
|
+
} else {
|
|
3092
|
+
sub = {
|
|
3093
|
+
text: `(no multi-agent support wired; cannot reach "${targetAgent}")`
|
|
3094
|
+
};
|
|
3095
|
+
}
|
|
3096
|
+
await hooks.step(`persist:toolexec:${call.id}`, () => deps.store.updateToolCall({
|
|
3097
|
+
toolCallId: call.id,
|
|
3098
|
+
status: "executed",
|
|
3099
|
+
output: sub
|
|
3100
|
+
}));
|
|
3101
|
+
return {
|
|
3102
|
+
id: call.id,
|
|
3103
|
+
name: call.name,
|
|
3104
|
+
output: sub
|
|
780
3105
|
};
|
|
781
3106
|
}
|
|
782
|
-
__name(
|
|
783
|
-
async function
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
3107
|
+
__name(delegateToolCall, "delegateToolCall");
|
|
3108
|
+
async function elicitToolCall(turn, claimed) {
|
|
3109
|
+
const { deps, hooks } = turn;
|
|
3110
|
+
const { call, ctx } = claimed;
|
|
3111
|
+
const parsed = await askInputSchema["~standard"].validate(call.input);
|
|
3112
|
+
if (parsed.issues !== void 0) {
|
|
3113
|
+
const error = `invalid ask input: ${parsed.issues.map((each) => `${(each.path ?? []).join(".") || "(root)"}: ${each.message}`).join("; ")}`;
|
|
3114
|
+
await hooks.step(`persist:toolfail:${call.id}`, () => deps.store.updateToolCall({
|
|
3115
|
+
toolCallId: call.id,
|
|
3116
|
+
status: "failed",
|
|
3117
|
+
error
|
|
3118
|
+
}));
|
|
3119
|
+
return {
|
|
3120
|
+
id: call.id,
|
|
3121
|
+
name: call.name,
|
|
3122
|
+
output: null,
|
|
3123
|
+
error
|
|
3124
|
+
};
|
|
3125
|
+
}
|
|
3126
|
+
const request = {
|
|
3127
|
+
id: call.id,
|
|
3128
|
+
source: "ask",
|
|
3129
|
+
questions: parsed.value.questions,
|
|
3130
|
+
...parsed.value.preamble !== void 0 ? {
|
|
3131
|
+
preamble: parsed.value.preamble
|
|
3132
|
+
} : {}
|
|
3133
|
+
};
|
|
3134
|
+
await hooks.step(`stream:elicitation:${call.id}`, async () => {
|
|
3135
|
+
await turn.writer.write(encodeStreamEvent({
|
|
3136
|
+
kind: "elicitation",
|
|
3137
|
+
id: call.id,
|
|
3138
|
+
request
|
|
3139
|
+
}));
|
|
790
3140
|
});
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
...turn.modelId !== void 0 ? {
|
|
800
|
-
modelId: turn.modelId
|
|
3141
|
+
const reply = await awaitElicitation(hooks, request, ctx);
|
|
3142
|
+
const result = settleElicitation(request, reply);
|
|
3143
|
+
await hooks.step(result.skipped ? `persist:toolreject:${call.id}` : `persist:toolexec:${call.id}`, () => deps.store.updateToolCall({
|
|
3144
|
+
toolCallId: call.id,
|
|
3145
|
+
status: result.skipped ? "rejected" : "executed",
|
|
3146
|
+
output: result,
|
|
3147
|
+
...result.skipped ? {
|
|
3148
|
+
error: "skipped by the user"
|
|
801
3149
|
} : {},
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
toolCalls: turn.toolCalls.length
|
|
3150
|
+
...reply.answeredByRef !== void 0 ? {
|
|
3151
|
+
executedByRef: reply.answeredByRef
|
|
3152
|
+
} : {}
|
|
806
3153
|
}));
|
|
3154
|
+
publishAgentToolCall({
|
|
3155
|
+
runId: hooks.runId,
|
|
3156
|
+
toolName: call.name,
|
|
3157
|
+
toolType: "action",
|
|
3158
|
+
status: result.skipped ? "rejected" : "executed"
|
|
3159
|
+
});
|
|
3160
|
+
return {
|
|
3161
|
+
id: call.id,
|
|
3162
|
+
name: call.name,
|
|
3163
|
+
output: result
|
|
3164
|
+
};
|
|
807
3165
|
}
|
|
808
|
-
__name(
|
|
809
|
-
function
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
3166
|
+
__name(elicitToolCall, "elicitToolCall");
|
|
3167
|
+
async function runClaimedToolCall(turn, claimed) {
|
|
3168
|
+
const { deps, input, hooks } = turn;
|
|
3169
|
+
const { call, toolType, ctx } = claimed;
|
|
3170
|
+
if (toolType === "agent") {
|
|
3171
|
+
return delegateToolCall(turn, claimed);
|
|
3172
|
+
}
|
|
3173
|
+
if (toolType === "ask") {
|
|
3174
|
+
return elicitToolCall(turn, claimed);
|
|
3175
|
+
}
|
|
3176
|
+
let deciderRef = input.actor.id;
|
|
3177
|
+
if (toolType === "action") {
|
|
3178
|
+
const decision = await hooks.awaitApproval(call, ctx);
|
|
3179
|
+
deciderRef = decision.executedByRef ?? input.actor.id;
|
|
3180
|
+
if (!decision.approved) {
|
|
3181
|
+
await hooks.step(`persist:toolreject:${call.id}`, () => deps.store.updateToolCall({
|
|
3182
|
+
toolCallId: call.id,
|
|
3183
|
+
status: "rejected",
|
|
3184
|
+
executedByRef: deciderRef,
|
|
3185
|
+
...decision.reason !== void 0 ? {
|
|
3186
|
+
error: decision.reason
|
|
3187
|
+
} : {}
|
|
3188
|
+
}));
|
|
3189
|
+
publishAgentToolCall({
|
|
3190
|
+
runId: hooks.runId,
|
|
3191
|
+
toolName: call.name,
|
|
3192
|
+
toolType,
|
|
3193
|
+
status: "rejected"
|
|
3194
|
+
});
|
|
3195
|
+
return {
|
|
3196
|
+
id: call.id,
|
|
3197
|
+
name: call.name,
|
|
3198
|
+
output: {
|
|
3199
|
+
rejected: true,
|
|
3200
|
+
reason: decision.reason ?? "rejected by user"
|
|
3201
|
+
},
|
|
3202
|
+
error: "rejected"
|
|
3203
|
+
};
|
|
3204
|
+
}
|
|
3205
|
+
}
|
|
3206
|
+
return recordToolOutcome(turn, claimed, await invokeClaimedTool(turn, claimed), deciderRef);
|
|
814
3207
|
}
|
|
815
|
-
__name(
|
|
3208
|
+
__name(runClaimedToolCall, "runClaimedToolCall");
|
|
3209
|
+
async function invokeClaimedToolsTogether(turn, parallel, claimed) {
|
|
3210
|
+
const settled = await parallel(claimed.map((entry) => () => invokeClaimedTool(turn, entry)));
|
|
3211
|
+
for (const outcome of settled) {
|
|
3212
|
+
if (!outcome.ok) {
|
|
3213
|
+
throw outcome.error;
|
|
3214
|
+
}
|
|
3215
|
+
}
|
|
3216
|
+
const results = [];
|
|
3217
|
+
for (const [index, entry] of claimed.entries()) {
|
|
3218
|
+
const outcome = settled[index];
|
|
3219
|
+
if (outcome?.ok === true) {
|
|
3220
|
+
results.push(await recordToolOutcome(turn, entry, outcome.value, turn.input.actor.id));
|
|
3221
|
+
}
|
|
3222
|
+
}
|
|
3223
|
+
return results;
|
|
3224
|
+
}
|
|
3225
|
+
__name(invokeClaimedToolsTogether, "invokeClaimedToolsTogether");
|
|
816
3226
|
async function runAgentLoop(deps, input, hooks) {
|
|
817
3227
|
const maxSteps = deps.maxSteps ?? 8;
|
|
818
3228
|
let system = await resolveSystemPrompt(deps, input);
|
|
3229
|
+
const inputProcessors = deps.inputProcessors ?? [];
|
|
3230
|
+
const outputProcessors = deps.outputProcessors ?? [];
|
|
3231
|
+
const gateMode = resolveOutputGateMode(outputProcessors);
|
|
3232
|
+
const gated = gateMode !== "off";
|
|
3233
|
+
const gateLookback = resolveGateLookback(outputProcessors);
|
|
3234
|
+
let structured;
|
|
819
3235
|
if (deps.quota !== void 0) {
|
|
820
3236
|
const quota = deps.quota;
|
|
821
3237
|
const state = await hooks.step("quota:check", () => quota.check(input.actor.id, deps.day));
|
|
@@ -849,25 +3265,18 @@ async function runAgentLoop(deps, input, hooks) {
|
|
|
849
3265
|
threadId: input.threadId,
|
|
850
3266
|
role: "user",
|
|
851
3267
|
content: input.userText,
|
|
3268
|
+
runId: hooks.runId,
|
|
852
3269
|
...input.attachments !== void 0 ? {
|
|
853
3270
|
attachments: input.attachments
|
|
854
3271
|
} : {}
|
|
855
3272
|
}));
|
|
856
3273
|
}
|
|
857
|
-
const
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
} : {},
|
|
864
|
-
...message.toolResults !== void 0 ? {
|
|
865
|
-
toolResults: message.toolResults
|
|
866
|
-
} : {},
|
|
867
|
-
...message.attachments !== void 0 ? {
|
|
868
|
-
attachments: message.attachments
|
|
869
|
-
} : {}
|
|
870
|
-
}));
|
|
3274
|
+
const history = await (hooks.patched?.(SELECTED_HISTORY_PATCH) ?? Promise.resolve(true)) ? await loadSelectedHistory(deps, input, hooks) : await loadWholeThread(deps, input, hooks);
|
|
3275
|
+
let modelMessages = history.messages;
|
|
3276
|
+
const summarize = deps.historyPolicy?.summarize?.bind(deps.historyPolicy);
|
|
3277
|
+
if (summarize !== void 0 && history.dropped.length > 0) {
|
|
3278
|
+
modelMessages = await foldDroppedHistory(summarize, deps, input, hooks, history);
|
|
3279
|
+
}
|
|
871
3280
|
const writer = await hooks.openSink();
|
|
872
3281
|
let lastText = "";
|
|
873
3282
|
let steps = 0;
|
|
@@ -891,9 +3300,41 @@ async function runAgentLoop(deps, input, hooks) {
|
|
|
891
3300
|
...input.agentName !== void 0 ? {
|
|
892
3301
|
agentName: input.agentName
|
|
893
3302
|
} : {},
|
|
3303
|
+
...input.parentRunId !== void 0 ? {
|
|
3304
|
+
parentRunId: input.parentRunId
|
|
3305
|
+
} : {},
|
|
894
3306
|
promptHash
|
|
895
3307
|
});
|
|
896
3308
|
});
|
|
3309
|
+
let memoryDigest;
|
|
3310
|
+
if (deps.memory !== void 0) {
|
|
3311
|
+
const config = deps.memory;
|
|
3312
|
+
memoryDigest = await hooks.step("memory:digest", () => offerMemories({
|
|
3313
|
+
config,
|
|
3314
|
+
ctx: skillContext(input),
|
|
3315
|
+
query: input.userText
|
|
3316
|
+
}));
|
|
3317
|
+
const digest = memoryDigest;
|
|
3318
|
+
const block = digest.entries.length > 0 ? buildMemoryBlock({
|
|
3319
|
+
entries: digest.entries,
|
|
3320
|
+
writable: memoryIsWritable(deps),
|
|
3321
|
+
partial: digest.omitted > 0 || digest.recalled === true
|
|
3322
|
+
}) : "";
|
|
3323
|
+
if (block.length > 0) {
|
|
3324
|
+
system = `${system}
|
|
3325
|
+
|
|
3326
|
+
${block}`;
|
|
3327
|
+
}
|
|
3328
|
+
publishAgentMemoryResolved({
|
|
3329
|
+
runId: hooks.runId,
|
|
3330
|
+
scopes: digest.scopes.length,
|
|
3331
|
+
offered: digest.entries.length,
|
|
3332
|
+
omitted: digest.omitted,
|
|
3333
|
+
pinnedOmitted: digest.pinnedOmitted,
|
|
3334
|
+
recalled: digest.recalled === true,
|
|
3335
|
+
promptChars: block.length
|
|
3336
|
+
});
|
|
3337
|
+
}
|
|
897
3338
|
let injectedPassages;
|
|
898
3339
|
if (deps.retriever !== void 0) {
|
|
899
3340
|
const retriever = deps.retriever;
|
|
@@ -919,6 +3360,24 @@ ${buildContextBlock(passages)}`;
|
|
|
919
3360
|
count: passages.length
|
|
920
3361
|
});
|
|
921
3362
|
}
|
|
3363
|
+
let skillOffer;
|
|
3364
|
+
if (deps.skills !== void 0) {
|
|
3365
|
+
const config = deps.skills;
|
|
3366
|
+
skillOffer = await hooks.step("skills:catalog", () => offerSkills(config, skillContext(input)));
|
|
3367
|
+
const block = skillOffer.entries.length > 0 ? buildSkillsBlock(skillOffer.entries) : "";
|
|
3368
|
+
if (block.length > 0) {
|
|
3369
|
+
system = `${system}
|
|
3370
|
+
|
|
3371
|
+
${block}`;
|
|
3372
|
+
}
|
|
3373
|
+
publishAgentSkillsResolved({
|
|
3374
|
+
runId: hooks.runId,
|
|
3375
|
+
scopes: skillOffer.scopes.length,
|
|
3376
|
+
offered: skillOffer.entries.length,
|
|
3377
|
+
omitted: skillOffer.omitted,
|
|
3378
|
+
promptChars: block.length
|
|
3379
|
+
});
|
|
3380
|
+
}
|
|
922
3381
|
let prices = [];
|
|
923
3382
|
if (deps.pricingStore !== void 0) {
|
|
924
3383
|
const pricingStore = deps.pricingStore;
|
|
@@ -928,36 +3387,124 @@ ${buildContextBlock(passages)}`;
|
|
|
928
3387
|
price.modelId,
|
|
929
3388
|
price
|
|
930
3389
|
]));
|
|
3390
|
+
if (deps.intake !== void 0) {
|
|
3391
|
+
const asked = await runIntake(deps.intake, deps, input, hooks, writer, history.hasAssistantMessage);
|
|
3392
|
+
if (asked !== null) {
|
|
3393
|
+
modelMessages.push(asked);
|
|
3394
|
+
}
|
|
3395
|
+
}
|
|
3396
|
+
const cancellable = hooks.cancelled !== void 0 && await (hooks.patched?.(CANCELLATION_PATCH) ?? Promise.resolve(true));
|
|
931
3397
|
for (let i = 0; i < maxSteps; i += 1) {
|
|
3398
|
+
await haltIfCancelled(hooks, cancellable, `cancel:check:${i}`);
|
|
932
3399
|
await hooks.step(`stream:step-start:${i}`, async () => {
|
|
933
3400
|
await writer.write(encodeStreamEvent({
|
|
934
3401
|
kind: "step-start"
|
|
935
3402
|
}));
|
|
936
3403
|
});
|
|
3404
|
+
let prompt = {
|
|
3405
|
+
system,
|
|
3406
|
+
messages: modelMessages
|
|
3407
|
+
};
|
|
3408
|
+
if (inputProcessors.length > 0) {
|
|
3409
|
+
prompt = await hooks.step(`process:input:${i}`, () => runInputProcessors(inputProcessors, prompt, processorContext(input, i)));
|
|
3410
|
+
}
|
|
937
3411
|
let turn;
|
|
938
3412
|
if (hooks.dispatchLlm) {
|
|
939
3413
|
turn = await hooks.dispatchLlm(i, {
|
|
940
3414
|
...input.agentName !== void 0 ? {
|
|
941
3415
|
agentName: input.agentName
|
|
942
3416
|
} : {},
|
|
943
|
-
system,
|
|
944
|
-
messages:
|
|
945
|
-
actor: input.actor
|
|
3417
|
+
system: prompt.system,
|
|
3418
|
+
messages: prompt.messages,
|
|
3419
|
+
actor: input.actor,
|
|
3420
|
+
...gated ? {
|
|
3421
|
+
bufferOutput: true
|
|
3422
|
+
} : {}
|
|
946
3423
|
});
|
|
947
3424
|
} else {
|
|
948
|
-
const tools =
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
3425
|
+
const tools = withMemoryTool({
|
|
3426
|
+
tools: withSkillTool({
|
|
3427
|
+
tools: withAskTool({
|
|
3428
|
+
tools: await deps.registry.definitionsFor(input.actor, deps.rolesPolicy, deps.toolAllowList),
|
|
3429
|
+
ask: deps.ask
|
|
3430
|
+
}),
|
|
3431
|
+
enabled: deps.skills !== void 0
|
|
3432
|
+
}),
|
|
3433
|
+
enabled: memoryIsWritable(deps)
|
|
3434
|
+
});
|
|
3435
|
+
turn = await hooks.step(`llm:${i}`, async () => {
|
|
3436
|
+
const incremental = gateMode === "incremental" ? createIncrementalGate({
|
|
3437
|
+
processors: outputProcessors,
|
|
3438
|
+
ctx: processorContext(input, i),
|
|
3439
|
+
lookbackChars: gateLookback,
|
|
3440
|
+
writer
|
|
3441
|
+
}) : void 0;
|
|
3442
|
+
const buffer = gateMode === "whole" ? createFrameBuffer() : void 0;
|
|
3443
|
+
const result = await traceLlmTurn(hooks.runId, i, () => deps.model.runTurn({
|
|
3444
|
+
system: prompt.system,
|
|
3445
|
+
messages: prompt.messages,
|
|
3446
|
+
tools,
|
|
3447
|
+
sink: incremental?.writer ?? buffer?.writer ?? writer
|
|
3448
|
+
}));
|
|
3449
|
+
if (incremental !== void 0) {
|
|
3450
|
+
await incremental.settled();
|
|
3451
|
+
const refusal = incremental.rejection();
|
|
3452
|
+
return {
|
|
3453
|
+
...result,
|
|
3454
|
+
releasedText: incremental.released(),
|
|
3455
|
+
...refusal !== void 0 ? {
|
|
3456
|
+
gateRejection: refusal
|
|
3457
|
+
} : {}
|
|
3458
|
+
};
|
|
3459
|
+
}
|
|
3460
|
+
return buffer === void 0 ? result : {
|
|
3461
|
+
...result,
|
|
3462
|
+
bufferedFrames: buffer.frames()
|
|
3463
|
+
};
|
|
3464
|
+
});
|
|
3465
|
+
}
|
|
3466
|
+
let rejection;
|
|
3467
|
+
if (gated) {
|
|
3468
|
+
const gate = await hooks.step(`process:output:${i}`, async () => {
|
|
3469
|
+
const released = turn.releasedText;
|
|
3470
|
+
if (turn.gateRejection !== void 0) {
|
|
3471
|
+
return {
|
|
3472
|
+
text: turn.text,
|
|
3473
|
+
rejection: turn.gateRejection
|
|
3474
|
+
};
|
|
3475
|
+
}
|
|
3476
|
+
const settled = await runOutputProcessors(outputProcessors, {
|
|
3477
|
+
text: turn.text,
|
|
3478
|
+
toolCalls: turn.toolCalls
|
|
3479
|
+
}, processorContext(input, i));
|
|
3480
|
+
if (settled.rejection === void 0) {
|
|
3481
|
+
if (released === void 0) {
|
|
3482
|
+
for (const chunk of releaseGatedFrames(turn.bufferedFrames ?? [], settled.text)) {
|
|
3483
|
+
await writer.write(chunk);
|
|
3484
|
+
}
|
|
3485
|
+
} else {
|
|
3486
|
+
const tail = gateTail(outputProcessors, released, settled.text);
|
|
3487
|
+
if (tail.length > 0) {
|
|
3488
|
+
await writer.write(encodeStreamEvent({
|
|
3489
|
+
kind: "text",
|
|
3490
|
+
text: tail
|
|
3491
|
+
}));
|
|
3492
|
+
}
|
|
3493
|
+
}
|
|
3494
|
+
}
|
|
3495
|
+
return settled;
|
|
3496
|
+
});
|
|
3497
|
+
rejection = gate.rejection;
|
|
3498
|
+
turn = {
|
|
3499
|
+
...turn,
|
|
3500
|
+
text: gate.text
|
|
3501
|
+
};
|
|
955
3502
|
}
|
|
956
3503
|
const resolvedModelId = turn.modelId ?? deps.modelId ?? "unknown";
|
|
957
3504
|
const costUsd = resolveCostUsd(turn.usage, turn.costUsd, priceByModel.get(resolvedModelId));
|
|
958
3505
|
const toolCallsWithKind = turn.toolCalls.map((call) => ({
|
|
959
3506
|
...call,
|
|
960
|
-
kind: deps
|
|
3507
|
+
kind: declaredKind(deps, call.name)
|
|
961
3508
|
}));
|
|
962
3509
|
await hooks.step(`persist:usage:${i}`, () => deps.store.recordUsage({
|
|
963
3510
|
threadId: input.threadId,
|
|
@@ -974,6 +3521,9 @@ ${buildContextBlock(passages)}`;
|
|
|
974
3521
|
const quota = deps.quota;
|
|
975
3522
|
await hooks.step(`quota:bump:${i}`, () => quota.bump(input.actor.id, deps.day, turn.usage.inputTokens + turn.usage.outputTokens));
|
|
976
3523
|
}
|
|
3524
|
+
if (rejection !== void 0) {
|
|
3525
|
+
throw new OutputRejectedError(rejection.processor, rejection.reason);
|
|
3526
|
+
}
|
|
977
3527
|
steps += 1;
|
|
978
3528
|
totalInput += turn.usage.inputTokens;
|
|
979
3529
|
totalOutput += turn.usage.outputTokens;
|
|
@@ -985,6 +3535,9 @@ ${buildContextBlock(passages)}`;
|
|
|
985
3535
|
textLength: turn.text.length
|
|
986
3536
|
});
|
|
987
3537
|
const isFinalTurn = turn.toolCalls.length === 0;
|
|
3538
|
+
if (isFinalTurn && deps.outputSchema !== void 0) {
|
|
3539
|
+
structured = await structureAnswer(deps.outputSchema, deps, input, hooks, restatementPrompt(prompt.messages, turn.text, deps.outputFromTranscript === true), i);
|
|
3540
|
+
}
|
|
988
3541
|
let followUps;
|
|
989
3542
|
if (isFinalTurn && deps.followUpsCount !== void 0 && deps.followUpsCount > 0) {
|
|
990
3543
|
const count = deps.followUpsCount;
|
|
@@ -1006,8 +3559,12 @@ ${buildContextBlock(passages)}`;
|
|
|
1006
3559
|
modelId: result.modelId
|
|
1007
3560
|
} : {}
|
|
1008
3561
|
})));
|
|
1009
|
-
|
|
1010
|
-
|
|
3562
|
+
let suggestions = generated.followUps;
|
|
3563
|
+
if (outputProcessors.length > 0) {
|
|
3564
|
+
suggestions = await hooks.step(`process:output:followups:${i}`, () => gateFollowUps(outputProcessors, suggestions, processorContext(input, i)));
|
|
3565
|
+
}
|
|
3566
|
+
if (suggestions.length > 0) {
|
|
3567
|
+
followUps = suggestions;
|
|
1011
3568
|
}
|
|
1012
3569
|
await hooks.step(`persist:usage:followups:${i}`, () => deps.store.recordUsage({
|
|
1013
3570
|
threadId: input.threadId,
|
|
@@ -1017,10 +3574,58 @@ ${buildContextBlock(passages)}`;
|
|
|
1017
3574
|
usage: generated.usage
|
|
1018
3575
|
}));
|
|
1019
3576
|
}
|
|
3577
|
+
const synthetic = [];
|
|
3578
|
+
if (i === 0 && injectedPassages !== void 0) {
|
|
3579
|
+
const call = {
|
|
3580
|
+
id: `retrieve-${hooks.runId}`,
|
|
3581
|
+
name: "retrieve",
|
|
3582
|
+
input: {
|
|
3583
|
+
query: input.userText
|
|
3584
|
+
},
|
|
3585
|
+
kind: "read"
|
|
3586
|
+
};
|
|
3587
|
+
const output = {
|
|
3588
|
+
passages: injectedPassages
|
|
3589
|
+
};
|
|
3590
|
+
synthetic.push({
|
|
3591
|
+
step: "persist:retrieval",
|
|
3592
|
+
call,
|
|
3593
|
+
result: {
|
|
3594
|
+
id: call.id,
|
|
3595
|
+
name: call.name,
|
|
3596
|
+
output
|
|
3597
|
+
}
|
|
3598
|
+
});
|
|
3599
|
+
}
|
|
3600
|
+
if (structured !== void 0) {
|
|
3601
|
+
const call = {
|
|
3602
|
+
id: `structured-${hooks.runId}`,
|
|
3603
|
+
name: "structured_output",
|
|
3604
|
+
input: {},
|
|
3605
|
+
kind: "read"
|
|
3606
|
+
};
|
|
3607
|
+
synthetic.push({
|
|
3608
|
+
step: "persist:structured",
|
|
3609
|
+
call,
|
|
3610
|
+
result: {
|
|
3611
|
+
id: call.id,
|
|
3612
|
+
name: call.name,
|
|
3613
|
+
output: structured
|
|
3614
|
+
}
|
|
3615
|
+
});
|
|
3616
|
+
}
|
|
3617
|
+
const messageCalls = [
|
|
3618
|
+
...toolCallsWithKind,
|
|
3619
|
+
...synthetic.map((entry) => entry.call)
|
|
3620
|
+
];
|
|
3621
|
+
const syntheticResults = synthetic.map((entry) => entry.result);
|
|
1020
3622
|
const assistant = await hooks.step(`persist:assistant:${i}`, () => deps.store.appendMessage({
|
|
1021
3623
|
threadId: input.threadId,
|
|
1022
3624
|
role: "assistant",
|
|
1023
3625
|
content: turn.text,
|
|
3626
|
+
// Stamps which turn wrote this message, so a reader does not have to infer it from
|
|
3627
|
+
// timestamps — an inference a regenerate breaks, since it re-answers a surviving prompt.
|
|
3628
|
+
runId: hooks.runId,
|
|
1024
3629
|
usage: {
|
|
1025
3630
|
...turn.usage,
|
|
1026
3631
|
costUsd
|
|
@@ -1028,8 +3633,11 @@ ${buildContextBlock(passages)}`;
|
|
|
1028
3633
|
...input.agentName !== void 0 ? {
|
|
1029
3634
|
agentName: input.agentName
|
|
1030
3635
|
} : {},
|
|
1031
|
-
...
|
|
1032
|
-
toolCalls:
|
|
3636
|
+
...messageCalls.length > 0 ? {
|
|
3637
|
+
toolCalls: messageCalls
|
|
3638
|
+
} : {},
|
|
3639
|
+
...syntheticResults.length > 0 ? {
|
|
3640
|
+
toolResults: syntheticResults
|
|
1033
3641
|
} : {},
|
|
1034
3642
|
...followUps !== void 0 ? {
|
|
1035
3643
|
followUps
|
|
@@ -1038,33 +3646,43 @@ ${buildContextBlock(passages)}`;
|
|
|
1038
3646
|
const assistantMessage = {
|
|
1039
3647
|
role: "assistant",
|
|
1040
3648
|
content: turn.text,
|
|
1041
|
-
...
|
|
1042
|
-
toolCalls:
|
|
3649
|
+
...messageCalls.length > 0 ? {
|
|
3650
|
+
toolCalls: messageCalls
|
|
3651
|
+
} : {},
|
|
3652
|
+
...syntheticResults.length > 0 ? {
|
|
3653
|
+
toolResults: syntheticResults
|
|
1043
3654
|
} : {}
|
|
1044
3655
|
};
|
|
1045
3656
|
modelMessages.push(assistantMessage);
|
|
1046
|
-
|
|
1047
|
-
const
|
|
1048
|
-
|
|
1049
|
-
await hooks.step(`persist:retrieval:${assistant.id}`, async () => {
|
|
3657
|
+
for (const entry of synthetic) {
|
|
3658
|
+
const { call, result } = entry;
|
|
3659
|
+
await hooks.step(`${entry.step}:${assistant.id}`, async () => {
|
|
1050
3660
|
await deps.store.recordToolCall({
|
|
1051
|
-
toolCallId,
|
|
3661
|
+
toolCallId: call.id,
|
|
1052
3662
|
messageId: assistant.id,
|
|
1053
|
-
toolName:
|
|
3663
|
+
toolName: call.name,
|
|
1054
3664
|
toolType: "read",
|
|
1055
|
-
input:
|
|
1056
|
-
query: input.userText
|
|
1057
|
-
},
|
|
3665
|
+
input: call.input,
|
|
1058
3666
|
status: "auto_executed",
|
|
1059
3667
|
runId: hooks.runId
|
|
1060
3668
|
});
|
|
1061
3669
|
await deps.store.updateToolCall({
|
|
1062
|
-
toolCallId,
|
|
3670
|
+
toolCallId: call.id,
|
|
1063
3671
|
status: "executed",
|
|
1064
|
-
output:
|
|
1065
|
-
passages
|
|
1066
|
-
}
|
|
3672
|
+
output: result.output
|
|
1067
3673
|
});
|
|
3674
|
+
await writer.write(encodeStreamEvent({
|
|
3675
|
+
kind: "tool-input-available",
|
|
3676
|
+
id: call.id,
|
|
3677
|
+
name: call.name,
|
|
3678
|
+
input: call.input,
|
|
3679
|
+
toolKind: "read"
|
|
3680
|
+
}));
|
|
3681
|
+
await writer.write(encodeStreamEvent({
|
|
3682
|
+
kind: "tool-output",
|
|
3683
|
+
id: call.id,
|
|
3684
|
+
output: result.output
|
|
3685
|
+
}));
|
|
1068
3686
|
});
|
|
1069
3687
|
}
|
|
1070
3688
|
if (isFinalTurn) {
|
|
@@ -1077,218 +3695,46 @@ ${buildContextBlock(passages)}`;
|
|
|
1077
3695
|
});
|
|
1078
3696
|
break;
|
|
1079
3697
|
}
|
|
3698
|
+
await haltIfCancelled(hooks, cancellable, `cancel:tools:${i}`);
|
|
1080
3699
|
const results = [];
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
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;
|
|
3700
|
+
const turnCalls = {
|
|
3701
|
+
deps,
|
|
3702
|
+
input,
|
|
3703
|
+
hooks,
|
|
3704
|
+
messageId: assistant.id,
|
|
3705
|
+
writer,
|
|
3706
|
+
...skillOffer !== void 0 ? {
|
|
3707
|
+
skills: skillOffer
|
|
3708
|
+
} : {},
|
|
3709
|
+
...memoryDigest !== void 0 ? {
|
|
3710
|
+
memory: memoryDigest
|
|
3711
|
+
} : {}
|
|
3712
|
+
};
|
|
3713
|
+
const parallel = hooks.parallel;
|
|
3714
|
+
if (parallel !== void 0 && toolCallsWithKind.length > 1 && await (hooks.patched?.(PARALLEL_TOOLS_PATCH) ?? Promise.resolve(true))) {
|
|
3715
|
+
const claimed = [];
|
|
3716
|
+
for (const call of toolCallsWithKind) {
|
|
3717
|
+
claimed.push(await claimToolCall(turnCalls, call));
|
|
1142
3718
|
}
|
|
1143
|
-
|
|
1144
|
-
|
|
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
|
-
}
|
|
3719
|
+
if (claimed.every((entry) => entry.toolType === "read" || entry.toolType === "skill" || entry.toolType === "memory")) {
|
|
3720
|
+
results.push(...await invokeClaimedToolsTogether(turnCalls, parallel, claimed));
|
|
1182
3721
|
} else {
|
|
1183
|
-
|
|
1184
|
-
|
|
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;
|
|
3722
|
+
for (const entry of claimed) {
|
|
3723
|
+
results.push(await runClaimedToolCall(turnCalls, entry));
|
|
1266
3724
|
}
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
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
|
-
});
|
|
3725
|
+
}
|
|
3726
|
+
} else {
|
|
3727
|
+
for (const call of toolCallsWithKind) {
|
|
3728
|
+
results.push(await runClaimedToolCall(turnCalls, await claimToolCall(turnCalls, call)));
|
|
1288
3729
|
}
|
|
1289
3730
|
}
|
|
1290
|
-
|
|
3731
|
+
const settledResults = [
|
|
3732
|
+
...results,
|
|
3733
|
+
...syntheticResults
|
|
3734
|
+
];
|
|
3735
|
+
assistantMessage.toolResults = settledResults;
|
|
1291
3736
|
await hooks.step(`stream:tool-outputs:${i}`, async () => {
|
|
3737
|
+
await deps.store.setMessageToolResults(assistant.id, settledResults);
|
|
1292
3738
|
for (const result of results) {
|
|
1293
3739
|
await writer.write(encodeStreamEvent(result.error !== void 0 ? {
|
|
1294
3740
|
kind: "tool-output-error",
|
|
@@ -1309,9 +3755,34 @@ ${buildContextBlock(passages)}`;
|
|
|
1309
3755
|
}));
|
|
1310
3756
|
});
|
|
1311
3757
|
}
|
|
1312
|
-
if (
|
|
3758
|
+
if (history.title === "" || history.title === "New chat") {
|
|
1313
3759
|
await hooks.step("persist:title", () => deps.store.setTitle(input.threadId, deriveTitle(input.userText)));
|
|
1314
3760
|
}
|
|
3761
|
+
const delivery = input.deliverTo;
|
|
3762
|
+
if (delivery !== void 0) {
|
|
3763
|
+
await hooks.step("deliver:detached", async () => {
|
|
3764
|
+
if (await deps.store.getThread(delivery.threadId) === null) {
|
|
3765
|
+
return;
|
|
3766
|
+
}
|
|
3767
|
+
const agent = input.agentName ?? "default";
|
|
3768
|
+
await deps.store.appendMessage({
|
|
3769
|
+
threadId: delivery.threadId,
|
|
3770
|
+
role: "assistant",
|
|
3771
|
+
content: lastText,
|
|
3772
|
+
agentName: agent,
|
|
3773
|
+
runId: hooks.runId
|
|
3774
|
+
});
|
|
3775
|
+
await deps.store.updateToolCall({
|
|
3776
|
+
toolCallId: delivery.toolCallId,
|
|
3777
|
+
status: "executed",
|
|
3778
|
+
output: detachedDelivered({
|
|
3779
|
+
agent,
|
|
3780
|
+
runId: hooks.runId,
|
|
3781
|
+
text: lastText
|
|
3782
|
+
})
|
|
3783
|
+
});
|
|
3784
|
+
});
|
|
3785
|
+
}
|
|
1315
3786
|
await hooks.step("persist:run:end", async () => {
|
|
1316
3787
|
await deps.store.recordRunEnd?.({
|
|
1317
3788
|
runId: hooks.runId,
|
|
@@ -1328,7 +3799,10 @@ ${buildContextBlock(passages)}`;
|
|
|
1328
3799
|
outputTokens: totalOutput
|
|
1329
3800
|
});
|
|
1330
3801
|
return {
|
|
1331
|
-
text: lastText
|
|
3802
|
+
text: lastText,
|
|
3803
|
+
...structured !== void 0 ? {
|
|
3804
|
+
object: structured
|
|
3805
|
+
} : {}
|
|
1332
3806
|
};
|
|
1333
3807
|
}
|
|
1334
3808
|
__name(runAgentLoop, "runAgentLoop");
|
|
@@ -1343,6 +3817,7 @@ __name(runAgentLoop, "runAgentLoop");
|
|
|
1343
3817
|
AGENT_DURABLE_RUNNER,
|
|
1344
3818
|
AGENT_EMBEDDING_PROVIDER,
|
|
1345
3819
|
AGENT_GOVERNANCE_QUERIES,
|
|
3820
|
+
AGENT_MEMORY,
|
|
1346
3821
|
AGENT_MODEL,
|
|
1347
3822
|
AGENT_OPTIONS,
|
|
1348
3823
|
AGENT_PRICING_STORE,
|
|
@@ -1353,53 +3828,131 @@ __name(runAgentLoop, "runAgentLoop");
|
|
|
1353
3828
|
AGENT_ROLES_POLICY,
|
|
1354
3829
|
AGENT_RUNNER,
|
|
1355
3830
|
AGENT_SINK,
|
|
3831
|
+
AGENT_SKILLS,
|
|
3832
|
+
AGENT_SKILL_SOURCES,
|
|
1356
3833
|
AGENT_SPAN_EVENTS,
|
|
1357
3834
|
AGENT_STORE,
|
|
1358
3835
|
AGENT_TOOL_REGISTRY,
|
|
3836
|
+
ASK_TOOL_DESCRIPTION,
|
|
3837
|
+
ASK_TOOL_NAME,
|
|
1359
3838
|
AgentRegistry,
|
|
1360
3839
|
AgentStreamError,
|
|
3840
|
+
DEFAULT_HISTORY_SUMMARY_INSTRUCTION,
|
|
3841
|
+
DEFAULT_INCREMENTAL_LOOKBACK_CHARS,
|
|
3842
|
+
DEFAULT_INTAKE_PREAMBLE,
|
|
3843
|
+
DEFAULT_MAX_FACT_CHARS,
|
|
3844
|
+
DEFAULT_MAX_MEMORIES,
|
|
3845
|
+
DEFAULT_MAX_SKILLS,
|
|
3846
|
+
DEFAULT_STRUCTURED_OUTPUT_INSTRUCTION,
|
|
1361
3847
|
DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS,
|
|
1362
3848
|
DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS,
|
|
1363
3849
|
DefaultRolesPolicy,
|
|
3850
|
+
GLOBAL_SCOPE,
|
|
3851
|
+
MAX_ASK_QUESTIONS,
|
|
3852
|
+
OutputRejectedError,
|
|
3853
|
+
ProcessorFailedError,
|
|
1364
3854
|
QuotaExceededError,
|
|
3855
|
+
REMEMBER_TOOL_DESCRIPTION,
|
|
3856
|
+
REMEMBER_TOOL_NAME,
|
|
3857
|
+
RunCancelledError,
|
|
3858
|
+
SKILL_TOOL_DESCRIPTION,
|
|
3859
|
+
SKILL_TOOL_NAME,
|
|
3860
|
+
StructuredOutputError,
|
|
1365
3861
|
THREAD_DETAIL_CONTENT_CHARS,
|
|
1366
3862
|
ToolDisabledError,
|
|
1367
3863
|
ToolForbiddenError,
|
|
1368
3864
|
ToolInputInvalidError,
|
|
1369
3865
|
ToolNotFoundError,
|
|
1370
3866
|
ToolRegistry,
|
|
3867
|
+
actorScope,
|
|
1371
3868
|
agentDiagnosticKey,
|
|
3869
|
+
agentFailureCode,
|
|
3870
|
+
askInputSchema,
|
|
3871
|
+
askToolDefinition,
|
|
1372
3872
|
bucketByActor,
|
|
1373
3873
|
bucketByModel,
|
|
1374
3874
|
bucketByThread,
|
|
1375
3875
|
bucketUsageTrend,
|
|
3876
|
+
buildMemoryBlock,
|
|
3877
|
+
buildSkillsBlock,
|
|
1376
3878
|
canActorUseTool,
|
|
3879
|
+
compositeSkillProvider,
|
|
3880
|
+
createFrameBuffer,
|
|
3881
|
+
createIncrementalGate,
|
|
1377
3882
|
dayBoundsUtc,
|
|
3883
|
+
decodeStreamEvent,
|
|
3884
|
+
defaultScopeResolver,
|
|
3885
|
+
detachedDelivered,
|
|
3886
|
+
detachedStarted,
|
|
3887
|
+
detachedUnsettled,
|
|
1378
3888
|
encodeStreamEvent,
|
|
1379
3889
|
estimateCost,
|
|
3890
|
+
estimateMessageTokens,
|
|
3891
|
+
extractJson,
|
|
1380
3892
|
filterToolsByAllowList,
|
|
1381
3893
|
filterToolsByCanUse,
|
|
1382
3894
|
filterToolsByEnabled,
|
|
1383
3895
|
filterToolsByRole,
|
|
3896
|
+
gateFollowUps,
|
|
3897
|
+
gateTail,
|
|
1384
3898
|
invokeWithTransientRetry,
|
|
3899
|
+
isControlFlowSignal,
|
|
3900
|
+
isReplayIntegrityError,
|
|
1385
3901
|
isToolEnabled,
|
|
1386
3902
|
isTransientToolError,
|
|
3903
|
+
loadSkill,
|
|
3904
|
+
memoryForgetVerdict,
|
|
3905
|
+
memoryWriteVerdict,
|
|
3906
|
+
normalizeDelegation,
|
|
3907
|
+
normalizeElicitationReply,
|
|
3908
|
+
offerMemories,
|
|
3909
|
+
offerSkills,
|
|
1387
3910
|
publishAgentDelegated,
|
|
3911
|
+
publishAgentMemoryResolved,
|
|
3912
|
+
publishAgentMemoryWritten,
|
|
1388
3913
|
publishAgentMessage,
|
|
1389
3914
|
publishAgentQuotaExceeded,
|
|
1390
3915
|
publishAgentRetrieved,
|
|
1391
3916
|
publishAgentRunFailed,
|
|
1392
3917
|
publishAgentRunFinished,
|
|
1393
3918
|
publishAgentRunStarted,
|
|
3919
|
+
publishAgentSkillsResolved,
|
|
1394
3920
|
publishAgentToolCall,
|
|
1395
3921
|
publishAgentToolRetry,
|
|
3922
|
+
releaseGatedFrames,
|
|
3923
|
+
rememberInputSchema,
|
|
3924
|
+
rememberToolDefinition,
|
|
3925
|
+
renderElicitationAnswers,
|
|
3926
|
+
repairInstruction,
|
|
3927
|
+
resolveElicitation,
|
|
3928
|
+
resolveGateLookback,
|
|
3929
|
+
resolveMemoryDigest,
|
|
3930
|
+
resolveOutputGateMode,
|
|
3931
|
+
resolveSkillCatalog,
|
|
1396
3932
|
resolveToolTransientRetryNumbers,
|
|
1397
3933
|
rollupThreadUsage,
|
|
1398
3934
|
runAgentLoop,
|
|
3935
|
+
runInputProcessors,
|
|
3936
|
+
runOutputProcessors,
|
|
1399
3937
|
seedModelPrices,
|
|
3938
|
+
settleAll,
|
|
3939
|
+
settleElicitation,
|
|
3940
|
+
settleUnsettledDelegation,
|
|
3941
|
+
skillInputSchema,
|
|
3942
|
+
skillToolDefinition,
|
|
3943
|
+
skillWriteVerdict,
|
|
3944
|
+
staticSkillProvider,
|
|
3945
|
+
summarizeWithModel,
|
|
3946
|
+
tenantScope,
|
|
1400
3947
|
traceLlmTurn,
|
|
1401
3948
|
traceToolExecution,
|
|
1402
3949
|
truncateDetailContent,
|
|
1403
|
-
|
|
3950
|
+
validateStructured,
|
|
3951
|
+
windowHistory,
|
|
3952
|
+
withAskTool,
|
|
3953
|
+
withMemoryTool,
|
|
3954
|
+
withSkillTool,
|
|
3955
|
+
withToolTimeout,
|
|
3956
|
+
writeMemory
|
|
1404
3957
|
});
|
|
1405
3958
|
//# sourceMappingURL=index.cjs.map
|