@dudousxd/nestjs-agent 1.17.0 → 1.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chat-queue.service-Bqq00NN1.d.cts → chat-queue.service-5LIogd9K.d.cts} +27 -1
- package/dist/{chat-queue.service-Bqq00NN1.d.ts → chat-queue.service-5LIogd9K.d.ts} +27 -1
- package/dist/durable/index.cjs +1015 -955
- package/dist/durable/index.cjs.map +1 -1
- package/dist/durable/index.d.cts +1 -1
- package/dist/durable/index.d.ts +1 -1
- package/dist/durable/index.js +968 -908
- package/dist/durable/index.js.map +1 -1
- package/dist/index.cjs +400 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +87 -5
- package/dist/index.d.ts +87 -5
- package/dist/index.js +392 -11
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
package/dist/durable/index.cjs
CHANGED
|
@@ -30,10 +30,10 @@ __export(durable_exports, {
|
|
|
30
30
|
module.exports = __toCommonJS(durable_exports);
|
|
31
31
|
|
|
32
32
|
// src/durable/agent-run.workflow.ts
|
|
33
|
-
var
|
|
33
|
+
var import_nestjs_agent_core2 = require("@dudousxd/nestjs-agent-core");
|
|
34
34
|
var import_nestjs_durable2 = require("@dudousxd/nestjs-durable");
|
|
35
35
|
var import_nestjs_durable_core2 = require("@dudousxd/nestjs-durable-core");
|
|
36
|
-
var
|
|
36
|
+
var import_common2 = require("@nestjs/common");
|
|
37
37
|
|
|
38
38
|
// src/agent-deps.ts
|
|
39
39
|
function utcDay(date = /* @__PURE__ */ new Date()) {
|
|
@@ -51,9 +51,26 @@ function childSinkWriter(writer) {
|
|
|
51
51
|
}
|
|
52
52
|
__name(childSinkWriter, "childSinkWriter");
|
|
53
53
|
|
|
54
|
-
// src/queue/chat-queue.
|
|
54
|
+
// src/queue/chat-queue.token.ts
|
|
55
|
+
var AGENT_CHAT_QUEUE = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent:chat-queue");
|
|
56
|
+
|
|
57
|
+
// src/durable/agent-run.steps.ts
|
|
55
58
|
var import_nestjs_agent_core = require("@dudousxd/nestjs-agent-core");
|
|
59
|
+
var import_nestjs_durable = require("@dudousxd/nestjs-durable");
|
|
56
60
|
var import_common = require("@nestjs/common");
|
|
61
|
+
|
|
62
|
+
// src/durable/outside-workflow-ctx.ts
|
|
63
|
+
var import_nestjs_durable_core = require("@dudousxd/nestjs-durable-core");
|
|
64
|
+
function outsideWorkflowCtx(fn) {
|
|
65
|
+
return (0, import_nestjs_durable_core.runInWorkflowCtx)(void 0, fn);
|
|
66
|
+
}
|
|
67
|
+
__name(outsideWorkflowCtx, "outsideWorkflowCtx");
|
|
68
|
+
function stepOf(ctx) {
|
|
69
|
+
return (name, fn, ...rest) => ctx.localStep(name, (...args) => outsideWorkflowCtx(() => fn(...args)), ...rest);
|
|
70
|
+
}
|
|
71
|
+
__name(stepOf, "stepOf");
|
|
72
|
+
|
|
73
|
+
// src/durable/agent-run.steps.ts
|
|
57
74
|
function _ts_decorate(decorators, target, key, desc) {
|
|
58
75
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
59
76
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -80,737 +97,296 @@ function _ts_param(paramIndex, decorator) {
|
|
|
80
97
|
};
|
|
81
98
|
}
|
|
82
99
|
__name(_ts_param, "_ts_param");
|
|
83
|
-
var
|
|
84
|
-
var ChatQueueService = class _ChatQueueService {
|
|
100
|
+
var AgentRunSteps = class {
|
|
85
101
|
static {
|
|
86
|
-
__name(this, "
|
|
102
|
+
__name(this, "AgentRunSteps");
|
|
103
|
+
}
|
|
104
|
+
factory;
|
|
105
|
+
constructor(factory) {
|
|
106
|
+
this.factory = factory;
|
|
87
107
|
}
|
|
88
|
-
store;
|
|
89
|
-
sink;
|
|
90
|
-
quotaProvider;
|
|
91
|
-
options;
|
|
92
|
-
staging;
|
|
93
|
-
logger = new import_common.Logger(_ChatQueueService.name);
|
|
94
108
|
/**
|
|
95
|
-
*
|
|
96
|
-
*
|
|
109
|
+
* Retryable: every side effect (persist/quota/stream markers) happens loop-side under
|
|
110
|
+
* `hooks.step`, so a durable retry only re-runs the model call and re-streams its tokens — never
|
|
111
|
+
* double-writes. NEVER call `writer.end()`/`fail()` here: the workflow owns the stream's lifecycle,
|
|
112
|
+
* across however many turns/retries it takes.
|
|
97
113
|
*/
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
this.store = store;
|
|
101
|
-
this.sink = sink;
|
|
102
|
-
this.quotaProvider = quotaProvider;
|
|
103
|
-
this.options = options;
|
|
104
|
-
this.staging = staging;
|
|
105
|
-
}
|
|
106
|
-
/** Whether the bound store can hold a queue. Without one, a busy thread is not queued. */
|
|
107
|
-
get supported() {
|
|
108
|
-
return (0, import_nestjs_agent_core.isChatQueueStore)(this.store);
|
|
114
|
+
llm(input) {
|
|
115
|
+
return outsideWorkflowCtx(() => this.runLlm(input));
|
|
109
116
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
117
|
+
async runLlm(input) {
|
|
118
|
+
const deps = this.factory.forAgent(input.agentName);
|
|
119
|
+
const tools = (0, import_nestjs_agent_core.withMemoryTool)({
|
|
120
|
+
tools: (0, import_nestjs_agent_core.withSkillTool)({
|
|
121
|
+
tools: (0, import_nestjs_agent_core.withAskTool)({
|
|
122
|
+
tools: await deps.registry.definitionsFor(input.actor, deps.rolesPolicy, deps.toolAllowList, {
|
|
123
|
+
...input.threadId !== void 0 ? {
|
|
124
|
+
threadId: input.threadId
|
|
125
|
+
} : {},
|
|
126
|
+
...input.agentName !== void 0 ? {
|
|
127
|
+
agentName: input.agentName
|
|
128
|
+
} : {}
|
|
129
|
+
}),
|
|
130
|
+
ask: deps.ask
|
|
131
|
+
}),
|
|
132
|
+
enabled: deps.skills !== void 0
|
|
133
|
+
}),
|
|
134
|
+
enabled: deps.memory?.provider.write !== void 0
|
|
135
|
+
});
|
|
136
|
+
const buffer = input.bufferOutput === true ? (0, import_nestjs_agent_core.createFrameBuffer)() : void 0;
|
|
137
|
+
let writer;
|
|
138
|
+
if (buffer !== void 0) {
|
|
139
|
+
writer = buffer.writer;
|
|
140
|
+
} else {
|
|
141
|
+
const opened = await deps.sink.open(input.sinkRunId);
|
|
142
|
+
writer = input.childSink ? childSinkWriter(opened) : opened;
|
|
114
143
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
144
|
+
const frames = (0, import_nestjs_agent_core.observeTurnFrames)(writer);
|
|
145
|
+
const turn = (0, import_nestjs_agent_core.withTurnFrames)(await (0, import_nestjs_agent_core.traceLlmTurn)(input.runId, input.step, () => deps.model.runTurn({
|
|
146
|
+
system: input.system,
|
|
147
|
+
messages: input.messages,
|
|
148
|
+
tools,
|
|
149
|
+
sink: frames.writer,
|
|
150
|
+
...input.model !== void 0 ? {
|
|
151
|
+
model: input.model
|
|
152
|
+
} : {}
|
|
153
|
+
})), frames.summary());
|
|
154
|
+
const stamped = (0, import_nestjs_agent_core.stampToolKinds)(turn, deps);
|
|
155
|
+
return buffer === void 0 ? stamped : {
|
|
156
|
+
...stamped,
|
|
157
|
+
bufferedFrames: buffer.frames()
|
|
126
158
|
};
|
|
127
159
|
}
|
|
128
160
|
/**
|
|
129
|
-
*
|
|
130
|
-
*
|
|
161
|
+
* NO DURABLE retries — a tool may not be idempotent (a bare `@Step()` carries none, unlike `llm`
|
|
162
|
+
* above). What it does retry, in place, is a CLASSIFIED-TRANSIENT error from the tool's own
|
|
163
|
+
* invocation (a DB deadlock, a lock-wait timeout — see `isTransientToolError`): the server rolled
|
|
164
|
+
* that work back, so re-invoking it is safe, and doing it here (inside this one step, never a new
|
|
165
|
+
* checkpoint) is exactly how the non-dispatched loop path handles it too. The timeout is applied
|
|
166
|
+
* HERE, handler-side, via `withToolTimeout` — never as a durable dispatch `timeoutMs`, which
|
|
167
|
+
* bounds engine liveness (retryable) rather than the tool's own business outcome — and per
|
|
168
|
+
* ATTEMPT, so a retried invocation gets its own fresh timeout window.
|
|
131
169
|
*/
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
return true;
|
|
135
|
-
}
|
|
136
|
-
if (typeof runner.isRunActive !== "function") {
|
|
137
|
-
return true;
|
|
138
|
-
}
|
|
139
|
-
try {
|
|
140
|
-
return await runner.isRunActive(holder);
|
|
141
|
-
} catch {
|
|
142
|
-
return true;
|
|
143
|
-
}
|
|
170
|
+
tool(input) {
|
|
171
|
+
return outsideWorkflowCtx(() => this.runTool(input));
|
|
144
172
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
async holder(threadId, runner) {
|
|
150
|
-
const holder = await this.queueStore().activeRunForThread(threadId);
|
|
151
|
-
if (holder === null) {
|
|
152
|
-
return {
|
|
153
|
-
live: null,
|
|
154
|
-
stale: null
|
|
155
|
-
};
|
|
173
|
+
async runTool(input) {
|
|
174
|
+
const deps = this.factory.forAgent(input.ctx.agentName);
|
|
175
|
+
if (deps.registry.spec(input.toolName)?.kind === "action" && input.toolType !== "action") {
|
|
176
|
+
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`);
|
|
156
177
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
178
|
+
const sinkRunId = input.sinkRunId;
|
|
179
|
+
let opened;
|
|
180
|
+
const ui = (0, import_nestjs_agent_core.createUiCollector)(input.toolCallId, sinkRunId === void 0 ? void 0 : async (event) => {
|
|
181
|
+
opened ??= Promise.resolve(deps.sink.open(sinkRunId)).then((writer) => input.childSink === true ? childSinkWriter(writer) : writer);
|
|
182
|
+
await (await opened).write((0, import_nestjs_agent_core.encodeStreamEvent)(event));
|
|
183
|
+
});
|
|
184
|
+
const ctx = {
|
|
185
|
+
...(0, import_nestjs_agent_core.toolCallContext)(input.ctx, input.toolCallId),
|
|
186
|
+
emitUi: ui.emit
|
|
187
|
+
};
|
|
188
|
+
const localClassify = deps.toolTransientRetry !== false ? deps.toolTransientRetry?.classify : void 0;
|
|
189
|
+
const transientRetry = input.transientRetry === false ? false : {
|
|
190
|
+
attempts: input.transientRetry.attempts,
|
|
191
|
+
backoffMs: input.transientRetry.backoffMs,
|
|
192
|
+
...localClassify !== void 0 ? {
|
|
193
|
+
classify: localClassify
|
|
194
|
+
} : {}
|
|
163
195
|
};
|
|
196
|
+
const output = await (0, import_nestjs_agent_core.traceToolExecution)(input.ctx.runId, {
|
|
197
|
+
toolCallId: input.toolCallId,
|
|
198
|
+
toolName: input.toolName,
|
|
199
|
+
toolType: input.toolType
|
|
200
|
+
}, () => (0, import_nestjs_agent_core.invokeWithTransientRetry)(() => {
|
|
201
|
+
ui.restart();
|
|
202
|
+
const invocation = deps.registry.invoke(input.toolName, input.input, ctx, deps.rolesPolicy);
|
|
203
|
+
return input.timeoutMs !== void 0 ? (0, import_nestjs_agent_core.withToolTimeout)(invocation, input.timeoutMs, input.toolName) : invocation;
|
|
204
|
+
}, transientRetry, {
|
|
205
|
+
onRetry: /* @__PURE__ */ __name((attempt, error) => {
|
|
206
|
+
(0, import_nestjs_agent_core.publishAgentToolRetry)({
|
|
207
|
+
toolName: input.toolName,
|
|
208
|
+
toolCallId: input.toolCallId,
|
|
209
|
+
attempt,
|
|
210
|
+
message: error instanceof Error ? error.message : String(error)
|
|
211
|
+
});
|
|
212
|
+
}, "onRetry")
|
|
213
|
+
}));
|
|
214
|
+
return input.collectUi === true ? (0, import_nestjs_agent_core.wrapToolStepOutput)(output, ui.components()) : output;
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
_ts_decorate([
|
|
218
|
+
(0, import_nestjs_durable.Step)({
|
|
219
|
+
retries: 3
|
|
220
|
+
}),
|
|
221
|
+
_ts_metadata("design:type", Function),
|
|
222
|
+
_ts_metadata("design:paramtypes", [
|
|
223
|
+
typeof DispatchedLlmInput === "undefined" ? Object : DispatchedLlmInput
|
|
224
|
+
]),
|
|
225
|
+
_ts_metadata("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
226
|
+
], AgentRunSteps.prototype, "llm", null);
|
|
227
|
+
_ts_decorate([
|
|
228
|
+
(0, import_nestjs_durable.Step)(),
|
|
229
|
+
_ts_metadata("design:type", Function),
|
|
230
|
+
_ts_metadata("design:paramtypes", [
|
|
231
|
+
typeof DispatchedToolInput === "undefined" ? Object : DispatchedToolInput
|
|
232
|
+
]),
|
|
233
|
+
_ts_metadata("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
234
|
+
], AgentRunSteps.prototype, "tool", null);
|
|
235
|
+
AgentRunSteps = _ts_decorate([
|
|
236
|
+
(0, import_common.Injectable)(),
|
|
237
|
+
_ts_param(0, (0, import_common.Inject)(import_nestjs_agent_core.AGENT_DEPS_FACTORY)),
|
|
238
|
+
_ts_metadata("design:type", Function),
|
|
239
|
+
_ts_metadata("design:paramtypes", [
|
|
240
|
+
typeof AgentDepsFactory === "undefined" ? Object : AgentDepsFactory
|
|
241
|
+
])
|
|
242
|
+
], AgentRunSteps);
|
|
243
|
+
|
|
244
|
+
// src/durable/agent-run.workflow.ts
|
|
245
|
+
function _ts_decorate2(decorators, target, key, desc) {
|
|
246
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
247
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
248
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
249
|
+
} else {
|
|
250
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
251
|
+
if (d = decorators[i]) {
|
|
252
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
257
|
+
}
|
|
258
|
+
__name(_ts_decorate2, "_ts_decorate");
|
|
259
|
+
function _ts_metadata2(metadataKey, metadataValue) {
|
|
260
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
261
|
+
return Reflect.metadata(metadataKey, metadataValue);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
__name(_ts_metadata2, "_ts_metadata");
|
|
265
|
+
function _ts_param2(paramIndex, decorator) {
|
|
266
|
+
return function(target, key) {
|
|
267
|
+
decorator(target, key, paramIndex);
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
__name(_ts_param2, "_ts_param");
|
|
271
|
+
var AgentRunWorkflow = class _AgentRunWorkflow {
|
|
272
|
+
static {
|
|
273
|
+
__name(this, "AgentRunWorkflow");
|
|
274
|
+
}
|
|
275
|
+
factory;
|
|
276
|
+
store;
|
|
277
|
+
runs;
|
|
278
|
+
queue;
|
|
279
|
+
logger = new import_common2.Logger(_AgentRunWorkflow.name);
|
|
280
|
+
constructor(factory, store, runs, queue) {
|
|
281
|
+
this.factory = factory;
|
|
282
|
+
this.store = store;
|
|
283
|
+
this.runs = runs;
|
|
284
|
+
this.queue = queue;
|
|
164
285
|
}
|
|
165
286
|
/**
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
* the queue
|
|
169
|
-
* the stream learns what comes next from the `queue` frame, and so the thread is already free
|
|
170
|
-
* when the client sees the run end.
|
|
287
|
+
* Move the thread past this settling turn — to the next queued message, started here as a
|
|
288
|
+
* fire-and-forget `ctx.startChild` under the message's own id, or to a paused/empty queue — and
|
|
289
|
+
* answer the `queue` frame to write before the turn's terminal.
|
|
171
290
|
*
|
|
172
|
-
*
|
|
291
|
+
* Journaled: the decision (which message, claimed and popped) is one `localStep`, so a replay
|
|
292
|
+
* reads it back instead of popping a second message, and the start is the runtime's own
|
|
293
|
+
* replay-safe spawn. Gated by `ctx.patched`, so a run recorded before the queue existed replays
|
|
294
|
+
* against the history it has. A no-op for a sub-agent's run and on a store without a queue.
|
|
173
295
|
*/
|
|
174
|
-
async
|
|
175
|
-
|
|
176
|
-
|
|
296
|
+
async advanceQueue(ctx, input, outcome, error) {
|
|
297
|
+
const queue = this.queue;
|
|
298
|
+
if (queue === void 0 || !queue.supported || input.sinkRunId !== void 0 || input.deliverTo !== void 0) {
|
|
299
|
+
return void 0;
|
|
177
300
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
if (await store.activeRunForThread(threadId) !== args.runId) {
|
|
181
|
-
return {};
|
|
301
|
+
if (!await ctx.patched("agent:chat-queue")) {
|
|
302
|
+
return void 0;
|
|
182
303
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
let pause = await store.queuePause(threadId);
|
|
196
|
-
if (pause === null) {
|
|
197
|
-
const reason = pauseReasonFor(outcome, head);
|
|
198
|
-
if (reason !== null) {
|
|
199
|
-
pause = {
|
|
200
|
-
reason,
|
|
201
|
-
...outcome === "failed" && args.error !== void 0 ? {
|
|
202
|
-
message: args.error
|
|
203
|
-
} : {},
|
|
204
|
-
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
205
|
-
};
|
|
206
|
-
await store.setQueuePause(threadId, pause);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
if (pause === null) {
|
|
210
|
-
const blocked = await this.quotaBlock(head.actor);
|
|
211
|
-
if (blocked !== null) {
|
|
212
|
-
pause = {
|
|
213
|
-
reason: "quota_exceeded",
|
|
214
|
-
message: blocked,
|
|
215
|
-
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
216
|
-
};
|
|
217
|
-
await store.setQueuePause(threadId, pause);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
if (pause !== null) {
|
|
221
|
-
if (holding !== null) {
|
|
222
|
-
await store.releaseActiveStream(threadId, holding);
|
|
223
|
-
}
|
|
224
|
-
return {
|
|
225
|
-
frame: queueFrame(items, pause)
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
const claimed = await store.claimActiveStream(threadId, head.id, holding !== null ? {
|
|
229
|
-
replacing: holding
|
|
230
|
-
} : {});
|
|
231
|
-
if (!claimed) {
|
|
304
|
+
const plan = await stepOf(ctx)(`queue:${outcome}`, async () => {
|
|
305
|
+
try {
|
|
306
|
+
const settled = outcome === "completed" && await this.isCancelled(ctx.runId) ? "cancelled" : outcome;
|
|
307
|
+
return await queue.plan({
|
|
308
|
+
threadId: input.threadId,
|
|
309
|
+
runId: ctx.runId,
|
|
310
|
+
outcome: settled,
|
|
311
|
+
...error !== void 0 ? {
|
|
312
|
+
error
|
|
313
|
+
} : {}
|
|
314
|
+
});
|
|
315
|
+
} catch {
|
|
232
316
|
return {};
|
|
233
317
|
}
|
|
234
|
-
holding = head.id;
|
|
235
|
-
if (!await store.removeQueuedMessage(head.id)) {
|
|
236
|
-
await store.releaseActiveStream(threadId, head.id);
|
|
237
|
-
holding = null;
|
|
238
|
-
continue;
|
|
239
|
-
}
|
|
240
|
-
const next = {
|
|
241
|
-
runId: head.id,
|
|
242
|
-
messageId: head.id,
|
|
243
|
-
input: await this.inputFor(head)
|
|
244
|
-
};
|
|
245
|
-
return {
|
|
246
|
-
next,
|
|
247
|
-
frame: queueFrame(items.slice(1), null, {
|
|
248
|
-
messageId: head.id,
|
|
249
|
-
runId: head.id
|
|
250
|
-
})
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
if (holding !== null) {
|
|
254
|
-
await store.releaseActiveStream(threadId, holding);
|
|
255
|
-
}
|
|
256
|
-
return {};
|
|
257
|
-
}
|
|
258
|
-
/**
|
|
259
|
-
* {@link plan}, then start what it picked with `start`. What an in-process settle (the inline
|
|
260
|
-
* runner, a durable cancel issued outside a workflow) calls; answers the frame to write.
|
|
261
|
-
*/
|
|
262
|
-
async handoff(args, start) {
|
|
263
|
-
const plan = await this.plan(args);
|
|
264
|
-
if (plan.next === void 0) {
|
|
265
|
-
return plan.frame;
|
|
266
|
-
}
|
|
267
|
-
return await this.launch(args.threadId, plan.next, start) ? plan.frame : this.pausedFrame(args.threadId);
|
|
268
|
-
}
|
|
269
|
-
/**
|
|
270
|
-
* Start the head of an IDLE thread's queue — after a send queued behind a run that turned out to
|
|
271
|
-
* be gone, after a resume, after a stale holder. Does nothing while a live run holds the thread
|
|
272
|
-
* (its settle drains) or while the queue is paused. Answers the started run's id, if any.
|
|
273
|
-
*/
|
|
274
|
-
async kick(threadId, runner) {
|
|
275
|
-
if (!(0, import_nestjs_agent_core.isChatQueueStore)(this.store)) {
|
|
276
|
-
return void 0;
|
|
277
|
-
}
|
|
278
|
-
const { live, stale } = await this.holder(threadId, runner);
|
|
279
|
-
if (live !== null) {
|
|
280
|
-
return void 0;
|
|
281
|
-
}
|
|
282
|
-
if (stale !== null) {
|
|
283
|
-
this.logger.warn(`thread ${threadId} was held by run ${stale}, which is no longer running`);
|
|
284
|
-
}
|
|
285
|
-
const plan = await this.plan({
|
|
286
|
-
threadId,
|
|
287
|
-
runId: stale,
|
|
288
|
-
outcome: "completed"
|
|
289
318
|
});
|
|
290
|
-
|
|
291
|
-
|
|
319
|
+
const next = plan.next;
|
|
320
|
+
if (next === void 0) {
|
|
321
|
+
return plan.frame;
|
|
292
322
|
}
|
|
293
|
-
|
|
294
|
-
runId
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
323
|
+
try {
|
|
324
|
+
await ctx.startChild(_AgentRunWorkflow, next.input, next.runId);
|
|
325
|
+
return plan.frame;
|
|
326
|
+
} catch (failure) {
|
|
327
|
+
if ((0, import_nestjs_durable_core2.isWorkflowControlFlowSignal)(failure)) {
|
|
328
|
+
throw failure;
|
|
329
|
+
}
|
|
330
|
+
const reason = failure instanceof Error ? failure.message : String(failure);
|
|
331
|
+
return stepOf(ctx)("queue:restore", async () => {
|
|
332
|
+
await queue.restore(input.threadId, next, "start_failed", reason);
|
|
333
|
+
return queue.pausedFrame(input.threadId);
|
|
334
|
+
});
|
|
298
335
|
}
|
|
299
|
-
return started ? plan.next.runId : void 0;
|
|
300
336
|
}
|
|
301
337
|
/**
|
|
302
|
-
*
|
|
303
|
-
*
|
|
304
|
-
*
|
|
338
|
+
* Has someone asked this run to stop? Read from the runtime's own run status, which is where
|
|
339
|
+
* `DurableAgentRunner.cancel` puts it — `cancelling` while a compensating cancel is in flight,
|
|
340
|
+
* `cancelled` once it has settled.
|
|
341
|
+
*
|
|
342
|
+
* Costs a run read at each of the loop's observation points (two per step). That is a row the
|
|
343
|
+
* control plane already has, against a turn that is otherwise making model calls, and it buys the
|
|
344
|
+
* property that matters: the answer comes from a place BOTH the canceller and every pod that might
|
|
345
|
+
* replay this run can see.
|
|
346
|
+
*
|
|
347
|
+
* Failing to ask is not a cancel. A tenant with no gateway wired, or an operator briefly
|
|
348
|
+
* unreachable, answers "no" and the run carries on — the alternative is failing healthy runs
|
|
349
|
+
* because a status read timed out. The loop journals that answer like any other, so two processes
|
|
350
|
+
* can never disagree about what was seen here.
|
|
305
351
|
*/
|
|
306
|
-
async
|
|
307
|
-
this.starting.add(next.runId);
|
|
352
|
+
async isCancelled(runId) {
|
|
308
353
|
try {
|
|
309
|
-
|
|
310
|
-
return
|
|
311
|
-
} catch
|
|
312
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
313
|
-
this.logger.error(`queued message ${next.messageId} could not start: ${message}`);
|
|
314
|
-
await this.restore(threadId, next, "start_failed", message);
|
|
354
|
+
const status = (await this.runs?.getRunDetail(runId))?.run.status;
|
|
355
|
+
return status === "cancelled" || status === "cancelling";
|
|
356
|
+
} catch {
|
|
315
357
|
return false;
|
|
316
|
-
} finally {
|
|
317
|
-
this.starting.delete(next.runId);
|
|
318
358
|
}
|
|
319
359
|
}
|
|
320
|
-
/** Put a turn that never started back at the head of its queue, paused, and free the thread. */
|
|
321
|
-
async restore(threadId, next, reason, message) {
|
|
322
|
-
const store = this.queueStore();
|
|
323
|
-
const { input } = next;
|
|
324
|
-
await store.enqueueMessage({
|
|
325
|
-
threadId,
|
|
326
|
-
actor: input.actor,
|
|
327
|
-
content: input.userText,
|
|
328
|
-
at: "head",
|
|
329
|
-
...input.attachments !== void 0 ? {
|
|
330
|
-
attachments: input.attachments
|
|
331
|
-
} : {},
|
|
332
|
-
...input.agentName !== void 0 ? {
|
|
333
|
-
agentName: input.agentName
|
|
334
|
-
} : {},
|
|
335
|
-
...input.model !== void 0 ? {
|
|
336
|
-
model: input.model
|
|
337
|
-
} : {},
|
|
338
|
-
...input.pageContext !== void 0 ? {
|
|
339
|
-
pageContext: input.pageContext
|
|
340
|
-
} : {}
|
|
341
|
-
});
|
|
342
|
-
await store.setQueuePause(threadId, {
|
|
343
|
-
reason,
|
|
344
|
-
message,
|
|
345
|
-
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
346
|
-
});
|
|
347
|
-
await store.releaseActiveStream(threadId, next.runId);
|
|
348
|
-
}
|
|
349
|
-
/** A `queue` frame with the thread's current state. */
|
|
350
|
-
async pausedFrame(threadId) {
|
|
351
|
-
return {
|
|
352
|
-
kind: "queue",
|
|
353
|
-
queue: await this.state(threadId)
|
|
354
|
-
};
|
|
355
|
-
}
|
|
356
360
|
/**
|
|
357
|
-
*
|
|
358
|
-
*
|
|
359
|
-
*
|
|
361
|
+
* Settle the delegation a DETACHED run was started for, when that run ends without an answer.
|
|
362
|
+
*
|
|
363
|
+
* The loop delivers its own success (`deliver:detached`) but cannot catch its own crash, and the
|
|
364
|
+
* runtime settles the run row without knowing anything delegated it. Left alone, the card in the
|
|
365
|
+
* calling conversation says "started" for ever — the one state a reader can neither wait on nor
|
|
366
|
+
* act on. A no-op for every other run: only a detached one carries a delivery address.
|
|
360
367
|
*/
|
|
361
|
-
async
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
await this.write(holder, {
|
|
366
|
-
kind: "queue",
|
|
367
|
-
queue: state
|
|
368
|
-
}).catch((error) => {
|
|
369
|
-
this.logger.warn(`could not publish the queue of thread ${threadId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
370
|
-
});
|
|
368
|
+
async settleDetachedParent(ctx, input, outcome) {
|
|
369
|
+
const delivery = input.deliverTo;
|
|
370
|
+
if (delivery === void 0) {
|
|
371
|
+
return;
|
|
371
372
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
373
|
+
await stepOf(ctx)("deliver:detached:unsettled", () => (0, import_nestjs_agent_core2.settleUnsettledDelegation)({
|
|
374
|
+
store: this.store,
|
|
375
|
+
delivery,
|
|
376
|
+
agent: input.agentName ?? "default",
|
|
377
|
+
runId: ctx.runId,
|
|
378
|
+
status: outcome.status,
|
|
379
|
+
...outcome.error !== void 0 ? {
|
|
380
|
+
error: outcome.error
|
|
381
|
+
} : {}
|
|
382
|
+
}));
|
|
377
383
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
const { blocked } = await this.quotaProvider.report({
|
|
385
|
-
actor
|
|
386
|
-
});
|
|
387
|
-
if (blocked === void 0) {
|
|
388
|
-
return null;
|
|
389
|
-
}
|
|
390
|
-
return blocked.reason ?? `The ${blocked.period === "day" ? "daily" : "monthly"} quota is used up`;
|
|
391
|
-
} catch {
|
|
392
|
-
return null;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
/**
|
|
396
|
-
* The turn a queued message starts: everything it was queued with, today's date, and its
|
|
397
|
-
* attachments' urls minted afresh — the ones stored at enqueue time may have expired while it
|
|
398
|
-
* waited. An attachment the staging store no longer resolves keeps its stored url.
|
|
399
|
-
*/
|
|
400
|
-
async inputFor(message) {
|
|
401
|
-
const attachments = await this.freshAttachments(message.actor, message.attachments ?? []);
|
|
402
|
-
return {
|
|
403
|
-
threadId: message.threadId,
|
|
404
|
-
actor: message.actor,
|
|
405
|
-
userText: message.content,
|
|
406
|
-
day: utcDay(),
|
|
407
|
-
...message.agentName !== void 0 ? {
|
|
408
|
-
agentName: message.agentName
|
|
409
|
-
} : {},
|
|
410
|
-
...attachments.length > 0 ? {
|
|
411
|
-
attachments
|
|
412
|
-
} : {},
|
|
413
|
-
...message.pageContext !== void 0 ? {
|
|
414
|
-
pageContext: message.pageContext
|
|
415
|
-
} : {},
|
|
416
|
-
...message.model !== void 0 ? {
|
|
417
|
-
model: message.model
|
|
418
|
-
} : {}
|
|
419
|
-
};
|
|
420
|
-
}
|
|
421
|
-
async freshAttachments(actor, attachments) {
|
|
422
|
-
const staging = this.staging;
|
|
423
|
-
if (attachments.length === 0 || staging === void 0 || typeof staging.resolve !== "function") {
|
|
424
|
-
return attachments;
|
|
425
|
-
}
|
|
426
|
-
return Promise.all(attachments.map(async (attachment) => {
|
|
427
|
-
try {
|
|
428
|
-
return await staging.resolve({
|
|
429
|
-
mediaId: attachment.mediaId,
|
|
430
|
-
actor
|
|
431
|
-
}) ?? attachment;
|
|
432
|
-
} catch {
|
|
433
|
-
return attachment;
|
|
434
|
-
}
|
|
435
|
-
}));
|
|
436
|
-
}
|
|
437
|
-
};
|
|
438
|
-
ChatQueueService = _ts_decorate([
|
|
439
|
-
(0, import_common.Injectable)(),
|
|
440
|
-
_ts_param(0, (0, import_common.Inject)(import_nestjs_agent_core.AGENT_STORE)),
|
|
441
|
-
_ts_param(1, (0, import_common.Inject)(import_nestjs_agent_core.AGENT_SINK)),
|
|
442
|
-
_ts_param(2, (0, import_common.Optional)()),
|
|
443
|
-
_ts_param(2, (0, import_common.Inject)(import_nestjs_agent_core.AGENT_QUOTA_PROVIDER)),
|
|
444
|
-
_ts_param(3, (0, import_common.Optional)()),
|
|
445
|
-
_ts_param(3, (0, import_common.Inject)(import_nestjs_agent_core.AGENT_OPTIONS)),
|
|
446
|
-
_ts_param(4, (0, import_common.Optional)()),
|
|
447
|
-
_ts_param(4, (0, import_common.Inject)(import_nestjs_agent_core.AGENT_ATTACHMENT_STAGING)),
|
|
448
|
-
_ts_metadata("design:type", Function),
|
|
449
|
-
_ts_metadata("design:paramtypes", [
|
|
450
|
-
typeof AgentStore === "undefined" ? Object : AgentStore,
|
|
451
|
-
typeof TokenStreamSink === "undefined" ? Object : TokenStreamSink,
|
|
452
|
-
typeof QuotaProvider === "undefined" ? Object : QuotaProvider,
|
|
453
|
-
typeof Pick === "undefined" ? Object : Pick,
|
|
454
|
-
typeof AttachmentStagingStore === "undefined" ? Object : AttachmentStagingStore
|
|
455
|
-
])
|
|
456
|
-
], ChatQueueService);
|
|
457
|
-
function pauseReasonFor(outcome, head) {
|
|
458
|
-
if (outcome === "failed") {
|
|
459
|
-
return "run_failed";
|
|
460
|
-
}
|
|
461
|
-
if (outcome === "cancelled" && head.interrupt !== true) {
|
|
462
|
-
return "cancelled";
|
|
463
|
-
}
|
|
464
|
-
return null;
|
|
465
|
-
}
|
|
466
|
-
__name(pauseReasonFor, "pauseReasonFor");
|
|
467
|
-
function queueFrame(items, paused, started) {
|
|
468
|
-
return {
|
|
469
|
-
kind: "queue",
|
|
470
|
-
queue: {
|
|
471
|
-
items: items.map(import_nestjs_agent_core.queuedMessageView),
|
|
472
|
-
paused
|
|
473
|
-
},
|
|
474
|
-
...started !== void 0 ? {
|
|
475
|
-
started
|
|
476
|
-
} : {}
|
|
477
|
-
};
|
|
478
|
-
}
|
|
479
|
-
__name(queueFrame, "queueFrame");
|
|
480
|
-
|
|
481
|
-
// src/durable/agent-run.steps.ts
|
|
482
|
-
var import_nestjs_agent_core2 = require("@dudousxd/nestjs-agent-core");
|
|
483
|
-
var import_nestjs_durable = require("@dudousxd/nestjs-durable");
|
|
484
|
-
var import_common2 = require("@nestjs/common");
|
|
485
|
-
|
|
486
|
-
// src/durable/outside-workflow-ctx.ts
|
|
487
|
-
var import_nestjs_durable_core = require("@dudousxd/nestjs-durable-core");
|
|
488
|
-
function outsideWorkflowCtx(fn) {
|
|
489
|
-
return (0, import_nestjs_durable_core.runInWorkflowCtx)(void 0, fn);
|
|
490
|
-
}
|
|
491
|
-
__name(outsideWorkflowCtx, "outsideWorkflowCtx");
|
|
492
|
-
function stepOf(ctx) {
|
|
493
|
-
return (name, fn, ...rest) => ctx.localStep(name, (...args) => outsideWorkflowCtx(() => fn(...args)), ...rest);
|
|
494
|
-
}
|
|
495
|
-
__name(stepOf, "stepOf");
|
|
496
|
-
|
|
497
|
-
// src/durable/agent-run.steps.ts
|
|
498
|
-
function _ts_decorate2(decorators, target, key, desc) {
|
|
499
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
500
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
501
|
-
r = Reflect.decorate(decorators, target, key, desc);
|
|
502
|
-
} else {
|
|
503
|
-
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
504
|
-
if (d = decorators[i]) {
|
|
505
|
-
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
510
|
-
}
|
|
511
|
-
__name(_ts_decorate2, "_ts_decorate");
|
|
512
|
-
function _ts_metadata2(metadataKey, metadataValue) {
|
|
513
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
514
|
-
return Reflect.metadata(metadataKey, metadataValue);
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
__name(_ts_metadata2, "_ts_metadata");
|
|
518
|
-
function _ts_param2(paramIndex, decorator) {
|
|
519
|
-
return function(target, key) {
|
|
520
|
-
decorator(target, key, paramIndex);
|
|
521
|
-
};
|
|
522
|
-
}
|
|
523
|
-
__name(_ts_param2, "_ts_param");
|
|
524
|
-
var AgentRunSteps = class {
|
|
525
|
-
static {
|
|
526
|
-
__name(this, "AgentRunSteps");
|
|
527
|
-
}
|
|
528
|
-
factory;
|
|
529
|
-
constructor(factory) {
|
|
530
|
-
this.factory = factory;
|
|
531
|
-
}
|
|
532
|
-
/**
|
|
533
|
-
* Retryable: every side effect (persist/quota/stream markers) happens loop-side under
|
|
534
|
-
* `hooks.step`, so a durable retry only re-runs the model call and re-streams its tokens — never
|
|
535
|
-
* double-writes. NEVER call `writer.end()`/`fail()` here: the workflow owns the stream's lifecycle,
|
|
536
|
-
* across however many turns/retries it takes.
|
|
537
|
-
*/
|
|
538
|
-
llm(input) {
|
|
539
|
-
return outsideWorkflowCtx(() => this.runLlm(input));
|
|
540
|
-
}
|
|
541
|
-
async runLlm(input) {
|
|
542
|
-
const deps = this.factory.forAgent(input.agentName);
|
|
543
|
-
const tools = (0, import_nestjs_agent_core2.withMemoryTool)({
|
|
544
|
-
tools: (0, import_nestjs_agent_core2.withSkillTool)({
|
|
545
|
-
tools: (0, import_nestjs_agent_core2.withAskTool)({
|
|
546
|
-
tools: await deps.registry.definitionsFor(input.actor, deps.rolesPolicy, deps.toolAllowList, {
|
|
547
|
-
...input.threadId !== void 0 ? {
|
|
548
|
-
threadId: input.threadId
|
|
549
|
-
} : {},
|
|
550
|
-
...input.agentName !== void 0 ? {
|
|
551
|
-
agentName: input.agentName
|
|
552
|
-
} : {}
|
|
553
|
-
}),
|
|
554
|
-
ask: deps.ask
|
|
555
|
-
}),
|
|
556
|
-
enabled: deps.skills !== void 0
|
|
557
|
-
}),
|
|
558
|
-
enabled: deps.memory?.provider.write !== void 0
|
|
559
|
-
});
|
|
560
|
-
const buffer = input.bufferOutput === true ? (0, import_nestjs_agent_core2.createFrameBuffer)() : void 0;
|
|
561
|
-
let writer;
|
|
562
|
-
if (buffer !== void 0) {
|
|
563
|
-
writer = buffer.writer;
|
|
564
|
-
} else {
|
|
565
|
-
const opened = await deps.sink.open(input.sinkRunId);
|
|
566
|
-
writer = input.childSink ? childSinkWriter(opened) : opened;
|
|
567
|
-
}
|
|
568
|
-
const frames = (0, import_nestjs_agent_core2.observeTurnFrames)(writer);
|
|
569
|
-
const turn = (0, import_nestjs_agent_core2.withTurnFrames)(await (0, import_nestjs_agent_core2.traceLlmTurn)(input.runId, input.step, () => deps.model.runTurn({
|
|
570
|
-
system: input.system,
|
|
571
|
-
messages: input.messages,
|
|
572
|
-
tools,
|
|
573
|
-
sink: frames.writer,
|
|
574
|
-
...input.model !== void 0 ? {
|
|
575
|
-
model: input.model
|
|
576
|
-
} : {}
|
|
577
|
-
})), frames.summary());
|
|
578
|
-
const stamped = (0, import_nestjs_agent_core2.stampToolKinds)(turn, deps);
|
|
579
|
-
return buffer === void 0 ? stamped : {
|
|
580
|
-
...stamped,
|
|
581
|
-
bufferedFrames: buffer.frames()
|
|
582
|
-
};
|
|
583
|
-
}
|
|
584
|
-
/**
|
|
585
|
-
* NO DURABLE retries — a tool may not be idempotent (a bare `@Step()` carries none, unlike `llm`
|
|
586
|
-
* above). What it does retry, in place, is a CLASSIFIED-TRANSIENT error from the tool's own
|
|
587
|
-
* invocation (a DB deadlock, a lock-wait timeout — see `isTransientToolError`): the server rolled
|
|
588
|
-
* that work back, so re-invoking it is safe, and doing it here (inside this one step, never a new
|
|
589
|
-
* checkpoint) is exactly how the non-dispatched loop path handles it too. The timeout is applied
|
|
590
|
-
* HERE, handler-side, via `withToolTimeout` — never as a durable dispatch `timeoutMs`, which
|
|
591
|
-
* bounds engine liveness (retryable) rather than the tool's own business outcome — and per
|
|
592
|
-
* ATTEMPT, so a retried invocation gets its own fresh timeout window.
|
|
593
|
-
*/
|
|
594
|
-
tool(input) {
|
|
595
|
-
return outsideWorkflowCtx(() => this.runTool(input));
|
|
596
|
-
}
|
|
597
|
-
async runTool(input) {
|
|
598
|
-
const deps = this.factory.forAgent(input.ctx.agentName);
|
|
599
|
-
if (deps.registry.spec(input.toolName)?.kind === "action" && input.toolType !== "action") {
|
|
600
|
-
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`);
|
|
601
|
-
}
|
|
602
|
-
const sinkRunId = input.sinkRunId;
|
|
603
|
-
let opened;
|
|
604
|
-
const ui = (0, import_nestjs_agent_core2.createUiCollector)(input.toolCallId, sinkRunId === void 0 ? void 0 : async (event) => {
|
|
605
|
-
opened ??= Promise.resolve(deps.sink.open(sinkRunId)).then((writer) => input.childSink === true ? childSinkWriter(writer) : writer);
|
|
606
|
-
await (await opened).write((0, import_nestjs_agent_core2.encodeStreamEvent)(event));
|
|
607
|
-
});
|
|
608
|
-
const ctx = {
|
|
609
|
-
...(0, import_nestjs_agent_core2.toolCallContext)(input.ctx, input.toolCallId),
|
|
610
|
-
emitUi: ui.emit
|
|
611
|
-
};
|
|
612
|
-
const localClassify = deps.toolTransientRetry !== false ? deps.toolTransientRetry?.classify : void 0;
|
|
613
|
-
const transientRetry = input.transientRetry === false ? false : {
|
|
614
|
-
attempts: input.transientRetry.attempts,
|
|
615
|
-
backoffMs: input.transientRetry.backoffMs,
|
|
616
|
-
...localClassify !== void 0 ? {
|
|
617
|
-
classify: localClassify
|
|
618
|
-
} : {}
|
|
619
|
-
};
|
|
620
|
-
const output = await (0, import_nestjs_agent_core2.traceToolExecution)(input.ctx.runId, {
|
|
621
|
-
toolCallId: input.toolCallId,
|
|
622
|
-
toolName: input.toolName,
|
|
623
|
-
toolType: input.toolType
|
|
624
|
-
}, () => (0, import_nestjs_agent_core2.invokeWithTransientRetry)(() => {
|
|
625
|
-
ui.restart();
|
|
626
|
-
const invocation = deps.registry.invoke(input.toolName, input.input, ctx, deps.rolesPolicy);
|
|
627
|
-
return input.timeoutMs !== void 0 ? (0, import_nestjs_agent_core2.withToolTimeout)(invocation, input.timeoutMs, input.toolName) : invocation;
|
|
628
|
-
}, transientRetry, {
|
|
629
|
-
onRetry: /* @__PURE__ */ __name((attempt, error) => {
|
|
630
|
-
(0, import_nestjs_agent_core2.publishAgentToolRetry)({
|
|
631
|
-
toolName: input.toolName,
|
|
632
|
-
toolCallId: input.toolCallId,
|
|
633
|
-
attempt,
|
|
634
|
-
message: error instanceof Error ? error.message : String(error)
|
|
635
|
-
});
|
|
636
|
-
}, "onRetry")
|
|
637
|
-
}));
|
|
638
|
-
return input.collectUi === true ? (0, import_nestjs_agent_core2.wrapToolStepOutput)(output, ui.components()) : output;
|
|
639
|
-
}
|
|
640
|
-
};
|
|
641
|
-
_ts_decorate2([
|
|
642
|
-
(0, import_nestjs_durable.Step)({
|
|
643
|
-
retries: 3
|
|
644
|
-
}),
|
|
645
|
-
_ts_metadata2("design:type", Function),
|
|
646
|
-
_ts_metadata2("design:paramtypes", [
|
|
647
|
-
typeof DispatchedLlmInput === "undefined" ? Object : DispatchedLlmInput
|
|
648
|
-
]),
|
|
649
|
-
_ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
650
|
-
], AgentRunSteps.prototype, "llm", null);
|
|
651
|
-
_ts_decorate2([
|
|
652
|
-
(0, import_nestjs_durable.Step)(),
|
|
653
|
-
_ts_metadata2("design:type", Function),
|
|
654
|
-
_ts_metadata2("design:paramtypes", [
|
|
655
|
-
typeof DispatchedToolInput === "undefined" ? Object : DispatchedToolInput
|
|
656
|
-
]),
|
|
657
|
-
_ts_metadata2("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
658
|
-
], AgentRunSteps.prototype, "tool", null);
|
|
659
|
-
AgentRunSteps = _ts_decorate2([
|
|
660
|
-
(0, import_common2.Injectable)(),
|
|
661
|
-
_ts_param2(0, (0, import_common2.Inject)(import_nestjs_agent_core2.AGENT_DEPS_FACTORY)),
|
|
662
|
-
_ts_metadata2("design:type", Function),
|
|
663
|
-
_ts_metadata2("design:paramtypes", [
|
|
664
|
-
typeof AgentDepsFactory === "undefined" ? Object : AgentDepsFactory
|
|
665
|
-
])
|
|
666
|
-
], AgentRunSteps);
|
|
667
|
-
|
|
668
|
-
// src/durable/agent-run.workflow.ts
|
|
669
|
-
function _ts_decorate3(decorators, target, key, desc) {
|
|
670
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
671
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
672
|
-
r = Reflect.decorate(decorators, target, key, desc);
|
|
673
|
-
} else {
|
|
674
|
-
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
675
|
-
if (d = decorators[i]) {
|
|
676
|
-
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
681
|
-
}
|
|
682
|
-
__name(_ts_decorate3, "_ts_decorate");
|
|
683
|
-
function _ts_metadata3(metadataKey, metadataValue) {
|
|
684
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
685
|
-
return Reflect.metadata(metadataKey, metadataValue);
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
__name(_ts_metadata3, "_ts_metadata");
|
|
689
|
-
function _ts_param3(paramIndex, decorator) {
|
|
690
|
-
return function(target, key) {
|
|
691
|
-
decorator(target, key, paramIndex);
|
|
692
|
-
};
|
|
693
|
-
}
|
|
694
|
-
__name(_ts_param3, "_ts_param");
|
|
695
|
-
var AgentRunWorkflow = class _AgentRunWorkflow {
|
|
696
|
-
static {
|
|
697
|
-
__name(this, "AgentRunWorkflow");
|
|
698
|
-
}
|
|
699
|
-
factory;
|
|
700
|
-
store;
|
|
701
|
-
runs;
|
|
702
|
-
queue;
|
|
703
|
-
logger = new import_common3.Logger(_AgentRunWorkflow.name);
|
|
704
|
-
constructor(factory, store, runs, queue) {
|
|
705
|
-
this.factory = factory;
|
|
706
|
-
this.store = store;
|
|
707
|
-
this.runs = runs;
|
|
708
|
-
this.queue = queue;
|
|
709
|
-
}
|
|
710
|
-
/**
|
|
711
|
-
* Move the thread past this settling turn — to the next queued message, started here as a
|
|
712
|
-
* fire-and-forget `ctx.startChild` under the message's own id, or to a paused/empty queue — and
|
|
713
|
-
* answer the `queue` frame to write before the turn's terminal.
|
|
714
|
-
*
|
|
715
|
-
* Journaled: the decision (which message, claimed and popped) is one `localStep`, so a replay
|
|
716
|
-
* reads it back instead of popping a second message, and the start is the runtime's own
|
|
717
|
-
* replay-safe spawn. Gated by `ctx.patched`, so a run recorded before the queue existed replays
|
|
718
|
-
* against the history it has. A no-op for a sub-agent's run and on a store without a queue.
|
|
719
|
-
*/
|
|
720
|
-
async advanceQueue(ctx, input, outcome, error) {
|
|
721
|
-
const queue = this.queue;
|
|
722
|
-
if (queue === void 0 || !queue.supported || input.sinkRunId !== void 0 || input.deliverTo !== void 0) {
|
|
723
|
-
return void 0;
|
|
724
|
-
}
|
|
725
|
-
if (!await ctx.patched("agent:chat-queue")) {
|
|
726
|
-
return void 0;
|
|
727
|
-
}
|
|
728
|
-
const plan = await stepOf(ctx)(`queue:${outcome}`, async () => {
|
|
729
|
-
try {
|
|
730
|
-
const settled = outcome === "completed" && await this.isCancelled(ctx.runId) ? "cancelled" : outcome;
|
|
731
|
-
return await queue.plan({
|
|
732
|
-
threadId: input.threadId,
|
|
733
|
-
runId: ctx.runId,
|
|
734
|
-
outcome: settled,
|
|
735
|
-
...error !== void 0 ? {
|
|
736
|
-
error
|
|
737
|
-
} : {}
|
|
738
|
-
});
|
|
739
|
-
} catch {
|
|
740
|
-
return {};
|
|
741
|
-
}
|
|
742
|
-
});
|
|
743
|
-
const next = plan.next;
|
|
744
|
-
if (next === void 0) {
|
|
745
|
-
return plan.frame;
|
|
746
|
-
}
|
|
747
|
-
try {
|
|
748
|
-
await ctx.startChild(_AgentRunWorkflow, next.input, next.runId);
|
|
749
|
-
return plan.frame;
|
|
750
|
-
} catch (failure) {
|
|
751
|
-
if ((0, import_nestjs_durable_core2.isWorkflowControlFlowSignal)(failure)) {
|
|
752
|
-
throw failure;
|
|
753
|
-
}
|
|
754
|
-
const reason = failure instanceof Error ? failure.message : String(failure);
|
|
755
|
-
return stepOf(ctx)("queue:restore", async () => {
|
|
756
|
-
await queue.restore(input.threadId, next, "start_failed", reason);
|
|
757
|
-
return queue.pausedFrame(input.threadId);
|
|
758
|
-
});
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
/**
|
|
762
|
-
* Has someone asked this run to stop? Read from the runtime's own run status, which is where
|
|
763
|
-
* `DurableAgentRunner.cancel` puts it — `cancelling` while a compensating cancel is in flight,
|
|
764
|
-
* `cancelled` once it has settled.
|
|
765
|
-
*
|
|
766
|
-
* Costs a run read at each of the loop's observation points (two per step). That is a row the
|
|
767
|
-
* control plane already has, against a turn that is otherwise making model calls, and it buys the
|
|
768
|
-
* property that matters: the answer comes from a place BOTH the canceller and every pod that might
|
|
769
|
-
* replay this run can see.
|
|
770
|
-
*
|
|
771
|
-
* Failing to ask is not a cancel. A tenant with no gateway wired, or an operator briefly
|
|
772
|
-
* unreachable, answers "no" and the run carries on — the alternative is failing healthy runs
|
|
773
|
-
* because a status read timed out. The loop journals that answer like any other, so two processes
|
|
774
|
-
* can never disagree about what was seen here.
|
|
775
|
-
*/
|
|
776
|
-
async isCancelled(runId) {
|
|
777
|
-
try {
|
|
778
|
-
const status = (await this.runs?.getRunDetail(runId))?.run.status;
|
|
779
|
-
return status === "cancelled" || status === "cancelling";
|
|
780
|
-
} catch {
|
|
781
|
-
return false;
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
|
-
/**
|
|
785
|
-
* Settle the delegation a DETACHED run was started for, when that run ends without an answer.
|
|
786
|
-
*
|
|
787
|
-
* The loop delivers its own success (`deliver:detached`) but cannot catch its own crash, and the
|
|
788
|
-
* runtime settles the run row without knowing anything delegated it. Left alone, the card in the
|
|
789
|
-
* calling conversation says "started" for ever — the one state a reader can neither wait on nor
|
|
790
|
-
* act on. A no-op for every other run: only a detached one carries a delivery address.
|
|
791
|
-
*/
|
|
792
|
-
async settleDetachedParent(ctx, input, outcome) {
|
|
793
|
-
const delivery = input.deliverTo;
|
|
794
|
-
if (delivery === void 0) {
|
|
795
|
-
return;
|
|
796
|
-
}
|
|
797
|
-
await stepOf(ctx)("deliver:detached:unsettled", () => (0, import_nestjs_agent_core3.settleUnsettledDelegation)({
|
|
798
|
-
store: this.store,
|
|
799
|
-
delivery,
|
|
800
|
-
agent: input.agentName ?? "default",
|
|
801
|
-
runId: ctx.runId,
|
|
802
|
-
status: outcome.status,
|
|
803
|
-
...outcome.error !== void 0 ? {
|
|
804
|
-
error: outcome.error
|
|
805
|
-
} : {}
|
|
806
|
-
}));
|
|
807
|
-
}
|
|
808
|
-
async run(ctx, input) {
|
|
809
|
-
const day = input.day ?? utcDay();
|
|
810
|
-
const deps = this.factory.forAgent(input.agentName);
|
|
811
|
-
const dispatchSteps = await ctx.patched("agent:dispatched-steps");
|
|
812
|
-
if (input.sinkRunId !== void 0 || input.deliverTo !== void 0) {
|
|
813
|
-
await stepOf(ctx)("activate", () => this.store.setActiveStream(input.threadId, ctx.runId));
|
|
384
|
+
async run(ctx, input) {
|
|
385
|
+
const day = input.day ?? utcDay();
|
|
386
|
+
const deps = this.factory.forAgent(input.agentName);
|
|
387
|
+
const dispatchSteps = await ctx.patched("agent:dispatched-steps");
|
|
388
|
+
if (input.sinkRunId !== void 0 || input.deliverTo !== void 0) {
|
|
389
|
+
await stepOf(ctx)("activate", () => this.store.setActiveStream(input.threadId, ctx.runId));
|
|
814
390
|
}
|
|
815
391
|
const sinkRunId = input.sinkRunId ?? ctx.runId;
|
|
816
392
|
const chainBelow = [
|
|
@@ -835,7 +411,7 @@ var AgentRunWorkflow = class _AgentRunWorkflow {
|
|
|
835
411
|
end: /* @__PURE__ */ __name(async () => {
|
|
836
412
|
const frame = await this.advanceQueue(ctx, input, "completed");
|
|
837
413
|
if (frame !== void 0) {
|
|
838
|
-
await writer.write((0,
|
|
414
|
+
await writer.write((0, import_nestjs_agent_core2.encodeStreamEvent)(frame));
|
|
839
415
|
}
|
|
840
416
|
await writer.end();
|
|
841
417
|
}, "end")
|
|
@@ -867,7 +443,7 @@ var AgentRunWorkflow = class _AgentRunWorkflow {
|
|
|
867
443
|
// await, so launching a batch in one tick — what `settleAll` does — fixes the block of
|
|
868
444
|
// positions in call order however the tools then settle. `ctx.patched` keeps a run that
|
|
869
445
|
// recorded the one-call-at-a-time shape replaying against that shape.
|
|
870
|
-
parallel:
|
|
446
|
+
parallel: import_nestjs_agent_core2.settleAll,
|
|
871
447
|
cancelled: /* @__PURE__ */ __name(() => this.isCancelled(ctx.runId), "cancelled"),
|
|
872
448
|
patched: /* @__PURE__ */ __name((id) => ctx.patched(id), "patched"),
|
|
873
449
|
// Dispatched-step suspends must escape the loop's tool catch — control flow, not a tool
|
|
@@ -961,33 +537,33 @@ var AgentRunWorkflow = class _AgentRunWorkflow {
|
|
|
961
537
|
} : {}
|
|
962
538
|
};
|
|
963
539
|
try {
|
|
964
|
-
const result = await (0,
|
|
540
|
+
const result = await (0, import_nestjs_agent_core2.runAgentLoop)({
|
|
965
541
|
...deps,
|
|
966
542
|
day
|
|
967
543
|
}, input, hooks);
|
|
968
|
-
await stepOf(ctx)("deactivate", () => (0,
|
|
544
|
+
await stepOf(ctx)("deactivate", () => (0, import_nestjs_agent_core2.releaseThreadRun)(this.store, input.threadId, ctx.runId));
|
|
969
545
|
return result;
|
|
970
546
|
} catch (error) {
|
|
971
547
|
if ((0, import_nestjs_durable_core2.isWorkflowControlFlowSignal)(error)) {
|
|
972
548
|
throw error;
|
|
973
549
|
}
|
|
974
|
-
if (error instanceof
|
|
975
|
-
await stepOf(ctx)("deactivate", () => (0,
|
|
550
|
+
if (error instanceof import_nestjs_agent_core2.RunCancelledError) {
|
|
551
|
+
await stepOf(ctx)("deactivate", () => (0, import_nestjs_agent_core2.releaseThreadRun)(this.store, input.threadId, ctx.runId));
|
|
976
552
|
await this.settleDetachedParent(ctx, input, {
|
|
977
553
|
status: "cancelled"
|
|
978
554
|
});
|
|
979
555
|
throw error;
|
|
980
556
|
}
|
|
981
|
-
if ((0,
|
|
557
|
+
if ((0, import_nestjs_agent_core2.isReplayIntegrityError)(error)) {
|
|
982
558
|
const detail = error.message;
|
|
983
|
-
const code2 = (0,
|
|
559
|
+
const code2 = (0, import_nestjs_agent_core2.agentFailureCode)(error);
|
|
984
560
|
this.logger.error(`agent run ${ctx.runId} failed (${code2}): ${detail}`);
|
|
985
|
-
(0,
|
|
561
|
+
(0, import_nestjs_agent_core2.publishAgentRunFailed)({
|
|
986
562
|
runId: ctx.runId,
|
|
987
563
|
code: code2,
|
|
988
564
|
message: detail
|
|
989
565
|
});
|
|
990
|
-
await (0,
|
|
566
|
+
await (0, import_nestjs_agent_core2.settleDeadRun)(this.store, {
|
|
991
567
|
runId: ctx.runId,
|
|
992
568
|
threadId: input.threadId,
|
|
993
569
|
failure: {
|
|
@@ -995,13 +571,13 @@ var AgentRunWorkflow = class _AgentRunWorkflow {
|
|
|
995
571
|
message: detail
|
|
996
572
|
}
|
|
997
573
|
});
|
|
998
|
-
await (await hooks.openSink()).fail((0,
|
|
574
|
+
await (await hooks.openSink()).fail((0, import_nestjs_agent_core2.streamFailure)(error));
|
|
999
575
|
throw error;
|
|
1000
576
|
}
|
|
1001
577
|
const message = error instanceof Error ? error.message : String(error);
|
|
1002
|
-
const code = (0,
|
|
578
|
+
const code = (0, import_nestjs_agent_core2.agentFailureCode)(error);
|
|
1003
579
|
this.logger.error(`agent run ${ctx.runId} failed (${code}): ${message}`);
|
|
1004
|
-
(0,
|
|
580
|
+
(0, import_nestjs_agent_core2.publishAgentRunFailed)({
|
|
1005
581
|
runId: ctx.runId,
|
|
1006
582
|
code,
|
|
1007
583
|
message
|
|
@@ -1013,36 +589,37 @@ var AgentRunWorkflow = class _AgentRunWorkflow {
|
|
|
1013
589
|
errorCode: code,
|
|
1014
590
|
errorMessage: message
|
|
1015
591
|
});
|
|
1016
|
-
await Promise.resolve(this.store.failUnsettledToolCalls?.(ctx.runId,
|
|
592
|
+
await Promise.resolve(this.store.failUnsettledToolCalls?.(ctx.runId, import_nestjs_agent_core2.RUN_ENDED_BEFORE_TOOL_CALL)).catch(() => 0);
|
|
1017
593
|
});
|
|
1018
594
|
const queueFrame2 = await this.advanceQueue(ctx, input, "failed", message);
|
|
1019
|
-
await stepOf(ctx)("deactivate", () => (0,
|
|
595
|
+
await stepOf(ctx)("deactivate", () => (0, import_nestjs_agent_core2.releaseThreadRun)(this.store, input.threadId, ctx.runId));
|
|
1020
596
|
await this.settleDetachedParent(ctx, input, {
|
|
1021
597
|
status: "failed",
|
|
1022
598
|
error: message
|
|
1023
599
|
});
|
|
1024
600
|
const writer = await hooks.openSink();
|
|
1025
601
|
if (queueFrame2 !== void 0) {
|
|
1026
|
-
await writer.write((0,
|
|
602
|
+
await writer.write((0, import_nestjs_agent_core2.encodeStreamEvent)(queueFrame2));
|
|
1027
603
|
}
|
|
1028
|
-
await writer.fail((0,
|
|
604
|
+
await writer.fail((0, import_nestjs_agent_core2.streamFailure)(error));
|
|
1029
605
|
throw error;
|
|
1030
606
|
}
|
|
1031
607
|
}
|
|
1032
608
|
};
|
|
1033
|
-
AgentRunWorkflow =
|
|
1034
|
-
(0,
|
|
609
|
+
AgentRunWorkflow = _ts_decorate2([
|
|
610
|
+
(0, import_common2.Injectable)(),
|
|
1035
611
|
(0, import_nestjs_durable2.Workflow)({
|
|
1036
612
|
name: "agent.run",
|
|
1037
613
|
version: "1"
|
|
1038
614
|
}),
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
615
|
+
_ts_param2(0, (0, import_common2.Inject)(import_nestjs_agent_core2.AGENT_DEPS_FACTORY)),
|
|
616
|
+
_ts_param2(1, (0, import_common2.Inject)(import_nestjs_agent_core2.AGENT_STORE)),
|
|
617
|
+
_ts_param2(2, (0, import_common2.Optional)()),
|
|
618
|
+
_ts_param2(2, (0, import_common2.Inject)(import_nestjs_durable2.RUN_GATEWAY)),
|
|
619
|
+
_ts_param2(3, (0, import_common2.Optional)()),
|
|
620
|
+
_ts_param2(3, (0, import_common2.Inject)(AGENT_CHAT_QUEUE)),
|
|
621
|
+
_ts_metadata2("design:type", Function),
|
|
622
|
+
_ts_metadata2("design:paramtypes", [
|
|
1046
623
|
typeof AgentDepsFactory === "undefined" ? Object : AgentDepsFactory,
|
|
1047
624
|
typeof AgentStore === "undefined" ? Object : AgentStore,
|
|
1048
625
|
typeof RunGateway === "undefined" ? Object : RunGateway,
|
|
@@ -1056,13 +633,13 @@ __name(isSignalTimeout, "isSignalTimeout");
|
|
|
1056
633
|
|
|
1057
634
|
// src/durable/durable-agent-runner.ts
|
|
1058
635
|
var import_node_crypto = require("crypto");
|
|
1059
|
-
var
|
|
636
|
+
var import_nestjs_agent_core4 = require("@dudousxd/nestjs-agent-core");
|
|
1060
637
|
var import_nestjs_durable3 = require("@dudousxd/nestjs-durable");
|
|
1061
638
|
var import_nestjs_durable_core3 = require("@dudousxd/nestjs-durable-core");
|
|
1062
|
-
var
|
|
639
|
+
var import_common3 = require("@nestjs/common");
|
|
1063
640
|
|
|
1064
641
|
// src/in-process-sink.ts
|
|
1065
|
-
var
|
|
642
|
+
var import_nestjs_agent_core3 = require("@dudousxd/nestjs-agent-core");
|
|
1066
643
|
var InProcessTokenStreamSink = class {
|
|
1067
644
|
static {
|
|
1068
645
|
__name(this, "InProcessTokenStreamSink");
|
|
@@ -1117,7 +694,7 @@ var InProcessTokenStreamSink = class {
|
|
|
1117
694
|
}
|
|
1118
695
|
if (buf.ended) {
|
|
1119
696
|
if (buf.failure !== void 0) {
|
|
1120
|
-
throw new
|
|
697
|
+
throw new import_nestjs_agent_core3.AgentStreamError(buf.failure);
|
|
1121
698
|
}
|
|
1122
699
|
return;
|
|
1123
700
|
}
|
|
@@ -1130,7 +707,7 @@ var InProcessTokenStreamSink = class {
|
|
|
1130
707
|
};
|
|
1131
708
|
|
|
1132
709
|
// src/durable/durable-agent-runner.ts
|
|
1133
|
-
function
|
|
710
|
+
function _ts_decorate3(decorators, target, key, desc) {
|
|
1134
711
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1135
712
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
1136
713
|
r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -1143,19 +720,19 @@ function _ts_decorate4(decorators, target, key, desc) {
|
|
|
1143
720
|
}
|
|
1144
721
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1145
722
|
}
|
|
1146
|
-
__name(
|
|
1147
|
-
function
|
|
723
|
+
__name(_ts_decorate3, "_ts_decorate");
|
|
724
|
+
function _ts_metadata3(metadataKey, metadataValue) {
|
|
1148
725
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
1149
726
|
return Reflect.metadata(metadataKey, metadataValue);
|
|
1150
727
|
}
|
|
1151
728
|
}
|
|
1152
|
-
__name(
|
|
1153
|
-
function
|
|
729
|
+
__name(_ts_metadata3, "_ts_metadata");
|
|
730
|
+
function _ts_param3(paramIndex, decorator) {
|
|
1154
731
|
return function(target, key) {
|
|
1155
732
|
decorator(target, key, paramIndex);
|
|
1156
733
|
};
|
|
1157
734
|
}
|
|
1158
|
-
__name(
|
|
735
|
+
__name(_ts_param3, "_ts_param");
|
|
1159
736
|
function threadOfRun(input) {
|
|
1160
737
|
if (typeof input !== "object" || input === null || !("threadId" in input)) {
|
|
1161
738
|
return void 0;
|
|
@@ -1176,7 +753,7 @@ var DurableAgentRunner = class _DurableAgentRunner {
|
|
|
1176
753
|
store;
|
|
1177
754
|
sink;
|
|
1178
755
|
queue;
|
|
1179
|
-
logger = new
|
|
756
|
+
logger = new import_common3.Logger(_DurableAgentRunner.name);
|
|
1180
757
|
constructor(workflows, runs, store, sink, queue) {
|
|
1181
758
|
this.workflows = workflows;
|
|
1182
759
|
this.runs = runs;
|
|
@@ -1263,15 +840,15 @@ var DurableAgentRunner = class _DurableAgentRunner {
|
|
|
1263
840
|
runId: nextRunId
|
|
1264
841
|
}));
|
|
1265
842
|
if (frame !== void 0) {
|
|
1266
|
-
await writer.write((0,
|
|
843
|
+
await writer.write((0, import_nestjs_agent_core4.encodeStreamEvent)(frame));
|
|
1267
844
|
}
|
|
1268
845
|
} catch (error) {
|
|
1269
846
|
this.logger.error(`could not advance the queue of thread ${threadId} after cancelling ${runId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1270
847
|
}
|
|
1271
848
|
}
|
|
1272
|
-
await (0,
|
|
849
|
+
await (0, import_nestjs_agent_core4.releaseThreadRun)(this.store, threadId, runId);
|
|
1273
850
|
}
|
|
1274
|
-
await writer.write((0,
|
|
851
|
+
await writer.write((0, import_nestjs_agent_core4.encodeStreamEvent)({
|
|
1275
852
|
kind: "cancelled"
|
|
1276
853
|
}));
|
|
1277
854
|
await writer.end();
|
|
@@ -1298,14 +875,15 @@ var DurableAgentRunner = class _DurableAgentRunner {
|
|
|
1298
875
|
}
|
|
1299
876
|
}
|
|
1300
877
|
};
|
|
1301
|
-
DurableAgentRunner =
|
|
1302
|
-
(0,
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
878
|
+
DurableAgentRunner = _ts_decorate3([
|
|
879
|
+
(0, import_common3.Injectable)(),
|
|
880
|
+
_ts_param3(1, (0, import_common3.Inject)(import_nestjs_durable3.RUN_GATEWAY)),
|
|
881
|
+
_ts_param3(2, (0, import_common3.Inject)(import_nestjs_agent_core4.AGENT_STORE)),
|
|
882
|
+
_ts_param3(3, (0, import_common3.Inject)(import_nestjs_agent_core4.AGENT_SINK)),
|
|
883
|
+
_ts_param3(4, (0, import_common3.Optional)()),
|
|
884
|
+
_ts_param3(4, (0, import_common3.Inject)(AGENT_CHAT_QUEUE)),
|
|
885
|
+
_ts_metadata3("design:type", Function),
|
|
886
|
+
_ts_metadata3("design:paramtypes", [
|
|
1309
887
|
typeof import_nestjs_durable3.WorkflowService === "undefined" ? Object : import_nestjs_durable3.WorkflowService,
|
|
1310
888
|
typeof RunGateway === "undefined" ? Object : RunGateway,
|
|
1311
889
|
typeof AgentStore === "undefined" ? Object : AgentStore,
|
|
@@ -1315,9 +893,9 @@ DurableAgentRunner = _ts_decorate4([
|
|
|
1315
893
|
], DurableAgentRunner);
|
|
1316
894
|
|
|
1317
895
|
// src/durable/agent-durable.module.ts
|
|
1318
|
-
var
|
|
1319
|
-
var
|
|
1320
|
-
function
|
|
896
|
+
var import_nestjs_agent_core5 = require("@dudousxd/nestjs-agent-core");
|
|
897
|
+
var import_common4 = require("@nestjs/common");
|
|
898
|
+
function _ts_decorate4(decorators, target, key, desc) {
|
|
1321
899
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1322
900
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
1323
901
|
r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -1330,12 +908,12 @@ function _ts_decorate5(decorators, target, key, desc) {
|
|
|
1330
908
|
}
|
|
1331
909
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1332
910
|
}
|
|
1333
|
-
__name(
|
|
911
|
+
__name(_ts_decorate4, "_ts_decorate");
|
|
1334
912
|
function runnerProviders() {
|
|
1335
913
|
return [
|
|
1336
914
|
DurableAgentRunner,
|
|
1337
915
|
{
|
|
1338
|
-
provide:
|
|
916
|
+
provide: import_nestjs_agent_core5.AGENT_DURABLE_RUNNER,
|
|
1339
917
|
useExisting: DurableAgentRunner
|
|
1340
918
|
}
|
|
1341
919
|
];
|
|
@@ -1346,15 +924,15 @@ var AgentDurableHttpModule = class AgentDurableHttpModule2 {
|
|
|
1346
924
|
__name(this, "AgentDurableHttpModule");
|
|
1347
925
|
}
|
|
1348
926
|
};
|
|
1349
|
-
AgentDurableHttpModule =
|
|
1350
|
-
(0,
|
|
1351
|
-
(0,
|
|
927
|
+
AgentDurableHttpModule = _ts_decorate4([
|
|
928
|
+
(0, import_common4.Global)(),
|
|
929
|
+
(0, import_common4.Module)({
|
|
1352
930
|
providers: [
|
|
1353
931
|
AgentRunWorkflow,
|
|
1354
932
|
...runnerProviders()
|
|
1355
933
|
],
|
|
1356
934
|
exports: [
|
|
1357
|
-
|
|
935
|
+
import_nestjs_agent_core5.AGENT_DURABLE_RUNNER,
|
|
1358
936
|
AgentRunWorkflow
|
|
1359
937
|
]
|
|
1360
938
|
})
|
|
@@ -1384,16 +962,16 @@ var AgentDurableModule = class _AgentDurableModule {
|
|
|
1384
962
|
};
|
|
1385
963
|
}
|
|
1386
964
|
};
|
|
1387
|
-
AgentDurableModule =
|
|
1388
|
-
(0,
|
|
1389
|
-
(0,
|
|
965
|
+
AgentDurableModule = _ts_decorate4([
|
|
966
|
+
(0, import_common4.Global)(),
|
|
967
|
+
(0, import_common4.Module)({
|
|
1390
968
|
providers: [
|
|
1391
969
|
AgentRunWorkflow,
|
|
1392
970
|
AgentRunSteps,
|
|
1393
971
|
...runnerProviders()
|
|
1394
972
|
],
|
|
1395
973
|
exports: [
|
|
1396
|
-
|
|
974
|
+
import_nestjs_agent_core5.AGENT_DURABLE_RUNNER,
|
|
1397
975
|
AgentRunWorkflow,
|
|
1398
976
|
AgentRunSteps
|
|
1399
977
|
]
|
|
@@ -1406,10 +984,10 @@ var import_common27 = require("@nestjs/common");
|
|
|
1406
984
|
var import_core4 = require("@nestjs/core");
|
|
1407
985
|
|
|
1408
986
|
// src/agent-deps.factory.ts
|
|
987
|
+
var import_nestjs_agent_core6 = require("@dudousxd/nestjs-agent-core");
|
|
1409
988
|
var import_nestjs_agent_core7 = require("@dudousxd/nestjs-agent-core");
|
|
1410
|
-
var
|
|
1411
|
-
|
|
1412
|
-
function _ts_decorate6(decorators, target, key, desc) {
|
|
989
|
+
var import_common5 = require("@nestjs/common");
|
|
990
|
+
function _ts_decorate5(decorators, target, key, desc) {
|
|
1413
991
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1414
992
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
1415
993
|
r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -1422,19 +1000,19 @@ function _ts_decorate6(decorators, target, key, desc) {
|
|
|
1422
1000
|
}
|
|
1423
1001
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1424
1002
|
}
|
|
1425
|
-
__name(
|
|
1426
|
-
function
|
|
1003
|
+
__name(_ts_decorate5, "_ts_decorate");
|
|
1004
|
+
function _ts_metadata4(metadataKey, metadataValue) {
|
|
1427
1005
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
1428
1006
|
return Reflect.metadata(metadataKey, metadataValue);
|
|
1429
1007
|
}
|
|
1430
1008
|
}
|
|
1431
|
-
__name(
|
|
1432
|
-
function
|
|
1009
|
+
__name(_ts_metadata4, "_ts_metadata");
|
|
1010
|
+
function _ts_param4(paramIndex, decorator) {
|
|
1433
1011
|
return function(target, key) {
|
|
1434
1012
|
decorator(target, key, paramIndex);
|
|
1435
1013
|
};
|
|
1436
1014
|
}
|
|
1437
|
-
__name(
|
|
1015
|
+
__name(_ts_param4, "_ts_param");
|
|
1438
1016
|
function delegateToolName(args) {
|
|
1439
1017
|
const slug = args.target.replace(/[^a-zA-Z0-9]+/g, "_");
|
|
1440
1018
|
return args.detached === true ? `start_${slug}` : `ask_${slug}`;
|
|
@@ -1460,212 +1038,639 @@ var AgentDepsFactory2 = class {
|
|
|
1460
1038
|
this.model = model;
|
|
1461
1039
|
this.store = store;
|
|
1462
1040
|
this.sink = sink;
|
|
1463
|
-
this.rolesPolicy = rolesPolicy;
|
|
1464
|
-
this.registry = registry;
|
|
1465
|
-
this.agents = agents;
|
|
1466
|
-
this.promptContributors = promptContributors;
|
|
1467
|
-
this.pricingStore = pricingStore;
|
|
1468
|
-
this.skills = skills;
|
|
1469
|
-
this.memory = memory;
|
|
1041
|
+
this.rolesPolicy = rolesPolicy;
|
|
1042
|
+
this.registry = registry;
|
|
1043
|
+
this.agents = agents;
|
|
1044
|
+
this.promptContributors = promptContributors;
|
|
1045
|
+
this.pricingStore = pricingStore;
|
|
1046
|
+
this.skills = skills;
|
|
1047
|
+
this.memory = memory;
|
|
1048
|
+
}
|
|
1049
|
+
/** The turn's memory seam, shared with the read-back endpoint. Undefined → memory is not configured. */
|
|
1050
|
+
memoryConfig() {
|
|
1051
|
+
return this.memory;
|
|
1052
|
+
}
|
|
1053
|
+
/** The turn's skills seam, shared with the listing endpoint. Undefined → skills are not configured. */
|
|
1054
|
+
skillsConfig() {
|
|
1055
|
+
return this.skills;
|
|
1056
|
+
}
|
|
1057
|
+
/**
|
|
1058
|
+
* The agent a turn uses when the caller names none: the explicit `defaultAgent` option, else the
|
|
1059
|
+
* sole registered `@Agent` when there is exactly one, else `'default'` (a bare assistant).
|
|
1060
|
+
*/
|
|
1061
|
+
defaultAgentName() {
|
|
1062
|
+
if (this.options.defaultAgent !== void 0) {
|
|
1063
|
+
return this.options.defaultAgent;
|
|
1064
|
+
}
|
|
1065
|
+
const registered = this.agents.list();
|
|
1066
|
+
return registered.length === 1 ? registered[0]?.name ?? "default" : "default";
|
|
1067
|
+
}
|
|
1068
|
+
effectiveTools(definition) {
|
|
1069
|
+
if (definition === void 0) {
|
|
1070
|
+
return void 0;
|
|
1071
|
+
}
|
|
1072
|
+
const delegated = (definition.delegatesTo ?? []).map((edge) => {
|
|
1073
|
+
const { agent, detached } = (0, import_nestjs_agent_core6.normalizeDelegation)(edge);
|
|
1074
|
+
return delegateToolName({
|
|
1075
|
+
target: agent,
|
|
1076
|
+
detached
|
|
1077
|
+
});
|
|
1078
|
+
});
|
|
1079
|
+
if (definition.tools === void 0 && delegated.length === 0) {
|
|
1080
|
+
return void 0;
|
|
1081
|
+
}
|
|
1082
|
+
return [
|
|
1083
|
+
...definition.tools ?? [],
|
|
1084
|
+
...delegated
|
|
1085
|
+
];
|
|
1086
|
+
}
|
|
1087
|
+
forAgent(agentName) {
|
|
1088
|
+
const name = agentName ?? this.defaultAgentName();
|
|
1089
|
+
const definition = this.agents.get(name);
|
|
1090
|
+
const toolAllowList = this.effectiveTools(definition);
|
|
1091
|
+
const followUpsCount = this.followUpsCount();
|
|
1092
|
+
const retrieval = this.options.retrieval;
|
|
1093
|
+
const historyPolicy = this.historyPolicy(definition);
|
|
1094
|
+
const ask = definition?.ask ?? this.options.ask;
|
|
1095
|
+
return {
|
|
1096
|
+
model: this.model,
|
|
1097
|
+
store: this.store,
|
|
1098
|
+
sink: this.sink,
|
|
1099
|
+
rolesPolicy: this.rolesPolicy,
|
|
1100
|
+
...this.options.approvalPolicy !== void 0 ? {
|
|
1101
|
+
approvalPolicy: this.options.approvalPolicy
|
|
1102
|
+
} : {},
|
|
1103
|
+
registry: this.registry,
|
|
1104
|
+
promptContributors: this.promptContributors,
|
|
1105
|
+
systemPrompt: definition?.systemPrompt ?? this.options.systemPrompt ?? "You are a helpful assistant.",
|
|
1106
|
+
maxSteps: definition?.maxSteps ?? 8,
|
|
1107
|
+
...definition?.maxDelegationDepth !== void 0 ? {
|
|
1108
|
+
maxDelegationDepth: definition.maxDelegationDepth
|
|
1109
|
+
} : {},
|
|
1110
|
+
...definition?.maxAgentAppearances !== void 0 ? {
|
|
1111
|
+
maxAgentAppearances: definition.maxAgentAppearances
|
|
1112
|
+
} : {},
|
|
1113
|
+
...definition?.modelId !== void 0 ? {
|
|
1114
|
+
modelId: definition.modelId
|
|
1115
|
+
} : {},
|
|
1116
|
+
...this.pricingStore !== void 0 ? {
|
|
1117
|
+
pricingStore: this.pricingStore
|
|
1118
|
+
} : {},
|
|
1119
|
+
...historyPolicy !== void 0 ? {
|
|
1120
|
+
historyPolicy
|
|
1121
|
+
} : {},
|
|
1122
|
+
inputProcessors: this.options.inputProcessors ?? [],
|
|
1123
|
+
outputProcessors: this.options.outputProcessors ?? [],
|
|
1124
|
+
...definition?.outputSchema !== void 0 ? {
|
|
1125
|
+
outputSchema: definition.outputSchema
|
|
1126
|
+
} : {},
|
|
1127
|
+
...definition?.outputRepairAttempts !== void 0 ? {
|
|
1128
|
+
outputRepairAttempts: definition.outputRepairAttempts
|
|
1129
|
+
} : {},
|
|
1130
|
+
...definition?.intake !== void 0 ? {
|
|
1131
|
+
intake: definition.intake
|
|
1132
|
+
} : {},
|
|
1133
|
+
// Most specific wins, exactly as `historyPolicy` resolves: the agent's own `@Agent({ ask })`,
|
|
1134
|
+
// else the module-wide flag. Both are module config, so every process of a deployment agrees.
|
|
1135
|
+
...ask === true ? {
|
|
1136
|
+
ask: true
|
|
1137
|
+
} : {},
|
|
1138
|
+
// Module-wide, never per-agent: a skill is a procedure, not a persona, and an agent that could
|
|
1139
|
+
// opt out of one would make the catalog depend on which agent a turn happened to select — a
|
|
1140
|
+
// per-turn fact the worker re-deriving the tool list cannot see.
|
|
1141
|
+
...this.skills !== void 0 ? {
|
|
1142
|
+
skills: this.skills
|
|
1143
|
+
} : {},
|
|
1144
|
+
// Module-wide, never per-agent, for the same reason skills are: which memories a turn carries
|
|
1145
|
+
// cannot depend on which persona answered it, or the worker re-deriving a dispatched turn's
|
|
1146
|
+
// tool list would disagree with the loop about whether `remember` was offered.
|
|
1147
|
+
...this.memory !== void 0 ? {
|
|
1148
|
+
memory: this.memory
|
|
1149
|
+
} : {},
|
|
1150
|
+
...toolAllowList !== void 0 ? {
|
|
1151
|
+
toolAllowList
|
|
1152
|
+
} : {},
|
|
1153
|
+
...this.options.toolTimeoutMs !== void 0 ? {
|
|
1154
|
+
toolTimeoutMs: this.options.toolTimeoutMs
|
|
1155
|
+
} : {},
|
|
1156
|
+
...this.options.toolTransientRetry !== void 0 ? {
|
|
1157
|
+
toolTransientRetry: this.options.toolTransientRetry
|
|
1158
|
+
} : {},
|
|
1159
|
+
...followUpsCount !== void 0 ? {
|
|
1160
|
+
followUpsCount
|
|
1161
|
+
} : {},
|
|
1162
|
+
...retrieval?.mode === "inject" ? {
|
|
1163
|
+
retriever: retrieval.retriever,
|
|
1164
|
+
...retrieval.topK !== void 0 ? {
|
|
1165
|
+
retrievalTopK: retrieval.topK
|
|
1166
|
+
} : {}
|
|
1167
|
+
} : {}
|
|
1168
|
+
};
|
|
1169
|
+
}
|
|
1170
|
+
/**
|
|
1171
|
+
* The ceiling on how much of a thread this agent's turns carry, most specific wins: the agent's
|
|
1172
|
+
* own `@Agent({ history })`, else a module-wide custom `historyPolicy`, else the module-wide
|
|
1173
|
+
* `history` window. Undefined → unbounded, the behaviour of a module that configures none.
|
|
1174
|
+
*/
|
|
1175
|
+
historyPolicy(definition) {
|
|
1176
|
+
if (definition?.history !== void 0) {
|
|
1177
|
+
return this.window(definition.history);
|
|
1178
|
+
}
|
|
1179
|
+
if (this.options.historyPolicy !== void 0) {
|
|
1180
|
+
return this.options.historyPolicy;
|
|
1181
|
+
}
|
|
1182
|
+
return this.options.history === void 0 ? void 0 : this.window(this.options.history);
|
|
1183
|
+
}
|
|
1184
|
+
/** Build the built-in window policy from the declarative `{ maxMessages, maxTokens, summarize }`. */
|
|
1185
|
+
window(config) {
|
|
1186
|
+
return (0, import_nestjs_agent_core6.windowHistory)({
|
|
1187
|
+
...config.maxMessages !== void 0 ? {
|
|
1188
|
+
maxMessages: config.maxMessages
|
|
1189
|
+
} : {},
|
|
1190
|
+
...config.maxTokens !== void 0 ? {
|
|
1191
|
+
maxTokens: config.maxTokens
|
|
1192
|
+
} : {},
|
|
1193
|
+
// The shared module model, not a per-agent one: an agent's `modelId` is an accounting label,
|
|
1194
|
+
// and only one provider is ever bound.
|
|
1195
|
+
...config.summarize === true ? {
|
|
1196
|
+
summarize: (0, import_nestjs_agent_core6.summarizeWithModel)(this.model)
|
|
1197
|
+
} : {}
|
|
1198
|
+
});
|
|
1199
|
+
}
|
|
1200
|
+
/** Normalize the `followUps` option (`true` → 3, `{ count }` → count) to a number, or undefined. */
|
|
1201
|
+
followUpsCount() {
|
|
1202
|
+
const followUps = this.options.followUps;
|
|
1203
|
+
if (followUps === true) {
|
|
1204
|
+
return 3;
|
|
1205
|
+
}
|
|
1206
|
+
if (typeof followUps === "object") {
|
|
1207
|
+
return followUps.count;
|
|
1208
|
+
}
|
|
1209
|
+
return void 0;
|
|
1210
|
+
}
|
|
1211
|
+
};
|
|
1212
|
+
AgentDepsFactory2 = _ts_decorate5([
|
|
1213
|
+
(0, import_common5.Injectable)(),
|
|
1214
|
+
_ts_param4(0, (0, import_common5.Inject)(import_nestjs_agent_core7.AGENT_OPTIONS)),
|
|
1215
|
+
_ts_param4(1, (0, import_common5.Inject)(import_nestjs_agent_core6.AGENT_MODEL)),
|
|
1216
|
+
_ts_param4(2, (0, import_common5.Inject)(import_nestjs_agent_core6.AGENT_STORE)),
|
|
1217
|
+
_ts_param4(3, (0, import_common5.Inject)(import_nestjs_agent_core6.AGENT_SINK)),
|
|
1218
|
+
_ts_param4(4, (0, import_common5.Inject)(import_nestjs_agent_core6.AGENT_ROLES_POLICY)),
|
|
1219
|
+
_ts_param4(5, (0, import_common5.Inject)(import_nestjs_agent_core6.AGENT_TOOL_REGISTRY)),
|
|
1220
|
+
_ts_param4(6, (0, import_common5.Inject)(import_nestjs_agent_core6.AGENT_REGISTRY)),
|
|
1221
|
+
_ts_param4(7, (0, import_common5.Inject)(import_nestjs_agent_core6.AGENT_PROMPT_CONTRIBUTORS)),
|
|
1222
|
+
_ts_param4(8, (0, import_common5.Optional)()),
|
|
1223
|
+
_ts_param4(8, (0, import_common5.Inject)(import_nestjs_agent_core6.AGENT_PRICING_STORE)),
|
|
1224
|
+
_ts_param4(9, (0, import_common5.Optional)()),
|
|
1225
|
+
_ts_param4(9, (0, import_common5.Inject)(import_nestjs_agent_core6.AGENT_SKILLS)),
|
|
1226
|
+
_ts_param4(10, (0, import_common5.Optional)()),
|
|
1227
|
+
_ts_param4(10, (0, import_common5.Inject)(import_nestjs_agent_core6.AGENT_MEMORY)),
|
|
1228
|
+
_ts_metadata4("design:type", Function),
|
|
1229
|
+
_ts_metadata4("design:paramtypes", [
|
|
1230
|
+
typeof AgentModuleOptions === "undefined" ? Object : AgentModuleOptions,
|
|
1231
|
+
typeof ModelProvider === "undefined" ? Object : ModelProvider,
|
|
1232
|
+
typeof AgentStore === "undefined" ? Object : AgentStore,
|
|
1233
|
+
typeof TokenStreamSink === "undefined" ? Object : TokenStreamSink,
|
|
1234
|
+
typeof RolesPolicy === "undefined" ? Object : RolesPolicy,
|
|
1235
|
+
typeof import_nestjs_agent_core6.ToolRegistry === "undefined" ? Object : import_nestjs_agent_core6.ToolRegistry,
|
|
1236
|
+
typeof import_nestjs_agent_core6.AgentRegistry === "undefined" ? Object : import_nestjs_agent_core6.AgentRegistry,
|
|
1237
|
+
Array,
|
|
1238
|
+
Object,
|
|
1239
|
+
Object,
|
|
1240
|
+
Object
|
|
1241
|
+
])
|
|
1242
|
+
], AgentDepsFactory2);
|
|
1243
|
+
|
|
1244
|
+
// src/agent.service.ts
|
|
1245
|
+
var import_nestjs_agent_core10 = require("@dudousxd/nestjs-agent-core");
|
|
1246
|
+
var import_common8 = require("@nestjs/common");
|
|
1247
|
+
|
|
1248
|
+
// src/queue/chat-queue.service.ts
|
|
1249
|
+
var import_nestjs_agent_core8 = require("@dudousxd/nestjs-agent-core");
|
|
1250
|
+
var import_common6 = require("@nestjs/common");
|
|
1251
|
+
function _ts_decorate6(decorators, target, key, desc) {
|
|
1252
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1253
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
1254
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
1255
|
+
} else {
|
|
1256
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
1257
|
+
if (d = decorators[i]) {
|
|
1258
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1263
|
+
}
|
|
1264
|
+
__name(_ts_decorate6, "_ts_decorate");
|
|
1265
|
+
function _ts_metadata5(metadataKey, metadataValue) {
|
|
1266
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
1267
|
+
return Reflect.metadata(metadataKey, metadataValue);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
__name(_ts_metadata5, "_ts_metadata");
|
|
1271
|
+
function _ts_param5(paramIndex, decorator) {
|
|
1272
|
+
return function(target, key) {
|
|
1273
|
+
decorator(target, key, paramIndex);
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
__name(_ts_param5, "_ts_param");
|
|
1277
|
+
var MAX_DRAIN_ATTEMPTS = 8;
|
|
1278
|
+
var ChatQueueService2 = class _ChatQueueService {
|
|
1279
|
+
static {
|
|
1280
|
+
__name(this, "ChatQueueService");
|
|
1281
|
+
}
|
|
1282
|
+
store;
|
|
1283
|
+
sink;
|
|
1284
|
+
quotaProvider;
|
|
1285
|
+
options;
|
|
1286
|
+
staging;
|
|
1287
|
+
logger = new import_common6.Logger(_ChatQueueService.name);
|
|
1288
|
+
/**
|
|
1289
|
+
* Runs this process claimed a thread for and has not handed to a runner yet. A holder in here is
|
|
1290
|
+
* alive whatever the runner says — it simply has not registered the run yet.
|
|
1291
|
+
*/
|
|
1292
|
+
starting = /* @__PURE__ */ new Set();
|
|
1293
|
+
constructor(store, sink, quotaProvider, options, staging) {
|
|
1294
|
+
this.store = store;
|
|
1295
|
+
this.sink = sink;
|
|
1296
|
+
this.quotaProvider = quotaProvider;
|
|
1297
|
+
this.options = options;
|
|
1298
|
+
this.staging = staging;
|
|
1470
1299
|
}
|
|
1471
|
-
/**
|
|
1472
|
-
|
|
1473
|
-
return this.
|
|
1300
|
+
/** Whether the bound store can hold a queue. Without one, a busy thread is not queued. */
|
|
1301
|
+
get supported() {
|
|
1302
|
+
return (0, import_nestjs_agent_core8.isChatQueueStore)(this.store);
|
|
1474
1303
|
}
|
|
1475
|
-
/** The
|
|
1476
|
-
|
|
1477
|
-
|
|
1304
|
+
/** The bound store as a queue store, or a 501 naming what is missing. */
|
|
1305
|
+
queueStore() {
|
|
1306
|
+
if (!(0, import_nestjs_agent_core8.isChatQueueStore)(this.store)) {
|
|
1307
|
+
throw new import_common6.NotImplementedException("Queueing messages requires an AgentStore that implements ChatQueueStore (enqueueMessage, listQueue, \u2026, claimActiveStream, releaseActiveStream); the bound store does not.");
|
|
1308
|
+
}
|
|
1309
|
+
return this.store;
|
|
1310
|
+
}
|
|
1311
|
+
async state(threadId) {
|
|
1312
|
+
const store = this.queueStore();
|
|
1313
|
+
const [items, paused] = await Promise.all([
|
|
1314
|
+
store.listQueue(threadId),
|
|
1315
|
+
store.queuePause(threadId)
|
|
1316
|
+
]);
|
|
1317
|
+
return {
|
|
1318
|
+
items: items.map(import_nestjs_agent_core8.queuedMessageView),
|
|
1319
|
+
paused
|
|
1320
|
+
};
|
|
1478
1321
|
}
|
|
1479
1322
|
/**
|
|
1480
|
-
*
|
|
1481
|
-
*
|
|
1323
|
+
* Whether `holder` is still running. A run this process is about to start is; otherwise the
|
|
1324
|
+
* runner decides, and a runner that cannot tell says yes.
|
|
1482
1325
|
*/
|
|
1483
|
-
|
|
1484
|
-
if (this.
|
|
1485
|
-
return
|
|
1326
|
+
async isAlive(holder, runner) {
|
|
1327
|
+
if (this.starting.has(holder)) {
|
|
1328
|
+
return true;
|
|
1329
|
+
}
|
|
1330
|
+
if (typeof runner.isRunActive !== "function") {
|
|
1331
|
+
return true;
|
|
1332
|
+
}
|
|
1333
|
+
try {
|
|
1334
|
+
return await runner.isRunActive(holder);
|
|
1335
|
+
} catch {
|
|
1336
|
+
return true;
|
|
1486
1337
|
}
|
|
1487
|
-
const registered = this.agents.list();
|
|
1488
|
-
return registered.length === 1 ? registered[0]?.name ?? "default" : "default";
|
|
1489
1338
|
}
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1339
|
+
/**
|
|
1340
|
+
* The run holding `threadId`, or `null` when it is free — a holder the runner reports dead counts
|
|
1341
|
+
* as free, and is returned as `stale` so the caller can claim over it.
|
|
1342
|
+
*/
|
|
1343
|
+
async holder(threadId, runner) {
|
|
1344
|
+
const holder = await this.queueStore().activeRunForThread(threadId);
|
|
1345
|
+
if (holder === null) {
|
|
1346
|
+
return {
|
|
1347
|
+
live: null,
|
|
1348
|
+
stale: null
|
|
1349
|
+
};
|
|
1493
1350
|
}
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
}
|
|
1501
|
-
|
|
1502
|
-
|
|
1351
|
+
return await this.isAlive(holder, runner) ? {
|
|
1352
|
+
live: holder,
|
|
1353
|
+
stale: null
|
|
1354
|
+
} : {
|
|
1355
|
+
live: null,
|
|
1356
|
+
stale: holder
|
|
1357
|
+
};
|
|
1358
|
+
}
|
|
1359
|
+
/**
|
|
1360
|
+
* Decide what follows a TOP-LEVEL run that is settling on `threadId`, and move the thread there:
|
|
1361
|
+
* hand it to the next queued message (claimed and popped here, started by the caller), or pause
|
|
1362
|
+
* the queue, or release the thread. Call it BEFORE the run's terminal frame, so a client reading
|
|
1363
|
+
* the stream learns what comes next from the `queue` frame, and so the thread is already free
|
|
1364
|
+
* when the client sees the run end.
|
|
1365
|
+
*
|
|
1366
|
+
* A no-op returning `{}` on a store without a queue.
|
|
1367
|
+
*/
|
|
1368
|
+
async plan(args) {
|
|
1369
|
+
if (!(0, import_nestjs_agent_core8.isChatQueueStore)(this.store)) {
|
|
1370
|
+
return {};
|
|
1503
1371
|
}
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1372
|
+
const store = this.store;
|
|
1373
|
+
const { threadId, outcome } = args;
|
|
1374
|
+
if (await store.activeRunForThread(threadId) !== args.runId) {
|
|
1375
|
+
return {};
|
|
1376
|
+
}
|
|
1377
|
+
let holding = args.runId;
|
|
1378
|
+
for (let attempt = 0; attempt < MAX_DRAIN_ATTEMPTS; attempt += 1) {
|
|
1379
|
+
const items = await store.listQueue(threadId);
|
|
1380
|
+
const head = items[0];
|
|
1381
|
+
if (head === void 0) {
|
|
1382
|
+
if (holding !== null) {
|
|
1383
|
+
await store.releaseActiveStream(threadId, holding);
|
|
1384
|
+
holding = null;
|
|
1385
|
+
continue;
|
|
1386
|
+
}
|
|
1387
|
+
return {};
|
|
1388
|
+
}
|
|
1389
|
+
let pause = await store.queuePause(threadId);
|
|
1390
|
+
if (pause === null) {
|
|
1391
|
+
const reason = pauseReasonFor(outcome, head);
|
|
1392
|
+
if (reason !== null) {
|
|
1393
|
+
pause = {
|
|
1394
|
+
reason,
|
|
1395
|
+
...outcome === "failed" && args.error !== void 0 ? {
|
|
1396
|
+
message: args.error
|
|
1397
|
+
} : {},
|
|
1398
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1399
|
+
};
|
|
1400
|
+
await store.setQueuePause(threadId, pause);
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
if (pause === null) {
|
|
1404
|
+
const blocked = await this.quotaBlock(head.actor);
|
|
1405
|
+
if (blocked !== null) {
|
|
1406
|
+
pause = {
|
|
1407
|
+
reason: "quota_exceeded",
|
|
1408
|
+
message: blocked,
|
|
1409
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1410
|
+
};
|
|
1411
|
+
await store.setQueuePause(threadId, pause);
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
if (pause !== null) {
|
|
1415
|
+
if (holding !== null) {
|
|
1416
|
+
await store.releaseActiveStream(threadId, holding);
|
|
1417
|
+
}
|
|
1418
|
+
return {
|
|
1419
|
+
frame: queueFrame(items, pause)
|
|
1420
|
+
};
|
|
1421
|
+
}
|
|
1422
|
+
const claimed = await store.claimActiveStream(threadId, head.id, holding !== null ? {
|
|
1423
|
+
replacing: holding
|
|
1424
|
+
} : {});
|
|
1425
|
+
if (!claimed) {
|
|
1426
|
+
return {};
|
|
1427
|
+
}
|
|
1428
|
+
holding = head.id;
|
|
1429
|
+
if (!await store.removeQueuedMessage(head.id)) {
|
|
1430
|
+
await store.releaseActiveStream(threadId, head.id);
|
|
1431
|
+
holding = null;
|
|
1432
|
+
continue;
|
|
1433
|
+
}
|
|
1434
|
+
const next = {
|
|
1435
|
+
runId: head.id,
|
|
1436
|
+
messageId: head.id,
|
|
1437
|
+
input: await this.inputFor(head)
|
|
1438
|
+
};
|
|
1439
|
+
return {
|
|
1440
|
+
next,
|
|
1441
|
+
frame: queueFrame(items.slice(1), null, {
|
|
1442
|
+
messageId: head.id,
|
|
1443
|
+
runId: head.id
|
|
1444
|
+
})
|
|
1445
|
+
};
|
|
1446
|
+
}
|
|
1447
|
+
if (holding !== null) {
|
|
1448
|
+
await store.releaseActiveStream(threadId, holding);
|
|
1449
|
+
}
|
|
1450
|
+
return {};
|
|
1508
1451
|
}
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
const
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
}
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1452
|
+
/**
|
|
1453
|
+
* {@link plan}, then start what it picked with `start`. What an in-process settle (the inline
|
|
1454
|
+
* runner, a durable cancel issued outside a workflow) calls; answers the frame to write.
|
|
1455
|
+
*/
|
|
1456
|
+
async handoff(args, start) {
|
|
1457
|
+
const plan = await this.plan(args);
|
|
1458
|
+
if (plan.next === void 0) {
|
|
1459
|
+
return plan.frame;
|
|
1460
|
+
}
|
|
1461
|
+
return await this.launch(args.threadId, plan.next, start) ? plan.frame : this.pausedFrame(args.threadId);
|
|
1462
|
+
}
|
|
1463
|
+
/**
|
|
1464
|
+
* Start the head of an IDLE thread's queue — after a send queued behind a run that turned out to
|
|
1465
|
+
* be gone, after a resume, after a stale holder. Does nothing while a live run holds the thread
|
|
1466
|
+
* (its settle drains) or while the queue is paused. Answers the started run's id, if any.
|
|
1467
|
+
*/
|
|
1468
|
+
async kick(threadId, runner) {
|
|
1469
|
+
if (!(0, import_nestjs_agent_core8.isChatQueueStore)(this.store)) {
|
|
1470
|
+
return void 0;
|
|
1471
|
+
}
|
|
1472
|
+
const { live, stale } = await this.holder(threadId, runner);
|
|
1473
|
+
if (live !== null) {
|
|
1474
|
+
return void 0;
|
|
1475
|
+
}
|
|
1476
|
+
if (stale !== null) {
|
|
1477
|
+
this.logger.warn(`thread ${threadId} was held by run ${stale}, which is no longer running`);
|
|
1478
|
+
}
|
|
1479
|
+
const plan = await this.plan({
|
|
1480
|
+
threadId,
|
|
1481
|
+
runId: stale,
|
|
1482
|
+
outcome: "completed"
|
|
1483
|
+
});
|
|
1484
|
+
if (plan.next === void 0) {
|
|
1485
|
+
return void 0;
|
|
1486
|
+
}
|
|
1487
|
+
const started = await this.launch(threadId, plan.next, (input, runId) => runner.start(input, {
|
|
1488
|
+
runId
|
|
1489
|
+
}));
|
|
1490
|
+
if (started && plan.frame !== void 0) {
|
|
1491
|
+
await this.write(plan.next.runId, plan.frame);
|
|
1492
|
+
}
|
|
1493
|
+
return started ? plan.next.runId : void 0;
|
|
1494
|
+
}
|
|
1495
|
+
/**
|
|
1496
|
+
* Start a turn the thread is already claimed for. On failure the message goes back to the head of
|
|
1497
|
+
* the queue, the queue pauses (`start_failed`), and the claim is released — nothing is lost and
|
|
1498
|
+
* nothing is left holding the thread.
|
|
1499
|
+
*/
|
|
1500
|
+
async launch(threadId, next, start) {
|
|
1501
|
+
this.starting.add(next.runId);
|
|
1502
|
+
try {
|
|
1503
|
+
await start(next.input, next.runId);
|
|
1504
|
+
return true;
|
|
1505
|
+
} catch (error) {
|
|
1506
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1507
|
+
this.logger.error(`queued message ${next.messageId} could not start: ${message}`);
|
|
1508
|
+
await this.restore(threadId, next, "start_failed", message);
|
|
1509
|
+
return false;
|
|
1510
|
+
} finally {
|
|
1511
|
+
this.starting.delete(next.runId);
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
/** Put a turn that never started back at the head of its queue, paused, and free the thread. */
|
|
1515
|
+
async restore(threadId, next, reason, message) {
|
|
1516
|
+
const store = this.queueStore();
|
|
1517
|
+
const { input } = next;
|
|
1518
|
+
await store.enqueueMessage({
|
|
1519
|
+
threadId,
|
|
1520
|
+
actor: input.actor,
|
|
1521
|
+
content: input.userText,
|
|
1522
|
+
at: "head",
|
|
1523
|
+
...input.attachments !== void 0 ? {
|
|
1524
|
+
attachments: input.attachments
|
|
1577
1525
|
} : {},
|
|
1578
|
-
...
|
|
1579
|
-
|
|
1526
|
+
...input.agentName !== void 0 ? {
|
|
1527
|
+
agentName: input.agentName
|
|
1580
1528
|
} : {},
|
|
1581
|
-
...
|
|
1582
|
-
|
|
1529
|
+
...input.model !== void 0 ? {
|
|
1530
|
+
model: input.model
|
|
1583
1531
|
} : {},
|
|
1584
|
-
...
|
|
1585
|
-
|
|
1586
|
-
...retrieval.topK !== void 0 ? {
|
|
1587
|
-
retrievalTopK: retrieval.topK
|
|
1588
|
-
} : {}
|
|
1532
|
+
...input.pageContext !== void 0 ? {
|
|
1533
|
+
pageContext: input.pageContext
|
|
1589
1534
|
} : {}
|
|
1535
|
+
});
|
|
1536
|
+
await store.setQueuePause(threadId, {
|
|
1537
|
+
reason,
|
|
1538
|
+
message,
|
|
1539
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1540
|
+
});
|
|
1541
|
+
await store.releaseActiveStream(threadId, next.runId);
|
|
1542
|
+
}
|
|
1543
|
+
/** A `queue` frame with the thread's current state. */
|
|
1544
|
+
async pausedFrame(threadId) {
|
|
1545
|
+
return {
|
|
1546
|
+
kind: "queue",
|
|
1547
|
+
queue: await this.state(threadId)
|
|
1590
1548
|
};
|
|
1591
1549
|
}
|
|
1592
1550
|
/**
|
|
1593
|
-
*
|
|
1594
|
-
*
|
|
1595
|
-
*
|
|
1551
|
+
* Tell whoever is watching the thread that its queue changed: a `queue` frame into the stream of
|
|
1552
|
+
* the run holding it. Best-effort — a thread nobody is streaming has no one to tell, and the next
|
|
1553
|
+
* read of the thread carries the queue anyway.
|
|
1596
1554
|
*/
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1555
|
+
async publish(threadId) {
|
|
1556
|
+
const state = await this.state(threadId);
|
|
1557
|
+
const holder = await this.queueStore().activeRunForThread(threadId);
|
|
1558
|
+
if (holder !== null) {
|
|
1559
|
+
await this.write(holder, {
|
|
1560
|
+
kind: "queue",
|
|
1561
|
+
queue: state
|
|
1562
|
+
}).catch((error) => {
|
|
1563
|
+
this.logger.warn(`could not publish the queue of thread ${threadId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1564
|
+
});
|
|
1600
1565
|
}
|
|
1601
|
-
|
|
1602
|
-
|
|
1566
|
+
return state;
|
|
1567
|
+
}
|
|
1568
|
+
async write(runId, frame) {
|
|
1569
|
+
const writer = await this.sink.open(runId);
|
|
1570
|
+
await writer.write((0, import_nestjs_agent_core8.encodeStreamEvent)(frame));
|
|
1571
|
+
}
|
|
1572
|
+
/** Why `actor` may not start a turn now (the quota message), or `null`. */
|
|
1573
|
+
async quotaBlock(actor) {
|
|
1574
|
+
if (this.options?.quota === void 0 || this.quotaProvider === void 0) {
|
|
1575
|
+
return null;
|
|
1576
|
+
}
|
|
1577
|
+
try {
|
|
1578
|
+
const { blocked } = await this.quotaProvider.report({
|
|
1579
|
+
actor
|
|
1580
|
+
});
|
|
1581
|
+
if (blocked === void 0) {
|
|
1582
|
+
return null;
|
|
1583
|
+
}
|
|
1584
|
+
return blocked.reason ?? `The ${blocked.period === "day" ? "daily" : "monthly"} quota is used up`;
|
|
1585
|
+
} catch {
|
|
1586
|
+
return null;
|
|
1603
1587
|
}
|
|
1604
|
-
return this.options.history === void 0 ? void 0 : this.window(this.options.history);
|
|
1605
1588
|
}
|
|
1606
|
-
/**
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1589
|
+
/**
|
|
1590
|
+
* The turn a queued message starts: everything it was queued with, today's date, and its
|
|
1591
|
+
* attachments' urls minted afresh — the ones stored at enqueue time may have expired while it
|
|
1592
|
+
* waited. An attachment the staging store no longer resolves keeps its stored url.
|
|
1593
|
+
*/
|
|
1594
|
+
async inputFor(message) {
|
|
1595
|
+
const attachments = await this.freshAttachments(message.actor, message.attachments ?? []);
|
|
1596
|
+
return {
|
|
1597
|
+
threadId: message.threadId,
|
|
1598
|
+
actor: message.actor,
|
|
1599
|
+
userText: message.content,
|
|
1600
|
+
day: utcDay(),
|
|
1601
|
+
...message.agentName !== void 0 ? {
|
|
1602
|
+
agentName: message.agentName
|
|
1611
1603
|
} : {},
|
|
1612
|
-
...
|
|
1613
|
-
|
|
1604
|
+
...attachments.length > 0 ? {
|
|
1605
|
+
attachments
|
|
1614
1606
|
} : {},
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1607
|
+
...message.pageContext !== void 0 ? {
|
|
1608
|
+
pageContext: message.pageContext
|
|
1609
|
+
} : {},
|
|
1610
|
+
...message.model !== void 0 ? {
|
|
1611
|
+
model: message.model
|
|
1619
1612
|
} : {}
|
|
1620
|
-
}
|
|
1613
|
+
};
|
|
1621
1614
|
}
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
return 3;
|
|
1627
|
-
}
|
|
1628
|
-
if (typeof followUps === "object") {
|
|
1629
|
-
return followUps.count;
|
|
1615
|
+
async freshAttachments(actor, attachments) {
|
|
1616
|
+
const staging = this.staging;
|
|
1617
|
+
if (attachments.length === 0 || staging === void 0 || typeof staging.resolve !== "function") {
|
|
1618
|
+
return attachments;
|
|
1630
1619
|
}
|
|
1631
|
-
return
|
|
1620
|
+
return Promise.all(attachments.map(async (attachment) => {
|
|
1621
|
+
try {
|
|
1622
|
+
return await staging.resolve({
|
|
1623
|
+
mediaId: attachment.mediaId,
|
|
1624
|
+
actor
|
|
1625
|
+
}) ?? attachment;
|
|
1626
|
+
} catch {
|
|
1627
|
+
return attachment;
|
|
1628
|
+
}
|
|
1629
|
+
}));
|
|
1632
1630
|
}
|
|
1633
1631
|
};
|
|
1634
|
-
|
|
1632
|
+
ChatQueueService2 = _ts_decorate6([
|
|
1635
1633
|
(0, import_common6.Injectable)(),
|
|
1636
|
-
_ts_param5(0, (0, import_common6.Inject)(import_nestjs_agent_core8.
|
|
1637
|
-
_ts_param5(1, (0, import_common6.Inject)(
|
|
1638
|
-
_ts_param5(2, (0, import_common6.
|
|
1639
|
-
_ts_param5(
|
|
1640
|
-
_ts_param5(
|
|
1641
|
-
_ts_param5(
|
|
1642
|
-
_ts_param5(
|
|
1643
|
-
_ts_param5(
|
|
1644
|
-
_ts_param5(8, (0, import_common6.Optional)()),
|
|
1645
|
-
_ts_param5(8, (0, import_common6.Inject)(import_nestjs_agent_core7.AGENT_PRICING_STORE)),
|
|
1646
|
-
_ts_param5(9, (0, import_common6.Optional)()),
|
|
1647
|
-
_ts_param5(9, (0, import_common6.Inject)(import_nestjs_agent_core7.AGENT_SKILLS)),
|
|
1648
|
-
_ts_param5(10, (0, import_common6.Optional)()),
|
|
1649
|
-
_ts_param5(10, (0, import_common6.Inject)(import_nestjs_agent_core7.AGENT_MEMORY)),
|
|
1634
|
+
_ts_param5(0, (0, import_common6.Inject)(import_nestjs_agent_core8.AGENT_STORE)),
|
|
1635
|
+
_ts_param5(1, (0, import_common6.Inject)(import_nestjs_agent_core8.AGENT_SINK)),
|
|
1636
|
+
_ts_param5(2, (0, import_common6.Optional)()),
|
|
1637
|
+
_ts_param5(2, (0, import_common6.Inject)(import_nestjs_agent_core8.AGENT_QUOTA_PROVIDER)),
|
|
1638
|
+
_ts_param5(3, (0, import_common6.Optional)()),
|
|
1639
|
+
_ts_param5(3, (0, import_common6.Inject)(import_nestjs_agent_core8.AGENT_OPTIONS)),
|
|
1640
|
+
_ts_param5(4, (0, import_common6.Optional)()),
|
|
1641
|
+
_ts_param5(4, (0, import_common6.Inject)(import_nestjs_agent_core8.AGENT_ATTACHMENT_STAGING)),
|
|
1650
1642
|
_ts_metadata5("design:type", Function),
|
|
1651
1643
|
_ts_metadata5("design:paramtypes", [
|
|
1652
|
-
typeof AgentModuleOptions === "undefined" ? Object : AgentModuleOptions,
|
|
1653
|
-
typeof ModelProvider === "undefined" ? Object : ModelProvider,
|
|
1654
1644
|
typeof AgentStore === "undefined" ? Object : AgentStore,
|
|
1655
1645
|
typeof TokenStreamSink === "undefined" ? Object : TokenStreamSink,
|
|
1656
|
-
typeof
|
|
1657
|
-
typeof
|
|
1658
|
-
typeof
|
|
1659
|
-
Array,
|
|
1660
|
-
Object,
|
|
1661
|
-
Object,
|
|
1662
|
-
Object
|
|
1646
|
+
typeof QuotaProvider === "undefined" ? Object : QuotaProvider,
|
|
1647
|
+
typeof Pick === "undefined" ? Object : Pick,
|
|
1648
|
+
typeof AttachmentStagingStore === "undefined" ? Object : AttachmentStagingStore
|
|
1663
1649
|
])
|
|
1664
|
-
],
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1650
|
+
], ChatQueueService2);
|
|
1651
|
+
function pauseReasonFor(outcome, head) {
|
|
1652
|
+
if (outcome === "failed") {
|
|
1653
|
+
return "run_failed";
|
|
1654
|
+
}
|
|
1655
|
+
if (outcome === "cancelled" && head.interrupt !== true) {
|
|
1656
|
+
return "cancelled";
|
|
1657
|
+
}
|
|
1658
|
+
return null;
|
|
1659
|
+
}
|
|
1660
|
+
__name(pauseReasonFor, "pauseReasonFor");
|
|
1661
|
+
function queueFrame(items, paused, started) {
|
|
1662
|
+
return {
|
|
1663
|
+
kind: "queue",
|
|
1664
|
+
queue: {
|
|
1665
|
+
items: items.map(import_nestjs_agent_core8.queuedMessageView),
|
|
1666
|
+
paused
|
|
1667
|
+
},
|
|
1668
|
+
...started !== void 0 ? {
|
|
1669
|
+
started
|
|
1670
|
+
} : {}
|
|
1671
|
+
};
|
|
1672
|
+
}
|
|
1673
|
+
__name(queueFrame, "queueFrame");
|
|
1669
1674
|
|
|
1670
1675
|
// src/run-not-active.exception.ts
|
|
1671
1676
|
var import_nestjs_agent_core9 = require("@dudousxd/nestjs-agent-core");
|
|
@@ -1906,6 +1911,9 @@ var AgentService = class {
|
|
|
1906
1911
|
actor: params.actor,
|
|
1907
1912
|
...params.transient === true ? {
|
|
1908
1913
|
transient: true
|
|
1914
|
+
} : {},
|
|
1915
|
+
...params.newThreadId !== void 0 ? {
|
|
1916
|
+
id: params.newThreadId
|
|
1909
1917
|
} : {}
|
|
1910
1918
|
});
|
|
1911
1919
|
threadId = created.id;
|
|
@@ -2330,6 +2338,38 @@ var AgentService = class {
|
|
|
2330
2338
|
});
|
|
2331
2339
|
throw new RunNotActiveException(runId);
|
|
2332
2340
|
}
|
|
2341
|
+
/** Who owns the thread, or `null` when there is no such (live) thread. */
|
|
2342
|
+
async threadOwner(threadId) {
|
|
2343
|
+
return this.store.ownerOfThread(threadId);
|
|
2344
|
+
}
|
|
2345
|
+
/**
|
|
2346
|
+
* May `actor` continue the run whose stream is `runId` — the AG-UI resume? Only the actor whose
|
|
2347
|
+
* thread is streaming it (`403` otherwise), and only while it still is: a run that is over is
|
|
2348
|
+
* waiting on no one (`409 run_not_active`), whatever an old interrupt id says.
|
|
2349
|
+
*/
|
|
2350
|
+
async assertResumable(actor, runId) {
|
|
2351
|
+
const owner = await this.store.ownerOfActiveStream(runId);
|
|
2352
|
+
if (owner === null) {
|
|
2353
|
+
throw new RunNotActiveException(runId);
|
|
2354
|
+
}
|
|
2355
|
+
if (owner !== actor.id) {
|
|
2356
|
+
throw new import_common8.ForbiddenException("run belongs to another actor");
|
|
2357
|
+
}
|
|
2358
|
+
}
|
|
2359
|
+
/**
|
|
2360
|
+
* Everything {@link approve} / {@link reject} check before they signal — who may decide, and
|
|
2361
|
+
* that the request has not lapsed — without signalling. For a caller that settles several
|
|
2362
|
+
* decisions at once and must refuse all of them if one is refused (an AG-UI resume).
|
|
2363
|
+
*/
|
|
2364
|
+
async checkDecision(actor, toolCallId2) {
|
|
2365
|
+
await this.assertMayDecide(actor, toolCallId2);
|
|
2366
|
+
await this.assertNotExpired(toolCallId2);
|
|
2367
|
+
}
|
|
2368
|
+
/** Everything {@link answer} checks before it signals, without signalling — see {@link checkDecision}. */
|
|
2369
|
+
async checkAnswer(actor, toolCallId2, answers2) {
|
|
2370
|
+
await this.assertOwnsToolCall(actor, toolCallId2);
|
|
2371
|
+
await this.assertAnswersFit(toolCallId2, answers2);
|
|
2372
|
+
}
|
|
2333
2373
|
async cancel(actor, runId) {
|
|
2334
2374
|
await this.assertOwnsActiveStream(actor, runId);
|
|
2335
2375
|
return this.runner.cancel(runId);
|
|
@@ -2722,7 +2762,7 @@ AgentService = _ts_decorate7([
|
|
|
2722
2762
|
typeof ModelCatalog === "undefined" ? Object : ModelCatalog,
|
|
2723
2763
|
typeof QuotaProvider === "undefined" ? Object : QuotaProvider,
|
|
2724
2764
|
typeof Pick === "undefined" ? Object : Pick,
|
|
2725
|
-
typeof
|
|
2765
|
+
typeof ChatQueueService2 === "undefined" ? Object : ChatQueueService2
|
|
2726
2766
|
])
|
|
2727
2767
|
], AgentService);
|
|
2728
2768
|
|
|
@@ -5569,7 +5609,7 @@ InlineAgentRunner = _ts_decorate25([
|
|
|
5569
5609
|
_ts_metadata24("design:paramtypes", [
|
|
5570
5610
|
typeof AgentDepsFactory === "undefined" ? Object : AgentDepsFactory,
|
|
5571
5611
|
typeof AgentStore === "undefined" ? Object : AgentStore,
|
|
5572
|
-
typeof
|
|
5612
|
+
typeof ChatQueueService2 === "undefined" ? Object : ChatQueueService2
|
|
5573
5613
|
])
|
|
5574
5614
|
], InlineAgentRunner);
|
|
5575
5615
|
function isThreadTurn2(input) {
|
|
@@ -5784,7 +5824,11 @@ function sharedProviders(durable) {
|
|
|
5784
5824
|
SkillDiscoveryService,
|
|
5785
5825
|
// The thread message queue — every surface, since both runners and the durable workflow settle
|
|
5786
5826
|
// into it, and the chat routes enqueue into it.
|
|
5787
|
-
|
|
5827
|
+
ChatQueueService2,
|
|
5828
|
+
{
|
|
5829
|
+
provide: AGENT_CHAT_QUEUE,
|
|
5830
|
+
useExisting: ChatQueueService2
|
|
5831
|
+
},
|
|
5788
5832
|
InlineAgentRunner,
|
|
5789
5833
|
AgentService,
|
|
5790
5834
|
// Bound ALWAYS (durable or inline) — the console's cross-thread approvals inbox routes decisions
|
|
@@ -5846,7 +5890,8 @@ function exportsFor() {
|
|
|
5846
5890
|
import_nestjs_agent_core31.AGENT_DEPS_FACTORY,
|
|
5847
5891
|
AgentDepsFactory2,
|
|
5848
5892
|
AgentService,
|
|
5849
|
-
|
|
5893
|
+
ChatQueueService2,
|
|
5894
|
+
AGENT_CHAT_QUEUE,
|
|
5850
5895
|
InlineAgentRunner,
|
|
5851
5896
|
import_nestjs_agent_core31.AGENT_APPROVAL_PORT
|
|
5852
5897
|
];
|
|
@@ -5867,15 +5912,28 @@ var BASE_CONTROLLERS = [
|
|
|
5867
5912
|
ConfigController,
|
|
5868
5913
|
AttachmentsController
|
|
5869
5914
|
];
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5915
|
+
function adapterControllers(adapters) {
|
|
5916
|
+
return (adapters ?? []).flatMap((adapter) => adapter.controllers);
|
|
5917
|
+
}
|
|
5918
|
+
__name(adapterControllers, "adapterControllers");
|
|
5919
|
+
function adapterProviders(adapters) {
|
|
5920
|
+
return (adapters ?? []).flatMap((adapter) => adapter.providers ?? []);
|
|
5921
|
+
}
|
|
5922
|
+
__name(adapterProviders, "adapterProviders");
|
|
5923
|
+
function controllersForSurface(surface, adapters) {
|
|
5924
|
+
return surface === "engine" ? [] : [
|
|
5925
|
+
...BASE_CONTROLLERS,
|
|
5926
|
+
...adapterControllers(adapters)
|
|
5927
|
+
];
|
|
5873
5928
|
}
|
|
5874
5929
|
__name(controllersForSurface, "controllersForSurface");
|
|
5875
5930
|
var GUARDS_METADATA = "__guards__";
|
|
5876
|
-
function applyGuards(guards) {
|
|
5931
|
+
function applyGuards(guards, adapters) {
|
|
5877
5932
|
const resolved = guards ?? [];
|
|
5878
|
-
for (const controller of
|
|
5933
|
+
for (const controller of [
|
|
5934
|
+
...BASE_CONTROLLERS,
|
|
5935
|
+
...adapterControllers(adapters)
|
|
5936
|
+
]) {
|
|
5879
5937
|
Reflect.defineMetadata(GUARDS_METADATA, resolved, controller);
|
|
5880
5938
|
}
|
|
5881
5939
|
}
|
|
@@ -5901,7 +5959,7 @@ var AgentModule = class _AgentModule {
|
|
|
5901
5959
|
}
|
|
5902
5960
|
static forRoot(options) {
|
|
5903
5961
|
const path = options.path ?? DEFAULT_PATH;
|
|
5904
|
-
applyGuards(options.guards);
|
|
5962
|
+
applyGuards(options.guards, options.adapters);
|
|
5905
5963
|
return {
|
|
5906
5964
|
module: _AgentModule,
|
|
5907
5965
|
global: true,
|
|
@@ -5909,21 +5967,22 @@ var AgentModule = class _AgentModule {
|
|
|
5909
5967
|
import_core4.DiscoveryModule,
|
|
5910
5968
|
routerFor(path)
|
|
5911
5969
|
],
|
|
5912
|
-
controllers: controllersForSurface(options.surface),
|
|
5970
|
+
controllers: controllersForSurface(options.surface, options.adapters),
|
|
5913
5971
|
providers: [
|
|
5914
5972
|
{
|
|
5915
5973
|
provide: import_nestjs_agent_core31.AGENT_OPTIONS,
|
|
5916
5974
|
useValue: options
|
|
5917
5975
|
},
|
|
5918
5976
|
...sharedProviders(options.durable ?? false),
|
|
5919
|
-
...guardProviders(options.guards)
|
|
5977
|
+
...guardProviders(options.guards),
|
|
5978
|
+
...adapterProviders(options.adapters)
|
|
5920
5979
|
],
|
|
5921
5980
|
exports: exportsFor()
|
|
5922
5981
|
};
|
|
5923
5982
|
}
|
|
5924
5983
|
static forRootAsync(options) {
|
|
5925
5984
|
const path = options.path ?? DEFAULT_PATH;
|
|
5926
|
-
applyGuards(options.guards);
|
|
5985
|
+
applyGuards(options.guards, options.adapters);
|
|
5927
5986
|
return {
|
|
5928
5987
|
module: _AgentModule,
|
|
5929
5988
|
global: true,
|
|
@@ -5932,7 +5991,7 @@ var AgentModule = class _AgentModule {
|
|
|
5932
5991
|
routerFor(path),
|
|
5933
5992
|
...options.imports ?? []
|
|
5934
5993
|
],
|
|
5935
|
-
controllers: controllersForSurface(options.surface),
|
|
5994
|
+
controllers: controllersForSurface(options.surface, options.adapters),
|
|
5936
5995
|
providers: [
|
|
5937
5996
|
{
|
|
5938
5997
|
provide: import_nestjs_agent_core31.AGENT_OPTIONS,
|
|
@@ -5950,7 +6009,8 @@ var AgentModule = class _AgentModule {
|
|
|
5950
6009
|
inject: options.inject ?? []
|
|
5951
6010
|
},
|
|
5952
6011
|
...sharedProviders(options.durable ?? false),
|
|
5953
|
-
...guardProviders(options.guards)
|
|
6012
|
+
...guardProviders(options.guards),
|
|
6013
|
+
...adapterProviders(options.adapters)
|
|
5954
6014
|
],
|
|
5955
6015
|
exports: exportsFor()
|
|
5956
6016
|
};
|