@dudousxd/nestjs-agent 1.39.1 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -7
- package/dist/a2ui/index.cjs +1 -0
- package/dist/a2ui/index.cjs.map +1 -1
- package/dist/a2ui/index.d.cts +3 -2
- package/dist/a2ui/index.d.ts +3 -2
- package/dist/a2ui/index.js +2 -1
- package/dist/a2ui/index.js.map +1 -1
- package/dist/{chat-queue.service-YjiKVTKE.d.ts → chat-queue.service-BjPCw4Pf.d.ts} +104 -43
- package/dist/{chat-queue.service-fopUN313.d.cts → chat-queue.service-C49HIuEV.d.cts} +104 -43
- package/dist/durable/index.cjs +13572 -1754
- package/dist/durable/index.cjs.map +1 -1
- package/dist/durable/index.d.cts +6 -6
- package/dist/durable/index.d.ts +6 -6
- package/dist/durable/index.js +12228 -390
- package/dist/durable/index.js.map +1 -1
- package/dist/genui/index.cjs.map +1 -1
- package/dist/genui/index.d.cts +4 -6
- package/dist/genui/index.d.ts +4 -6
- package/dist/genui/index.js.map +1 -1
- package/dist/{index-BJFM1tG8.d.cts → index-BBkyvNUi.d.cts} +1 -1
- package/dist/{index-De98CGXa.d.ts → index-CRCbsO6E.d.ts} +1 -1
- package/dist/index.cjs +12408 -450
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +318 -18
- package/dist/index.d.ts +318 -18
- package/dist/index.js +12313 -346
- package/dist/index.js.map +1 -1
- package/dist/media/index.cjs +4 -9
- package/dist/media/index.cjs.map +1 -1
- package/dist/media/index.d.cts +14 -3
- package/dist/media/index.d.ts +14 -3
- package/dist/media/index.js +6 -11
- package/dist/media/index.js.map +1 -1
- package/dist/workflows/index.cjs +1496 -0
- package/dist/workflows/index.cjs.map +1 -0
- package/dist/workflows/index.d.cts +158 -0
- package/dist/workflows/index.d.ts +158 -0
- package/dist/workflows/index.js +1464 -0
- package/dist/workflows/index.js.map +1 -0
- package/package.json +39 -8
|
@@ -0,0 +1,1464 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
|
|
4
|
+
// src/workflows/agent-workflows.module.ts
|
|
5
|
+
import { AGENT_WORKFLOWS_RUNNER } from "@dudousxd/nestjs-agent-core";
|
|
6
|
+
import { Global, Module } from "@nestjs/common";
|
|
7
|
+
|
|
8
|
+
// src/workflows/agent-run.flow.ts
|
|
9
|
+
import { Workflow } from "@nestjs/workflows";
|
|
10
|
+
|
|
11
|
+
// src/workflows/agent-turn.executor.ts
|
|
12
|
+
import { AGENT_DEPS_FACTORY, AGENT_OPTIONS, AGENT_STORE, RUN_ENDED_BEFORE_TOOL_CALL, RunCancelledError as RunCancelledError2, agentFailureCode, agentRunContext, encodeStreamEvent as encodeStreamEvent2, isReplayIntegrityError as isReplayIntegrityError2, publishAgentRunFailed, releaseThreadRun, runAgentLoop, runDurationMs, runEndTimings, settleAll, settleDeadRun, settleUnsettledDelegation, streamFailure } from "@dudousxd/nestjs-agent-core";
|
|
13
|
+
import { Inject, Injectable, Logger, Optional } from "@nestjs/common";
|
|
14
|
+
import { ChildWorkflowFailedError, NonRetryableStepError, StepFailedError, WORKFLOWS_MODULE_OPTIONS, WorkflowClient } from "@nestjs/workflows";
|
|
15
|
+
|
|
16
|
+
// src/agent-deps.ts
|
|
17
|
+
function utcDay(date = /* @__PURE__ */ new Date()) {
|
|
18
|
+
return date.toISOString().slice(0, 10);
|
|
19
|
+
}
|
|
20
|
+
__name(utcDay, "utcDay");
|
|
21
|
+
function childSinkWriter(writer) {
|
|
22
|
+
return {
|
|
23
|
+
write: /* @__PURE__ */ __name((chunk) => writer.write(chunk), "write"),
|
|
24
|
+
// The top-level run owns end/fail — but what the child wrote must not be held back past it.
|
|
25
|
+
end: /* @__PURE__ */ __name(async () => {
|
|
26
|
+
await writer.flush?.();
|
|
27
|
+
}, "end"),
|
|
28
|
+
fail: /* @__PURE__ */ __name(async () => {
|
|
29
|
+
await writer.flush?.();
|
|
30
|
+
}, "fail"),
|
|
31
|
+
flush: /* @__PURE__ */ __name(async () => {
|
|
32
|
+
await writer.flush?.();
|
|
33
|
+
}, "flush")
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
__name(childSinkWriter, "childSinkWriter");
|
|
37
|
+
|
|
38
|
+
// src/agent.options.ts
|
|
39
|
+
function durableEngineOf(durable) {
|
|
40
|
+
if (durable === void 0 || durable === false) return void 0;
|
|
41
|
+
if (durable === true) return "workflows";
|
|
42
|
+
return durable.engine ?? "workflows";
|
|
43
|
+
}
|
|
44
|
+
__name(durableEngineOf, "durableEngineOf");
|
|
45
|
+
|
|
46
|
+
// src/queue/chat-queue.token.ts
|
|
47
|
+
var AGENT_CHAT_QUEUE = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent:chat-queue");
|
|
48
|
+
|
|
49
|
+
// src/runner/agent-step-bodies.ts
|
|
50
|
+
import { createNegotiatedUiCollector } from "@dudousxd/nestjs-agent-core";
|
|
51
|
+
import { prepareActionProposal, resolveActionProposalApproval } from "@dudousxd/nestjs-agent-core";
|
|
52
|
+
import { announcedToolCalls, createFrameBuffer, createNoopEmitUi, encodeStreamEvent, intersectAllowLists, invokeWithTransientRetry, isControlFlowSignal, isReplayIntegrityError, observeFirstText, observeTurnFrames, previewToolInputs, publishAgentToolRetry, registryInputPreviews, stampToolKinds, toolCallContext, traceLlmTurn, traceToolExecution, withAskTool, withChannelDelivery, withMemoryTool, withSkillTool, withToolTimeout, withTurnFrames, wrapToolPreflightDenied, wrapToolStepOutput } from "@dudousxd/nestjs-agent-core";
|
|
53
|
+
import { turnChannel } from "@dudousxd/nestjs-agent-core/genui";
|
|
54
|
+
async function runLlmStep(factory, input, options = {}) {
|
|
55
|
+
const deps = factory.forAgent(input.agentName);
|
|
56
|
+
const tools = withMemoryTool({
|
|
57
|
+
tools: withSkillTool({
|
|
58
|
+
tools: withAskTool({
|
|
59
|
+
tools: await deps.registry.definitionsFor(
|
|
60
|
+
input.actor,
|
|
61
|
+
deps.rolesPolicy,
|
|
62
|
+
// The persona narrowing the loop journaled in `persona:resolve` rides the envelope:
|
|
63
|
+
// this worker's own persona config may already say something else.
|
|
64
|
+
intersectAllowLists(deps.toolAllowList, input.personaAllowedTools),
|
|
65
|
+
{
|
|
66
|
+
...input.threadId !== void 0 ? {
|
|
67
|
+
threadId: input.threadId
|
|
68
|
+
} : {},
|
|
69
|
+
...input.preflightContext?.uiCapabilities !== void 0 ? {
|
|
70
|
+
uiCapabilities: input.preflightContext.uiCapabilities
|
|
71
|
+
} : {},
|
|
72
|
+
channel: turnChannel(input.preflightContext?.pageContext),
|
|
73
|
+
...input.agentName !== void 0 ? {
|
|
74
|
+
agentName: input.agentName
|
|
75
|
+
} : {}
|
|
76
|
+
}
|
|
77
|
+
),
|
|
78
|
+
ask: deps.ask
|
|
79
|
+
}),
|
|
80
|
+
enabled: deps.skills !== void 0 && input.builtins?.skills !== false
|
|
81
|
+
}),
|
|
82
|
+
enabled: deps.memory?.provider.write !== void 0 && input.builtins?.memory !== false
|
|
83
|
+
});
|
|
84
|
+
const buffer = input.bufferOutput === true ? createFrameBuffer() : void 0;
|
|
85
|
+
let writer;
|
|
86
|
+
let firstText;
|
|
87
|
+
if (buffer !== void 0) {
|
|
88
|
+
writer = buffer.writer;
|
|
89
|
+
} else {
|
|
90
|
+
const opened = await deps.sink.open(input.sinkRunId);
|
|
91
|
+
firstText = observeFirstText(input.childSink ? childSinkWriter(opened) : opened);
|
|
92
|
+
writer = firstText.writer;
|
|
93
|
+
}
|
|
94
|
+
const announced = announcedToolCalls(writer);
|
|
95
|
+
const previews = previewToolInputs(announced.writer, registryInputPreviews(deps.registry, tools, {
|
|
96
|
+
actor: input.actor,
|
|
97
|
+
...input.threadId !== void 0 ? {
|
|
98
|
+
threadId: input.threadId
|
|
99
|
+
} : {},
|
|
100
|
+
...input.agentName !== void 0 ? {
|
|
101
|
+
agentName: input.agentName
|
|
102
|
+
} : {},
|
|
103
|
+
...input.preflightContext?.uiCapabilities !== void 0 ? {
|
|
104
|
+
uiCapabilities: input.preflightContext.uiCapabilities
|
|
105
|
+
} : {},
|
|
106
|
+
channel: turnChannel(input.preflightContext?.pageContext)
|
|
107
|
+
}));
|
|
108
|
+
const frames = observeTurnFrames(previews.writer);
|
|
109
|
+
const turn = withTurnFrames(await traceLlmTurn(input.runId, input.step, () => deps.model.runTurn({
|
|
110
|
+
system: input.system,
|
|
111
|
+
messages: input.messages,
|
|
112
|
+
tools,
|
|
113
|
+
sink: frames.writer,
|
|
114
|
+
...input.model !== void 0 ? {
|
|
115
|
+
model: input.model
|
|
116
|
+
} : {},
|
|
117
|
+
...options.abortSignal !== void 0 ? {
|
|
118
|
+
abortSignal: options.abortSignal
|
|
119
|
+
} : {}
|
|
120
|
+
})), frames.summary());
|
|
121
|
+
const stamped = stampToolKinds(turn, deps);
|
|
122
|
+
await announced.announceRest(stamped.toolCalls, tools);
|
|
123
|
+
const allowedTools = intersectAllowLists(deps.toolAllowList, input.personaAllowedTools);
|
|
124
|
+
for (const call of stamped.toolCalls) {
|
|
125
|
+
if (call.kind !== "action") continue;
|
|
126
|
+
try {
|
|
127
|
+
const context = input.preflightContext ?? {
|
|
128
|
+
actor: input.actor,
|
|
129
|
+
threadId: input.threadId ?? "",
|
|
130
|
+
runId: input.runId,
|
|
131
|
+
requestId: input.runId,
|
|
132
|
+
...input.agentName !== void 0 ? {
|
|
133
|
+
agentName: input.agentName
|
|
134
|
+
} : {}
|
|
135
|
+
};
|
|
136
|
+
if (input.actionApprovalMode === "independent") {
|
|
137
|
+
const spec = deps.registry.spec(call.name);
|
|
138
|
+
call.actionApproval = await resolveActionProposalApproval({
|
|
139
|
+
actor: input.actor,
|
|
140
|
+
store: deps.store,
|
|
141
|
+
tool: {
|
|
142
|
+
name: call.name,
|
|
143
|
+
kind: "action",
|
|
144
|
+
...spec !== void 0 ? {
|
|
145
|
+
spec
|
|
146
|
+
} : {}
|
|
147
|
+
},
|
|
148
|
+
thread: {
|
|
149
|
+
threadId: context.threadId,
|
|
150
|
+
runId: input.runId,
|
|
151
|
+
...input.agentName !== void 0 ? {
|
|
152
|
+
agentName: input.agentName
|
|
153
|
+
} : {}
|
|
154
|
+
},
|
|
155
|
+
...deps.approvalPolicy !== void 0 ? {
|
|
156
|
+
policy: deps.approvalPolicy
|
|
157
|
+
} : {}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
if (call.actionApproval?.mode === "ask") {
|
|
161
|
+
call.prepared = await prepareActionProposal(deps.registry, call.name, call.input, {
|
|
162
|
+
...toolCallContext(context, call.id),
|
|
163
|
+
emitUi: createNoopEmitUi(call.id)
|
|
164
|
+
}, deps.rolesPolicy, allowedTools === void 0 ? {} : {
|
|
165
|
+
allowedTools
|
|
166
|
+
});
|
|
167
|
+
call.preflight = call.prepared.preflight;
|
|
168
|
+
} else {
|
|
169
|
+
call.preflight = await deps.registry.prepare(call.name, call.input, {
|
|
170
|
+
...toolCallContext(context, call.id),
|
|
171
|
+
emitUi: createNoopEmitUi(call.id)
|
|
172
|
+
}, deps.rolesPolicy, allowedTools === void 0 ? {} : {
|
|
173
|
+
allowedTools
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
} catch (error) {
|
|
177
|
+
if (isControlFlowSignal(error) || isReplayIntegrityError(error)) throw error;
|
|
178
|
+
call.preflight = {
|
|
179
|
+
status: "failed",
|
|
180
|
+
error: error instanceof Error ? error.message : String(error)
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
const shown = previews.shown();
|
|
185
|
+
const previewed = shown.length > 0 ? {
|
|
186
|
+
...stamped,
|
|
187
|
+
previews: shown
|
|
188
|
+
} : stamped;
|
|
189
|
+
const firstTextAt = firstText?.firstTextAt();
|
|
190
|
+
if (buffer !== void 0) {
|
|
191
|
+
return {
|
|
192
|
+
...previewed,
|
|
193
|
+
bufferedFrames: buffer.frames()
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
return firstTextAt === void 0 ? previewed : {
|
|
197
|
+
...previewed,
|
|
198
|
+
firstTextAt
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
__name(runLlmStep, "runLlmStep");
|
|
202
|
+
async function runToolStep(factory, input, options = {}) {
|
|
203
|
+
const deps = factory.forAgent(input.ctx.agentName);
|
|
204
|
+
if (deps.registry.spec(input.toolName)?.kind === "action" && input.toolType !== "action") {
|
|
205
|
+
throw new Error(`tool "${input.toolName}" is an action tool but was dispatched without approval: the dispatching process resolved its kind against a registry that does not have it`);
|
|
206
|
+
}
|
|
207
|
+
const sinkRunId = input.sinkRunId;
|
|
208
|
+
let opened;
|
|
209
|
+
const ui = createNegotiatedUiCollector(input.toolCallId, input.ctx, deps.resolveUiCatalog, sinkRunId === void 0 ? void 0 : async (event) => {
|
|
210
|
+
opened ??= Promise.resolve(deps.sink.open(sinkRunId)).then((writer) => input.childSink === true ? childSinkWriter(writer) : writer);
|
|
211
|
+
await (await opened).write(encodeStreamEvent(event));
|
|
212
|
+
});
|
|
213
|
+
const ctx = {
|
|
214
|
+
...toolCallContext(input.ctx, input.toolCallId),
|
|
215
|
+
emitUi: ui.emit,
|
|
216
|
+
...options.abortSignal !== void 0 ? {
|
|
217
|
+
abortSignal: options.abortSignal
|
|
218
|
+
} : {}
|
|
219
|
+
};
|
|
220
|
+
const localClassify = deps.toolTransientRetry !== false ? deps.toolTransientRetry?.classify : void 0;
|
|
221
|
+
const transientRetry = input.transientRetry === false ? false : {
|
|
222
|
+
attempts: input.transientRetry.attempts,
|
|
223
|
+
backoffMs: input.transientRetry.backoffMs,
|
|
224
|
+
...localClassify !== void 0 ? {
|
|
225
|
+
classify: localClassify
|
|
226
|
+
} : {}
|
|
227
|
+
};
|
|
228
|
+
const allowedTools = intersectAllowLists(deps.toolAllowList, input.allowedTools === void 0 ? void 0 : [
|
|
229
|
+
...input.allowedTools
|
|
230
|
+
]);
|
|
231
|
+
let output;
|
|
232
|
+
const toolStartedAt = Date.now();
|
|
233
|
+
try {
|
|
234
|
+
output = await traceToolExecution(input.ctx.runId, {
|
|
235
|
+
toolCallId: input.toolCallId,
|
|
236
|
+
toolName: input.toolName,
|
|
237
|
+
toolType: input.toolType
|
|
238
|
+
}, () => invokeWithTransientRetry(() => {
|
|
239
|
+
ui.restart();
|
|
240
|
+
const invocation = deps.registry.invoke(input.toolName, input.input, ctx, deps.rolesPolicy, allowedTools === void 0 ? {} : {
|
|
241
|
+
allowedTools
|
|
242
|
+
});
|
|
243
|
+
return input.timeoutMs !== void 0 ? withToolTimeout(invocation, input.timeoutMs, input.toolName) : invocation;
|
|
244
|
+
}, transientRetry, {
|
|
245
|
+
onRetry: /* @__PURE__ */ __name((attempt, error) => {
|
|
246
|
+
publishAgentToolRetry({
|
|
247
|
+
toolName: input.toolName,
|
|
248
|
+
toolCallId: input.toolCallId,
|
|
249
|
+
attempt,
|
|
250
|
+
message: error instanceof Error ? error.message : String(error)
|
|
251
|
+
});
|
|
252
|
+
}, "onRetry")
|
|
253
|
+
}));
|
|
254
|
+
} catch (error) {
|
|
255
|
+
if (error instanceof Error && error.name === "ToolPreflightDeniedError") {
|
|
256
|
+
return wrapToolPreflightDenied(error.message);
|
|
257
|
+
}
|
|
258
|
+
throw error;
|
|
259
|
+
}
|
|
260
|
+
const executionMs = Date.now() - toolStartedAt;
|
|
261
|
+
output = await withChannelDelivery(deps, input.ctx, output, ui.components());
|
|
262
|
+
return input.collectUi === true ? wrapToolStepOutput(output, ui.components(), ui.text(), executionMs) : output;
|
|
263
|
+
}
|
|
264
|
+
__name(runToolStep, "runToolStep");
|
|
265
|
+
|
|
266
|
+
// src/workflows/agent-reply.signal.ts
|
|
267
|
+
import { WorkflowSignal } from "@nestjs/workflows";
|
|
268
|
+
var AGENT_REPLY = new WorkflowSignal("aviary.agent.reply");
|
|
269
|
+
function replyKey(runId, toolCallId) {
|
|
270
|
+
return `${runId}:${toolCallId}`;
|
|
271
|
+
}
|
|
272
|
+
__name(replyKey, "replyKey");
|
|
273
|
+
|
|
274
|
+
// src/workflows/turn-journal.ts
|
|
275
|
+
import { OutputRejectedError, QuotaExceededError, RunCancelledError, StructuredOutputError } from "@dudousxd/nestjs-agent-core";
|
|
276
|
+
import { isWorkflowInterrupt } from "@nestjs/workflows";
|
|
277
|
+
var CONTROL_FLOW_SIGNAL = /* @__PURE__ */ Symbol.for("aviary:durable:control-flow");
|
|
278
|
+
function markControlFlow(error) {
|
|
279
|
+
if (isWorkflowInterrupt(error) && typeof error === "object" && error !== null) {
|
|
280
|
+
error[CONTROL_FLOW_SIGNAL] = true;
|
|
281
|
+
}
|
|
282
|
+
return error;
|
|
283
|
+
}
|
|
284
|
+
__name(markControlFlow, "markControlFlow");
|
|
285
|
+
var SegmentBoundary = class extends Error {
|
|
286
|
+
static {
|
|
287
|
+
__name(this, "SegmentBoundary");
|
|
288
|
+
}
|
|
289
|
+
constructor() {
|
|
290
|
+
super("The turn goes on in a child workflow instance");
|
|
291
|
+
this.name = "SegmentBoundary";
|
|
292
|
+
this[CONTROL_FLOW_SIGNAL] = true;
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
function isEngineControlFlow(error) {
|
|
296
|
+
return isWorkflowInterrupt(error) || error instanceof SegmentBoundary;
|
|
297
|
+
}
|
|
298
|
+
__name(isEngineControlFlow, "isEngineControlFlow");
|
|
299
|
+
function serializeTurnError(error) {
|
|
300
|
+
if (!(error instanceof Error)) {
|
|
301
|
+
return {
|
|
302
|
+
name: "Error",
|
|
303
|
+
message: String(error)
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
const props = {};
|
|
307
|
+
for (const [key, value] of Object.entries(error)) {
|
|
308
|
+
if (key === "name" || key === "message" || key === "stack") continue;
|
|
309
|
+
try {
|
|
310
|
+
const json = JSON.stringify(value);
|
|
311
|
+
if (json !== void 0) props[key] = JSON.parse(json);
|
|
312
|
+
} catch {
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return {
|
|
316
|
+
name: error.name,
|
|
317
|
+
message: error.message,
|
|
318
|
+
...Object.keys(props).length > 0 ? {
|
|
319
|
+
props
|
|
320
|
+
} : {}
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
__name(serializeTurnError, "serializeTurnError");
|
|
324
|
+
function stepFailureCause(error) {
|
|
325
|
+
const cause = error.cause;
|
|
326
|
+
if (typeof cause === "object" && cause !== null) {
|
|
327
|
+
const { name, message } = cause;
|
|
328
|
+
if (typeof message === "string") {
|
|
329
|
+
return {
|
|
330
|
+
name: typeof name === "string" ? name : "Error",
|
|
331
|
+
message
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
if (cause === void 0 || cause === null) return {
|
|
336
|
+
name: "Error",
|
|
337
|
+
message: error.message
|
|
338
|
+
};
|
|
339
|
+
return {
|
|
340
|
+
name: "Error",
|
|
341
|
+
message: typeof cause === "string" ? cause : safeString(cause)
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
__name(stepFailureCause, "stepFailureCause");
|
|
345
|
+
function safeString(value) {
|
|
346
|
+
try {
|
|
347
|
+
return JSON.stringify(value) ?? String(value);
|
|
348
|
+
} catch {
|
|
349
|
+
return String(value);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
__name(safeString, "safeString");
|
|
353
|
+
var KNOWN_ERRORS = {
|
|
354
|
+
QuotaExceededError,
|
|
355
|
+
RunCancelledError,
|
|
356
|
+
OutputRejectedError,
|
|
357
|
+
StructuredOutputError
|
|
358
|
+
};
|
|
359
|
+
function rebuildTurnError(serialized) {
|
|
360
|
+
const prototype = KNOWN_ERRORS[serialized.name]?.prototype ?? Error.prototype;
|
|
361
|
+
const error = Object.create(prototype);
|
|
362
|
+
Object.assign(error, serialized.props ?? {});
|
|
363
|
+
Object.defineProperty(error, "name", {
|
|
364
|
+
value: serialized.name,
|
|
365
|
+
writable: true,
|
|
366
|
+
configurable: true
|
|
367
|
+
});
|
|
368
|
+
Object.defineProperty(error, "message", {
|
|
369
|
+
value: serialized.message,
|
|
370
|
+
writable: true,
|
|
371
|
+
configurable: true
|
|
372
|
+
});
|
|
373
|
+
Object.defineProperty(error, "stack", {
|
|
374
|
+
value: `${serialized.name}: ${serialized.message}`,
|
|
375
|
+
writable: true,
|
|
376
|
+
configurable: true
|
|
377
|
+
});
|
|
378
|
+
return error;
|
|
379
|
+
}
|
|
380
|
+
__name(rebuildTurnError, "rebuildTurnError");
|
|
381
|
+
var TurnJournal = class {
|
|
382
|
+
static {
|
|
383
|
+
__name(this, "TurnJournal");
|
|
384
|
+
}
|
|
385
|
+
counts = /* @__PURE__ */ new Map();
|
|
386
|
+
/** Every operation's outcome so far: the carried ones, then this instance's. */
|
|
387
|
+
outcomes;
|
|
388
|
+
/** Model calls this instance made itself (not carried). */
|
|
389
|
+
liveModelCalls = 0;
|
|
390
|
+
constructor(carried = {}) {
|
|
391
|
+
this.outcomes = {
|
|
392
|
+
...carried
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
/** `base` the first time, `base#2` the second, ... */
|
|
396
|
+
unique(base) {
|
|
397
|
+
const count = (this.counts.get(base) ?? 0) + 1;
|
|
398
|
+
this.counts.set(base, count);
|
|
399
|
+
return count === 1 ? base : `${base}#${count}`;
|
|
400
|
+
}
|
|
401
|
+
/** Was `name` carried from an earlier segment, or already settled in this one? */
|
|
402
|
+
has(name) {
|
|
403
|
+
return name in this.outcomes;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Run `live` (a `ctx` operation) once per run: a name an earlier segment settled answers from
|
|
407
|
+
* `carried`. A failure is recorded too, so a later segment replays it as the same failure; the
|
|
408
|
+
* engine's own control flow is not.
|
|
409
|
+
*/
|
|
410
|
+
async op(name, live) {
|
|
411
|
+
const known = this.outcomes[name];
|
|
412
|
+
if (known !== void 0) {
|
|
413
|
+
if ("e" in known) throw rebuildTurnError(known.e);
|
|
414
|
+
return known.v;
|
|
415
|
+
}
|
|
416
|
+
try {
|
|
417
|
+
const value = await live();
|
|
418
|
+
this.outcomes[name] = value === void 0 ? {} : {
|
|
419
|
+
v: value
|
|
420
|
+
};
|
|
421
|
+
return value;
|
|
422
|
+
} catch (error) {
|
|
423
|
+
if (isEngineControlFlow(error)) throw markControlFlow(error);
|
|
424
|
+
this.outcomes[name] = {
|
|
425
|
+
e: serializeTurnError(error)
|
|
426
|
+
};
|
|
427
|
+
throw error;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
// src/workflows/agent-turn.executor.ts
|
|
433
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
434
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
435
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
436
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
437
|
+
} else {
|
|
438
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
439
|
+
if (d = decorators[i]) {
|
|
440
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
445
|
+
}
|
|
446
|
+
__name(_ts_decorate, "_ts_decorate");
|
|
447
|
+
function _ts_metadata(metadataKey, metadataValue) {
|
|
448
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
449
|
+
return Reflect.metadata(metadataKey, metadataValue);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
__name(_ts_metadata, "_ts_metadata");
|
|
453
|
+
function _ts_param(paramIndex, decorator) {
|
|
454
|
+
return function(target, key) {
|
|
455
|
+
decorator(target, key, paramIndex);
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
__name(_ts_param, "_ts_param");
|
|
459
|
+
var AGENT_RUN_WORKFLOW = "aviary.agent.run";
|
|
460
|
+
var AGENT_RUN_SEGMENT_WORKFLOW = "aviary.agent.run.segment";
|
|
461
|
+
var DEFAULT_STEPS_PER_INSTANCE = 10;
|
|
462
|
+
var SegmentFailed = class SegmentFailed2 extends Error {
|
|
463
|
+
static {
|
|
464
|
+
__name(this, "SegmentFailed");
|
|
465
|
+
}
|
|
466
|
+
cause;
|
|
467
|
+
constructor(cause) {
|
|
468
|
+
super(cause.message), this.cause = cause;
|
|
469
|
+
this.name = "SegmentFailed";
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
function isConfigurationError(error) {
|
|
473
|
+
return error instanceof Error && (error.name === "AiConfigurationError" || error.name === "AgentConfigurationError");
|
|
474
|
+
}
|
|
475
|
+
__name(isConfigurationError, "isConfigurationError");
|
|
476
|
+
function isFatalDefinitionError(error) {
|
|
477
|
+
return isReplayIntegrityError2(error) || error instanceof Error && (error.name === "WorkflowDefinitionError" || error.name === "WorkflowJournalLimitError");
|
|
478
|
+
}
|
|
479
|
+
__name(isFatalDefinitionError, "isFatalDefinitionError");
|
|
480
|
+
var AgentTurnExecutor = class {
|
|
481
|
+
static {
|
|
482
|
+
__name(this, "AgentTurnExecutor");
|
|
483
|
+
}
|
|
484
|
+
factory;
|
|
485
|
+
store;
|
|
486
|
+
queue;
|
|
487
|
+
client;
|
|
488
|
+
workflowsOptions;
|
|
489
|
+
logger = new Logger("AgentRunFlow");
|
|
490
|
+
stepsPerInstance;
|
|
491
|
+
constructor(factory, store, options, queue, client, workflowsOptions) {
|
|
492
|
+
this.factory = factory;
|
|
493
|
+
this.store = store;
|
|
494
|
+
this.queue = queue;
|
|
495
|
+
this.client = client;
|
|
496
|
+
this.workflowsOptions = workflowsOptions;
|
|
497
|
+
const durable = options?.durable;
|
|
498
|
+
const configured = durableEngineOf(durable) === "workflows" && typeof durable === "object" ? durable.stepsPerInstance : void 0;
|
|
499
|
+
this.stepsPerInstance = configured !== void 0 && Number.isInteger(configured) && configured > 0 ? configured : DEFAULT_STEPS_PER_INSTANCE;
|
|
500
|
+
}
|
|
501
|
+
/** A turn from its first instance. */
|
|
502
|
+
run(ctx, input) {
|
|
503
|
+
return this.execute(ctx, {
|
|
504
|
+
input,
|
|
505
|
+
runId: ctx.workflowId,
|
|
506
|
+
segment: 0,
|
|
507
|
+
carried: {}
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
async execute(ctx, segment) {
|
|
511
|
+
const { input, runId } = segment;
|
|
512
|
+
const journal = new TurnJournal(segment.carried);
|
|
513
|
+
const day = input.day ?? utcDay();
|
|
514
|
+
const deps = this.factory.forAgent(input.agentName);
|
|
515
|
+
const sinkRunId = input.sinkRunId ?? runId;
|
|
516
|
+
const childSink = input.sinkRunId !== void 0;
|
|
517
|
+
const originals = /* @__PURE__ */ new Map();
|
|
518
|
+
const pending = /* @__PURE__ */ new Map();
|
|
519
|
+
const showPending = /* @__PURE__ */ __name(() => ctx.setStatus(pending.size > 0 ? {
|
|
520
|
+
pendingReplies: [
|
|
521
|
+
...pending.values()
|
|
522
|
+
]
|
|
523
|
+
} : null), "showPending");
|
|
524
|
+
const checkpoint = /* @__PURE__ */ __name((name, fn) => journal.op(name, async () => {
|
|
525
|
+
const envelope = await this.ctxCall(() => ctx.step(name, async () => {
|
|
526
|
+
try {
|
|
527
|
+
const value = await fn();
|
|
528
|
+
return value === void 0 ? {} : {
|
|
529
|
+
v: value
|
|
530
|
+
};
|
|
531
|
+
} catch (error) {
|
|
532
|
+
originals.set(name, error);
|
|
533
|
+
return {
|
|
534
|
+
e: serializeTurnError(error)
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
}));
|
|
538
|
+
if ("e" in envelope) {
|
|
539
|
+
throw originals.get(name) ?? rebuildTurnError(envelope.e);
|
|
540
|
+
}
|
|
541
|
+
return envelope.v;
|
|
542
|
+
}), "checkpoint");
|
|
543
|
+
const step = /* @__PURE__ */ __name((name, fn) => checkpoint(journal.unique(name), fn), "step");
|
|
544
|
+
const awaitReply = /* @__PURE__ */ __name(async (call, timeoutMs) => {
|
|
545
|
+
const name = journal.unique(`reply:${call.id}`);
|
|
546
|
+
pending.set(call.id, {
|
|
547
|
+
key: replyKey(runId, call.id),
|
|
548
|
+
runId,
|
|
549
|
+
toolCallId: call.id,
|
|
550
|
+
toolName: call.toolName,
|
|
551
|
+
kind: call.kind
|
|
552
|
+
});
|
|
553
|
+
showPending();
|
|
554
|
+
const reply = await journal.op(name, () => this.ctxCall(() => ctx.waitForSignal(name, AGENT_REPLY, {
|
|
555
|
+
key: replyKey(runId, call.id),
|
|
556
|
+
...timeoutMs !== void 0 ? {
|
|
557
|
+
timeout: timeoutMs
|
|
558
|
+
} : {}
|
|
559
|
+
})));
|
|
560
|
+
pending.delete(call.id);
|
|
561
|
+
showPending();
|
|
562
|
+
return reply;
|
|
563
|
+
}, "awaitReply");
|
|
564
|
+
const chainBelow = [
|
|
565
|
+
...input.delegationPath ?? [],
|
|
566
|
+
...input.agentName !== void 0 ? [
|
|
567
|
+
input.agentName
|
|
568
|
+
] : []
|
|
569
|
+
];
|
|
570
|
+
const subThread = /* @__PURE__ */ __name((agentName) => step(`subthread:${agentName}`, async () => {
|
|
571
|
+
const thread = await this.store.createThread({
|
|
572
|
+
actor: input.actor,
|
|
573
|
+
transient: true
|
|
574
|
+
});
|
|
575
|
+
return thread.id;
|
|
576
|
+
}), "subThread");
|
|
577
|
+
if (input.sinkRunId !== void 0 || input.deliverTo !== void 0) {
|
|
578
|
+
await step("activate", () => this.store.setActiveStream(input.threadId, runId));
|
|
579
|
+
}
|
|
580
|
+
const hooks = {
|
|
581
|
+
runId,
|
|
582
|
+
queueMs: /* @__PURE__ */ __name(async () => {
|
|
583
|
+
const status = await this.client?.getStatus(runId);
|
|
584
|
+
if (status === void 0 || status === null) return void 0;
|
|
585
|
+
const now = this.workflowsOptions?.clock?.now() ?? Date.now();
|
|
586
|
+
const waited = now - status.createdAt;
|
|
587
|
+
return Number.isFinite(waited) && waited >= 0 ? waited : void 0;
|
|
588
|
+
}, "queueMs"),
|
|
589
|
+
openSink: /* @__PURE__ */ __name(async () => {
|
|
590
|
+
if (childSink) {
|
|
591
|
+
return childSinkWriter(await deps.sink.open(sinkRunId));
|
|
592
|
+
}
|
|
593
|
+
const writer = await deps.sink.open(runId);
|
|
594
|
+
return {
|
|
595
|
+
write: /* @__PURE__ */ __name((chunk) => writer.write(chunk), "write"),
|
|
596
|
+
fail: /* @__PURE__ */ __name((failure) => writer.fail(failure), "fail"),
|
|
597
|
+
end: /* @__PURE__ */ __name(async () => {
|
|
598
|
+
const frame = await this.advanceQueue(ctx, step, journal, runId, input, "completed");
|
|
599
|
+
if (frame !== void 0) {
|
|
600
|
+
await writer.write(encodeStreamEvent2(frame));
|
|
601
|
+
}
|
|
602
|
+
await writer.end();
|
|
603
|
+
}, "end")
|
|
604
|
+
};
|
|
605
|
+
}, "openSink"),
|
|
606
|
+
awaitApproval: /* @__PURE__ */ __name(async (call, _toolCtx, opts) => {
|
|
607
|
+
const reply = await awaitReply({
|
|
608
|
+
id: call.id,
|
|
609
|
+
toolName: call.name,
|
|
610
|
+
kind: "approval"
|
|
611
|
+
}, opts?.timeoutMs);
|
|
612
|
+
return reply === null ? {
|
|
613
|
+
approved: false,
|
|
614
|
+
expired: true
|
|
615
|
+
} : reply;
|
|
616
|
+
}, "awaitApproval"),
|
|
617
|
+
awaitAnswers: /* @__PURE__ */ __name(async (request) => {
|
|
618
|
+
const reply = await awaitReply({
|
|
619
|
+
id: request.id,
|
|
620
|
+
toolName: request.source,
|
|
621
|
+
kind: "elicitation"
|
|
622
|
+
});
|
|
623
|
+
return reply ?? {
|
|
624
|
+
approved: false
|
|
625
|
+
};
|
|
626
|
+
}, "awaitAnswers"),
|
|
627
|
+
step,
|
|
628
|
+
parallel: settleAll,
|
|
629
|
+
isControlFlowError: isEngineControlFlow,
|
|
630
|
+
runAgent: /* @__PURE__ */ __name(async (agentName, task) => {
|
|
631
|
+
const name = journal.unique(`delegate:${agentName}`);
|
|
632
|
+
const subThreadId = await subThread(agentName);
|
|
633
|
+
const child = {
|
|
634
|
+
agentName,
|
|
635
|
+
threadId: subThreadId,
|
|
636
|
+
actor: input.actor,
|
|
637
|
+
userText: task,
|
|
638
|
+
day,
|
|
639
|
+
delegationDepth: (input.delegationDepth ?? 0) + 1,
|
|
640
|
+
delegationPath: chainBelow,
|
|
641
|
+
parentRunId: runId,
|
|
642
|
+
sinkRunId
|
|
643
|
+
};
|
|
644
|
+
return journal.op(name, () => this.ctxCall(() => ctx.executeChild(AGENT_RUN_WORKFLOW, child, {
|
|
645
|
+
id: `${ctx.workflowId}/${name}`
|
|
646
|
+
})));
|
|
647
|
+
}, "runAgent"),
|
|
648
|
+
// A detached delegation outlives the turn that started it, and a Stop on that turn: an
|
|
649
|
+
// abandoned child, not a cancelled one.
|
|
650
|
+
startAgent: /* @__PURE__ */ __name(async ({ agentName, task, toolCallId }) => {
|
|
651
|
+
const name = journal.unique(`detach:${toolCallId}`);
|
|
652
|
+
const subThreadId = await subThread(agentName);
|
|
653
|
+
const child = {
|
|
654
|
+
agentName,
|
|
655
|
+
threadId: subThreadId,
|
|
656
|
+
actor: input.actor,
|
|
657
|
+
userText: task,
|
|
658
|
+
day,
|
|
659
|
+
delegationDepth: (input.delegationDepth ?? 0) + 1,
|
|
660
|
+
delegationPath: chainBelow,
|
|
661
|
+
parentRunId: runId,
|
|
662
|
+
deliverTo: {
|
|
663
|
+
threadId: input.threadId,
|
|
664
|
+
toolCallId
|
|
665
|
+
}
|
|
666
|
+
};
|
|
667
|
+
const childRunId = await journal.op(name, async () => {
|
|
668
|
+
const handle = await this.ctxCall(() => ctx.startChild(AGENT_RUN_WORKFLOW, child, {
|
|
669
|
+
id: `${runId}.detached.${toolCallId}`,
|
|
670
|
+
parentClose: "abandon"
|
|
671
|
+
}));
|
|
672
|
+
return handle.id;
|
|
673
|
+
});
|
|
674
|
+
return {
|
|
675
|
+
runId: childRunId
|
|
676
|
+
};
|
|
677
|
+
}, "startAgent"),
|
|
678
|
+
dispatchLlm: /* @__PURE__ */ __name((index, envelope) => {
|
|
679
|
+
const name = journal.unique(`llm:${index}`);
|
|
680
|
+
if (!journal.has(name)) {
|
|
681
|
+
if (journal.liveModelCalls >= this.stepsPerInstance) {
|
|
682
|
+
throw new SegmentBoundary();
|
|
683
|
+
}
|
|
684
|
+
journal.liveModelCalls += 1;
|
|
685
|
+
}
|
|
686
|
+
return journal.op(name, async () => {
|
|
687
|
+
try {
|
|
688
|
+
return await this.ctxCall(() => ctx.step(name, (attempt) => runLlmStep(this.factory, {
|
|
689
|
+
...envelope,
|
|
690
|
+
runId,
|
|
691
|
+
step: index,
|
|
692
|
+
sinkRunId,
|
|
693
|
+
childSink
|
|
694
|
+
}, {
|
|
695
|
+
abortSignal: attempt.signal
|
|
696
|
+
}).catch((error) => {
|
|
697
|
+
if (!isConfigurationError(error)) throw error;
|
|
698
|
+
const fatal = new NonRetryableStepError(error.message);
|
|
699
|
+
fatal.name = error.name;
|
|
700
|
+
throw fatal;
|
|
701
|
+
})));
|
|
702
|
+
} catch (error) {
|
|
703
|
+
if (error instanceof StepFailedError) {
|
|
704
|
+
throw rebuildTurnError(stepFailureCause(error));
|
|
705
|
+
}
|
|
706
|
+
throw error;
|
|
707
|
+
}
|
|
708
|
+
});
|
|
709
|
+
}, "dispatchLlm"),
|
|
710
|
+
// A tool's failure is a result the model reads, not the step's: the step is retried only after
|
|
711
|
+
// a crash, and the tool's `ctx.idempotencyKey` (`<runId>:<toolCallId>`) is the same on that
|
|
712
|
+
// attempt, so a tool that passes it on does its side effect once.
|
|
713
|
+
dispatchTool: /* @__PURE__ */ __name((call, envelope) => checkpointTool(journal.unique(`tool:${call.id}`), call, envelope), "dispatchTool")
|
|
714
|
+
};
|
|
715
|
+
const checkpointTool = /* @__PURE__ */ __name((name, call, envelope) => journal.op(name, async () => {
|
|
716
|
+
const outcome = await this.ctxCall(() => ctx.step(name, async (attempt) => {
|
|
717
|
+
try {
|
|
718
|
+
const value = await runToolStep(this.factory, {
|
|
719
|
+
...envelope,
|
|
720
|
+
toolCallId: call.id,
|
|
721
|
+
toolType: call.kind === "action" ? "action" : "read",
|
|
722
|
+
sinkRunId,
|
|
723
|
+
childSink
|
|
724
|
+
}, {
|
|
725
|
+
abortSignal: attempt.signal
|
|
726
|
+
});
|
|
727
|
+
return value === void 0 ? {} : {
|
|
728
|
+
v: value
|
|
729
|
+
};
|
|
730
|
+
} catch (error) {
|
|
731
|
+
originals.set(name, error);
|
|
732
|
+
return {
|
|
733
|
+
e: serializeTurnError(error)
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
}));
|
|
737
|
+
if ("e" in outcome) throw originals.get(name) ?? rebuildTurnError(outcome.e);
|
|
738
|
+
return outcome.v;
|
|
739
|
+
}), "checkpointTool");
|
|
740
|
+
try {
|
|
741
|
+
const result = await runAgentLoop({
|
|
742
|
+
...deps,
|
|
743
|
+
day
|
|
744
|
+
}, input, hooks);
|
|
745
|
+
await step("deactivate", () => releaseThreadRun(this.store, input.threadId, runId));
|
|
746
|
+
return result;
|
|
747
|
+
} catch (error) {
|
|
748
|
+
if (error instanceof SegmentBoundary) {
|
|
749
|
+
return this.continueInSegment(ctx, {
|
|
750
|
+
...segment,
|
|
751
|
+
carried: journal.outcomes
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
if (isEngineControlFlow(error) || error instanceof SegmentFailed) {
|
|
755
|
+
throw error;
|
|
756
|
+
}
|
|
757
|
+
if (error instanceof RunCancelledError2) {
|
|
758
|
+
await step("deactivate", () => releaseThreadRun(this.store, input.threadId, runId));
|
|
759
|
+
await this.settleDetachedParent(step, runId, input, {
|
|
760
|
+
status: "cancelled"
|
|
761
|
+
});
|
|
762
|
+
throw error;
|
|
763
|
+
}
|
|
764
|
+
const durationMs = runDurationMs(error);
|
|
765
|
+
const timed = durationMs !== void 0 ? {
|
|
766
|
+
durationMs
|
|
767
|
+
} : {};
|
|
768
|
+
const measured = runEndTimings(error);
|
|
769
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
770
|
+
const code = agentFailureCode(error);
|
|
771
|
+
this.logger.error(`agent run ${runId} failed (${code}): ${message}`);
|
|
772
|
+
publishAgentRunFailed({
|
|
773
|
+
runId,
|
|
774
|
+
threadId: input.threadId,
|
|
775
|
+
code,
|
|
776
|
+
message,
|
|
777
|
+
...timed,
|
|
778
|
+
...measured,
|
|
779
|
+
context: agentRunContext(input)
|
|
780
|
+
});
|
|
781
|
+
if (isFatalDefinitionError(error)) {
|
|
782
|
+
await settleDeadRun(this.store, {
|
|
783
|
+
runId,
|
|
784
|
+
threadId: input.threadId,
|
|
785
|
+
failure: {
|
|
786
|
+
code,
|
|
787
|
+
message,
|
|
788
|
+
...timed
|
|
789
|
+
}
|
|
790
|
+
});
|
|
791
|
+
await (await hooks.openSink()).fail(streamFailure(error));
|
|
792
|
+
throw error;
|
|
793
|
+
}
|
|
794
|
+
try {
|
|
795
|
+
await step("persist:run:fail", async () => {
|
|
796
|
+
await this.store.recordRunEnd?.({
|
|
797
|
+
runId,
|
|
798
|
+
status: "failed",
|
|
799
|
+
...timed,
|
|
800
|
+
errorCode: code,
|
|
801
|
+
errorMessage: message
|
|
802
|
+
});
|
|
803
|
+
await Promise.resolve(this.store.failUnsettledToolCalls?.(runId, RUN_ENDED_BEFORE_TOOL_CALL)).catch(() => 0);
|
|
804
|
+
});
|
|
805
|
+
const queueFrame = await this.advanceQueue(ctx, step, journal, runId, input, "failed", message);
|
|
806
|
+
await step("deactivate", () => releaseThreadRun(this.store, input.threadId, runId));
|
|
807
|
+
await this.settleDetachedParent(step, runId, input, {
|
|
808
|
+
status: "failed",
|
|
809
|
+
error: message
|
|
810
|
+
});
|
|
811
|
+
const writer = await hooks.openSink();
|
|
812
|
+
if (queueFrame !== void 0) {
|
|
813
|
+
await writer.write(encodeStreamEvent2(queueFrame));
|
|
814
|
+
}
|
|
815
|
+
await writer.fail(streamFailure(error));
|
|
816
|
+
} catch (settling) {
|
|
817
|
+
if (isEngineControlFlow(settling)) throw markControlFlow(settling);
|
|
818
|
+
throw settling;
|
|
819
|
+
}
|
|
820
|
+
throw error;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
/** The turn goes on in a child instance, from what this one (and those before it) settled. */
|
|
824
|
+
async continueInSegment(ctx, segment) {
|
|
825
|
+
const next = {
|
|
826
|
+
...segment,
|
|
827
|
+
segment: segment.segment + 1
|
|
828
|
+
};
|
|
829
|
+
try {
|
|
830
|
+
return await this.ctxCall(() => ctx.executeChild(AGENT_RUN_SEGMENT_WORKFLOW, next, {
|
|
831
|
+
id: `${segment.runId}~${next.segment}`
|
|
832
|
+
}));
|
|
833
|
+
} catch (error) {
|
|
834
|
+
if (error instanceof ChildWorkflowFailedError) throw new SegmentFailed(error);
|
|
835
|
+
throw error;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* Hand the thread on past this settling turn, as the `aviary` engine does: the decision is one
|
|
840
|
+
* checkpoint, and the next message starts as an abandoned child under its own id, so the turn
|
|
841
|
+
* ending doesn't cancel it.
|
|
842
|
+
*/
|
|
843
|
+
async advanceQueue(ctx, step, journal, runId, input, outcome, error) {
|
|
844
|
+
const queue = this.queue;
|
|
845
|
+
if (queue === void 0 || !queue.supported || input.sinkRunId !== void 0 || input.deliverTo !== void 0) {
|
|
846
|
+
return void 0;
|
|
847
|
+
}
|
|
848
|
+
const plan = await step(`queue:${outcome}`, async () => {
|
|
849
|
+
try {
|
|
850
|
+
const settled = outcome === "completed" && await this.isCancelled(runId) ? "cancelled" : outcome;
|
|
851
|
+
return await queue.plan({
|
|
852
|
+
threadId: input.threadId,
|
|
853
|
+
runId,
|
|
854
|
+
outcome: settled,
|
|
855
|
+
...error !== void 0 ? {
|
|
856
|
+
error
|
|
857
|
+
} : {}
|
|
858
|
+
});
|
|
859
|
+
} catch {
|
|
860
|
+
return {};
|
|
861
|
+
}
|
|
862
|
+
});
|
|
863
|
+
const next = plan.next;
|
|
864
|
+
if (next === void 0) {
|
|
865
|
+
return plan.frame;
|
|
866
|
+
}
|
|
867
|
+
try {
|
|
868
|
+
await journal.op(journal.unique(`queue:start:${next.runId}`), async () => {
|
|
869
|
+
const handle = await this.ctxCall(() => ctx.startChild(AGENT_RUN_WORKFLOW, next.input, {
|
|
870
|
+
id: next.runId,
|
|
871
|
+
parentClose: "abandon"
|
|
872
|
+
}));
|
|
873
|
+
return handle.id;
|
|
874
|
+
});
|
|
875
|
+
return plan.frame;
|
|
876
|
+
} catch (failure) {
|
|
877
|
+
if (isEngineControlFlow(failure)) throw failure;
|
|
878
|
+
const reason = failure instanceof Error ? failure.message : String(failure);
|
|
879
|
+
return step("queue:restore", async () => {
|
|
880
|
+
await queue.restore(input.threadId, next, "start_failed", reason);
|
|
881
|
+
return queue.pausedFrame(input.threadId);
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
async isCancelled(runId) {
|
|
886
|
+
try {
|
|
887
|
+
return (await this.client?.getStatus(runId))?.cancelRequested === true;
|
|
888
|
+
} catch {
|
|
889
|
+
return false;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
async settleDetachedParent(step, runId, input, outcome) {
|
|
893
|
+
const delivery = input.deliverTo;
|
|
894
|
+
if (delivery === void 0) return;
|
|
895
|
+
await step("deliver:detached:unsettled", () => settleUnsettledDelegation({
|
|
896
|
+
store: this.store,
|
|
897
|
+
delivery,
|
|
898
|
+
agent: input.agentName ?? "default",
|
|
899
|
+
runId,
|
|
900
|
+
status: outcome.status,
|
|
901
|
+
...outcome.error !== void 0 ? {
|
|
902
|
+
error: outcome.error
|
|
903
|
+
} : {}
|
|
904
|
+
}));
|
|
905
|
+
}
|
|
906
|
+
/** A `ctx` call whose interrupt carries core's control-flow marker. */
|
|
907
|
+
async ctxCall(call) {
|
|
908
|
+
try {
|
|
909
|
+
return await call();
|
|
910
|
+
} catch (error) {
|
|
911
|
+
throw markControlFlow(error);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
};
|
|
915
|
+
AgentTurnExecutor = _ts_decorate([
|
|
916
|
+
Injectable(),
|
|
917
|
+
_ts_param(0, Inject(AGENT_DEPS_FACTORY)),
|
|
918
|
+
_ts_param(1, Inject(AGENT_STORE)),
|
|
919
|
+
_ts_param(2, Optional()),
|
|
920
|
+
_ts_param(2, Inject(AGENT_OPTIONS)),
|
|
921
|
+
_ts_param(3, Optional()),
|
|
922
|
+
_ts_param(3, Inject(AGENT_CHAT_QUEUE)),
|
|
923
|
+
_ts_param(4, Optional()),
|
|
924
|
+
_ts_param(5, Optional()),
|
|
925
|
+
_ts_param(5, Inject(WORKFLOWS_MODULE_OPTIONS)),
|
|
926
|
+
_ts_metadata("design:type", Function),
|
|
927
|
+
_ts_metadata("design:paramtypes", [
|
|
928
|
+
typeof AgentDepsFactory === "undefined" ? Object : AgentDepsFactory,
|
|
929
|
+
typeof AgentStore === "undefined" ? Object : AgentStore,
|
|
930
|
+
typeof AgentModuleOptions === "undefined" ? Object : AgentModuleOptions,
|
|
931
|
+
typeof ChatQueueService === "undefined" ? Object : ChatQueueService,
|
|
932
|
+
typeof WorkflowClient === "undefined" ? Object : WorkflowClient,
|
|
933
|
+
typeof WorkflowsModuleOptions === "undefined" ? Object : WorkflowsModuleOptions
|
|
934
|
+
])
|
|
935
|
+
], AgentTurnExecutor);
|
|
936
|
+
|
|
937
|
+
// src/workflows/agent-run.flow.ts
|
|
938
|
+
function _ts_decorate2(decorators, target, key, desc) {
|
|
939
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
940
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
941
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
942
|
+
} else {
|
|
943
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
944
|
+
if (d = decorators[i]) {
|
|
945
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
950
|
+
}
|
|
951
|
+
__name(_ts_decorate2, "_ts_decorate");
|
|
952
|
+
function _ts_metadata2(metadataKey, metadataValue) {
|
|
953
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
954
|
+
return Reflect.metadata(metadataKey, metadataValue);
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
__name(_ts_metadata2, "_ts_metadata");
|
|
958
|
+
var AgentRunFlow = class {
|
|
959
|
+
static {
|
|
960
|
+
__name(this, "AgentRunFlow");
|
|
961
|
+
}
|
|
962
|
+
turns;
|
|
963
|
+
constructor(turns) {
|
|
964
|
+
this.turns = turns;
|
|
965
|
+
}
|
|
966
|
+
run(ctx, input) {
|
|
967
|
+
return this.turns.run(ctx, input);
|
|
968
|
+
}
|
|
969
|
+
};
|
|
970
|
+
AgentRunFlow = _ts_decorate2([
|
|
971
|
+
Workflow(AGENT_RUN_WORKFLOW),
|
|
972
|
+
_ts_metadata2("design:type", Function),
|
|
973
|
+
_ts_metadata2("design:paramtypes", [
|
|
974
|
+
typeof AgentTurnExecutor === "undefined" ? Object : AgentTurnExecutor
|
|
975
|
+
])
|
|
976
|
+
], AgentRunFlow);
|
|
977
|
+
var AgentRunSegmentFlow = class {
|
|
978
|
+
static {
|
|
979
|
+
__name(this, "AgentRunSegmentFlow");
|
|
980
|
+
}
|
|
981
|
+
turns;
|
|
982
|
+
constructor(turns) {
|
|
983
|
+
this.turns = turns;
|
|
984
|
+
}
|
|
985
|
+
run(ctx, segment) {
|
|
986
|
+
return this.turns.execute(ctx, segment);
|
|
987
|
+
}
|
|
988
|
+
};
|
|
989
|
+
AgentRunSegmentFlow = _ts_decorate2([
|
|
990
|
+
Workflow(AGENT_RUN_SEGMENT_WORKFLOW),
|
|
991
|
+
_ts_metadata2("design:type", Function),
|
|
992
|
+
_ts_metadata2("design:paramtypes", [
|
|
993
|
+
typeof AgentTurnExecutor === "undefined" ? Object : AgentTurnExecutor
|
|
994
|
+
])
|
|
995
|
+
], AgentRunSegmentFlow);
|
|
996
|
+
|
|
997
|
+
// src/workflows/workflows-agent-runner.ts
|
|
998
|
+
import { randomUUID } from "crypto";
|
|
999
|
+
import { AGENT_SINK, AGENT_STORE as AGENT_STORE2, encodeStreamEvent as encodeStreamEvent3, publishAgentRunCancelled, releaseThreadRun as releaseThreadRun2, settleUnsettledDelegation as settleUnsettledDelegation2 } from "@dudousxd/nestjs-agent-core";
|
|
1000
|
+
import { Inject as Inject2, Injectable as Injectable2, Logger as Logger2, Optional as Optional2 } from "@nestjs/common";
|
|
1001
|
+
import { WorkflowClient as WorkflowClient2, WorkflowNotFoundError } from "@nestjs/workflows";
|
|
1002
|
+
|
|
1003
|
+
// src/in-process-sink.ts
|
|
1004
|
+
import { AgentStreamError } from "@dudousxd/nestjs-agent-core";
|
|
1005
|
+
var LIVE_TTL_MS = 36e5;
|
|
1006
|
+
var ENDED_GRACE_MS = 6e4;
|
|
1007
|
+
var InProcessTokenStreamSink = class {
|
|
1008
|
+
static {
|
|
1009
|
+
__name(this, "InProcessTokenStreamSink");
|
|
1010
|
+
}
|
|
1011
|
+
runs = /* @__PURE__ */ new Map();
|
|
1012
|
+
/** Subscribers of a run nothing has opened yet, woken by its `open()`. */
|
|
1013
|
+
waiting = /* @__PURE__ */ new Map();
|
|
1014
|
+
buffer(runId) {
|
|
1015
|
+
let buf = this.runs.get(runId);
|
|
1016
|
+
if (buf === void 0) {
|
|
1017
|
+
buf = {
|
|
1018
|
+
chunks: [],
|
|
1019
|
+
ended: false,
|
|
1020
|
+
notify: /* @__PURE__ */ new Set(),
|
|
1021
|
+
lastWriteAt: Date.now(),
|
|
1022
|
+
expiry: void 0
|
|
1023
|
+
};
|
|
1024
|
+
this.runs.set(runId, buf);
|
|
1025
|
+
this.expireAfter(runId, buf, LIVE_TTL_MS);
|
|
1026
|
+
const waiters = this.waiting.get(runId);
|
|
1027
|
+
this.waiting.delete(runId);
|
|
1028
|
+
for (const resolve of waiters ?? []) {
|
|
1029
|
+
resolve();
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
return buf;
|
|
1033
|
+
}
|
|
1034
|
+
expireAfter(runId, buf, ms) {
|
|
1035
|
+
if (buf.expiry !== void 0) {
|
|
1036
|
+
clearTimeout(buf.expiry);
|
|
1037
|
+
}
|
|
1038
|
+
buf.expiry = setTimeout(() => {
|
|
1039
|
+
buf.expiry = void 0;
|
|
1040
|
+
const idle = Date.now() - buf.lastWriteAt;
|
|
1041
|
+
if (!buf.ended && idle < LIVE_TTL_MS) {
|
|
1042
|
+
this.expireAfter(runId, buf, LIVE_TTL_MS - idle);
|
|
1043
|
+
return;
|
|
1044
|
+
}
|
|
1045
|
+
this.drop(runId, buf);
|
|
1046
|
+
}, ms);
|
|
1047
|
+
buf.expiry.unref?.();
|
|
1048
|
+
}
|
|
1049
|
+
/** Forget the run, and let anyone still following it finish as if it had ended. */
|
|
1050
|
+
drop(runId, buf) {
|
|
1051
|
+
if (buf.expiry !== void 0) {
|
|
1052
|
+
clearTimeout(buf.expiry);
|
|
1053
|
+
buf.expiry = void 0;
|
|
1054
|
+
}
|
|
1055
|
+
if (this.runs.get(runId) === buf) {
|
|
1056
|
+
this.runs.delete(runId);
|
|
1057
|
+
}
|
|
1058
|
+
buf.ended = true;
|
|
1059
|
+
this.wake(buf);
|
|
1060
|
+
}
|
|
1061
|
+
wake(buf) {
|
|
1062
|
+
for (const resolve of buf.notify) {
|
|
1063
|
+
resolve();
|
|
1064
|
+
}
|
|
1065
|
+
buf.notify.clear();
|
|
1066
|
+
}
|
|
1067
|
+
finish(runId, buf) {
|
|
1068
|
+
buf.ended = true;
|
|
1069
|
+
this.wake(buf);
|
|
1070
|
+
this.expireAfter(runId, buf, ENDED_GRACE_MS);
|
|
1071
|
+
}
|
|
1072
|
+
/**
|
|
1073
|
+
* The run's writer. Each call finds the run's buffer afresh, so a run that went quiet past the
|
|
1074
|
+
* live TTL (parked on a person) and then writes again starts a new buffer its next subscriber
|
|
1075
|
+
* follows, rather than writing into one nothing reads.
|
|
1076
|
+
*/
|
|
1077
|
+
open(runId) {
|
|
1078
|
+
this.buffer(runId);
|
|
1079
|
+
return {
|
|
1080
|
+
write: /* @__PURE__ */ __name((chunk) => {
|
|
1081
|
+
const buf = this.buffer(runId);
|
|
1082
|
+
buf.chunks.push(chunk);
|
|
1083
|
+
buf.lastWriteAt = Date.now();
|
|
1084
|
+
this.wake(buf);
|
|
1085
|
+
}, "write"),
|
|
1086
|
+
end: /* @__PURE__ */ __name(() => {
|
|
1087
|
+
this.finish(runId, this.buffer(runId));
|
|
1088
|
+
}, "end"),
|
|
1089
|
+
fail: /* @__PURE__ */ __name((error) => {
|
|
1090
|
+
const buf = this.buffer(runId);
|
|
1091
|
+
buf.failure = error;
|
|
1092
|
+
this.finish(runId, buf);
|
|
1093
|
+
}, "fail")
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
1096
|
+
async *subscribe(runId, options = {}) {
|
|
1097
|
+
const { signal } = options;
|
|
1098
|
+
let buf = this.runs.get(runId);
|
|
1099
|
+
while (buf === void 0) {
|
|
1100
|
+
const waiters = this.waiting.get(runId) ?? /* @__PURE__ */ new Set();
|
|
1101
|
+
this.waiting.set(runId, waiters);
|
|
1102
|
+
let resolve = /* @__PURE__ */ __name(() => {
|
|
1103
|
+
}, "resolve");
|
|
1104
|
+
const opened = new Promise((r) => {
|
|
1105
|
+
resolve = r;
|
|
1106
|
+
});
|
|
1107
|
+
waiters.add(resolve);
|
|
1108
|
+
try {
|
|
1109
|
+
if (!await untilAborted(opened, signal)) {
|
|
1110
|
+
return;
|
|
1111
|
+
}
|
|
1112
|
+
} finally {
|
|
1113
|
+
waiters.delete(resolve);
|
|
1114
|
+
if (waiters.size === 0 && this.waiting.get(runId) === waiters) {
|
|
1115
|
+
this.waiting.delete(runId);
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
buf = this.runs.get(runId);
|
|
1119
|
+
}
|
|
1120
|
+
let index = 0;
|
|
1121
|
+
while (true) {
|
|
1122
|
+
while (index < buf.chunks.length) {
|
|
1123
|
+
const chunk = buf.chunks[index];
|
|
1124
|
+
index += 1;
|
|
1125
|
+
if (chunk !== void 0) {
|
|
1126
|
+
yield chunk;
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
if (buf.ended) {
|
|
1130
|
+
if (buf.failure !== void 0) {
|
|
1131
|
+
throw new AgentStreamError(buf.failure);
|
|
1132
|
+
}
|
|
1133
|
+
return;
|
|
1134
|
+
}
|
|
1135
|
+
const current = buf;
|
|
1136
|
+
let resolve = /* @__PURE__ */ __name(() => {
|
|
1137
|
+
}, "resolve");
|
|
1138
|
+
const woken = new Promise((r) => {
|
|
1139
|
+
resolve = r;
|
|
1140
|
+
});
|
|
1141
|
+
current.notify.add(resolve);
|
|
1142
|
+
try {
|
|
1143
|
+
if (!await untilAborted(woken, signal)) {
|
|
1144
|
+
return;
|
|
1145
|
+
}
|
|
1146
|
+
} finally {
|
|
1147
|
+
current.notify.delete(resolve);
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
close(runId) {
|
|
1152
|
+
const buf = this.runs.get(runId);
|
|
1153
|
+
if (buf?.expiry !== void 0) {
|
|
1154
|
+
clearTimeout(buf.expiry);
|
|
1155
|
+
}
|
|
1156
|
+
this.runs.delete(runId);
|
|
1157
|
+
}
|
|
1158
|
+
};
|
|
1159
|
+
async function untilAborted(promise, signal) {
|
|
1160
|
+
if (signal === void 0) {
|
|
1161
|
+
await promise;
|
|
1162
|
+
return true;
|
|
1163
|
+
}
|
|
1164
|
+
if (signal.aborted) {
|
|
1165
|
+
return false;
|
|
1166
|
+
}
|
|
1167
|
+
let onAbort = /* @__PURE__ */ __name(() => {
|
|
1168
|
+
}, "onAbort");
|
|
1169
|
+
const aborted = new Promise((resolve) => {
|
|
1170
|
+
onAbort = /* @__PURE__ */ __name(() => resolve(false), "onAbort");
|
|
1171
|
+
signal.addEventListener("abort", onAbort, {
|
|
1172
|
+
once: true
|
|
1173
|
+
});
|
|
1174
|
+
});
|
|
1175
|
+
try {
|
|
1176
|
+
return await Promise.race([
|
|
1177
|
+
promise.then(() => true),
|
|
1178
|
+
aborted
|
|
1179
|
+
]);
|
|
1180
|
+
} finally {
|
|
1181
|
+
signal.removeEventListener("abort", onAbort);
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
__name(untilAborted, "untilAborted");
|
|
1185
|
+
|
|
1186
|
+
// src/workflows/workflows-agent-runner.ts
|
|
1187
|
+
function _ts_decorate3(decorators, target, key, desc) {
|
|
1188
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1189
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
1190
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
1191
|
+
} else {
|
|
1192
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
1193
|
+
if (d = decorators[i]) {
|
|
1194
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1199
|
+
}
|
|
1200
|
+
__name(_ts_decorate3, "_ts_decorate");
|
|
1201
|
+
function _ts_metadata3(metadataKey, metadataValue) {
|
|
1202
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
1203
|
+
return Reflect.metadata(metadataKey, metadataValue);
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
__name(_ts_metadata3, "_ts_metadata");
|
|
1207
|
+
function _ts_param2(paramIndex, decorator) {
|
|
1208
|
+
return function(target, key) {
|
|
1209
|
+
decorator(target, key, paramIndex);
|
|
1210
|
+
};
|
|
1211
|
+
}
|
|
1212
|
+
__name(_ts_param2, "_ts_param");
|
|
1213
|
+
var ENDED = /* @__PURE__ */ new Set([
|
|
1214
|
+
"completed",
|
|
1215
|
+
"failed",
|
|
1216
|
+
"cancelled",
|
|
1217
|
+
"compensation_failed"
|
|
1218
|
+
]);
|
|
1219
|
+
function recorded(input) {
|
|
1220
|
+
return typeof input === "object" && input !== null ? input : {};
|
|
1221
|
+
}
|
|
1222
|
+
__name(recorded, "recorded");
|
|
1223
|
+
function deliveryOf(input) {
|
|
1224
|
+
const { deliverTo, agentName } = recorded(input);
|
|
1225
|
+
if (typeof deliverTo !== "object" || deliverTo === null || typeof deliverTo.threadId !== "string" || typeof deliverTo.toolCallId !== "string") {
|
|
1226
|
+
return void 0;
|
|
1227
|
+
}
|
|
1228
|
+
return {
|
|
1229
|
+
delivery: deliverTo,
|
|
1230
|
+
agent: typeof agentName === "string" ? agentName : "default"
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1233
|
+
__name(deliveryOf, "deliveryOf");
|
|
1234
|
+
function runContextOf(input) {
|
|
1235
|
+
const { actor, agentName, parentRunId } = recorded(input);
|
|
1236
|
+
if (typeof actor?.id !== "string") return void 0;
|
|
1237
|
+
return {
|
|
1238
|
+
actorId: actor.id,
|
|
1239
|
+
...typeof agentName === "string" ? {
|
|
1240
|
+
agentName
|
|
1241
|
+
} : {},
|
|
1242
|
+
...typeof actor.tenantRef === "string" ? {
|
|
1243
|
+
tenantRef: actor.tenantRef
|
|
1244
|
+
} : {},
|
|
1245
|
+
...typeof parentRunId === "string" ? {
|
|
1246
|
+
parentRunId
|
|
1247
|
+
} : {}
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
1250
|
+
__name(runContextOf, "runContextOf");
|
|
1251
|
+
var WorkflowsAgentRunner = class _WorkflowsAgentRunner {
|
|
1252
|
+
static {
|
|
1253
|
+
__name(this, "WorkflowsAgentRunner");
|
|
1254
|
+
}
|
|
1255
|
+
store;
|
|
1256
|
+
sink;
|
|
1257
|
+
queue;
|
|
1258
|
+
logger = new Logger2(_WorkflowsAgentRunner.name);
|
|
1259
|
+
client;
|
|
1260
|
+
constructor(store, sink, client, queue) {
|
|
1261
|
+
this.store = store;
|
|
1262
|
+
this.sink = sink;
|
|
1263
|
+
this.queue = queue;
|
|
1264
|
+
if (client === void 0) {
|
|
1265
|
+
throw new Error("AgentWorkflowsModule runs turns on @nestjs/workflows: import WorkflowsModule.forRoot() from '@nestjs/workflows' (WorkflowsModule.forRoot({ worker: false }) on a process that must not run turns, such as an API pod). No WorkflowClient was found.");
|
|
1266
|
+
}
|
|
1267
|
+
this.client = client;
|
|
1268
|
+
if (this.sink instanceof InProcessTokenStreamSink) {
|
|
1269
|
+
this.logger.warn("durable turns with the default InProcessTokenStreamSink, which only buffers tokens in this process: fine while this process runs the workflow worker, but a turn claimed by another process cannot stream to this one. Wire a cross-process TokenStreamSink (e.g. the Redis one) before running several processes.");
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
async start(input, options = {}) {
|
|
1273
|
+
const stamped = {
|
|
1274
|
+
...input,
|
|
1275
|
+
day: input.day ?? utcDay()
|
|
1276
|
+
};
|
|
1277
|
+
const runId = options.runId ?? randomUUID();
|
|
1278
|
+
await this.client.start(AgentRunFlow, stamped, {
|
|
1279
|
+
id: runId
|
|
1280
|
+
});
|
|
1281
|
+
return {
|
|
1282
|
+
runId
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
/** Not ended as far as the engine knows. An unknown run counts as running, and so does one it can't be asked about. */
|
|
1286
|
+
async isRunActive(runId) {
|
|
1287
|
+
try {
|
|
1288
|
+
const status = (await this.client.getStatus(runId))?.status;
|
|
1289
|
+
return status === void 0 || !ENDED.has(status);
|
|
1290
|
+
} catch {
|
|
1291
|
+
return true;
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
async signal(runId, toolCallId, reply) {
|
|
1295
|
+
const key = replyKey(runId, toolCallId);
|
|
1296
|
+
await this.client.signal(AGENT_REPLY, reply, {
|
|
1297
|
+
key,
|
|
1298
|
+
id: key
|
|
1299
|
+
});
|
|
1300
|
+
}
|
|
1301
|
+
/** The engine's view of a run: status, custom status, waits, children. `null` for an unknown id. */
|
|
1302
|
+
getStatus(runId) {
|
|
1303
|
+
return this.client.getStatus(runId, {
|
|
1304
|
+
children: true
|
|
1305
|
+
});
|
|
1306
|
+
}
|
|
1307
|
+
/**
|
|
1308
|
+
* The calls of run `runId` waiting for a person now, in the instance it started in, in the
|
|
1309
|
+
* instances it went on in, and in the sub-agent runs it delegated to.
|
|
1310
|
+
*/
|
|
1311
|
+
async pendingReplies(runId) {
|
|
1312
|
+
const found = [];
|
|
1313
|
+
const visit = /* @__PURE__ */ __name(async (id) => {
|
|
1314
|
+
const details = await this.client.getStatus(id, {
|
|
1315
|
+
children: true
|
|
1316
|
+
});
|
|
1317
|
+
if (details === null) return;
|
|
1318
|
+
const status = details.customStatus;
|
|
1319
|
+
found.push(...status?.pendingReplies ?? []);
|
|
1320
|
+
for (const child of details.children ?? []) {
|
|
1321
|
+
if (!ENDED.has(child.status) && child.parentClose !== "abandon") await visit(child.id);
|
|
1322
|
+
}
|
|
1323
|
+
}, "visit");
|
|
1324
|
+
await visit(runId);
|
|
1325
|
+
return found;
|
|
1326
|
+
}
|
|
1327
|
+
/**
|
|
1328
|
+
* Stop a run: the engine stops the turn at its next `ctx` call (a parked turn at once), and
|
|
1329
|
+
* cancels the sub-agent runs it is waiting on. What the engine knows nothing about is settled
|
|
1330
|
+
* here, as on the `aviary` engine: the delegation a detached run answers, the thread's queue and
|
|
1331
|
+
* live stream, the subscriber's stream (a `cancelled` frame and a normal end), the run's row.
|
|
1332
|
+
*/
|
|
1333
|
+
async cancel(runId) {
|
|
1334
|
+
this.logger.log(`cancelling agent run ${runId}`);
|
|
1335
|
+
const details = await this.client.getStatus(runId).catch(() => null);
|
|
1336
|
+
const input = details?.input;
|
|
1337
|
+
const { threadId, sinkRunId, deliverTo } = recorded(input);
|
|
1338
|
+
try {
|
|
1339
|
+
await this.client.cancel(runId, "Stopped");
|
|
1340
|
+
} catch (error) {
|
|
1341
|
+
if (!(error instanceof WorkflowNotFoundError)) throw error;
|
|
1342
|
+
}
|
|
1343
|
+
const target = deliveryOf(input);
|
|
1344
|
+
if (target !== void 0) {
|
|
1345
|
+
await settleUnsettledDelegation2({
|
|
1346
|
+
store: this.store,
|
|
1347
|
+
delivery: target.delivery,
|
|
1348
|
+
agent: target.agent,
|
|
1349
|
+
runId,
|
|
1350
|
+
status: "cancelled"
|
|
1351
|
+
}).catch((error) => this.logger.error(`could not settle the delegation of cancelled run ${runId}: ${error instanceof Error ? error.message : String(error)}`));
|
|
1352
|
+
}
|
|
1353
|
+
const writer = await this.sink.open(runId);
|
|
1354
|
+
if (typeof threadId === "string") {
|
|
1355
|
+
const threadTurn = sinkRunId === void 0 && deliverTo === void 0;
|
|
1356
|
+
if (this.queue?.supported === true && threadTurn) {
|
|
1357
|
+
try {
|
|
1358
|
+
const frame = await this.queue.handoff({
|
|
1359
|
+
threadId,
|
|
1360
|
+
runId,
|
|
1361
|
+
outcome: "cancelled"
|
|
1362
|
+
}, (next, nextRunId) => this.start(next, {
|
|
1363
|
+
runId: nextRunId
|
|
1364
|
+
}));
|
|
1365
|
+
if (frame !== void 0) await writer.write(encodeStreamEvent3(frame));
|
|
1366
|
+
} catch (error) {
|
|
1367
|
+
this.logger.error(`could not advance the queue of thread ${threadId} after cancelling ${runId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
await releaseThreadRun2(this.store, threadId, runId);
|
|
1371
|
+
}
|
|
1372
|
+
await writer.write(encodeStreamEvent3({
|
|
1373
|
+
kind: "cancelled"
|
|
1374
|
+
}));
|
|
1375
|
+
await writer.end();
|
|
1376
|
+
const durationMs = details !== null && details !== void 0 ? Math.max(0, details.updatedAt - details.createdAt) : void 0;
|
|
1377
|
+
const context = runContextOf(input);
|
|
1378
|
+
publishAgentRunCancelled({
|
|
1379
|
+
runId,
|
|
1380
|
+
...typeof threadId === "string" ? {
|
|
1381
|
+
threadId
|
|
1382
|
+
} : {},
|
|
1383
|
+
...durationMs !== void 0 ? {
|
|
1384
|
+
durationMs
|
|
1385
|
+
} : {},
|
|
1386
|
+
...context !== void 0 ? {
|
|
1387
|
+
context
|
|
1388
|
+
} : {}
|
|
1389
|
+
});
|
|
1390
|
+
await this.store.recordRunEnd?.({
|
|
1391
|
+
runId,
|
|
1392
|
+
status: "cancelled",
|
|
1393
|
+
...durationMs !== void 0 ? {
|
|
1394
|
+
durationMs
|
|
1395
|
+
} : {}
|
|
1396
|
+
});
|
|
1397
|
+
}
|
|
1398
|
+
};
|
|
1399
|
+
WorkflowsAgentRunner = _ts_decorate3([
|
|
1400
|
+
Injectable2(),
|
|
1401
|
+
_ts_param2(0, Inject2(AGENT_STORE2)),
|
|
1402
|
+
_ts_param2(1, Inject2(AGENT_SINK)),
|
|
1403
|
+
_ts_param2(2, Optional2()),
|
|
1404
|
+
_ts_param2(3, Optional2()),
|
|
1405
|
+
_ts_param2(3, Inject2(AGENT_CHAT_QUEUE)),
|
|
1406
|
+
_ts_metadata3("design:type", Function),
|
|
1407
|
+
_ts_metadata3("design:paramtypes", [
|
|
1408
|
+
typeof AgentStore === "undefined" ? Object : AgentStore,
|
|
1409
|
+
typeof TokenStreamSink === "undefined" ? Object : TokenStreamSink,
|
|
1410
|
+
typeof WorkflowClient2 === "undefined" ? Object : WorkflowClient2,
|
|
1411
|
+
typeof ChatQueueService === "undefined" ? Object : ChatQueueService
|
|
1412
|
+
])
|
|
1413
|
+
], WorkflowsAgentRunner);
|
|
1414
|
+
|
|
1415
|
+
// src/workflows/agent-workflows.module.ts
|
|
1416
|
+
function _ts_decorate4(decorators, target, key, desc) {
|
|
1417
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1418
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
1419
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
1420
|
+
} else {
|
|
1421
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
1422
|
+
if (d = decorators[i]) {
|
|
1423
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1428
|
+
}
|
|
1429
|
+
__name(_ts_decorate4, "_ts_decorate");
|
|
1430
|
+
var AgentWorkflowsModule = class {
|
|
1431
|
+
static {
|
|
1432
|
+
__name(this, "AgentWorkflowsModule");
|
|
1433
|
+
}
|
|
1434
|
+
};
|
|
1435
|
+
AgentWorkflowsModule = _ts_decorate4([
|
|
1436
|
+
Global(),
|
|
1437
|
+
Module({
|
|
1438
|
+
providers: [
|
|
1439
|
+
AgentTurnExecutor,
|
|
1440
|
+
AgentRunFlow,
|
|
1441
|
+
AgentRunSegmentFlow,
|
|
1442
|
+
WorkflowsAgentRunner,
|
|
1443
|
+
{
|
|
1444
|
+
provide: AGENT_WORKFLOWS_RUNNER,
|
|
1445
|
+
useExisting: WorkflowsAgentRunner
|
|
1446
|
+
}
|
|
1447
|
+
],
|
|
1448
|
+
exports: [
|
|
1449
|
+
AGENT_WORKFLOWS_RUNNER,
|
|
1450
|
+
WorkflowsAgentRunner
|
|
1451
|
+
]
|
|
1452
|
+
})
|
|
1453
|
+
], AgentWorkflowsModule);
|
|
1454
|
+
export {
|
|
1455
|
+
AGENT_REPLY,
|
|
1456
|
+
AGENT_RUN_SEGMENT_WORKFLOW,
|
|
1457
|
+
AGENT_RUN_WORKFLOW,
|
|
1458
|
+
AgentRunFlow,
|
|
1459
|
+
AgentRunSegmentFlow,
|
|
1460
|
+
AgentWorkflowsModule,
|
|
1461
|
+
WorkflowsAgentRunner,
|
|
1462
|
+
replyKey
|
|
1463
|
+
};
|
|
1464
|
+
//# sourceMappingURL=index.js.map
|