@cuylabs/agent-runtime-dapr 0.5.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.
@@ -0,0 +1,1997 @@
1
+ import {
2
+ DaprExecutionStore,
3
+ createDaprExecutionObserver,
4
+ createDaprLoggingObserver,
5
+ createWorkflowObserverBridge
6
+ } from "./chunk-2CEICSJH.js";
7
+ import {
8
+ DaprWorkflowClient,
9
+ createDaprAgentTurnWorkflowKit
10
+ } from "./chunk-DILON56B.js";
11
+ import {
12
+ DaprSidecarClient,
13
+ isDaprConflictError
14
+ } from "./chunk-A34CHK2E.js";
15
+
16
+ // src/host/invoker.ts
17
+ var DEFAULT_DAPR_HTTP_ENDPOINT = "http://127.0.0.1:3500";
18
+ var DEFAULT_REQUEST_TIMEOUT_MS = 15e3;
19
+ function trimTrailingSlash(input) {
20
+ return input.replace(/\/+$/, "");
21
+ }
22
+ function ensureNonEmpty(input, label) {
23
+ const normalized = input.trim();
24
+ if (!normalized) {
25
+ throw new Error(`${label} must not be empty`);
26
+ }
27
+ return normalized;
28
+ }
29
+ function ensurePositiveInt(input, label) {
30
+ if (!Number.isFinite(input)) {
31
+ throw new Error(`${label} must be a finite number`);
32
+ }
33
+ const normalized = Math.floor(input);
34
+ if (normalized <= 0) {
35
+ throw new Error(`${label} must be greater than zero`);
36
+ }
37
+ return normalized;
38
+ }
39
+ function toQueryString(query) {
40
+ if (!query) {
41
+ return "";
42
+ }
43
+ const params = new URLSearchParams();
44
+ for (const [key, value] of Object.entries(query)) {
45
+ if (value === void 0) {
46
+ continue;
47
+ }
48
+ params.set(key, String(value));
49
+ }
50
+ const encoded = params.toString();
51
+ return encoded ? `?${encoded}` : "";
52
+ }
53
+ function parseJson(text2) {
54
+ if (!text2.trim()) {
55
+ return void 0;
56
+ }
57
+ return JSON.parse(text2);
58
+ }
59
+ function normalizeMethodPath(methodPath) {
60
+ return methodPath.split("/").map((part) => part.trim()).filter(Boolean).map((part) => encodeURIComponent(part)).join("/");
61
+ }
62
+ function isAbortError(error) {
63
+ return error instanceof Error && error.name === "AbortError";
64
+ }
65
+ var DaprServiceInvoker = class {
66
+ daprHttpEndpoint;
67
+ apiToken;
68
+ requestTimeoutMs;
69
+ fetchImpl;
70
+ constructor(options = {}) {
71
+ this.daprHttpEndpoint = trimTrailingSlash(
72
+ options.daprHttpEndpoint ?? DEFAULT_DAPR_HTTP_ENDPOINT
73
+ );
74
+ this.apiToken = options.apiToken?.trim() || void 0;
75
+ this.requestTimeoutMs = ensurePositiveInt(
76
+ options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,
77
+ "requestTimeoutMs"
78
+ );
79
+ if (options.fetch) {
80
+ this.fetchImpl = options.fetch;
81
+ } else if (typeof globalThis.fetch === "function") {
82
+ this.fetchImpl = globalThis.fetch.bind(globalThis);
83
+ } else {
84
+ throw new Error(
85
+ "No fetch implementation available. Provide options.fetch."
86
+ );
87
+ }
88
+ }
89
+ async invokeMethod(appId, methodPath, options = {}) {
90
+ const normalizedAppId = ensureNonEmpty(appId, "appId");
91
+ const normalizedMethod = normalizeMethodPath(
92
+ ensureNonEmpty(methodPath, "methodPath")
93
+ );
94
+ const timeoutMs = ensurePositiveInt(
95
+ options.timeoutMs ?? this.requestTimeoutMs,
96
+ "timeoutMs"
97
+ );
98
+ const query = toQueryString(options.query);
99
+ const method = options.method ?? (options.body === void 0 ? "GET" : "POST");
100
+ const headers = new Headers(options.headers);
101
+ let body;
102
+ if (options.body !== void 0) {
103
+ 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) {
104
+ body = options.body;
105
+ } else {
106
+ if (!headers.has("content-type")) {
107
+ headers.set("content-type", "application/json");
108
+ }
109
+ body = JSON.stringify(options.body);
110
+ }
111
+ }
112
+ if (this.apiToken && !headers.has("dapr-api-token")) {
113
+ headers.set("dapr-api-token", this.apiToken);
114
+ }
115
+ const timeoutController = new AbortController();
116
+ const timeout = setTimeout(() => {
117
+ timeoutController.abort();
118
+ }, timeoutMs);
119
+ timeout.unref?.();
120
+ const url = `${this.daprHttpEndpoint}/v1.0/invoke/${encodeURIComponent(normalizedAppId)}/method/${normalizedMethod}${query}`;
121
+ try {
122
+ const response = await this.fetchImpl(url, {
123
+ method,
124
+ headers,
125
+ body,
126
+ signal: timeoutController.signal
127
+ });
128
+ const text2 = await response.text();
129
+ if (response.status < 200 || response.status >= 300) {
130
+ throw new Error(
131
+ `Dapr service invocation failed (${response.status}) ${method} ${methodPath}${text2 ? `: ${text2}` : ""}`
132
+ );
133
+ }
134
+ let parsed;
135
+ if (text2.trim()) {
136
+ try {
137
+ parsed = parseJson(text2);
138
+ } catch {
139
+ parsed = text2;
140
+ }
141
+ }
142
+ return {
143
+ status: response.status,
144
+ data: parsed,
145
+ headers: response.headers
146
+ };
147
+ } catch (error) {
148
+ if (isAbortError(error)) {
149
+ throw new Error(
150
+ `Dapr service invocation timed out after ${timeoutMs}ms: ${method} ${methodPath}`
151
+ );
152
+ }
153
+ if (error instanceof Error) {
154
+ throw error;
155
+ }
156
+ throw new Error(String(error));
157
+ } finally {
158
+ clearTimeout(timeout);
159
+ }
160
+ }
161
+ };
162
+ async function invokeRemoteAgentRun(invoker, appId, request, methodPath = "agents/run") {
163
+ const response = await invoker.invokeMethod(appId, methodPath, {
164
+ method: "POST",
165
+ body: request
166
+ });
167
+ if (!response.data) {
168
+ throw new Error("Remote agent invocation returned no response body");
169
+ }
170
+ return response.data;
171
+ }
172
+
173
+ // src/host/workflow-host.ts
174
+ import { randomUUID } from "crypto";
175
+ import {
176
+ SessionManager,
177
+ createAgentWorkflowTurnState,
178
+ snapshotAgentWorkflowMessages
179
+ } from "@cuylabs/agent-core";
180
+
181
+ // src/http.ts
182
+ var DEFAULT_HANDLED_STATUS = 200;
183
+ var DEFAULT_UNHANDLED_STATUS = 404;
184
+ var DEFAULT_ERROR_STATUS = 500;
185
+ function normalizeStatus(value, fallback) {
186
+ if (value === void 0) {
187
+ return fallback;
188
+ }
189
+ const normalized = Math.floor(value);
190
+ if (normalized < 100 || normalized > 599) {
191
+ throw new Error(`Invalid HTTP status code: ${value}`);
192
+ }
193
+ return normalized;
194
+ }
195
+ function createDaprHttpJobHandler(options) {
196
+ const handledStatus = normalizeStatus(options.handledStatus, DEFAULT_HANDLED_STATUS);
197
+ const unhandledStatus = normalizeStatus(options.unhandledStatus, DEFAULT_UNHANDLED_STATUS);
198
+ const errorStatus = normalizeStatus(options.errorStatus, DEFAULT_ERROR_STATUS);
199
+ return async (jobName) => {
200
+ const normalizedJobName = String(jobName).trim();
201
+ if (!normalizedJobName) {
202
+ return {
203
+ status: unhandledStatus,
204
+ handled: false
205
+ };
206
+ }
207
+ try {
208
+ const handled = await options.driver.handleJobTriggerByName(normalizedJobName);
209
+ return {
210
+ status: handled ? handledStatus : unhandledStatus,
211
+ handled
212
+ };
213
+ } catch (error) {
214
+ if (options.onError) {
215
+ await options.onError(error, normalizedJobName);
216
+ }
217
+ return {
218
+ status: errorStatus,
219
+ handled: false,
220
+ error
221
+ };
222
+ }
223
+ };
224
+ }
225
+
226
+ // src/jobs/api.ts
227
+ import {
228
+ computeNextRunAtMs
229
+ } from "@cuylabs/agent-runtime";
230
+ function toGoDurationMs(everyMs) {
231
+ const normalized = Math.max(1, Math.floor(everyMs));
232
+ return `${normalized}ms`;
233
+ }
234
+ function normalizeDaprCronExpression(expr) {
235
+ const parts = expr.trim().split(/\s+/).filter(Boolean);
236
+ if (parts.length === 5) {
237
+ return `0 ${parts.join(" ")}`;
238
+ }
239
+ if (parts.length === 6) {
240
+ return parts.join(" ");
241
+ }
242
+ throw new Error(`Dapr cron schedules must have 5 or 6 fields. Received: ${expr}`);
243
+ }
244
+ var DaprJobsApi = class {
245
+ client;
246
+ jobNamePrefix;
247
+ now;
248
+ constructor(options) {
249
+ this.client = options.client;
250
+ this.jobNamePrefix = options.jobNamePrefix;
251
+ this.now = options.now ?? (() => Date.now());
252
+ }
253
+ toDaprJobName(jobId) {
254
+ const encoded = Buffer.from(jobId, "utf8").toString("base64url");
255
+ return `${this.jobNamePrefix}${encoded}`;
256
+ }
257
+ fromDaprJobName(jobName) {
258
+ if (!jobName.startsWith(this.jobNamePrefix)) {
259
+ return void 0;
260
+ }
261
+ const encoded = jobName.slice(this.jobNamePrefix.length);
262
+ try {
263
+ return Buffer.from(encoded, "base64url").toString("utf8");
264
+ } catch {
265
+ return void 0;
266
+ }
267
+ }
268
+ async syncJob(job) {
269
+ if (!job.enabled) {
270
+ await this.deleteJob(job.id);
271
+ return;
272
+ }
273
+ const payload = this.toSchedulePayload(job);
274
+ const name = this.toDaprJobName(job.id);
275
+ await this.client.requestJson(`/v1.0-alpha1/jobs/${encodeURIComponent(name)}`, {
276
+ method: "POST",
277
+ body: JSON.stringify(payload)
278
+ }, [200, 201, 204]);
279
+ }
280
+ async deleteJob(jobId) {
281
+ const name = this.toDaprJobName(jobId);
282
+ await this.client.requestJson(`/v1.0-alpha1/jobs/${encodeURIComponent(name)}`, {
283
+ method: "DELETE"
284
+ }, [200, 204, 404]);
285
+ }
286
+ toSchedulePayload(job) {
287
+ const payload = {
288
+ overwrite: true,
289
+ data: {
290
+ source: "@cuylabs/agent-runtime-dapr",
291
+ jobId: job.id
292
+ }
293
+ };
294
+ if (job.schedule.kind === "at") {
295
+ payload.dueTime = new Date(job.schedule.at).toISOString();
296
+ return payload;
297
+ }
298
+ if (job.schedule.kind === "every") {
299
+ payload.schedule = `@every ${toGoDurationMs(job.schedule.everyMs)}`;
300
+ if (job.schedule.anchorMs !== void 0) {
301
+ const nextAnchor = computeNextRunAtMs(job.schedule, this.now());
302
+ if (nextAnchor !== void 0) {
303
+ payload.dueTime = new Date(nextAnchor).toISOString();
304
+ }
305
+ }
306
+ return payload;
307
+ }
308
+ if (job.schedule.timezone && !["UTC", "ETC/UTC", "Z"].includes(job.schedule.timezone.trim().toUpperCase())) {
309
+ throw new Error(
310
+ `Dapr jobs API does not expose timezone selection for cron schedules (received: ${job.schedule.timezone})`
311
+ );
312
+ }
313
+ payload.schedule = normalizeDaprCronExpression(job.schedule.expr);
314
+ return payload;
315
+ }
316
+ };
317
+
318
+ // src/driver.ts
319
+ var DEFAULT_KEY_PREFIX = "agent-runtime:";
320
+ var DEFAULT_JOB_NAME_PREFIX = "agent-runtime-job-";
321
+ var DEFAULT_INDEX_UPDATE_RETRIES = 4;
322
+ var STORED_JOB_KIND = "@cuylabs/agent-runtime-dapr/job";
323
+ var STORED_JOB_VERSION = 1;
324
+ function cloneJob(job) {
325
+ return structuredClone(job);
326
+ }
327
+ function ensureNonEmpty2(input, label) {
328
+ const trimmed = input.trim();
329
+ if (!trimmed) {
330
+ throw new Error(`${label} must not be empty`);
331
+ }
332
+ return trimmed;
333
+ }
334
+ var DaprRuntimeDriver = class {
335
+ name = "dapr";
336
+ client;
337
+ jobsApi;
338
+ keyPrefix;
339
+ context;
340
+ started = false;
341
+ constructor(options) {
342
+ this.client = new DaprSidecarClient(options);
343
+ this.keyPrefix = ensureNonEmpty2(options.keyPrefix ?? DEFAULT_KEY_PREFIX, "keyPrefix");
344
+ this.jobsApi = new DaprJobsApi({
345
+ client: this.client,
346
+ jobNamePrefix: ensureNonEmpty2(
347
+ options.jobNamePrefix ?? DEFAULT_JOB_NAME_PREFIX,
348
+ "jobNamePrefix"
349
+ )
350
+ });
351
+ }
352
+ async start(context) {
353
+ this.context = context;
354
+ this.started = true;
355
+ try {
356
+ await this.client.verifySidecar();
357
+ } catch (error) {
358
+ this.started = false;
359
+ this.context = void 0;
360
+ throw error;
361
+ }
362
+ }
363
+ async stop() {
364
+ this.started = false;
365
+ this.context = void 0;
366
+ }
367
+ async listJobs() {
368
+ const listed = /* @__PURE__ */ new Map();
369
+ try {
370
+ const queryJobs = await this.listJobsViaStateQuery();
371
+ for (const job of queryJobs) {
372
+ listed.set(job.id, job);
373
+ }
374
+ } catch (error) {
375
+ this.context?.logger.warn("Failed to list Dapr runtime jobs via state query", {
376
+ error: String(error)
377
+ });
378
+ }
379
+ try {
380
+ const indexedJobs = await this.listJobsFromIndex();
381
+ for (const job of indexedJobs) {
382
+ if (!listed.has(job.id)) {
383
+ listed.set(job.id, job);
384
+ }
385
+ }
386
+ } catch (error) {
387
+ this.context?.logger.warn("Failed to list Dapr runtime jobs via legacy index", {
388
+ error: String(error)
389
+ });
390
+ }
391
+ return [...listed.values()].map((job) => cloneJob(job)).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
392
+ }
393
+ async getJob(jobId) {
394
+ const current = await this.readJob(jobId);
395
+ return current ? cloneJob(current) : void 0;
396
+ }
397
+ async upsertJob(job) {
398
+ const copy = cloneJob(job);
399
+ await this.writeJob(copy);
400
+ await this.addToIndex(copy.id).catch((error) => {
401
+ this.context?.logger.warn("Failed to update legacy Dapr job index after upsert", {
402
+ jobId: copy.id,
403
+ error: String(error)
404
+ });
405
+ });
406
+ try {
407
+ await this.syncScheduledJob(copy);
408
+ } catch (error) {
409
+ this.context?.logger.warn("Failed to synchronize Dapr job schedule", {
410
+ jobId: copy.id,
411
+ error: String(error)
412
+ });
413
+ throw error;
414
+ }
415
+ return cloneJob(copy);
416
+ }
417
+ async removeJob(jobId) {
418
+ const existed = await this.readJob(jobId) !== void 0;
419
+ await this.client.deleteState(this.stateKeyForJob(jobId));
420
+ await this.removeFromIndex(jobId).catch((error) => {
421
+ this.context?.logger.warn("Failed to update legacy Dapr job index after removal", {
422
+ jobId,
423
+ error: String(error)
424
+ });
425
+ });
426
+ try {
427
+ await this.deleteScheduledJob(jobId);
428
+ } catch (error) {
429
+ this.context?.logger.warn("Failed to delete Dapr scheduled job", {
430
+ jobId,
431
+ error: String(error)
432
+ });
433
+ }
434
+ return existed;
435
+ }
436
+ /**
437
+ * Handle a Dapr scheduler callback routed to `/job/:name`.
438
+ * Returns false when the job name is not managed by this driver.
439
+ */
440
+ async handleJobTriggerByName(jobName) {
441
+ if (!this.started || !this.context) {
442
+ return false;
443
+ }
444
+ const jobId = this.fromDaprJobName(jobName);
445
+ if (!jobId) {
446
+ return false;
447
+ }
448
+ await this.context.onDue(jobId);
449
+ return true;
450
+ }
451
+ async syncScheduledJob(job) {
452
+ await this.jobsApi.syncJob(job);
453
+ }
454
+ fromDaprJobName(jobName) {
455
+ return this.jobsApi.fromDaprJobName(jobName);
456
+ }
457
+ stateKeyForJob(jobId) {
458
+ return `${this.keyPrefix}jobs/${jobId}`;
459
+ }
460
+ stateKeyForIndex() {
461
+ return `${this.keyPrefix}index`;
462
+ }
463
+ async readJob(jobId) {
464
+ const value = await this.client.getState(this.stateKeyForJob(jobId));
465
+ if (!value || typeof value !== "object") {
466
+ return void 0;
467
+ }
468
+ return this.decodeStoredJob(value);
469
+ }
470
+ async writeJob(job) {
471
+ const envelope = {
472
+ kind: STORED_JOB_KIND,
473
+ version: STORED_JOB_VERSION,
474
+ job
475
+ };
476
+ await this.client.saveState(this.stateKeyForJob(job.id), envelope);
477
+ }
478
+ async readIndex() {
479
+ const value = (await this.client.getStateEntry(this.stateKeyForIndex())).value;
480
+ if (!Array.isArray(value)) {
481
+ return [];
482
+ }
483
+ return [...new Set(value.filter((entry) => typeof entry === "string"))];
484
+ }
485
+ async writeIndex(ids, etag) {
486
+ await this.client.saveState(this.stateKeyForIndex(), [...new Set(ids)], {
487
+ etag,
488
+ concurrency: etag ? "first-write" : void 0
489
+ });
490
+ }
491
+ async addToIndex(jobId) {
492
+ await this.updateIndex((ids) => {
493
+ if (ids.includes(jobId)) {
494
+ return void 0;
495
+ }
496
+ return [...ids, jobId];
497
+ });
498
+ }
499
+ async removeFromIndex(jobId) {
500
+ await this.updateIndex((ids) => {
501
+ const next = ids.filter((id) => id !== jobId);
502
+ return next.length === ids.length ? void 0 : next;
503
+ });
504
+ }
505
+ async listJobsViaStateQuery() {
506
+ const jobs = [];
507
+ let token;
508
+ do {
509
+ const response = await this.client.queryState({
510
+ filter: {
511
+ EQ: {
512
+ kind: STORED_JOB_KIND
513
+ }
514
+ },
515
+ page: {
516
+ limit: 100,
517
+ ...token ? { token } : {}
518
+ }
519
+ });
520
+ if (!response?.results?.length) {
521
+ token = response?.token?.trim() || void 0;
522
+ continue;
523
+ }
524
+ for (const result of response.results) {
525
+ if (result.error || result.data === void 0) {
526
+ continue;
527
+ }
528
+ const job = this.decodeStoredJob(result.data);
529
+ if (job) {
530
+ jobs.push(job);
531
+ }
532
+ }
533
+ token = response.token?.trim() || void 0;
534
+ } while (token);
535
+ return jobs;
536
+ }
537
+ async listJobsFromIndex() {
538
+ const ids = await this.readIndex();
539
+ const jobs = await Promise.all(ids.map((id) => this.readJob(id)));
540
+ const present = jobs.filter((entry) => Boolean(entry));
541
+ if (present.length !== ids.length) {
542
+ await this.writeIndex(present.map((entry) => entry.id)).catch((error) => {
543
+ this.context?.logger.warn("Failed to compact legacy Dapr job index", {
544
+ error: String(error)
545
+ });
546
+ });
547
+ }
548
+ return present;
549
+ }
550
+ decodeStoredJob(value) {
551
+ if (!value || typeof value !== "object") {
552
+ return void 0;
553
+ }
554
+ const envelope = value;
555
+ if (envelope.kind === STORED_JOB_KIND) {
556
+ if (envelope.version !== STORED_JOB_VERSION) {
557
+ throw new Error(
558
+ `Unsupported Dapr runtime job record version: ${String(envelope.version)}`
559
+ );
560
+ }
561
+ if (envelope.job && typeof envelope.job === "object") {
562
+ return envelope.job;
563
+ }
564
+ return void 0;
565
+ }
566
+ return value;
567
+ }
568
+ async updateIndex(updater) {
569
+ for (let attempt = 0; attempt < DEFAULT_INDEX_UPDATE_RETRIES; attempt += 1) {
570
+ const current = await this.client.getStateEntry(this.stateKeyForIndex());
571
+ const ids = Array.isArray(current.value) ? [...new Set(current.value.filter((entry) => typeof entry === "string"))] : [];
572
+ const next = updater(ids);
573
+ if (!next) {
574
+ return;
575
+ }
576
+ try {
577
+ await this.writeIndex(next, current.etag);
578
+ return;
579
+ } catch (error) {
580
+ if (isDaprConflictError(error) && attempt + 1 < DEFAULT_INDEX_UPDATE_RETRIES) {
581
+ continue;
582
+ }
583
+ throw error;
584
+ }
585
+ }
586
+ }
587
+ async deleteScheduledJob(jobId) {
588
+ await this.jobsApi.deleteJob(jobId);
589
+ }
590
+ };
591
+
592
+ // src/store.ts
593
+ import { isTerminalRunStatus } from "@cuylabs/agent-runtime";
594
+ var DEFAULT_KEY_PREFIX2 = "agent-runtime:orchestrator:";
595
+ var DEFAULT_INDEX_UPDATE_RETRIES2 = 4;
596
+ var STORED_RUN_KIND = "@cuylabs/agent-runtime-dapr/orchestrator-run";
597
+ var STORED_RUN_VERSION = 1;
598
+ function cloneRun(run) {
599
+ return structuredClone(run);
600
+ }
601
+ function ensureNonEmpty3(input, label) {
602
+ const trimmed = input.trim();
603
+ if (!trimmed) {
604
+ throw new Error(`${label} must not be empty`);
605
+ }
606
+ return trimmed;
607
+ }
608
+ var DaprOrchestratorRunStore = class {
609
+ client;
610
+ keyPrefix;
611
+ constructor(options) {
612
+ this.client = new DaprSidecarClient(options);
613
+ this.keyPrefix = ensureNonEmpty3(options.keyPrefix ?? DEFAULT_KEY_PREFIX2, "keyPrefix");
614
+ }
615
+ async start() {
616
+ await this.client.verifySidecar();
617
+ }
618
+ async stop() {
619
+ }
620
+ async get(runId) {
621
+ const current = await this.readRun(runId);
622
+ return current ? cloneRun(current) : void 0;
623
+ }
624
+ async list() {
625
+ const listed = /* @__PURE__ */ new Map();
626
+ try {
627
+ const queryRuns = await this.listRunsViaStateQuery();
628
+ for (const run of queryRuns) {
629
+ listed.set(run.id, run);
630
+ }
631
+ } catch {
632
+ }
633
+ const indexedRuns = await this.listRunsFromIndex().catch(() => []);
634
+ for (const run of indexedRuns) {
635
+ if (!listed.has(run.id)) {
636
+ listed.set(run.id, run);
637
+ }
638
+ }
639
+ return [...listed.values()].map((run) => cloneRun(run)).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
640
+ }
641
+ async upsert(run) {
642
+ const copy = cloneRun(run);
643
+ await this.writeRun(copy);
644
+ await this.addToIndex(copy.id).catch(() => {
645
+ });
646
+ return cloneRun(copy);
647
+ }
648
+ async remove(runId) {
649
+ const existed = await this.readRun(runId) !== void 0;
650
+ await this.client.deleteState(this.stateKeyForRun(runId));
651
+ await this.removeFromIndex(runId).catch(() => {
652
+ });
653
+ return existed;
654
+ }
655
+ async cleanup(options = {}) {
656
+ const now = options.now ?? (() => Date.now());
657
+ const includeActive = options.includeActive ?? false;
658
+ const cutoff = options.maxAgeMs !== void 0 ? now() - options.maxAgeMs : void 0;
659
+ const statuses = options.statuses ? new Set(options.statuses) : void 0;
660
+ const runs = await this.list();
661
+ const eligible = runs.filter((run) => {
662
+ if (!includeActive && !isTerminalRunStatus(run.state.status)) {
663
+ return false;
664
+ }
665
+ if (statuses && !statuses.has(run.state.status)) {
666
+ return false;
667
+ }
668
+ return true;
669
+ });
670
+ const toDelete = /* @__PURE__ */ new Set();
671
+ if (cutoff !== void 0) {
672
+ for (const run of eligible) {
673
+ const updatedAtMs = Date.parse(run.updatedAt);
674
+ if (Number.isFinite(updatedAtMs) && updatedAtMs < cutoff) {
675
+ toDelete.add(run.id);
676
+ }
677
+ }
678
+ }
679
+ if (options.maxRuns !== void 0 && Number.isFinite(options.maxRuns) && options.maxRuns >= 0) {
680
+ const normalizedMaxRuns = Math.floor(options.maxRuns);
681
+ const overflow = [...eligible].sort((left, right) => {
682
+ const leftMs = Date.parse(left.updatedAt);
683
+ const rightMs = Date.parse(right.updatedAt);
684
+ return rightMs - leftMs;
685
+ }).slice(normalizedMaxRuns);
686
+ for (const run of overflow) {
687
+ toDelete.add(run.id);
688
+ }
689
+ }
690
+ const deletedRunIds = [];
691
+ for (const runId of toDelete) {
692
+ if (await this.remove(runId)) {
693
+ deletedRunIds.push(runId);
694
+ }
695
+ }
696
+ return {
697
+ deletedRuns: deletedRunIds.length,
698
+ deletedRunIds
699
+ };
700
+ }
701
+ stateKeyForRun(runId) {
702
+ return `${this.keyPrefix}runs/${runId}`;
703
+ }
704
+ stateKeyForIndex() {
705
+ return `${this.keyPrefix}index`;
706
+ }
707
+ async readRun(runId) {
708
+ const value = await this.client.getState(this.stateKeyForRun(runId));
709
+ if (!value || typeof value !== "object") {
710
+ return void 0;
711
+ }
712
+ return this.decodeStoredRun(value);
713
+ }
714
+ async writeRun(run) {
715
+ const envelope = {
716
+ kind: STORED_RUN_KIND,
717
+ version: STORED_RUN_VERSION,
718
+ run
719
+ };
720
+ await this.client.saveState(this.stateKeyForRun(run.id), envelope);
721
+ }
722
+ async readIndex() {
723
+ const value = (await this.client.getStateEntry(this.stateKeyForIndex())).value;
724
+ if (!Array.isArray(value)) {
725
+ return [];
726
+ }
727
+ return [...new Set(value.filter((entry) => typeof entry === "string"))];
728
+ }
729
+ async writeIndex(ids, etag) {
730
+ await this.client.saveState(this.stateKeyForIndex(), [...new Set(ids)], {
731
+ etag,
732
+ concurrency: etag ? "first-write" : void 0
733
+ });
734
+ }
735
+ async addToIndex(runId) {
736
+ await this.updateIndex((ids) => {
737
+ if (ids.includes(runId)) {
738
+ return void 0;
739
+ }
740
+ return [...ids, runId];
741
+ });
742
+ }
743
+ async removeFromIndex(runId) {
744
+ await this.updateIndex((ids) => {
745
+ const next = ids.filter((id) => id !== runId);
746
+ return next.length === ids.length ? void 0 : next;
747
+ });
748
+ }
749
+ async listRunsViaStateQuery() {
750
+ const runs = [];
751
+ let token;
752
+ do {
753
+ const response = await this.client.queryState({
754
+ filter: {
755
+ EQ: {
756
+ kind: STORED_RUN_KIND
757
+ }
758
+ },
759
+ page: {
760
+ limit: 100,
761
+ ...token ? { token } : {}
762
+ }
763
+ });
764
+ if (!response?.results?.length) {
765
+ token = response?.token?.trim() || void 0;
766
+ continue;
767
+ }
768
+ for (const result of response.results) {
769
+ if (result.error || result.data === void 0) {
770
+ continue;
771
+ }
772
+ const run = this.decodeStoredRun(result.data);
773
+ if (run) {
774
+ runs.push(run);
775
+ }
776
+ }
777
+ token = response.token?.trim() || void 0;
778
+ } while (token);
779
+ return runs;
780
+ }
781
+ async listRunsFromIndex() {
782
+ const ids = await this.readIndex();
783
+ const runs = await Promise.all(ids.map((id) => this.readRun(id)));
784
+ const present = runs.filter((entry) => Boolean(entry));
785
+ if (present.length !== ids.length) {
786
+ await this.writeIndex(present.map((entry) => entry.id)).catch(() => {
787
+ });
788
+ }
789
+ return present;
790
+ }
791
+ decodeStoredRun(value) {
792
+ if (!value || typeof value !== "object") {
793
+ return void 0;
794
+ }
795
+ const envelope = value;
796
+ if (envelope.kind === STORED_RUN_KIND) {
797
+ if (envelope.version !== STORED_RUN_VERSION) {
798
+ throw new Error(
799
+ `Unsupported Dapr orchestrator run record version: ${String(envelope.version)}`
800
+ );
801
+ }
802
+ if (envelope.run && typeof envelope.run === "object") {
803
+ return envelope.run;
804
+ }
805
+ return void 0;
806
+ }
807
+ return value;
808
+ }
809
+ async updateIndex(updater) {
810
+ for (let attempt = 0; attempt < DEFAULT_INDEX_UPDATE_RETRIES2; attempt += 1) {
811
+ const current = await this.client.getStateEntry(this.stateKeyForIndex());
812
+ const ids = Array.isArray(current.value) ? [...new Set(current.value.filter((entry) => typeof entry === "string"))] : [];
813
+ const next = updater(ids);
814
+ if (!next) {
815
+ return;
816
+ }
817
+ try {
818
+ await this.writeIndex(next, current.etag);
819
+ return;
820
+ } catch (error) {
821
+ if (isDaprConflictError(error) && attempt + 1 < DEFAULT_INDEX_UPDATE_RETRIES2) {
822
+ continue;
823
+ }
824
+ throw error;
825
+ }
826
+ }
827
+ }
828
+ };
829
+
830
+ // src/host/workflow-host.ts
831
+ function buildToolRecord(agent) {
832
+ return Object.fromEntries(
833
+ agent.getTools().map((tool) => [tool.id, tool])
834
+ );
835
+ }
836
+ function createScopedSessionManager(agent) {
837
+ return new SessionManager(agent.getSessionManager().getStorage());
838
+ }
839
+ async function ensureSessionLoaded(agent, sessionId) {
840
+ const sessions = createScopedSessionManager(agent);
841
+ const storage = sessions.getStorage();
842
+ let existingEntries;
843
+ try {
844
+ existingEntries = await storage.read(sessionId);
845
+ } catch (error) {
846
+ if (!(error instanceof Error) || !error.message.startsWith("Session not found:")) {
847
+ throw error;
848
+ }
849
+ existingEntries = [];
850
+ }
851
+ if (existingEntries.length === 0) {
852
+ await sessions.create({
853
+ id: sessionId,
854
+ cwd: agent.cwd,
855
+ title: `Workflow ${sessionId}`
856
+ });
857
+ return sessions;
858
+ }
859
+ await sessions.load(sessionId);
860
+ return sessions;
861
+ }
862
+ function createUserMessage(message, createdAt) {
863
+ return {
864
+ id: randomUUID(),
865
+ role: "user",
866
+ content: message,
867
+ createdAt: new Date(createdAt)
868
+ };
869
+ }
870
+ function normalizeWorkflowInstanceId(explicitInstanceId, sessionId) {
871
+ const normalized = explicitInstanceId?.trim();
872
+ return normalized && normalized.length > 0 ? normalized : `turn_${sessionId}_${randomUUID().slice(0, 8)}`;
873
+ }
874
+ function createDaprAgentWorkflowHost(options) {
875
+ const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
876
+ const tools = buildToolRecord(options.agent);
877
+ const runtimeConfig = options.agent.getTurnRuntimeConfig();
878
+ const host = options.agent.getHost();
879
+ const middleware = options.agent.getMiddlewareRunner();
880
+ const observerBridge = options.observers && options.observers.length > 0 ? createWorkflowObserverBridge({
881
+ observers: options.observers,
882
+ payload: { message: "" },
883
+ trigger: "workflow"
884
+ }) : void 0;
885
+ const workflowKit = createDaprAgentTurnWorkflowKit({
886
+ workflowName: options.workflowName,
887
+ activityNames: options.activityNames,
888
+ observerBridge,
889
+ modelStepActivity: {
890
+ runtime: runtimeConfig,
891
+ tools,
892
+ ...options.mcpTools ? { mcpTools: options.mcpTools } : {},
893
+ host,
894
+ middleware,
895
+ reasoningLevel: options.agent.reasoningLevel,
896
+ ...options.createAbortSignal ? { createAbortSignal: options.createAbortSignal } : {},
897
+ now
898
+ },
899
+ toolCallActivity: {
900
+ tools,
901
+ cwd: options.agent.cwd,
902
+ host,
903
+ middleware,
904
+ ...options.createAbortSignal ? { createAbortSignal: options.createAbortSignal } : {},
905
+ now
906
+ },
907
+ commitActivity: {
908
+ persistMessages: async (sessionId, messages) => {
909
+ const sessions = await ensureSessionLoaded(options.agent, sessionId);
910
+ await sessions.addMessages(messages);
911
+ },
912
+ now
913
+ }
914
+ });
915
+ return {
916
+ workflowName: workflowKit.workflowName,
917
+ activityNames: workflowKit.activityNames,
918
+ register(runtime) {
919
+ return runtime.registerWorkflowWithName(
920
+ workflowKit.workflowName,
921
+ workflowKit.workflow
922
+ ).registerActivityWithName(
923
+ workflowKit.activities.modelStep.name,
924
+ workflowKit.activities.modelStep.handler
925
+ ).registerActivityWithName(
926
+ workflowKit.activities.toolCall.name,
927
+ workflowKit.activities.toolCall.handler
928
+ ).registerActivityWithName(
929
+ workflowKit.activities.stepCommit.name,
930
+ workflowKit.activities.stepCommit.handler
931
+ ).registerActivityWithName(
932
+ workflowKit.activities.outputCommit.name,
933
+ workflowKit.activities.outputCommit.handler
934
+ );
935
+ },
936
+ async createInitialState(request) {
937
+ const sessionId = request.sessionId?.trim() || `workflow_${randomUUID().slice(0, 8)}`;
938
+ const startedAt = now();
939
+ const sessions = await ensureSessionLoaded(options.agent, sessionId);
940
+ await sessions.addMessage(createUserMessage(request.message, startedAt));
941
+ const initialState = createAgentWorkflowTurnState({
942
+ sessionId,
943
+ startedAt,
944
+ maxSteps: request.maxSteps ?? runtimeConfig.maxSteps,
945
+ systemPrompts: await options.agent.buildSystemPrompts(
946
+ sessionId,
947
+ request.system
948
+ ),
949
+ initialMessages: snapshotAgentWorkflowMessages(sessions.getMessages())
950
+ });
951
+ return {
952
+ sessionId,
953
+ workflowInstanceId: normalizeWorkflowInstanceId(
954
+ request.workflowInstanceId,
955
+ sessionId
956
+ ),
957
+ initialState
958
+ };
959
+ },
960
+ async startTurn(client, request) {
961
+ const prepared = await this.createInitialState(request);
962
+ observerBridge?.updatePayload({ message: request.message });
963
+ await observerBridge?.notifyTaskStart(prepared.initialState);
964
+ const scheduleWorkflow = () => client.startWorkflow(this.workflowName, {
965
+ instanceId: prepared.workflowInstanceId,
966
+ input: prepared.initialState
967
+ });
968
+ try {
969
+ const ctx = observerBridge?.getOtelContext(prepared.sessionId);
970
+ if (ctx) {
971
+ const otelApi = await import("@opentelemetry/api").catch(
972
+ () => null
973
+ );
974
+ if (otelApi) {
975
+ await otelApi.context.with(
976
+ ctx,
977
+ scheduleWorkflow
978
+ );
979
+ return prepared;
980
+ }
981
+ }
982
+ await scheduleWorkflow();
983
+ } catch (error) {
984
+ await observerBridge?.notifyTaskError(
985
+ prepared.initialState,
986
+ error instanceof Error ? error : new Error(String(error))
987
+ );
988
+ throw error;
989
+ }
990
+ return prepared;
991
+ }
992
+ };
993
+ }
994
+ async function startDaprAgentWorkflowTurn(client, host, request) {
995
+ return host.startTurn(client, request);
996
+ }
997
+
998
+ // src/host/worker.ts
999
+ function normalizeKey(input, label) {
1000
+ const normalized = input.trim();
1001
+ if (!normalized) {
1002
+ throw new Error(`${label} must not be empty`);
1003
+ }
1004
+ return normalized;
1005
+ }
1006
+ function registerHosts(runtime, agents) {
1007
+ for (const agent of agents) {
1008
+ agent.host.register(runtime);
1009
+ }
1010
+ }
1011
+ function validateAgents(agents) {
1012
+ if (agents.length === 0) {
1013
+ throw new Error("Dapr workflow worker requires at least one agent host.");
1014
+ }
1015
+ const lookup = /* @__PURE__ */ new Map();
1016
+ const workflowNames = /* @__PURE__ */ new Set();
1017
+ for (const agent of agents) {
1018
+ const id = normalizeKey(agent.id, "agent id");
1019
+ if (lookup.has(id)) {
1020
+ throw new Error(`Duplicate Dapr workflow worker agent id: ${id}`);
1021
+ }
1022
+ const workflowName = normalizeKey(
1023
+ agent.host.workflowName,
1024
+ `workflow name for agent '${id}'`
1025
+ );
1026
+ if (workflowNames.has(workflowName)) {
1027
+ throw new Error(
1028
+ `Duplicate Dapr workflow name '${workflowName}' across worker agents.`
1029
+ );
1030
+ }
1031
+ workflowNames.add(workflowName);
1032
+ lookup.set(id, agent);
1033
+ for (const alias of agent.aliases ?? []) {
1034
+ const normalizedAlias = normalizeKey(alias, `alias for agent '${id}'`);
1035
+ if (lookup.has(normalizedAlias)) {
1036
+ throw new Error(
1037
+ `Duplicate Dapr workflow worker agent alias: ${normalizedAlias}`
1038
+ );
1039
+ }
1040
+ lookup.set(normalizedAlias, agent);
1041
+ }
1042
+ }
1043
+ return lookup;
1044
+ }
1045
+ function createDaprWorkflowWorker(options) {
1046
+ const agents = [...options.agents];
1047
+ const lookup = validateAgents(agents);
1048
+ const logger = options.logger;
1049
+ let running = false;
1050
+ let registered = false;
1051
+ return {
1052
+ runtime: options.runtime,
1053
+ agents,
1054
+ async start() {
1055
+ if (running) {
1056
+ return;
1057
+ }
1058
+ if (!registered) {
1059
+ registerHosts(options.runtime, agents);
1060
+ registered = true;
1061
+ }
1062
+ await options.runtime.start();
1063
+ running = true;
1064
+ logger?.info?.(
1065
+ `Dapr workflow worker started with ${agents.length} agent host(s).`
1066
+ );
1067
+ },
1068
+ async stop() {
1069
+ if (!running) {
1070
+ return;
1071
+ }
1072
+ logger?.info?.("Stopping workflow worker (gRPC stream cancel is expected)...");
1073
+ await options.runtime.stop();
1074
+ running = false;
1075
+ logger?.info?.("Dapr workflow worker stopped.");
1076
+ },
1077
+ isRunning() {
1078
+ return running;
1079
+ },
1080
+ listAgents() {
1081
+ return agents;
1082
+ },
1083
+ getAgent(idOrAlias) {
1084
+ const normalized = normalizeKey(idOrAlias, "agent id or alias");
1085
+ return lookup.get(normalized);
1086
+ }
1087
+ };
1088
+ }
1089
+
1090
+ // src/host/runtime-bundle.ts
1091
+ import {
1092
+ createAgentTaskRunner
1093
+ } from "@cuylabs/agent-core";
1094
+ import {
1095
+ createAgentRuntime
1096
+ } from "@cuylabs/agent-runtime";
1097
+ function toErrorMessage(error) {
1098
+ if (error instanceof Error && error.message) {
1099
+ return error.message;
1100
+ }
1101
+ return String(error);
1102
+ }
1103
+ function createExecutionContext(jobId, runtimeContext) {
1104
+ return {
1105
+ signal: runtimeContext.signal,
1106
+ trigger: runtimeContext.trigger,
1107
+ fallbackSessionKey: jobId
1108
+ };
1109
+ }
1110
+ function buildTaskRunnerOptions(options, executionObserver) {
1111
+ if (!options.taskRunnerOptions && !executionObserver) {
1112
+ return void 0;
1113
+ }
1114
+ const observers = [...options.taskRunnerOptions?.observers ?? []];
1115
+ if (executionObserver) {
1116
+ observers.push(executionObserver);
1117
+ }
1118
+ return {
1119
+ ...options.taskRunnerOptions,
1120
+ ...observers.length > 0 ? { observers } : {}
1121
+ };
1122
+ }
1123
+ function resolveExecutionStore(options) {
1124
+ if (options.executionStore && options.executionStoreOptions) {
1125
+ throw new Error(
1126
+ "Provide either executionStore or executionStoreOptions, not both."
1127
+ );
1128
+ }
1129
+ if (options.persistExecutionState === false) {
1130
+ if (options.executionStore || options.executionStoreOptions) {
1131
+ throw new Error(
1132
+ "Do not provide executionStore or executionStoreOptions when persistExecutionState is false."
1133
+ );
1134
+ }
1135
+ return void 0;
1136
+ }
1137
+ return options.executionStore ?? new DaprExecutionStore({
1138
+ ...options.driver,
1139
+ ...options.executionStoreOptions
1140
+ });
1141
+ }
1142
+ function createExecutor(runTask, options) {
1143
+ return async (job, runtimeContext) => {
1144
+ try {
1145
+ const result = await runTask(
1146
+ job.payload,
1147
+ createExecutionContext(job.id, runtimeContext)
1148
+ );
1149
+ if (options.onTaskResult) {
1150
+ await options.onTaskResult({
1151
+ jobId: job.id,
1152
+ payload: job.payload,
1153
+ runtimeContext,
1154
+ result
1155
+ });
1156
+ }
1157
+ return { status: "ok" };
1158
+ } catch (error) {
1159
+ const message = toErrorMessage(error);
1160
+ if (options.onTaskError) {
1161
+ try {
1162
+ await options.onTaskError({
1163
+ jobId: job.id,
1164
+ payload: job.payload,
1165
+ runtimeContext,
1166
+ error,
1167
+ message
1168
+ });
1169
+ } catch {
1170
+ }
1171
+ }
1172
+ return {
1173
+ status: "error",
1174
+ error: message
1175
+ };
1176
+ }
1177
+ };
1178
+ }
1179
+ function createDaprAgentRuntime(options) {
1180
+ const driver = new DaprRuntimeDriver(options.driver);
1181
+ const executionStore = resolveExecutionStore(options);
1182
+ if (options.taskRunner && executionStore) {
1183
+ throw new Error(
1184
+ "Automatic Dapr execution persistence requires createDaprAgentRuntime(...) to create the task runner. Remove taskRunner or set persistExecutionState to false."
1185
+ );
1186
+ }
1187
+ const executionObserver = executionStore ? createDaprExecutionObserver({ store: executionStore }) : void 0;
1188
+ const runTask = options.taskRunner ?? createAgentTaskRunner(
1189
+ options.agent,
1190
+ buildTaskRunnerOptions(options, executionObserver)
1191
+ );
1192
+ const runtime = createAgentRuntime({
1193
+ ...options.runtime,
1194
+ driver,
1195
+ execute: createExecutor(runTask, options)
1196
+ });
1197
+ const handleDaprJob = createDaprHttpJobHandler({ driver });
1198
+ return {
1199
+ runtime,
1200
+ driver,
1201
+ runTask,
1202
+ executionStore,
1203
+ handleDaprJob
1204
+ };
1205
+ }
1206
+
1207
+ // src/host/http.ts
1208
+ import {
1209
+ createServer
1210
+ } from "http";
1211
+ function json(value, status = 200) {
1212
+ if (status === 204 || status === 304) {
1213
+ return new Response(null, { status });
1214
+ }
1215
+ return new Response(JSON.stringify(value), {
1216
+ status,
1217
+ headers: {
1218
+ "content-type": "application/json; charset=utf-8"
1219
+ }
1220
+ });
1221
+ }
1222
+ function text(message, status = 200) {
1223
+ return new Response(message, { status });
1224
+ }
1225
+ function toErrorMessage2(error) {
1226
+ if (error instanceof Error && error.message) {
1227
+ return error.message;
1228
+ }
1229
+ return String(error);
1230
+ }
1231
+ function splitPath(pathname) {
1232
+ return pathname.split("/").map((part) => part.trim()).filter(Boolean);
1233
+ }
1234
+ async function parseJsonBody(request) {
1235
+ const raw = await request.text();
1236
+ if (!raw.trim()) {
1237
+ return {};
1238
+ }
1239
+ return JSON.parse(raw);
1240
+ }
1241
+ function resolveSingleAgent(app) {
1242
+ const agents = app.listAgents();
1243
+ return agents.length === 1 ? agents[0] : void 0;
1244
+ }
1245
+ async function resolveReadiness(app) {
1246
+ if (app.checkReadiness) {
1247
+ return await app.checkReadiness();
1248
+ }
1249
+ const running = app.isRunning();
1250
+ return {
1251
+ ok: running,
1252
+ checks: [
1253
+ {
1254
+ name: "app",
1255
+ ok: running,
1256
+ ...running ? {} : { detail: "Host app is not running." }
1257
+ }
1258
+ ]
1259
+ };
1260
+ }
1261
+ async function writeResponse(response, nodeResponse) {
1262
+ nodeResponse.statusCode = response.status;
1263
+ response.headers.forEach((value, key) => {
1264
+ nodeResponse.setHeader(key, value);
1265
+ });
1266
+ if (!response.body) {
1267
+ nodeResponse.end();
1268
+ return;
1269
+ }
1270
+ const arrayBuffer = await response.arrayBuffer();
1271
+ nodeResponse.end(Buffer.from(arrayBuffer));
1272
+ }
1273
+ async function toRequest(nodeRequest) {
1274
+ const origin = `http://${nodeRequest.headers.host ?? "127.0.0.1"}`;
1275
+ const url = new URL(nodeRequest.url ?? "/", origin);
1276
+ const method = nodeRequest.method ?? "GET";
1277
+ if (method === "GET" || method === "HEAD") {
1278
+ return new Request(url, { method });
1279
+ }
1280
+ const body = await new Promise((resolve, reject) => {
1281
+ const chunks = [];
1282
+ nodeRequest.on("data", (chunk) => {
1283
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
1284
+ });
1285
+ nodeRequest.once("end", () => resolve(Buffer.concat(chunks)));
1286
+ nodeRequest.once("error", reject);
1287
+ });
1288
+ return new Request(url, {
1289
+ method,
1290
+ headers: nodeRequest.headers,
1291
+ body,
1292
+ duplex: "half"
1293
+ });
1294
+ }
1295
+ async function handleExecutionLookup(agent, sessionId) {
1296
+ if (!agent.runtimeBundle.executionStore) {
1297
+ return json(
1298
+ { error: "Execution persistence is disabled for this agent." },
1299
+ 501
1300
+ );
1301
+ }
1302
+ const record = await agent.runtimeBundle.executionStore.getExecution(sessionId);
1303
+ if (!record) {
1304
+ return json({ error: `Execution not found: ${sessionId}` }, 404);
1305
+ }
1306
+ return json(record);
1307
+ }
1308
+ async function handleCheckpointLookup(agent, sessionId) {
1309
+ if (!agent.runtimeBundle.executionStore) {
1310
+ return json(
1311
+ { error: "Execution persistence is disabled for this agent." },
1312
+ 501
1313
+ );
1314
+ }
1315
+ const checkpoints = await agent.runtimeBundle.executionStore.listCheckpoints(sessionId);
1316
+ return json(checkpoints);
1317
+ }
1318
+ async function handleWorkflowLookup(workflowClient, instanceId) {
1319
+ if (!workflowClient) {
1320
+ return json({ error: "Workflow client is not configured." }, 501);
1321
+ }
1322
+ const workflow = await workflowClient.getWorkflow(instanceId);
1323
+ if (!workflow) {
1324
+ return json({ error: `Workflow not found: ${instanceId}` }, 404);
1325
+ }
1326
+ return json(workflow);
1327
+ }
1328
+ function createDaprHostHttpHandler(options) {
1329
+ return async function handle(request) {
1330
+ const url = new URL(request.url);
1331
+ const segments = splitPath(url.pathname);
1332
+ if (request.method === "GET" && segments.length === 1 && (segments[0] === "health" || segments[0] === "healthz")) {
1333
+ return json({
1334
+ status: "ok",
1335
+ mode: "liveness",
1336
+ running: options.app.isRunning(),
1337
+ agents: options.app.listAgents().map((agent) => ({
1338
+ id: agent.id,
1339
+ aliases: agent.aliases,
1340
+ workflowName: agent.workflowHost.workflowName
1341
+ }))
1342
+ });
1343
+ }
1344
+ if (request.method === "GET" && segments.length === 1 && (segments[0] === "ready" || segments[0] === "readyz")) {
1345
+ const readiness = await resolveReadiness(options.app);
1346
+ return json(
1347
+ {
1348
+ status: readiness.ok ? "ready" : "not-ready",
1349
+ mode: "readiness",
1350
+ ready: readiness.ok,
1351
+ checks: readiness.checks,
1352
+ agents: options.app.listAgents().map((agent) => ({
1353
+ id: agent.id,
1354
+ aliases: agent.aliases,
1355
+ workflowName: agent.workflowHost.workflowName
1356
+ }))
1357
+ },
1358
+ readiness.ok ? 200 : 503
1359
+ );
1360
+ }
1361
+ if (request.method === "GET" && segments.length === 1 && segments[0] === "agents") {
1362
+ return json(
1363
+ options.app.listAgents().map((agent) => ({
1364
+ id: agent.id,
1365
+ aliases: agent.aliases,
1366
+ description: agent.description,
1367
+ workflowName: agent.workflowHost.workflowName
1368
+ }))
1369
+ );
1370
+ }
1371
+ if (request.method === "POST" && segments.length === 2 && segments[0] === "job") {
1372
+ const result = await options.app.handleScheduledJob(segments[1]);
1373
+ return json(result, result.status);
1374
+ }
1375
+ if (request.method === "POST" && segments.length === 2 && segments[0] === "agents" && segments[1] === "run") {
1376
+ const body = await parseJsonBody(request);
1377
+ const selectedId = body.agentId?.trim() || resolveSingleAgent(options.app)?.id;
1378
+ if (!selectedId) {
1379
+ return json(
1380
+ {
1381
+ error: "agentId is required when the host app manages multiple agents."
1382
+ },
1383
+ 400
1384
+ );
1385
+ }
1386
+ try {
1387
+ const result = await options.app.runAgent(
1388
+ selectedId,
1389
+ body
1390
+ );
1391
+ return json(result);
1392
+ } catch (error) {
1393
+ return json({ error: toErrorMessage2(error) }, 404);
1394
+ }
1395
+ }
1396
+ if (request.method === "POST" && segments.length === 2 && segments[0] === "agents" && segments[1] === "workflow") {
1397
+ if (!options.workflowClient) {
1398
+ return json({ error: "Workflow client is not configured." }, 501);
1399
+ }
1400
+ const body = await parseJsonBody(request);
1401
+ const selectedId = body.agentId?.trim() || resolveSingleAgent(options.app)?.id;
1402
+ if (!selectedId) {
1403
+ return json(
1404
+ {
1405
+ error: "agentId is required when the host app manages multiple agents."
1406
+ },
1407
+ 400
1408
+ );
1409
+ }
1410
+ const agent = options.app.getAgent(selectedId);
1411
+ if (!agent) {
1412
+ return json({ error: `Unknown agent: ${selectedId}` }, 404);
1413
+ }
1414
+ try {
1415
+ const result = await agent.workflowHost.startTurn(
1416
+ options.workflowClient,
1417
+ body
1418
+ );
1419
+ return json({
1420
+ instanceId: result.workflowInstanceId,
1421
+ agentId: agent.id,
1422
+ workflowName: agent.workflowHost.workflowName,
1423
+ sessionId: result.sessionId
1424
+ }, 202);
1425
+ } catch (error) {
1426
+ return json({ error: toErrorMessage2(error) }, 500);
1427
+ }
1428
+ }
1429
+ if (segments[0] === "agents" && segments.length >= 2) {
1430
+ const agent = options.app.getAgent(segments[1]);
1431
+ if (!agent) {
1432
+ return json({ error: `Unknown agent: ${segments[1]}` }, 404);
1433
+ }
1434
+ if (request.method === "POST" && segments.length === 3 && segments[2] === "run") {
1435
+ const body = await parseJsonBody(request);
1436
+ const result = await options.app.runAgent(agent.id, body);
1437
+ return json(result);
1438
+ }
1439
+ if (request.method === "POST" && segments.length === 3 && segments[2] === "workflow") {
1440
+ if (!options.workflowClient) {
1441
+ return json({ error: "Workflow client is not configured." }, 501);
1442
+ }
1443
+ const body = await parseJsonBody(request);
1444
+ try {
1445
+ const result = await agent.workflowHost.startTurn(
1446
+ options.workflowClient,
1447
+ body
1448
+ );
1449
+ return json({
1450
+ instanceId: result.workflowInstanceId,
1451
+ agentId: agent.id,
1452
+ workflowName: agent.workflowHost.workflowName,
1453
+ sessionId: result.sessionId
1454
+ }, 202);
1455
+ } catch (error) {
1456
+ return json({ error: toErrorMessage2(error) }, 500);
1457
+ }
1458
+ }
1459
+ if (request.method === "GET" && segments.length === 4 && segments[2] === "executions") {
1460
+ return await handleExecutionLookup(agent, segments[3]);
1461
+ }
1462
+ if (request.method === "GET" && segments.length === 5 && segments[2] === "executions" && segments[4] === "checkpoints") {
1463
+ return await handleCheckpointLookup(agent, segments[3]);
1464
+ }
1465
+ if (request.method === "GET" && segments.length === 4 && segments[2] === "workflows") {
1466
+ return await handleWorkflowLookup(options.workflowClient, segments[3]);
1467
+ }
1468
+ }
1469
+ return text("Not found", 404);
1470
+ };
1471
+ }
1472
+ async function startDaprHostHttpServer(options) {
1473
+ const handler = createDaprHostHttpHandler(options);
1474
+ const server = createServer(async (req, res) => {
1475
+ try {
1476
+ const request = await toRequest(req);
1477
+ const response = await handler(request);
1478
+ await writeResponse(response, res);
1479
+ } catch (error) {
1480
+ await writeResponse(json({ error: toErrorMessage2(error) }, 500), res);
1481
+ }
1482
+ });
1483
+ await new Promise((resolve, reject) => {
1484
+ server.once("error", reject);
1485
+ server.listen(options.port, options.host, () => {
1486
+ server.off("error", reject);
1487
+ resolve();
1488
+ });
1489
+ });
1490
+ const address = server.address();
1491
+ if (!address || typeof address === "string") {
1492
+ throw new Error("Unable to resolve Dapr host HTTP server address.");
1493
+ }
1494
+ return {
1495
+ server,
1496
+ origin: `http://${address.address}:${address.port}`,
1497
+ close() {
1498
+ return new Promise((resolve, reject) => {
1499
+ server.close((error) => {
1500
+ if (error) {
1501
+ reject(error);
1502
+ return;
1503
+ }
1504
+ resolve();
1505
+ });
1506
+ });
1507
+ }
1508
+ };
1509
+ }
1510
+
1511
+ // src/host/runner.ts
1512
+ import process from "process";
1513
+ function resolveDaprConfig(options) {
1514
+ const daprHost = process.env.DAPR_HOST ?? "127.0.0.1";
1515
+ const daprHttpPort = process.env.DAPR_HTTP_PORT ?? "3500";
1516
+ return {
1517
+ daprHttpEndpoint: options.daprHttpEndpoint ?? `http://${daprHost}:${daprHttpPort}`,
1518
+ stateStoreName: options.stateStoreName ?? "statestore",
1519
+ workflowComponent: options.workflowComponent ?? "dapr"
1520
+ };
1521
+ }
1522
+ function buildObservers(options) {
1523
+ const observers = [];
1524
+ if (options.logging !== false) {
1525
+ observers.push(
1526
+ createDaprLoggingObserver({
1527
+ prefix: options.logPrefix ?? `[${options.name}]`
1528
+ })
1529
+ );
1530
+ }
1531
+ if (options.observers) {
1532
+ observers.push(...options.observers);
1533
+ }
1534
+ return observers;
1535
+ }
1536
+ function toErrorMessage3(error) {
1537
+ if (error instanceof Error && error.message) {
1538
+ return error.message;
1539
+ }
1540
+ return String(error);
1541
+ }
1542
+ function createAggregateLifecycleError(message, errors) {
1543
+ if (errors.length === 1 && errors[0] instanceof Error) {
1544
+ return errors[0];
1545
+ }
1546
+ return new AggregateError(errors, message);
1547
+ }
1548
+ async function stopRuntimeSafely(runtime, errors) {
1549
+ try {
1550
+ await runtime.stop();
1551
+ } catch (error) {
1552
+ errors.push(error);
1553
+ }
1554
+ }
1555
+ async function collectSingleRunnerReadiness(params) {
1556
+ const checks = [];
1557
+ const runtimeStarted = params.runtimeBundle.runtime.status().started;
1558
+ const workerRunning = params.worker.isRunning();
1559
+ checks.push({
1560
+ name: "runtime",
1561
+ ok: runtimeStarted,
1562
+ ...runtimeStarted ? {} : { detail: "Agent runtime is not started." }
1563
+ });
1564
+ checks.push({
1565
+ name: "workflow-worker",
1566
+ ok: workerRunning,
1567
+ ...workerRunning ? {} : { detail: "Workflow worker is not running." }
1568
+ });
1569
+ const sidecarClient = new DaprSidecarClient({
1570
+ stateStoreName: params.config.stateStoreName,
1571
+ daprHttpEndpoint: params.config.daprHttpEndpoint,
1572
+ ...params.driverOptions,
1573
+ verifySidecarOnStart: true
1574
+ });
1575
+ try {
1576
+ await sidecarClient.verifySidecar();
1577
+ checks.push({ name: "dapr-sidecar", ok: true });
1578
+ } catch (error) {
1579
+ checks.push({
1580
+ name: "dapr-sidecar",
1581
+ ok: false,
1582
+ detail: toErrorMessage3(error)
1583
+ });
1584
+ }
1585
+ try {
1586
+ await sidecarClient.getStateEntry("__agent-runtime-ready__");
1587
+ checks.push({ name: "state-store", ok: true });
1588
+ } catch (error) {
1589
+ checks.push({
1590
+ name: "state-store",
1591
+ ok: false,
1592
+ detail: toErrorMessage3(error)
1593
+ });
1594
+ }
1595
+ return {
1596
+ ok: checks.every((check) => check.ok),
1597
+ checks
1598
+ };
1599
+ }
1600
+ function createDaprAgentRunner(options) {
1601
+ const { agent } = options;
1602
+ const name = options.name ?? agent.name;
1603
+ const config = resolveDaprConfig({ ...options, name });
1604
+ const observers = buildObservers({ ...options, name });
1605
+ const workflowHost = createDaprAgentWorkflowHost({
1606
+ agent,
1607
+ observers,
1608
+ ...options.workflowHost
1609
+ });
1610
+ const runtimeBundle = createDaprAgentRuntime({
1611
+ agent,
1612
+ driver: {
1613
+ stateStoreName: config.stateStoreName,
1614
+ daprHttpEndpoint: config.daprHttpEndpoint,
1615
+ ...options.driverOptions
1616
+ },
1617
+ taskRunnerOptions: {
1618
+ ...options.runtimeOptions?.taskRunnerOptions,
1619
+ observers
1620
+ },
1621
+ ...options.runtimeOptions
1622
+ });
1623
+ const worker = createDaprWorkflowWorker({
1624
+ runtime: options.workflowRuntime,
1625
+ agents: [
1626
+ {
1627
+ id: name,
1628
+ host: workflowHost,
1629
+ aliases: options.aliases,
1630
+ description: options.description
1631
+ }
1632
+ ]
1633
+ });
1634
+ const workflowClient = new DaprWorkflowClient({
1635
+ daprHttpEndpoint: config.daprHttpEndpoint,
1636
+ workflowComponent: config.workflowComponent
1637
+ });
1638
+ const agentInfo = {
1639
+ id: name,
1640
+ aliases: options.aliases ?? [],
1641
+ description: options.description,
1642
+ workflowHost,
1643
+ runtimeBundle: { executionStore: runtimeBundle.executionStore }
1644
+ };
1645
+ const app = {
1646
+ isRunning: () => worker.isRunning(),
1647
+ listAgents: () => [agentInfo],
1648
+ getAgent: (id) => id === name || (options.aliases ?? []).includes(id) ? agentInfo : void 0,
1649
+ runAgent: async (_id, payload) => runtimeBundle.runTask(payload, {
1650
+ trigger: "http",
1651
+ fallbackSessionKey: `${name}-http`
1652
+ }),
1653
+ handleScheduledJob: async (jobName) => runtimeBundle.handleDaprJob(jobName),
1654
+ checkReadiness: async () => await collectSingleRunnerReadiness({
1655
+ config,
1656
+ driverOptions: options.driverOptions,
1657
+ runtimeBundle,
1658
+ worker
1659
+ })
1660
+ };
1661
+ let started = false;
1662
+ let httpServer;
1663
+ function log(message) {
1664
+ if (options.logging !== false) {
1665
+ console.log(`[${name}] ${message}`);
1666
+ }
1667
+ }
1668
+ return {
1669
+ name,
1670
+ workflowHost,
1671
+ runtimeBundle,
1672
+ worker,
1673
+ workflowClient,
1674
+ async start() {
1675
+ if (started) return;
1676
+ const startupErrors = [];
1677
+ try {
1678
+ await runtimeBundle.runtime.start();
1679
+ try {
1680
+ await worker.start();
1681
+ } catch (error) {
1682
+ startupErrors.push(error);
1683
+ await stopRuntimeSafely(runtimeBundle.runtime, startupErrors);
1684
+ throw createAggregateLifecycleError(
1685
+ "Failed to start Dapr agent runner cleanly.",
1686
+ startupErrors
1687
+ );
1688
+ }
1689
+ started = true;
1690
+ log("Worker started");
1691
+ } catch (error) {
1692
+ if (error instanceof Error) {
1693
+ throw error;
1694
+ }
1695
+ throw new Error(String(error));
1696
+ }
1697
+ },
1698
+ async serve(serveOptions) {
1699
+ if (!started) {
1700
+ await this.start();
1701
+ }
1702
+ const port = serveOptions?.port ?? 3e3;
1703
+ httpServer = await startDaprHostHttpServer({
1704
+ app,
1705
+ workflowClient,
1706
+ port,
1707
+ host: serveOptions?.host
1708
+ });
1709
+ log(`HTTP listening on ${httpServer.origin}`);
1710
+ await new Promise((resolve) => {
1711
+ let shuttingDown = false;
1712
+ const shutdown = async (signal) => {
1713
+ if (shuttingDown) return;
1714
+ shuttingDown = true;
1715
+ log(`${signal} \u2014 shutting down`);
1716
+ await this.stop();
1717
+ resolve();
1718
+ };
1719
+ process.once("SIGINT", () => void shutdown("SIGINT"));
1720
+ process.once("SIGTERM", () => void shutdown("SIGTERM"));
1721
+ });
1722
+ },
1723
+ async run(message, runOptions) {
1724
+ if (!started) {
1725
+ throw new Error(
1726
+ "Runner is not started. Call start() or serve() first."
1727
+ );
1728
+ }
1729
+ return runtimeBundle.runTask(
1730
+ { message, sessionId: runOptions?.sessionId },
1731
+ { trigger: "programmatic", fallbackSessionKey: `${name}-run` }
1732
+ );
1733
+ },
1734
+ async stop() {
1735
+ const stopErrors = [];
1736
+ if (httpServer) {
1737
+ try {
1738
+ await httpServer.close();
1739
+ } catch (error) {
1740
+ stopErrors.push(error);
1741
+ } finally {
1742
+ httpServer = void 0;
1743
+ }
1744
+ }
1745
+ try {
1746
+ await worker.stop();
1747
+ } catch (error) {
1748
+ stopErrors.push(error);
1749
+ }
1750
+ await stopRuntimeSafely(runtimeBundle.runtime, stopErrors);
1751
+ started = false;
1752
+ log("Stopped");
1753
+ if (stopErrors.length > 0) {
1754
+ throw createAggregateLifecycleError(
1755
+ "Failed to stop Dapr agent runner cleanly.",
1756
+ stopErrors
1757
+ );
1758
+ }
1759
+ }
1760
+ };
1761
+ }
1762
+ function createDaprMultiAgentRunner(options) {
1763
+ const config = resolveDaprConfig({
1764
+ ...options,
1765
+ // Satisfy resolveDaprConfig's DaprAgentRunnerOptions shape
1766
+ agent: options.agents[0].agent,
1767
+ name: "multi-agent"
1768
+ });
1769
+ const loggingEnabled = options.logging !== false;
1770
+ const entries = options.agents.map((ac) => {
1771
+ const observers = [];
1772
+ if (loggingEnabled) {
1773
+ observers.push(createDaprLoggingObserver({ prefix: `[${ac.name}]` }));
1774
+ }
1775
+ if (options.observers) {
1776
+ observers.push(...options.observers);
1777
+ }
1778
+ const workflowHost = createDaprAgentWorkflowHost({
1779
+ agent: ac.agent,
1780
+ workflowName: `${ac.name}:turn`,
1781
+ observers
1782
+ });
1783
+ const runtimeBundle = createDaprAgentRuntime({
1784
+ agent: ac.agent,
1785
+ driver: {
1786
+ stateStoreName: config.stateStoreName,
1787
+ daprHttpEndpoint: config.daprHttpEndpoint,
1788
+ ...options.driverOptions
1789
+ },
1790
+ taskRunnerOptions: { observers }
1791
+ });
1792
+ const info = {
1793
+ id: ac.name,
1794
+ aliases: ac.aliases ?? [],
1795
+ description: ac.description,
1796
+ workflowHost,
1797
+ runtimeBundle: { executionStore: runtimeBundle.executionStore }
1798
+ };
1799
+ return { ...ac, workflowHost, runtimeBundle, info };
1800
+ });
1801
+ const worker = createDaprWorkflowWorker({
1802
+ runtime: options.workflowRuntime,
1803
+ agents: entries.map((e) => ({
1804
+ id: e.name,
1805
+ host: e.workflowHost,
1806
+ aliases: e.aliases,
1807
+ description: e.description
1808
+ }))
1809
+ });
1810
+ const workflowClient = new DaprWorkflowClient({
1811
+ daprHttpEndpoint: config.daprHttpEndpoint,
1812
+ workflowComponent: config.workflowComponent
1813
+ });
1814
+ const agentMap = new Map(entries.map((e) => [e.name, e]));
1815
+ for (const e of entries) {
1816
+ for (const alias of e.aliases ?? []) {
1817
+ agentMap.set(alias, e);
1818
+ }
1819
+ }
1820
+ const app = {
1821
+ isRunning: () => worker.isRunning(),
1822
+ listAgents: () => entries.map((e) => e.info),
1823
+ getAgent: (id) => agentMap.get(id)?.info,
1824
+ runAgent: async (id, payload) => {
1825
+ const entry = agentMap.get(id);
1826
+ if (!entry) throw new Error(`Unknown agent: ${id}`);
1827
+ return entry.runtimeBundle.runTask(payload, {
1828
+ trigger: "http",
1829
+ fallbackSessionKey: `${entry.name}-http`
1830
+ });
1831
+ },
1832
+ handleScheduledJob: async (jobName) => {
1833
+ for (const e of entries) {
1834
+ const result = await e.runtimeBundle.handleDaprJob(jobName);
1835
+ if (result.handled) return result;
1836
+ }
1837
+ return { handled: false, status: 404 };
1838
+ },
1839
+ checkReadiness: async () => {
1840
+ const checks = [];
1841
+ const workerRunning = worker.isRunning();
1842
+ const runtimesRunning = entries.every(
1843
+ (entry) => entry.runtimeBundle.runtime.status().started
1844
+ );
1845
+ checks.push({
1846
+ name: "workflow-worker",
1847
+ ok: workerRunning,
1848
+ ...workerRunning ? {} : { detail: "Workflow worker is not running." }
1849
+ });
1850
+ checks.push({
1851
+ name: "runtimes",
1852
+ ok: runtimesRunning,
1853
+ ...runtimesRunning ? {} : { detail: "One or more agent runtimes are not started." }
1854
+ });
1855
+ const sidecarClient = new DaprSidecarClient({
1856
+ stateStoreName: config.stateStoreName,
1857
+ daprHttpEndpoint: config.daprHttpEndpoint,
1858
+ ...options.driverOptions,
1859
+ verifySidecarOnStart: true
1860
+ });
1861
+ try {
1862
+ await sidecarClient.verifySidecar();
1863
+ checks.push({ name: "dapr-sidecar", ok: true });
1864
+ } catch (error) {
1865
+ checks.push({
1866
+ name: "dapr-sidecar",
1867
+ ok: false,
1868
+ detail: toErrorMessage3(error)
1869
+ });
1870
+ }
1871
+ try {
1872
+ await sidecarClient.getStateEntry("__agent-runtime-ready__");
1873
+ checks.push({ name: "state-store", ok: true });
1874
+ } catch (error) {
1875
+ checks.push({
1876
+ name: "state-store",
1877
+ ok: false,
1878
+ detail: toErrorMessage3(error)
1879
+ });
1880
+ }
1881
+ return {
1882
+ ok: checks.every((check) => check.ok),
1883
+ checks
1884
+ };
1885
+ }
1886
+ };
1887
+ let started = false;
1888
+ let httpServer;
1889
+ function log(message) {
1890
+ if (loggingEnabled) {
1891
+ console.log(`[multi-agent] ${message}`);
1892
+ }
1893
+ }
1894
+ return {
1895
+ async start() {
1896
+ if (started) return;
1897
+ const startedRuntimes = [];
1898
+ const startupErrors = [];
1899
+ try {
1900
+ for (const entry of entries) {
1901
+ await entry.runtimeBundle.runtime.start();
1902
+ startedRuntimes.push(entry.runtimeBundle.runtime);
1903
+ }
1904
+ try {
1905
+ await worker.start();
1906
+ } catch (error) {
1907
+ startupErrors.push(error);
1908
+ for (const runtime of startedRuntimes.reverse()) {
1909
+ await stopRuntimeSafely(runtime, startupErrors);
1910
+ }
1911
+ throw createAggregateLifecycleError(
1912
+ "Failed to start Dapr multi-agent runner cleanly.",
1913
+ startupErrors
1914
+ );
1915
+ }
1916
+ started = true;
1917
+ log(
1918
+ `Worker started \u2014 agents: ${entries.map((e) => e.name).join(", ")}`
1919
+ );
1920
+ } catch (error) {
1921
+ if (error instanceof Error) {
1922
+ throw error;
1923
+ }
1924
+ throw new Error(String(error));
1925
+ }
1926
+ },
1927
+ async serve(serveOptions) {
1928
+ if (!started) {
1929
+ await this.start();
1930
+ }
1931
+ const port = serveOptions?.port ?? 3e3;
1932
+ httpServer = await startDaprHostHttpServer({
1933
+ app,
1934
+ workflowClient,
1935
+ port,
1936
+ host: serveOptions?.host
1937
+ });
1938
+ log(`HTTP listening on ${httpServer.origin}`);
1939
+ await new Promise((resolve) => {
1940
+ let shuttingDown = false;
1941
+ const shutdown = async (signal) => {
1942
+ if (shuttingDown) return;
1943
+ shuttingDown = true;
1944
+ log(`${signal} \u2014 shutting down`);
1945
+ await this.stop();
1946
+ resolve();
1947
+ };
1948
+ process.once("SIGINT", () => void shutdown("SIGINT"));
1949
+ process.once("SIGTERM", () => void shutdown("SIGTERM"));
1950
+ });
1951
+ },
1952
+ async stop() {
1953
+ const stopErrors = [];
1954
+ if (httpServer) {
1955
+ try {
1956
+ await httpServer.close();
1957
+ } catch (error) {
1958
+ stopErrors.push(error);
1959
+ } finally {
1960
+ httpServer = void 0;
1961
+ }
1962
+ }
1963
+ try {
1964
+ await worker.stop();
1965
+ } catch (error) {
1966
+ stopErrors.push(error);
1967
+ }
1968
+ for (const entry of entries) {
1969
+ await stopRuntimeSafely(entry.runtimeBundle.runtime, stopErrors);
1970
+ }
1971
+ started = false;
1972
+ log("Stopped");
1973
+ if (stopErrors.length > 0) {
1974
+ throw createAggregateLifecycleError(
1975
+ "Failed to stop Dapr multi-agent runner cleanly.",
1976
+ stopErrors
1977
+ );
1978
+ }
1979
+ }
1980
+ };
1981
+ }
1982
+
1983
+ export {
1984
+ createDaprHttpJobHandler,
1985
+ DaprRuntimeDriver,
1986
+ DaprOrchestratorRunStore,
1987
+ DaprServiceInvoker,
1988
+ invokeRemoteAgentRun,
1989
+ createDaprAgentWorkflowHost,
1990
+ startDaprAgentWorkflowTurn,
1991
+ createDaprWorkflowWorker,
1992
+ createDaprAgentRuntime,
1993
+ createDaprHostHttpHandler,
1994
+ startDaprHostHttpServer,
1995
+ createDaprAgentRunner,
1996
+ createDaprMultiAgentRunner
1997
+ };