@cuylabs/agent-runtime-dapr 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +154 -19
- package/dist/{chunk-2CEICSJH.js → chunk-5CJIC4YB.js} +184 -38
- package/dist/{chunk-A34CHK2E.js → chunk-MQJ4LZOX.js} +30 -4
- package/dist/chunk-O7H3XGY2.js +11222 -0
- package/dist/chunk-YQQTUE6B.js +993 -0
- package/dist/chunk-YS2CWYBQ.js +1358 -0
- package/dist/client-UsEIzDF6.d.ts +322 -0
- package/dist/dispatch/index.d.ts +9 -0
- package/dist/dispatch/index.js +17 -0
- package/dist/execution/index.d.ts +5 -4
- package/dist/execution/index.js +2 -2
- package/dist/host/index.d.ts +8 -4
- package/dist/host/index.js +28 -8
- package/dist/index-BY0FipV1.d.ts +770 -0
- package/dist/index-CFm5LORU.d.ts +63 -0
- package/dist/index-UtePd9on.d.ts +101 -0
- package/dist/index.d.ts +62 -14
- package/dist/index.js +76 -6
- package/dist/invoker-B6ikdYaz.d.ts +50 -0
- package/dist/{store-pRLGfYhN.d.ts → store-BXBIDz40.d.ts} +24 -3
- package/dist/team/index.d.ts +612 -0
- package/dist/team/index.js +30 -0
- package/dist/worker-CXq0IFGX.d.ts +42 -0
- package/dist/workflow/index.d.ts +4 -225
- package/dist/workflow/index.js +2 -2
- package/dist/{workflow-bridge-C8Z1yr0Y.d.ts → workflow-bridge-BcicHH1Y.d.ts} +4 -2
- package/dist/workflow-host-D6W6fXoL.d.ts +459 -0
- package/package.json +16 -6
- package/dist/chunk-DILON56B.js +0 -668
- package/dist/chunk-R47X4FG2.js +0 -2009
- package/dist/index-BCMkUMAf.d.ts +0 -564
|
@@ -0,0 +1,993 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DaprSidecarClient,
|
|
3
|
+
isDaprConflictError
|
|
4
|
+
} from "./chunk-MQJ4LZOX.js";
|
|
5
|
+
|
|
6
|
+
// src/dispatch/runtime.ts
|
|
7
|
+
import {
|
|
8
|
+
ensureNonEmpty as ensureNonEmpty2,
|
|
9
|
+
mergeInspection,
|
|
10
|
+
sleep
|
|
11
|
+
} from "@cuylabs/agent-core";
|
|
12
|
+
|
|
13
|
+
// src/host/invoker.ts
|
|
14
|
+
var DEFAULT_DAPR_HTTP_ENDPOINT = "http://127.0.0.1:3500";
|
|
15
|
+
var DEFAULT_REQUEST_TIMEOUT_MS = 15e3;
|
|
16
|
+
function trimTrailingSlash(input) {
|
|
17
|
+
return input.replace(/\/+$/, "");
|
|
18
|
+
}
|
|
19
|
+
function ensureNonEmpty(input, label) {
|
|
20
|
+
const normalized = input.trim();
|
|
21
|
+
if (!normalized) {
|
|
22
|
+
throw new Error(`${label} must not be empty`);
|
|
23
|
+
}
|
|
24
|
+
return normalized;
|
|
25
|
+
}
|
|
26
|
+
function ensurePositiveInt(input, label) {
|
|
27
|
+
if (!Number.isFinite(input)) {
|
|
28
|
+
throw new Error(`${label} must be a finite number`);
|
|
29
|
+
}
|
|
30
|
+
const normalized = Math.floor(input);
|
|
31
|
+
if (normalized <= 0) {
|
|
32
|
+
throw new Error(`${label} must be greater than zero`);
|
|
33
|
+
}
|
|
34
|
+
return normalized;
|
|
35
|
+
}
|
|
36
|
+
function toQueryString(query) {
|
|
37
|
+
if (!query) {
|
|
38
|
+
return "";
|
|
39
|
+
}
|
|
40
|
+
const params = new URLSearchParams();
|
|
41
|
+
for (const [key, value] of Object.entries(query)) {
|
|
42
|
+
if (value === void 0) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
params.set(key, String(value));
|
|
46
|
+
}
|
|
47
|
+
const encoded = params.toString();
|
|
48
|
+
return encoded ? `?${encoded}` : "";
|
|
49
|
+
}
|
|
50
|
+
function parseJson(text) {
|
|
51
|
+
if (!text.trim()) {
|
|
52
|
+
return void 0;
|
|
53
|
+
}
|
|
54
|
+
return JSON.parse(text);
|
|
55
|
+
}
|
|
56
|
+
function normalizeMethodPath(methodPath) {
|
|
57
|
+
return methodPath.split("/").map((part) => part.trim()).filter(Boolean).map((part) => encodeURIComponent(part)).join("/");
|
|
58
|
+
}
|
|
59
|
+
function isAbortError(error) {
|
|
60
|
+
return error instanceof Error && error.name === "AbortError";
|
|
61
|
+
}
|
|
62
|
+
var DaprServiceInvoker = class {
|
|
63
|
+
daprHttpEndpoint;
|
|
64
|
+
apiToken;
|
|
65
|
+
requestTimeoutMs;
|
|
66
|
+
fetchImpl;
|
|
67
|
+
constructor(options = {}) {
|
|
68
|
+
this.daprHttpEndpoint = trimTrailingSlash(
|
|
69
|
+
options.daprHttpEndpoint ?? DEFAULT_DAPR_HTTP_ENDPOINT
|
|
70
|
+
);
|
|
71
|
+
this.apiToken = options.apiToken?.trim() || void 0;
|
|
72
|
+
this.requestTimeoutMs = ensurePositiveInt(
|
|
73
|
+
options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,
|
|
74
|
+
"requestTimeoutMs"
|
|
75
|
+
);
|
|
76
|
+
if (options.fetch) {
|
|
77
|
+
this.fetchImpl = options.fetch;
|
|
78
|
+
} else if (typeof globalThis.fetch === "function") {
|
|
79
|
+
this.fetchImpl = globalThis.fetch.bind(globalThis);
|
|
80
|
+
} else {
|
|
81
|
+
throw new Error(
|
|
82
|
+
"No fetch implementation available. Provide options.fetch."
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async invokeMethod(appId, methodPath, options = {}) {
|
|
87
|
+
const normalizedAppId = ensureNonEmpty(appId, "appId");
|
|
88
|
+
const normalizedMethod = normalizeMethodPath(
|
|
89
|
+
ensureNonEmpty(methodPath, "methodPath")
|
|
90
|
+
);
|
|
91
|
+
const timeoutMs = ensurePositiveInt(
|
|
92
|
+
options.timeoutMs ?? this.requestTimeoutMs,
|
|
93
|
+
"timeoutMs"
|
|
94
|
+
);
|
|
95
|
+
const query = toQueryString(options.query);
|
|
96
|
+
const method = options.method ?? (options.body === void 0 ? "GET" : "POST");
|
|
97
|
+
const headers = new Headers(options.headers);
|
|
98
|
+
let body;
|
|
99
|
+
if (options.body !== void 0) {
|
|
100
|
+
if (typeof options.body === "string" || options.body instanceof Blob || options.body instanceof ArrayBuffer || ArrayBuffer.isView(options.body) || options.body instanceof URLSearchParams || options.body instanceof FormData) {
|
|
101
|
+
body = options.body;
|
|
102
|
+
} else {
|
|
103
|
+
if (!headers.has("content-type")) {
|
|
104
|
+
headers.set("content-type", "application/json");
|
|
105
|
+
}
|
|
106
|
+
body = JSON.stringify(options.body);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (this.apiToken && !headers.has("dapr-api-token")) {
|
|
110
|
+
headers.set("dapr-api-token", this.apiToken);
|
|
111
|
+
}
|
|
112
|
+
const timeoutController = new AbortController();
|
|
113
|
+
const timeout = setTimeout(() => {
|
|
114
|
+
timeoutController.abort();
|
|
115
|
+
}, timeoutMs);
|
|
116
|
+
timeout.unref?.();
|
|
117
|
+
const url = `${this.daprHttpEndpoint}/v1.0/invoke/${encodeURIComponent(normalizedAppId)}/method/${normalizedMethod}${query}`;
|
|
118
|
+
try {
|
|
119
|
+
const response = await this.fetchImpl(url, {
|
|
120
|
+
method,
|
|
121
|
+
headers,
|
|
122
|
+
body,
|
|
123
|
+
signal: timeoutController.signal
|
|
124
|
+
});
|
|
125
|
+
const text = await response.text();
|
|
126
|
+
if (response.status < 200 || response.status >= 300) {
|
|
127
|
+
throw new Error(
|
|
128
|
+
`Dapr service invocation failed (${response.status}) ${method} ${methodPath}${text ? `: ${text}` : ""}`
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
let parsed;
|
|
132
|
+
if (text.trim()) {
|
|
133
|
+
try {
|
|
134
|
+
parsed = parseJson(text);
|
|
135
|
+
} catch {
|
|
136
|
+
parsed = text;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
status: response.status,
|
|
141
|
+
data: parsed,
|
|
142
|
+
headers: response.headers
|
|
143
|
+
};
|
|
144
|
+
} catch (error) {
|
|
145
|
+
if (isAbortError(error)) {
|
|
146
|
+
throw new Error(
|
|
147
|
+
`Dapr service invocation timed out after ${timeoutMs}ms: ${method} ${methodPath}`
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
if (error instanceof Error) {
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
throw new Error(String(error));
|
|
154
|
+
} finally {
|
|
155
|
+
clearTimeout(timeout);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
async function invokeRemoteAgentRun(invoker, appId, request, methodPath = "agents/run") {
|
|
160
|
+
const response = await invoker.invokeMethod(appId, methodPath, {
|
|
161
|
+
method: "POST",
|
|
162
|
+
body: request
|
|
163
|
+
});
|
|
164
|
+
if (!response.data) {
|
|
165
|
+
throw new Error("Remote agent invocation returned no response body");
|
|
166
|
+
}
|
|
167
|
+
return response.data;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// src/dispatch/runtime.ts
|
|
171
|
+
var DEFAULT_KEY_PREFIX = "agent-runtime:dispatch:";
|
|
172
|
+
var STORED_KIND = "@cuylabs/agent-runtime-dapr/dispatch-record";
|
|
173
|
+
var STORED_VERSION = 1;
|
|
174
|
+
var DEFAULT_INDEX_UPDATE_RETRIES = 4;
|
|
175
|
+
var DEFAULT_POLL_INTERVAL_MS = 500;
|
|
176
|
+
function cloneRecord(record) {
|
|
177
|
+
return structuredClone(record);
|
|
178
|
+
}
|
|
179
|
+
function toStoredRecord(record) {
|
|
180
|
+
return {
|
|
181
|
+
kind: STORED_KIND,
|
|
182
|
+
version: STORED_VERSION,
|
|
183
|
+
record
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function fromStoredRecord(value) {
|
|
187
|
+
if (!value || typeof value !== "object") {
|
|
188
|
+
return void 0;
|
|
189
|
+
}
|
|
190
|
+
const envelope = value;
|
|
191
|
+
if (envelope.kind !== STORED_KIND || envelope.version !== STORED_VERSION || !envelope.record) {
|
|
192
|
+
return void 0;
|
|
193
|
+
}
|
|
194
|
+
return cloneRecord(envelope.record);
|
|
195
|
+
}
|
|
196
|
+
function normalizeStatuses(status) {
|
|
197
|
+
if (!status) {
|
|
198
|
+
return void 0;
|
|
199
|
+
}
|
|
200
|
+
return new Set(Array.isArray(status) ? status : [status]);
|
|
201
|
+
}
|
|
202
|
+
function createDaprDispatchRecordWriter(options) {
|
|
203
|
+
const client = new DaprSidecarClient(options);
|
|
204
|
+
const agentId = ensureNonEmpty2(options.agentId, "agentId");
|
|
205
|
+
const keyPrefix = ensureNonEmpty2(
|
|
206
|
+
options.keyPrefix ?? DEFAULT_KEY_PREFIX,
|
|
207
|
+
"keyPrefix"
|
|
208
|
+
);
|
|
209
|
+
function recordKey(id) {
|
|
210
|
+
return `${keyPrefix}records/${agentId}/${id}`;
|
|
211
|
+
}
|
|
212
|
+
function globalIndexKey() {
|
|
213
|
+
return `${keyPrefix}record-index/${agentId}`;
|
|
214
|
+
}
|
|
215
|
+
function sessionIndexKey(sessionId) {
|
|
216
|
+
return `${keyPrefix}session-index/${agentId}/${sessionId}`;
|
|
217
|
+
}
|
|
218
|
+
async function readIndex(key) {
|
|
219
|
+
const entry = await client.getStateEntry(key);
|
|
220
|
+
if (entry.value === void 0) {
|
|
221
|
+
return { exists: false };
|
|
222
|
+
}
|
|
223
|
+
if (!Array.isArray(entry.value)) {
|
|
224
|
+
return { ids: [], etag: entry.etag, exists: true };
|
|
225
|
+
}
|
|
226
|
+
return {
|
|
227
|
+
ids: [...new Set(entry.value.filter((item) => typeof item === "string"))],
|
|
228
|
+
etag: entry.etag,
|
|
229
|
+
exists: true
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
async function writeIndex(key, ids, etag) {
|
|
233
|
+
await client.saveState(key, [...new Set(ids)], {
|
|
234
|
+
...etag ? { etag } : {},
|
|
235
|
+
concurrency: etag ? "first-write" : void 0
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
async function updateIndex(key, updater) {
|
|
239
|
+
for (let attempt = 0; attempt < DEFAULT_INDEX_UPDATE_RETRIES; attempt += 1) {
|
|
240
|
+
const current = await readIndex(key);
|
|
241
|
+
const next = updater(current.ids ?? []);
|
|
242
|
+
if (!next) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
try {
|
|
246
|
+
await writeIndex(key, next, current.etag);
|
|
247
|
+
return;
|
|
248
|
+
} catch (error) {
|
|
249
|
+
if (isDaprConflictError(error) && attempt + 1 < DEFAULT_INDEX_UPDATE_RETRIES) {
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
throw error;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
async function addRecordToIndex(key, id) {
|
|
257
|
+
await updateIndex(key, (ids) => {
|
|
258
|
+
if (ids.includes(id)) {
|
|
259
|
+
return void 0;
|
|
260
|
+
}
|
|
261
|
+
return [...ids, id];
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
return {
|
|
265
|
+
async saveStartedRecord(record) {
|
|
266
|
+
await client.saveState(recordKey(record.id), toStoredRecord(record), {
|
|
267
|
+
concurrency: "first-write"
|
|
268
|
+
});
|
|
269
|
+
await addRecordToIndex(globalIndexKey(), record.id);
|
|
270
|
+
if (record.parentSessionId) {
|
|
271
|
+
await addRecordToIndex(sessionIndexKey(record.parentSessionId), record.id);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
function mapWorkflowStatus(status) {
|
|
277
|
+
switch (status) {
|
|
278
|
+
case "COMPLETED":
|
|
279
|
+
return "completed";
|
|
280
|
+
case "FAILED":
|
|
281
|
+
return "failed";
|
|
282
|
+
case "TERMINATED":
|
|
283
|
+
return "cancelled";
|
|
284
|
+
default:
|
|
285
|
+
return "running";
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
function createWorkflowDispatchTarget(options) {
|
|
289
|
+
return {
|
|
290
|
+
name: options.name,
|
|
291
|
+
description: options.description,
|
|
292
|
+
async start(input) {
|
|
293
|
+
const prepared = await options.host.startTurn(
|
|
294
|
+
options.client,
|
|
295
|
+
options.buildRequest?.(input) ?? {
|
|
296
|
+
message: input.brief,
|
|
297
|
+
sessionId: input.sessionId
|
|
298
|
+
}
|
|
299
|
+
);
|
|
300
|
+
if (options.waitForStart) {
|
|
301
|
+
await options.client.waitForWorkflowStart(
|
|
302
|
+
prepared.workflowInstanceId
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
return {
|
|
306
|
+
sessionId: prepared.sessionId,
|
|
307
|
+
executionId: prepared.workflowInstanceId
|
|
308
|
+
};
|
|
309
|
+
},
|
|
310
|
+
async redirect(input) {
|
|
311
|
+
if (!options.host.steerTurn) {
|
|
312
|
+
throw new Error(
|
|
313
|
+
`Workflow dispatch target "${options.name}" does not expose durable steering.`
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
const executionId = input.record.executionId ?? ensureNonEmpty2(input.record.id, "record.id");
|
|
317
|
+
await options.host.steerTurn(options.client, {
|
|
318
|
+
workflowInstanceId: executionId,
|
|
319
|
+
sessionId: input.record.sessionId ?? ensureNonEmpty2(input.record.parentSessionId ?? "", "record.sessionId"),
|
|
320
|
+
message: input.message
|
|
321
|
+
});
|
|
322
|
+
},
|
|
323
|
+
async cancel(input) {
|
|
324
|
+
const executionId = ensureNonEmpty2(
|
|
325
|
+
input.record.executionId ?? "",
|
|
326
|
+
"record.executionId"
|
|
327
|
+
);
|
|
328
|
+
await options.client.terminateWorkflow(executionId);
|
|
329
|
+
},
|
|
330
|
+
async check(input) {
|
|
331
|
+
const executionId = input.record.executionId;
|
|
332
|
+
if (!executionId) {
|
|
333
|
+
return void 0;
|
|
334
|
+
}
|
|
335
|
+
const workflow = await options.client.getWorkflow(executionId);
|
|
336
|
+
if (!workflow) {
|
|
337
|
+
return {
|
|
338
|
+
status: "failed",
|
|
339
|
+
error: `Workflow "${executionId}" was not found.`
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
const snapshot = {
|
|
343
|
+
status: mapWorkflowStatus(workflow.runtimeStatus),
|
|
344
|
+
updatedAt: workflow.lastUpdatedAt ?? workflow.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
345
|
+
};
|
|
346
|
+
if (options.readCompletion && snapshot.status !== "running") {
|
|
347
|
+
const completion = await options.readCompletion({
|
|
348
|
+
record: input.record,
|
|
349
|
+
workflow
|
|
350
|
+
});
|
|
351
|
+
if (completion?.result) {
|
|
352
|
+
snapshot.result = completion.result;
|
|
353
|
+
}
|
|
354
|
+
if (completion?.error) {
|
|
355
|
+
snapshot.error = completion.error;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return snapshot;
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
function createRemoteAgentDispatchTarget(options) {
|
|
363
|
+
const invoker = options.invoker ?? new DaprServiceInvoker(options.invokerOptions);
|
|
364
|
+
function resolveAgentId(record) {
|
|
365
|
+
return options.agentId ?? record.agentId ?? record.targetType;
|
|
366
|
+
}
|
|
367
|
+
return {
|
|
368
|
+
name: options.name,
|
|
369
|
+
description: options.description,
|
|
370
|
+
async start(input) {
|
|
371
|
+
const methodPath = options.agentId ? `agents/${encodeURIComponent(options.agentId)}/run-durable` : "agents/run-durable";
|
|
372
|
+
const response = await invoker.invokeMethod(options.appId, methodPath, {
|
|
373
|
+
method: "POST",
|
|
374
|
+
body: options.buildRunRequest?.(input) ?? {
|
|
375
|
+
message: input.brief,
|
|
376
|
+
sessionId: input.sessionId ?? input.parentSessionId,
|
|
377
|
+
...options.agentId ? {} : { agentId: options.name }
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
if (!response.data?.instanceId) {
|
|
381
|
+
throw new Error(
|
|
382
|
+
`Remote agent "${options.appId}" did not return a workflow instanceId.`
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
return {
|
|
386
|
+
sessionId: response.data.sessionId,
|
|
387
|
+
executionId: response.data.instanceId,
|
|
388
|
+
...response.data.agentId ? { agentId: response.data.agentId } : {}
|
|
389
|
+
};
|
|
390
|
+
},
|
|
391
|
+
async redirect(input) {
|
|
392
|
+
const executionId = ensureNonEmpty2(
|
|
393
|
+
input.record.executionId ?? input.record.id,
|
|
394
|
+
"record.executionId"
|
|
395
|
+
);
|
|
396
|
+
await invoker.invokeMethod(
|
|
397
|
+
options.appId,
|
|
398
|
+
`agents/${encodeURIComponent(resolveAgentId(input.record))}/steer`,
|
|
399
|
+
{
|
|
400
|
+
method: "POST",
|
|
401
|
+
body: {
|
|
402
|
+
workflowInstanceId: executionId,
|
|
403
|
+
sessionId: input.record.sessionId ?? input.record.parentSessionId,
|
|
404
|
+
message: input.message
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
);
|
|
408
|
+
},
|
|
409
|
+
async cancel(input) {
|
|
410
|
+
const executionId = ensureNonEmpty2(
|
|
411
|
+
input.record.executionId ?? input.record.id,
|
|
412
|
+
"record.executionId"
|
|
413
|
+
);
|
|
414
|
+
await invoker.invokeMethod(
|
|
415
|
+
options.appId,
|
|
416
|
+
`agents/${encodeURIComponent(resolveAgentId(input.record))}/workflows/${encodeURIComponent(executionId)}/terminate`,
|
|
417
|
+
{
|
|
418
|
+
method: "POST",
|
|
419
|
+
body: { reason: input.reason }
|
|
420
|
+
}
|
|
421
|
+
);
|
|
422
|
+
},
|
|
423
|
+
async check(input) {
|
|
424
|
+
const executionId = ensureNonEmpty2(
|
|
425
|
+
input.record.executionId ?? input.record.id,
|
|
426
|
+
"record.executionId"
|
|
427
|
+
);
|
|
428
|
+
const agentId = resolveAgentId(input.record);
|
|
429
|
+
const workflow = await invoker.invokeMethod(
|
|
430
|
+
options.appId,
|
|
431
|
+
`agents/${encodeURIComponent(agentId)}/workflows/${encodeURIComponent(executionId)}`,
|
|
432
|
+
{ method: "GET" }
|
|
433
|
+
);
|
|
434
|
+
const runtimeStatus = workflow.data?.runtimeStatus;
|
|
435
|
+
if (!runtimeStatus) {
|
|
436
|
+
return void 0;
|
|
437
|
+
}
|
|
438
|
+
const inspection = {
|
|
439
|
+
status: mapWorkflowStatus(runtimeStatus),
|
|
440
|
+
updatedAt: workflow.data?.lastUpdatedAt ?? workflow.data?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
441
|
+
};
|
|
442
|
+
if (inspection.status === "completed") {
|
|
443
|
+
const execution = await invoker.invokeMethod(
|
|
444
|
+
options.appId,
|
|
445
|
+
`agents/${encodeURIComponent(agentId)}/executions/${encodeURIComponent(
|
|
446
|
+
input.record.sessionId ?? ""
|
|
447
|
+
)}`,
|
|
448
|
+
{ method: "GET" }
|
|
449
|
+
).catch(() => ({ data: void 0 }));
|
|
450
|
+
if (execution.data?.result) {
|
|
451
|
+
inspection.result = {
|
|
452
|
+
response: execution.data.result.response ?? "",
|
|
453
|
+
usage: execution.data.result.usage ?? {
|
|
454
|
+
inputTokens: 0,
|
|
455
|
+
outputTokens: 0,
|
|
456
|
+
totalTokens: 0
|
|
457
|
+
},
|
|
458
|
+
toolCalls: execution.data.result.toolCalls ?? []
|
|
459
|
+
};
|
|
460
|
+
} else if (execution.data?.error?.message) {
|
|
461
|
+
inspection.error = execution.data.error.message;
|
|
462
|
+
} else {
|
|
463
|
+
inspection.result = {
|
|
464
|
+
response: `[Remote workflow ${executionId} completed]`,
|
|
465
|
+
usage: {
|
|
466
|
+
inputTokens: 0,
|
|
467
|
+
outputTokens: 0,
|
|
468
|
+
totalTokens: 0
|
|
469
|
+
},
|
|
470
|
+
toolCalls: []
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
} else if (inspection.status === "failed" || inspection.status === "cancelled") {
|
|
474
|
+
const execution = await invoker.invokeMethod(
|
|
475
|
+
options.appId,
|
|
476
|
+
`agents/${encodeURIComponent(agentId)}/executions/${encodeURIComponent(
|
|
477
|
+
input.record.sessionId ?? ""
|
|
478
|
+
)}`,
|
|
479
|
+
{ method: "GET" }
|
|
480
|
+
).catch(() => ({ data: void 0 }));
|
|
481
|
+
if (execution.data?.error?.message) {
|
|
482
|
+
inspection.error = execution.data.error.message;
|
|
483
|
+
} else {
|
|
484
|
+
inspection.error = inspection.status === "cancelled" ? `Remote workflow "${executionId}" was cancelled.` : `Remote workflow "${executionId}" failed.`;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
return inspection;
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
function createDaprDispatchRuntime(options) {
|
|
492
|
+
const client = new DaprSidecarClient(options);
|
|
493
|
+
const agentId = ensureNonEmpty2(options.agentId, "agentId");
|
|
494
|
+
const keyPrefix = ensureNonEmpty2(
|
|
495
|
+
options.keyPrefix ?? DEFAULT_KEY_PREFIX,
|
|
496
|
+
"keyPrefix"
|
|
497
|
+
);
|
|
498
|
+
const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
499
|
+
const createId = options.createId ?? (() => crypto.randomUUID());
|
|
500
|
+
const pollIntervalMs = Math.max(25, Math.floor(options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS));
|
|
501
|
+
const targets = new Map(
|
|
502
|
+
options.targets.map((target) => [target.name, target])
|
|
503
|
+
);
|
|
504
|
+
function recordKey(id) {
|
|
505
|
+
return `${keyPrefix}records/${agentId}/${id}`;
|
|
506
|
+
}
|
|
507
|
+
function globalIndexKey() {
|
|
508
|
+
return `${keyPrefix}record-index/${agentId}`;
|
|
509
|
+
}
|
|
510
|
+
function sessionIndexKey(sessionId) {
|
|
511
|
+
return `${keyPrefix}session-index/${agentId}/${sessionId}`;
|
|
512
|
+
}
|
|
513
|
+
async function getStoredRecord(id) {
|
|
514
|
+
const entry = await client.getStateEntry(recordKey(id));
|
|
515
|
+
return {
|
|
516
|
+
record: fromStoredRecord(entry.value),
|
|
517
|
+
etag: entry.etag
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
async function saveRecord(record, etag) {
|
|
521
|
+
await client.saveState(recordKey(record.id), toStoredRecord(record), {
|
|
522
|
+
...etag ? { etag } : {},
|
|
523
|
+
concurrency: "first-write"
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
async function readIndex(key) {
|
|
527
|
+
const entry = await client.getStateEntry(key);
|
|
528
|
+
if (entry.value === void 0) {
|
|
529
|
+
return { exists: false };
|
|
530
|
+
}
|
|
531
|
+
if (!Array.isArray(entry.value)) {
|
|
532
|
+
return { ids: [], etag: entry.etag, exists: true };
|
|
533
|
+
}
|
|
534
|
+
return {
|
|
535
|
+
ids: [...new Set(entry.value.filter((item) => typeof item === "string"))],
|
|
536
|
+
etag: entry.etag,
|
|
537
|
+
exists: true
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
async function writeIndex(key, ids, etag) {
|
|
541
|
+
await client.saveState(key, [...new Set(ids)], {
|
|
542
|
+
...etag ? { etag } : {},
|
|
543
|
+
concurrency: etag ? "first-write" : void 0
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
async function updateIndex(key, updater) {
|
|
547
|
+
for (let attempt = 0; attempt < DEFAULT_INDEX_UPDATE_RETRIES; attempt += 1) {
|
|
548
|
+
const current = await readIndex(key);
|
|
549
|
+
const next = updater(current.ids ?? []);
|
|
550
|
+
if (!next) {
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
try {
|
|
554
|
+
await writeIndex(key, next, current.etag);
|
|
555
|
+
return;
|
|
556
|
+
} catch (error) {
|
|
557
|
+
if (isDaprConflictError(error) && attempt + 1 < DEFAULT_INDEX_UPDATE_RETRIES) {
|
|
558
|
+
continue;
|
|
559
|
+
}
|
|
560
|
+
throw error;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
async function addRecordToIndex(key, id) {
|
|
565
|
+
await updateIndex(key, (ids) => {
|
|
566
|
+
if (ids.includes(id)) {
|
|
567
|
+
return void 0;
|
|
568
|
+
}
|
|
569
|
+
return [...ids, id];
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
async function updateStoredRecord(id, updater) {
|
|
573
|
+
for (let attempt = 0; attempt < DEFAULT_INDEX_UPDATE_RETRIES; attempt += 1) {
|
|
574
|
+
const current = await getStoredRecord(id);
|
|
575
|
+
if (!current.record) {
|
|
576
|
+
throw new Error(`Unknown dispatch "${id}".`);
|
|
577
|
+
}
|
|
578
|
+
const next = updater(current.record);
|
|
579
|
+
try {
|
|
580
|
+
await saveRecord(next, current.etag);
|
|
581
|
+
return cloneRecord(next);
|
|
582
|
+
} catch (error) {
|
|
583
|
+
if (isDaprConflictError(error) && attempt + 1 < DEFAULT_INDEX_UPDATE_RETRIES) {
|
|
584
|
+
continue;
|
|
585
|
+
}
|
|
586
|
+
throw error;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
throw new Error(`Failed to update dispatch "${id}".`);
|
|
590
|
+
}
|
|
591
|
+
async function refreshRecord(id) {
|
|
592
|
+
const current = await getStoredRecord(id);
|
|
593
|
+
if (!current.record) {
|
|
594
|
+
return void 0;
|
|
595
|
+
}
|
|
596
|
+
const target = targets.get(current.record.targetType);
|
|
597
|
+
if (!target?.check || current.record.status !== "running") {
|
|
598
|
+
return current.record;
|
|
599
|
+
}
|
|
600
|
+
const inspection = await target.check({
|
|
601
|
+
record: cloneRecord(current.record)
|
|
602
|
+
});
|
|
603
|
+
if (!inspection) {
|
|
604
|
+
return current.record;
|
|
605
|
+
}
|
|
606
|
+
const next = mergeInspection(current.record, inspection, now());
|
|
607
|
+
if (JSON.stringify(next) === JSON.stringify(current.record)) {
|
|
608
|
+
return next;
|
|
609
|
+
}
|
|
610
|
+
try {
|
|
611
|
+
await saveRecord(next, current.etag);
|
|
612
|
+
return cloneRecord(next);
|
|
613
|
+
} catch (error) {
|
|
614
|
+
if (isDaprConflictError(error)) {
|
|
615
|
+
return (await getStoredRecord(id)).record;
|
|
616
|
+
}
|
|
617
|
+
throw error;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
async function waitForCheck(id, checkOptions) {
|
|
621
|
+
const waitMs = checkOptions?.waitMs;
|
|
622
|
+
if (!waitMs || waitMs <= 0) {
|
|
623
|
+
return refreshRecord(id);
|
|
624
|
+
}
|
|
625
|
+
const deadline = Date.now() + waitMs;
|
|
626
|
+
let current = await refreshRecord(id);
|
|
627
|
+
while (current && current.status === "running" && Date.now() < deadline) {
|
|
628
|
+
await sleep(pollIntervalMs);
|
|
629
|
+
current = await refreshRecord(id);
|
|
630
|
+
}
|
|
631
|
+
return current;
|
|
632
|
+
}
|
|
633
|
+
async function listIndexedRecords(key) {
|
|
634
|
+
const current = await readIndex(key);
|
|
635
|
+
if (!current.exists) {
|
|
636
|
+
return [];
|
|
637
|
+
}
|
|
638
|
+
const entries = await Promise.all(
|
|
639
|
+
(current.ids ?? []).map((id) => getStoredRecord(id))
|
|
640
|
+
);
|
|
641
|
+
const records = [];
|
|
642
|
+
const presentIds = [];
|
|
643
|
+
for (const entry of entries) {
|
|
644
|
+
if (!entry.record || entry.record.agentId !== agentId) {
|
|
645
|
+
continue;
|
|
646
|
+
}
|
|
647
|
+
presentIds.push(entry.record.id);
|
|
648
|
+
records.push(entry.record);
|
|
649
|
+
}
|
|
650
|
+
if (presentIds.length !== (current.ids ?? []).length) {
|
|
651
|
+
await writeIndex(key, presentIds, current.etag).catch(() => {
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
return records;
|
|
655
|
+
}
|
|
656
|
+
return {
|
|
657
|
+
describeTargets() {
|
|
658
|
+
return options.targets.map((target) => ({
|
|
659
|
+
name: target.name,
|
|
660
|
+
description: target.description
|
|
661
|
+
}));
|
|
662
|
+
},
|
|
663
|
+
async start(input) {
|
|
664
|
+
const target = targets.get(
|
|
665
|
+
ensureNonEmpty2(input.targetType, "targetType")
|
|
666
|
+
);
|
|
667
|
+
if (!target) {
|
|
668
|
+
throw new Error(`Unknown dispatch target "${input.targetType}".`);
|
|
669
|
+
}
|
|
670
|
+
const id = createId();
|
|
671
|
+
const startedAt = now();
|
|
672
|
+
const title = input.title?.trim() || `Dispatch: ${target.name}`;
|
|
673
|
+
const brief = ensureNonEmpty2(input.brief, "brief");
|
|
674
|
+
const launched = await target.start({
|
|
675
|
+
id,
|
|
676
|
+
brief,
|
|
677
|
+
title,
|
|
678
|
+
parentSessionId: input.parentSessionId
|
|
679
|
+
});
|
|
680
|
+
const record = {
|
|
681
|
+
id,
|
|
682
|
+
agentId,
|
|
683
|
+
targetType: target.name,
|
|
684
|
+
title,
|
|
685
|
+
brief,
|
|
686
|
+
status: "running",
|
|
687
|
+
createdAt: startedAt,
|
|
688
|
+
updatedAt: startedAt,
|
|
689
|
+
parentSessionId: input.parentSessionId,
|
|
690
|
+
sessionId: launched.sessionId,
|
|
691
|
+
executionId: launched.executionId,
|
|
692
|
+
redirectCount: 0
|
|
693
|
+
};
|
|
694
|
+
await saveRecord(record);
|
|
695
|
+
await addRecordToIndex(globalIndexKey(), record.id);
|
|
696
|
+
if (record.parentSessionId) {
|
|
697
|
+
await addRecordToIndex(sessionIndexKey(record.parentSessionId), record.id);
|
|
698
|
+
}
|
|
699
|
+
return cloneRecord(record);
|
|
700
|
+
},
|
|
701
|
+
async check(id, checkOptions) {
|
|
702
|
+
const record = await waitForCheck(id, checkOptions);
|
|
703
|
+
return record ? cloneRecord(record) : void 0;
|
|
704
|
+
},
|
|
705
|
+
async redirect(id, message) {
|
|
706
|
+
const current = await refreshRecord(id);
|
|
707
|
+
if (!current) {
|
|
708
|
+
throw new Error(`Unknown dispatch "${id}".`);
|
|
709
|
+
}
|
|
710
|
+
if (current.status !== "running") {
|
|
711
|
+
throw new Error(
|
|
712
|
+
`Dispatch "${id}" is ${current.status} and cannot be redirected.`
|
|
713
|
+
);
|
|
714
|
+
}
|
|
715
|
+
const target = targets.get(current.targetType);
|
|
716
|
+
if (!target) {
|
|
717
|
+
throw new Error(`No target registered for dispatch target "${current.targetType}".`);
|
|
718
|
+
}
|
|
719
|
+
const nextMessage = ensureNonEmpty2(message, "message");
|
|
720
|
+
await target.redirect({
|
|
721
|
+
record: cloneRecord(current),
|
|
722
|
+
message: nextMessage
|
|
723
|
+
});
|
|
724
|
+
return updateStoredRecord(id, (record) => ({
|
|
725
|
+
...record,
|
|
726
|
+
updatedAt: now(),
|
|
727
|
+
redirectCount: record.redirectCount + 1,
|
|
728
|
+
lastRedirect: nextMessage
|
|
729
|
+
}));
|
|
730
|
+
},
|
|
731
|
+
async cancel(id, reason) {
|
|
732
|
+
const current = await refreshRecord(id);
|
|
733
|
+
if (!current) {
|
|
734
|
+
throw new Error(`Unknown dispatch "${id}".`);
|
|
735
|
+
}
|
|
736
|
+
if (current.status !== "running") {
|
|
737
|
+
return cloneRecord(current);
|
|
738
|
+
}
|
|
739
|
+
const target = targets.get(current.targetType);
|
|
740
|
+
if (!target) {
|
|
741
|
+
throw new Error(`No target registered for dispatch target "${current.targetType}".`);
|
|
742
|
+
}
|
|
743
|
+
await target.cancel({
|
|
744
|
+
record: cloneRecord(current),
|
|
745
|
+
reason
|
|
746
|
+
});
|
|
747
|
+
return updateStoredRecord(id, (record) => ({
|
|
748
|
+
...record,
|
|
749
|
+
status: "cancelled",
|
|
750
|
+
updatedAt: now(),
|
|
751
|
+
...reason ? { error: reason } : {}
|
|
752
|
+
}));
|
|
753
|
+
},
|
|
754
|
+
async list(listOptions = {}) {
|
|
755
|
+
const indexKey = listOptions.parentSessionId ? sessionIndexKey(listOptions.parentSessionId) : globalIndexKey();
|
|
756
|
+
const statuses = normalizeStatuses(listOptions.status);
|
|
757
|
+
const records = await listIndexedRecords(indexKey);
|
|
758
|
+
const refreshed = await Promise.all(
|
|
759
|
+
records.map(
|
|
760
|
+
(record) => record.status === "running" ? refreshRecord(record.id) : Promise.resolve(record)
|
|
761
|
+
)
|
|
762
|
+
);
|
|
763
|
+
return refreshed.filter((record) => record !== void 0).filter(
|
|
764
|
+
(record) => (!statuses || statuses.has(record.status)) && (!listOptions.targetType || record.targetType === listOptions.targetType)
|
|
765
|
+
).map((record) => cloneRecord(record)).sort((left, right) => left.createdAt.localeCompare(right.createdAt));
|
|
766
|
+
}
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
// src/dispatch/executor.ts
|
|
771
|
+
import {
|
|
772
|
+
createCompositeDispatchTaskExecutor,
|
|
773
|
+
createDispatchTaskExecutor
|
|
774
|
+
} from "@cuylabs/agent-core";
|
|
775
|
+
|
|
776
|
+
// src/dispatch/completion.ts
|
|
777
|
+
function zeroUsage() {
|
|
778
|
+
return {
|
|
779
|
+
inputTokens: 0,
|
|
780
|
+
outputTokens: 0,
|
|
781
|
+
totalTokens: 0
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
function toDispatchResult(value) {
|
|
785
|
+
if (!value) {
|
|
786
|
+
return void 0;
|
|
787
|
+
}
|
|
788
|
+
if (typeof value === "string") {
|
|
789
|
+
const response = value.trim();
|
|
790
|
+
return response ? { response, usage: zeroUsage(), toolCalls: [] } : void 0;
|
|
791
|
+
}
|
|
792
|
+
if (typeof value !== "object") {
|
|
793
|
+
return void 0;
|
|
794
|
+
}
|
|
795
|
+
const candidate = value;
|
|
796
|
+
if (typeof candidate.response !== "string" || !candidate.response.trim()) {
|
|
797
|
+
return void 0;
|
|
798
|
+
}
|
|
799
|
+
const toolCalls = Array.isArray(candidate.toolCalls) ? candidate.toolCalls : [];
|
|
800
|
+
return {
|
|
801
|
+
response: candidate.response,
|
|
802
|
+
usage: {
|
|
803
|
+
inputTokens: candidate.usage?.inputTokens ?? 0,
|
|
804
|
+
outputTokens: candidate.usage?.outputTokens ?? 0,
|
|
805
|
+
totalTokens: candidate.usage?.totalTokens ?? 0
|
|
806
|
+
},
|
|
807
|
+
toolCalls
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
function parseJsonProperty(value) {
|
|
811
|
+
if (!value) {
|
|
812
|
+
return void 0;
|
|
813
|
+
}
|
|
814
|
+
try {
|
|
815
|
+
return JSON.parse(value);
|
|
816
|
+
} catch {
|
|
817
|
+
return value;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
async function readWorkflowCompletion(input) {
|
|
821
|
+
const { record, workflow, executionStore } = input;
|
|
822
|
+
if (executionStore && record.sessionId) {
|
|
823
|
+
const execution = await executionStore.getExecution(record.sessionId);
|
|
824
|
+
if (execution?.result) {
|
|
825
|
+
return {
|
|
826
|
+
result: {
|
|
827
|
+
response: execution.result.response,
|
|
828
|
+
usage: {
|
|
829
|
+
inputTokens: execution.result.usage?.inputTokens ?? 0,
|
|
830
|
+
outputTokens: execution.result.usage?.outputTokens ?? 0,
|
|
831
|
+
totalTokens: execution.result.usage?.totalTokens ?? 0
|
|
832
|
+
},
|
|
833
|
+
toolCalls: execution.result.toolCalls
|
|
834
|
+
}
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
if (execution?.error?.message) {
|
|
838
|
+
return { error: execution.error.message };
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
const outputResult = toDispatchResult(
|
|
842
|
+
parseJsonProperty(workflow.properties["dapr.workflow.output"])
|
|
843
|
+
);
|
|
844
|
+
if (outputResult) {
|
|
845
|
+
return { result: outputResult };
|
|
846
|
+
}
|
|
847
|
+
const statusResult = toDispatchResult(
|
|
848
|
+
parseJsonProperty(workflow.properties["dapr.workflow.custom_status"])
|
|
849
|
+
);
|
|
850
|
+
if (statusResult) {
|
|
851
|
+
return { result: statusResult };
|
|
852
|
+
}
|
|
853
|
+
if (workflow.runtimeStatus === "FAILED") {
|
|
854
|
+
return { error: `Workflow "${workflow.instanceId}" failed.` };
|
|
855
|
+
}
|
|
856
|
+
if (workflow.runtimeStatus === "TERMINATED") {
|
|
857
|
+
return { error: `Workflow "${workflow.instanceId}" was terminated.` };
|
|
858
|
+
}
|
|
859
|
+
return {
|
|
860
|
+
result: {
|
|
861
|
+
response: `[Workflow ${workflow.instanceId} completed]`,
|
|
862
|
+
usage: zeroUsage(),
|
|
863
|
+
toolCalls: []
|
|
864
|
+
}
|
|
865
|
+
};
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
// src/dispatch/executor.ts
|
|
869
|
+
function createDispatchRecord(input) {
|
|
870
|
+
return {
|
|
871
|
+
id: input.dispatchId,
|
|
872
|
+
agentId: input.startResult.agentId ?? input.memberId,
|
|
873
|
+
targetType: input.targetName,
|
|
874
|
+
title: input.taskTitle,
|
|
875
|
+
brief: input.prompt,
|
|
876
|
+
status: "running",
|
|
877
|
+
createdAt: input.startedAt,
|
|
878
|
+
updatedAt: input.startedAt,
|
|
879
|
+
parentSessionId: input.parentSessionId,
|
|
880
|
+
sessionId: input.startResult.sessionId ?? input.memberSessionId,
|
|
881
|
+
executionId: input.startResult.executionId ?? input.dispatchId,
|
|
882
|
+
redirectCount: 0
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
function createDaprWorkflowDispatchExecutor(options) {
|
|
886
|
+
const targets = [...options.workflowHosts.entries()].map(
|
|
887
|
+
([name, host]) => createWorkflowDispatchTarget({
|
|
888
|
+
name,
|
|
889
|
+
description: `Durable workflow-backed member "${name}".`,
|
|
890
|
+
host,
|
|
891
|
+
client: options.workflowClient,
|
|
892
|
+
buildRequest: (input) => ({
|
|
893
|
+
message: input.brief,
|
|
894
|
+
sessionId: input.sessionId,
|
|
895
|
+
workflowInstanceId: input.id
|
|
896
|
+
}),
|
|
897
|
+
readCompletion: async ({ record, workflow }) => await readWorkflowCompletion({
|
|
898
|
+
record,
|
|
899
|
+
workflow,
|
|
900
|
+
executionStore: options.executionStore
|
|
901
|
+
})
|
|
902
|
+
})
|
|
903
|
+
);
|
|
904
|
+
return createDispatchTaskExecutor({
|
|
905
|
+
targets,
|
|
906
|
+
timeoutMs: options.timeoutMs,
|
|
907
|
+
pollIntervalMs: options.pollIntervalMs,
|
|
908
|
+
createRecord: ({
|
|
909
|
+
taskInput,
|
|
910
|
+
target,
|
|
911
|
+
dispatchId,
|
|
912
|
+
startedAt,
|
|
913
|
+
startResult
|
|
914
|
+
}) => createDispatchRecord({
|
|
915
|
+
taskTitle: taskInput.task.title,
|
|
916
|
+
prompt: taskInput.prompt,
|
|
917
|
+
parentSessionId: taskInput.parentSessionId,
|
|
918
|
+
memberSessionId: taskInput.runtime.member.sessionId,
|
|
919
|
+
memberId: taskInput.runtime.member.id,
|
|
920
|
+
targetName: target.name,
|
|
921
|
+
dispatchId,
|
|
922
|
+
startedAt,
|
|
923
|
+
startResult
|
|
924
|
+
})
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
function createDaprAppDispatchExecutor(options) {
|
|
928
|
+
const targets = [...options.appsByRole.entries()].map(
|
|
929
|
+
([name, appId]) => createRemoteAgentDispatchTarget({
|
|
930
|
+
name,
|
|
931
|
+
description: `App-backed member "${name}" on app "${appId}".`,
|
|
932
|
+
appId,
|
|
933
|
+
invoker: options.invoker,
|
|
934
|
+
invokerOptions: options.invoker ? void 0 : options.invokerOptions
|
|
935
|
+
})
|
|
936
|
+
);
|
|
937
|
+
return createDispatchTaskExecutor({
|
|
938
|
+
targets,
|
|
939
|
+
timeoutMs: options.timeoutMs,
|
|
940
|
+
pollIntervalMs: options.pollIntervalMs,
|
|
941
|
+
createRecord: ({
|
|
942
|
+
taskInput,
|
|
943
|
+
target,
|
|
944
|
+
dispatchId,
|
|
945
|
+
startedAt,
|
|
946
|
+
startResult
|
|
947
|
+
}) => createDispatchRecord({
|
|
948
|
+
taskTitle: taskInput.task.title,
|
|
949
|
+
prompt: taskInput.prompt,
|
|
950
|
+
parentSessionId: taskInput.parentSessionId,
|
|
951
|
+
memberSessionId: taskInput.runtime.member.sessionId,
|
|
952
|
+
memberId: taskInput.runtime.member.id,
|
|
953
|
+
targetName: target.name,
|
|
954
|
+
dispatchId,
|
|
955
|
+
startedAt,
|
|
956
|
+
startResult
|
|
957
|
+
})
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
function createDaprCompositeDispatchExecutor(options) {
|
|
961
|
+
const workflowExecutor = options.workflow ? createDaprWorkflowDispatchExecutor(options.workflow) : void 0;
|
|
962
|
+
const appExecutor = options.app ? createDaprAppDispatchExecutor(options.app) : void 0;
|
|
963
|
+
const routes = [];
|
|
964
|
+
if (workflowExecutor && options.workflow) {
|
|
965
|
+
routes.push({
|
|
966
|
+
matches: (input) => options.workflow.workflowHosts.has(input.runtime.member.role),
|
|
967
|
+
executor: workflowExecutor
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
if (appExecutor && options.app) {
|
|
971
|
+
routes.push({
|
|
972
|
+
matches: (input) => options.app.appsByRole.has(input.runtime.member.role),
|
|
973
|
+
executor: appExecutor
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
return createCompositeDispatchTaskExecutor({
|
|
977
|
+
routes,
|
|
978
|
+
fallback: options.fallback
|
|
979
|
+
});
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
export {
|
|
983
|
+
DaprServiceInvoker,
|
|
984
|
+
invokeRemoteAgentRun,
|
|
985
|
+
createDaprDispatchRecordWriter,
|
|
986
|
+
createWorkflowDispatchTarget,
|
|
987
|
+
createRemoteAgentDispatchTarget,
|
|
988
|
+
createDaprDispatchRuntime,
|
|
989
|
+
readWorkflowCompletion,
|
|
990
|
+
createDaprWorkflowDispatchExecutor,
|
|
991
|
+
createDaprAppDispatchExecutor,
|
|
992
|
+
createDaprCompositeDispatchExecutor
|
|
993
|
+
};
|