glove-foundry 0.4.0 → 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,730 @@
1
+ import {
2
+ mountFoundryGuidance,
3
+ mountFoundryWorkbench
4
+ } from "./chunk-LW5PJ2FN.js";
5
+ import {
6
+ EMPTY_CAPABILITY_REGISTRY,
7
+ EMPTY_FOUNDRY_APPLICATION,
8
+ FOUNDRY_APPROVAL_DIRECTORY_ENV,
9
+ FOUNDRY_COMPOSED_PLAYBOOK_BRAND,
10
+ FOUNDRY_CORE_COMMAND_EVENT,
11
+ FoundryApprovalDisplayManager,
12
+ MemoryFoundryDataAdapter,
13
+ agentPlaybookId,
14
+ agentScheduleActivationId,
15
+ agentScheduleRevision,
16
+ composedPlaybookRevision,
17
+ createFoundryCoreTools,
18
+ createInstalledApplicationTransmissionTools,
19
+ freezeGloveMessage,
20
+ installRegistry,
21
+ isFoundryApplication,
22
+ isFoundrySchedule,
23
+ isInboxCapableStore,
24
+ materializeComposedPlaybook,
25
+ mountAgentDefinitionMemory,
26
+ mountFoundrySurfaces,
27
+ normalizeScheduleTiming,
28
+ toGloveMessage,
29
+ toGloveRequestInput,
30
+ withFoundryPermissions
31
+ } from "./chunk-KBMD4RYU.js";
32
+ import {
33
+ FOUNDRY_APPLICATION_ENV,
34
+ FOUNDRY_EVENT_PREFIX,
35
+ FOUNDRY_EXECUTION_MARKER,
36
+ defineAgentFromModule,
37
+ internalAgentName,
38
+ resolveResolvable
39
+ } from "./chunk-5NFLGHOC.js";
40
+
41
+ // src/agent-runtime.ts
42
+ import { pathToFileURL } from "node:url";
43
+ import { Glove } from "glove-core";
44
+ import { mountMesh } from "glove-mesh";
45
+ import { Effect } from "effect";
46
+ import { signal } from "station-signal";
47
+ import { z } from "zod";
48
+ var INBOX_ITEMS_SCHEMA = z.array(z.object({
49
+ id: z.string().min(1),
50
+ tag: z.string(),
51
+ request: z.string(),
52
+ response: z.string().nullable(),
53
+ status: z.enum(["pending", "resolved", "consumed"]),
54
+ blocking: z.boolean(),
55
+ created_at: z.string(),
56
+ resolved_at: z.string().nullable()
57
+ }));
58
+ async function hydrateInbox(store, items, emit) {
59
+ if (!isInboxCapableStore(store)) {
60
+ throw new Error("Agent inbox loading requires an inbox-capable Glove StoreAdapter.");
61
+ }
62
+ const loaded = INBOX_ITEMS_SCHEMA.parse(items);
63
+ const existing = new Map((await store.getInboxItems()).map((item) => [item.id, item]));
64
+ let added = 0;
65
+ let updated = 0;
66
+ for (const item of loaded) {
67
+ const current = existing.get(item.id);
68
+ if (!current) {
69
+ await store.addInboxItem({ ...item });
70
+ added++;
71
+ continue;
72
+ }
73
+ if (current.status !== item.status || current.response !== item.response || current.resolved_at !== item.resolved_at) {
74
+ await store.updateInboxItem(item.id, {
75
+ status: item.status,
76
+ response: item.response,
77
+ resolved_at: item.resolved_at
78
+ });
79
+ updated++;
80
+ }
81
+ }
82
+ emit({
83
+ type: "foundry.definition.inboxes.loaded",
84
+ data: { count: loaded.length, added, updated }
85
+ });
86
+ }
87
+ function extractOutput(result) {
88
+ if (result == null || typeof result !== "object") return result;
89
+ const object = result;
90
+ if (Array.isArray(object.messages)) {
91
+ const last = object.messages.at(-1);
92
+ return last?.text ?? "";
93
+ }
94
+ return "text" in object ? object.text : result;
95
+ }
96
+ function serializable(value) {
97
+ try {
98
+ return JSON.parse(JSON.stringify(value));
99
+ } catch {
100
+ return String(value);
101
+ }
102
+ }
103
+ function writeAgentEvent(type, data) {
104
+ const line = `${FOUNDRY_EVENT_PREFIX}${JSON.stringify({
105
+ type,
106
+ data: serializable(data),
107
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
108
+ })}
109
+ `;
110
+ return new Promise((resolveWrite, rejectWrite) => {
111
+ process.stdout.write(line, (error) => {
112
+ if (error) rejectWrite(error);
113
+ else resolveWrite();
114
+ });
115
+ });
116
+ }
117
+ function executionSubscriber() {
118
+ return {
119
+ async record(eventType, data) {
120
+ await writeAgentEvent(eventType, data);
121
+ }
122
+ };
123
+ }
124
+ async function resolveAgentValue(definition, value, context, field) {
125
+ context.controls.emit({
126
+ type: "foundry.assembly.resolve.start",
127
+ data: { field }
128
+ });
129
+ const resolved = await resolveResolvable(
130
+ typeof value === "function" ? value(definition, context) : value
131
+ );
132
+ context.controls.emit({
133
+ type: "foundry.assembly.resolve.complete",
134
+ data: {
135
+ field,
136
+ count: Array.isArray(resolved) ? resolved.length : void 0
137
+ }
138
+ });
139
+ return resolved;
140
+ }
141
+ var HANDLER_ONLY_MODEL = {
142
+ name: "foundry-handler",
143
+ setSystemPrompt: () => void 0,
144
+ prompt: async () => {
145
+ throw new Error(
146
+ "This is a model-free Foundry agent. Define run/spawn or configure a model."
147
+ );
148
+ }
149
+ };
150
+ async function loadRuntimeApplication() {
151
+ const path = process.env[FOUNDRY_APPLICATION_ENV];
152
+ if (!path) return EMPTY_FOUNDRY_APPLICATION;
153
+ const imported = await import(pathToFileURL(path).href);
154
+ if (!isFoundryApplication(imported.default)) {
155
+ throw new Error(
156
+ `${path} must default-export defineApplication(...) for installation resolution.`
157
+ );
158
+ }
159
+ return imported.default;
160
+ }
161
+ async function executeSpawned(spawned, message, signal2) {
162
+ if (spawned && typeof spawned === "object" && "processRequest" in spawned && typeof spawned.processRequest === "function") {
163
+ return extractOutput(
164
+ await spawned.processRequest(toGloveRequestInput(message), signal2)
165
+ );
166
+ }
167
+ if (spawned && typeof spawned === "object" && "run" in spawned && typeof spawned.run === "function") {
168
+ return spawned.run(
169
+ message,
170
+ signal2
171
+ );
172
+ }
173
+ return spawned;
174
+ }
175
+ async function runDefinition(definition, id, runtimeValue) {
176
+ const envelope = runtimeValue;
177
+ const request = envelope.request;
178
+ const input = request;
179
+ const runId = process.env.STATION_SIGNAL_RUN_ID ?? "unknown";
180
+ const subscriber = executionSubscriber();
181
+ const abortController = new AbortController();
182
+ const onTerminate = () => abortController.abort();
183
+ process.once("SIGTERM", onTerminate);
184
+ let disposeSurfaces;
185
+ const cleanups = [];
186
+ const application = await loadRuntimeApplication();
187
+ const storeFactory = definition.store ?? application.conversationStore;
188
+ const store = storeFactory ? await storeFactory({
189
+ definitionId: id,
190
+ agentId: request.agentId,
191
+ conversationId: request.conversationId,
192
+ workspaceId: request.workspaceId
193
+ }) : null;
194
+ const runtimeStore = store ? withFoundryPermissions(store) : null;
195
+ const history = Object.freeze(
196
+ (runtimeStore ? await runtimeStore.getMessages() : []).map(freezeGloveMessage)
197
+ );
198
+ const message = toGloveMessage(request.message);
199
+ const messages = Object.freeze([...history, message]);
200
+ const controls = {
201
+ signal: abortController.signal,
202
+ commands: [],
203
+ emit: (event) => {
204
+ void writeAgentEvent(event.type, event.data).catch((cause) => {
205
+ process.stderr.write(
206
+ `Foundry failed to forward agent event: ${cause instanceof Error ? cause.message : String(cause)}
207
+ `
208
+ );
209
+ });
210
+ }
211
+ };
212
+ try {
213
+ const registry = definition.components ?? {
214
+ capabilities: EMPTY_CAPABILITY_REGISTRY,
215
+ native: { layers: Object.freeze([]), subscribers: Object.freeze([]) }
216
+ };
217
+ const installations = envelope.agent.installations;
218
+ const data = application.data ?? new MemoryFoundryDataAdapter();
219
+ const initialAssemblyContext = {
220
+ definitionId: id,
221
+ agentId: request.agentId,
222
+ conversationId: request.conversationId,
223
+ workspaceId: request.workspaceId,
224
+ name: internalAgentName(id),
225
+ runId,
226
+ mode: "agent",
227
+ request,
228
+ agentInstance: envelope.agent,
229
+ conversation: envelope.conversation,
230
+ activations: Object.freeze([...envelope.activations ?? []]),
231
+ data,
232
+ input,
233
+ message,
234
+ messageInput: request.message,
235
+ messageText: message.text,
236
+ history,
237
+ messages,
238
+ installations,
239
+ store: runtimeStore,
240
+ subscriber,
241
+ controls
242
+ };
243
+ const assemblyContext = initialAssemblyContext;
244
+ const resolveOptional = async (field, value, fallback) => value === void 0 ? fallback : resolveAgentValue(
245
+ definition,
246
+ value,
247
+ assemblyContext,
248
+ field
249
+ );
250
+ const [model, systemPrompt, displayManager, compactionLimit, compactionInstructions, maxTurns] = await Promise.all([
251
+ resolveOptional("model", definition.model, HANDLER_ONLY_MODEL),
252
+ resolveOptional("systemPrompt", definition.systemPrompt, ""),
253
+ resolveOptional(
254
+ "displayManager",
255
+ definition.displayManager,
256
+ new FoundryApprovalDisplayManager({
257
+ directory: process.env[FOUNDRY_APPROVAL_DIRECTORY_ENV],
258
+ runId,
259
+ definitionId: id,
260
+ agentId: request.agentId,
261
+ conversationId: request.conversationId,
262
+ workspaceId: request.workspaceId,
263
+ signal: abortController.signal,
264
+ emit: controls.emit
265
+ })
266
+ ),
267
+ resolveOptional("compactionLimit", definition.compactionLimit, void 0),
268
+ resolveOptional("compactionInstructions", definition.compactionInstructions, "Preserve goals, decisions, unresolved work, tool results, and pending inbox items."),
269
+ resolveOptional("maxTurns", definition.maxTurns, void 0)
270
+ ]);
271
+ const base = new Glove({
272
+ ...runtimeStore ? { store: runtimeStore } : {},
273
+ model,
274
+ displayManager,
275
+ systemPrompt,
276
+ serverMode: definition.serverMode ?? true,
277
+ ...definition.maxRetries !== void 0 ? { maxRetries: definition.maxRetries } : {},
278
+ ...definition.maxConsecutiveErrors !== void 0 ? { maxConsecutiveErrors: definition.maxConsecutiveErrors } : {},
279
+ compaction_config: {
280
+ compaction_instructions: compactionInstructions,
281
+ ...maxTurns !== void 0 ? { max_turns: maxTurns } : {},
282
+ ...compactionLimit !== void 0 ? { compaction_context_limit: compactionLimit } : {}
283
+ },
284
+ ...definition.enableToolResultSummary !== void 0 ? { enableToolResultSummary: definition.enableToolResultSummary } : {}
285
+ }).build();
286
+ base.addSubscriber(subscriber);
287
+ const [tools, hooks, skills, subagents, memory, inboxItems, layers, subscribers, calls, playbooks, schedules, mesh, workingEnvironment, repl] = await Promise.all([
288
+ resolveOptional("tools", definition.tools, []),
289
+ resolveOptional("hooks", definition.hooks, []),
290
+ resolveOptional("skills", definition.skills, []),
291
+ resolveOptional("subagents", definition.subagents, []),
292
+ resolveOptional("memory", definition.memory, []),
293
+ definition.inboxes ? resolveAgentValue(
294
+ definition,
295
+ definition.inboxes,
296
+ assemblyContext,
297
+ "inboxes"
298
+ ) : Promise.resolve([]),
299
+ resolveOptional("layers", definition.layers, []),
300
+ resolveOptional("subscribers", definition.subscribers, []),
301
+ resolveOptional("calls", definition.calls, []),
302
+ resolveOptional("playbooks", definition.playbooks, []),
303
+ resolveOptional("schedules", definition.schedules, []),
304
+ resolveOptional("mesh", definition.mesh, void 0),
305
+ resolveOptional("workingEnvironment", definition.workingEnvironment, void 0),
306
+ resolveOptional("repl", definition.repl, void 0)
307
+ ]);
308
+ const playbookNames = /* @__PURE__ */ new Set();
309
+ const desiredPlaybooks = definition.playbooks === void 0 ? envelope.agent.playbooks : playbooks.map((playbook) => {
310
+ if (playbook[FOUNDRY_COMPOSED_PLAYBOOK_BRAND] !== true) {
311
+ throw new Error("Agent playbooks must be created at runtime with composePlaybook(...).");
312
+ }
313
+ if (playbookNames.has(playbook.name)) {
314
+ throw new Error(`Duplicate composed playbook name "${playbook.name}".`);
315
+ }
316
+ playbookNames.add(playbook.name);
317
+ const revision = composedPlaybookRevision(playbook);
318
+ return materializeComposedPlaybook(
319
+ playbook,
320
+ agentPlaybookId(id, request.agentId, playbook.name),
321
+ revision
322
+ );
323
+ });
324
+ if (definition.playbooks !== void 0) {
325
+ const playbookSync = {
326
+ id: `playbook_sync_${runId}`,
327
+ type: "playbook.sync",
328
+ definitionId: id,
329
+ agentId: request.agentId,
330
+ conversationId: request.conversationId,
331
+ workspaceId: request.workspaceId,
332
+ playbooks: desiredPlaybooks
333
+ };
334
+ controls.commands.push(playbookSync);
335
+ controls.emit({ type: FOUNDRY_CORE_COMMAND_EVENT, data: playbookSync });
336
+ controls.emit({
337
+ type: "foundry.definition.playbooks.composed",
338
+ data: { count: desiredPlaybooks.length, names: desiredPlaybooks.map((item) => item.playbookName) }
339
+ });
340
+ }
341
+ const scheduleNames = /* @__PURE__ */ new Set();
342
+ const desiredSchedules = schedules.map((schedule) => {
343
+ if (!isFoundrySchedule(schedule)) {
344
+ throw new Error("Agent schedules must be created with defineSchedule(...).");
345
+ }
346
+ if (scheduleNames.has(schedule.name)) {
347
+ throw new Error(`Duplicate agent schedule name "${schedule.name}".`);
348
+ }
349
+ scheduleNames.add(schedule.name);
350
+ return {
351
+ id: agentScheduleActivationId(id, request.agentId, schedule.name),
352
+ name: schedule.name,
353
+ revision: agentScheduleRevision(schedule),
354
+ message: schedule.message,
355
+ ...schedule.payload !== void 0 ? { payload: schedule.payload } : {},
356
+ timing: normalizeScheduleTiming(schedule.timing),
357
+ enabled: schedule.enabled !== false
358
+ };
359
+ });
360
+ const scheduleSync = {
361
+ id: `schedule_sync_${runId}`,
362
+ type: "schedule.sync",
363
+ definitionId: id,
364
+ agentId: request.agentId,
365
+ conversationId: request.conversationId,
366
+ workspaceId: request.workspaceId,
367
+ schedules: desiredSchedules
368
+ };
369
+ controls.commands.push(scheduleSync);
370
+ controls.emit({ type: FOUNDRY_CORE_COMMAND_EVENT, data: scheduleSync });
371
+ controls.emit({
372
+ type: "foundry.definition.schedules.loaded",
373
+ data: { count: desiredSchedules.length, names: desiredSchedules.map((item) => item.name) }
374
+ });
375
+ const effectiveInstallations = [...installations];
376
+ for (const tool of createFoundryCoreTools(assemblyContext, desiredSchedules)) base.fold(tool);
377
+ const applicationTransmissionTools = createInstalledApplicationTransmissionTools(
378
+ assemblyContext,
379
+ registry.capabilities.applications,
380
+ effectiveInstallations,
381
+ desiredPlaybooks
382
+ );
383
+ for (const tool of applicationTransmissionTools) base.fold(tool);
384
+ if (applicationTransmissionTools.length > 0) {
385
+ controls.emit({
386
+ type: "foundry.application.transmission-tools.mounted",
387
+ data: {
388
+ tools: applicationTransmissionTools.map((tool) => tool.name)
389
+ }
390
+ });
391
+ }
392
+ for (const tool of tools) base.fold(tool);
393
+ for (const hook of hooks) base.defineHook(hook.name, hook.handler);
394
+ for (const skill of skills) base.defineSkill(skill);
395
+ for (const subagent of subagents) base.defineSubAgent(subagent);
396
+ const workbench = await mountFoundryWorkbench({
397
+ glove: base,
398
+ context: assemblyContext,
399
+ ...workingEnvironment ? { workingEnvironment } : {},
400
+ ...repl ? { repl } : {},
401
+ deferRepl: Boolean(repl?.programmaticTools)
402
+ });
403
+ cleanups.push(workbench.dispose);
404
+ const callByName = /* @__PURE__ */ new Map();
405
+ const invoke = async (name, callInput) => {
406
+ const call = callByName.get(name);
407
+ if (!call) throw new Error(`Foundry call "${name}" is not available.`);
408
+ const parsed = call.input.parse(callInput);
409
+ const value = await resolveResolvable(call.handler(parsed, callContext));
410
+ return call.output.parse(value);
411
+ };
412
+ const surfaceContext = {
413
+ definitionId: id,
414
+ agentId: request.agentId,
415
+ conversationId: request.conversationId,
416
+ workspaceId: request.workspaceId,
417
+ runId,
418
+ input,
419
+ request,
420
+ message,
421
+ messageInput: request.message,
422
+ messageText: message.text,
423
+ history,
424
+ messages,
425
+ glove: base,
426
+ ...workbench.workingEnvironment ? { workingEnvironment: workbench.workingEnvironment, vfs: workbench.vfs } : {},
427
+ ...workbench.repl ? { repl: workbench.repl } : {},
428
+ signal: abortController.signal,
429
+ emit: controls.emit
430
+ };
431
+ const guidance = await mountFoundryGuidance(base, assemblyContext, {
432
+ facts: await resolveOptional("facts", definition.facts, void 0),
433
+ goals: await resolveOptional("goals", definition.goals, void 0),
434
+ forms: await resolveOptional("forms", definition.forms, void 0),
435
+ contextProviders: await resolveOptional("contextProviders", definition.contextProviders, [])
436
+ });
437
+ cleanups.push(async () => {
438
+ try {
439
+ await guidance.snapshot();
440
+ } finally {
441
+ guidance.dispose();
442
+ }
443
+ });
444
+ const callContext = {
445
+ ...surfaceContext,
446
+ ...guidance.handles,
447
+ installations: effectiveInstallations,
448
+ onCleanup: (cleanup) => {
449
+ cleanups.push(cleanup);
450
+ },
451
+ invoke
452
+ };
453
+ for (const call of calls) {
454
+ if (callByName.has(call.name)) throw new Error(`Duplicate Foundry call "${call.name}".`);
455
+ callByName.set(call.name, call);
456
+ if (call.exposeToAgent ?? true) {
457
+ base.fold({
458
+ name: call.name,
459
+ description: call.description,
460
+ inputSchema: call.input,
461
+ async do(callInput) {
462
+ try {
463
+ return { status: "success", data: await invoke(call.name, callInput) };
464
+ } catch (cause) {
465
+ return {
466
+ status: "error",
467
+ data: null,
468
+ message: cause instanceof Error ? cause.message : String(cause)
469
+ };
470
+ }
471
+ }
472
+ });
473
+ }
474
+ }
475
+ disposeSurfaces = await mountFoundrySurfaces({
476
+ registry: registry.native,
477
+ layers,
478
+ subscribers,
479
+ context: surfaceContext
480
+ });
481
+ await Effect.runPromise(
482
+ installRegistry({
483
+ registry: registry.capabilities,
484
+ installations: effectiveInstallations,
485
+ context: {
486
+ definitionId: id,
487
+ agentId: request.agentId,
488
+ conversationId: request.conversationId,
489
+ workspaceId: request.workspaceId,
490
+ runId,
491
+ input,
492
+ request,
493
+ message,
494
+ messageInput: request.message,
495
+ messageText: message.text,
496
+ history,
497
+ messages,
498
+ glove: base,
499
+ store: base.store,
500
+ emit: controls.emit
501
+ },
502
+ ...definition.mcpAdapter ? { mcpAdapter: definition.mcpAdapter } : {},
503
+ ...definition.accountSessions ? { accountSessions: definition.accountSessions } : {}
504
+ })
505
+ );
506
+ await Effect.runPromise(
507
+ mountAgentDefinitionMemory({
508
+ registry: registry.capabilities,
509
+ memory,
510
+ context: {
511
+ definitionId: id,
512
+ agentId: request.agentId,
513
+ conversationId: request.conversationId,
514
+ workspaceId: request.workspaceId,
515
+ runId,
516
+ input,
517
+ request,
518
+ message,
519
+ messageInput: request.message,
520
+ messageText: message.text,
521
+ history,
522
+ messages,
523
+ glove: base,
524
+ store: base.store,
525
+ emit: controls.emit
526
+ }
527
+ })
528
+ );
529
+ if (definition.inboxes) {
530
+ await hydrateInbox(base.store, inboxItems, controls.emit);
531
+ }
532
+ if (mesh) {
533
+ await mountMesh(base, {
534
+ adapter: mesh.adapter,
535
+ identity: {
536
+ id: mesh.identity?.id ?? request.agentId,
537
+ name: mesh.identity?.name ?? request.agentId,
538
+ description: mesh.identity?.description ?? definition.description,
539
+ ...mesh.identity?.capabilities ? { capabilities: mesh.identity.capabilities } : {},
540
+ metadata: {
541
+ definitionId: id,
542
+ conversationId: request.conversationId,
543
+ workspaceId: request.workspaceId,
544
+ ...mesh.identity?.metadata ?? {}
545
+ }
546
+ }
547
+ });
548
+ cleanups.push(() => mesh.adapter.unregister());
549
+ }
550
+ if (definition.configure) {
551
+ await resolveResolvable(definition.configure(base, callContext));
552
+ }
553
+ await workbench.mountRepl();
554
+ const glove = definition.build ? await resolveResolvable(definition.build(base, assemblyContext)) ?? base : base;
555
+ const runtimeContext = { ...callContext, glove };
556
+ const defaultRun = async (messageInput = assemblyContext.messageInput) => extractOutput(
557
+ await glove.processRequest(
558
+ toGloveRequestInput(messageInput),
559
+ abortController.signal
560
+ )
561
+ );
562
+ const spawn = async (messageInput = assemblyContext.messageInput) => definition.spawn ? executeSpawned(
563
+ await resolveResolvable(definition.spawn(glove, runtimeContext, messageInput)),
564
+ messageInput,
565
+ abortController.signal
566
+ ) : defaultRun(messageInput);
567
+ const handlerContext = {
568
+ ...runtimeContext,
569
+ defaultRun,
570
+ defaultHandler: defaultRun,
571
+ spawn
572
+ };
573
+ const result = definition.run ? await resolveResolvable(definition.run(glove, handlerContext)) : definition.handler ? await resolveResolvable(definition.handler(handlerContext)) : definition.spawn ? await spawn() : await defaultRun();
574
+ await guidance.snapshot();
575
+ const sleep = [...controls.commands].reverse().find(
576
+ (command) => command.type === "sleep"
577
+ );
578
+ return {
579
+ status: sleep ? "suspended" : "completed",
580
+ value: serializable(result),
581
+ agentId: request.agentId,
582
+ conversationId: request.conversationId,
583
+ workspaceId: request.workspaceId,
584
+ ...sleep && sleep.type === "sleep" ? { suspension: { commandId: sleep.id, wakeAt: sleep.wakeAt } } : {}
585
+ };
586
+ } finally {
587
+ const failures = [];
588
+ for (const cleanup of cleanups.reverse()) {
589
+ try {
590
+ await cleanup();
591
+ } catch (cause) {
592
+ failures.push(cause);
593
+ }
594
+ }
595
+ try {
596
+ if (disposeSurfaces) await disposeSurfaces();
597
+ } catch (cause) {
598
+ failures.push(cause);
599
+ }
600
+ process.removeListener("SIGTERM", onTerminate);
601
+ if (failures.length > 0) throw new AggregateError(failures, "Foundry agent cleanup failed.");
602
+ }
603
+ }
604
+ function compileAgentDefinition(definition, route) {
605
+ const contentPartSchema = z.object({
606
+ type: z.enum(["text", "image", "video", "document"]),
607
+ text: z.string().optional(),
608
+ name: z.string().optional(),
609
+ source: z.object({
610
+ type: z.enum(["base64", "url"]),
611
+ media_type: z.string(),
612
+ data: z.string().optional(),
613
+ url: z.string().optional()
614
+ }).optional()
615
+ });
616
+ const requestSchema = z.object({
617
+ agentId: z.string().min(1),
618
+ conversationId: z.string().min(1),
619
+ workspaceId: z.string().min(1),
620
+ message: z.union([z.string(), z.array(contentPartSchema)]),
621
+ payload: z.unknown().optional(),
622
+ context: z.record(z.string(), z.unknown()).optional(),
623
+ source: z.object({
624
+ kind: z.enum(["direct", "transmission", "activation", "spawn", "background"]),
625
+ id: z.string().optional(),
626
+ provider: z.string().optional(),
627
+ eventId: z.string().optional(),
628
+ threadKey: z.string().optional()
629
+ }).optional()
630
+ });
631
+ const executionEnvelope = z.object({
632
+ [FOUNDRY_EXECUTION_MARKER]: z.literal(true),
633
+ request: requestSchema,
634
+ agent: z.object({
635
+ id: z.string(),
636
+ definitionId: z.string(),
637
+ workspaceId: z.string(),
638
+ context: z.record(z.string(), z.unknown()),
639
+ installations: z.array(z.object({
640
+ kind: z.enum(["tool", "application", "mcp"]),
641
+ id: z.string(),
642
+ config: z.unknown().optional()
643
+ })),
644
+ playbooks: z.array(z.object({
645
+ id: z.string(),
646
+ transmissionId: z.string(),
647
+ enabled: z.boolean().optional(),
648
+ match: z.object({
649
+ event: z.string().optional(),
650
+ routeIds: z.array(z.string()).optional(),
651
+ predicate: z.object({
652
+ name: z.string(),
653
+ parameters: z.record(z.string(), z.unknown()).optional()
654
+ }).optional()
655
+ }).optional(),
656
+ directives: z.array(z.object({
657
+ action: z.string(),
658
+ instruction: z.string(),
659
+ parameters: z.record(z.string(), z.unknown()).optional()
660
+ })),
661
+ applications: z.array(z.string()).optional(),
662
+ outbound: z.array(z.object({
663
+ routeId: z.string(),
664
+ applicationId: z.string().optional(),
665
+ event: z.string().optional(),
666
+ accountId: z.string().optional(),
667
+ applicationAccountId: z.string().optional(),
668
+ instruction: z.string().optional()
669
+ })).optional(),
670
+ serialization: z.record(z.string(), z.unknown()).optional(),
671
+ origin: z.enum(["agent-definition", "instance"]).optional(),
672
+ playbookName: z.string().optional(),
673
+ definitionRevision: z.string().optional()
674
+ })),
675
+ createdAt: z.string(),
676
+ updatedAt: z.string()
677
+ }),
678
+ conversation: z.object({
679
+ id: z.string(),
680
+ agentId: z.string(),
681
+ workspaceId: z.string(),
682
+ title: z.string().optional(),
683
+ context: z.record(z.string(), z.unknown()),
684
+ createdAt: z.string(),
685
+ updatedAt: z.string()
686
+ }),
687
+ activations: z.array(z.object({
688
+ id: z.string(),
689
+ kind: z.enum(["scheduled", "sleep"]),
690
+ definitionId: z.string(),
691
+ agentId: z.string(),
692
+ conversationId: z.string(),
693
+ workspaceId: z.string(),
694
+ message: z.string(),
695
+ payload: z.unknown().optional(),
696
+ timing: z.union([
697
+ z.object({ kind: z.literal("at"), at: z.string() }),
698
+ z.object({ kind: z.literal("every"), intervalMs: z.number() }),
699
+ z.object({ kind: z.literal("cron"), expression: z.string(), timezone: z.string() })
700
+ ]),
701
+ origin: z.enum(["agent-definition", "agent-tool"]),
702
+ scheduleName: z.string().optional(),
703
+ definitionRevision: z.string().optional(),
704
+ status: z.enum(["pending", "active", "paused", "completed", "cancelled"]),
705
+ createdByRunId: z.string(),
706
+ lastRunId: z.string().optional(),
707
+ createdAt: z.string(),
708
+ updatedAt: z.string()
709
+ })).default([])
710
+ });
711
+ let builder = signal(internalAgentName(route)).input(executionEnvelope).output(z.object({
712
+ status: z.enum(["completed", "suspended"]),
713
+ value: z.unknown(),
714
+ agentId: z.string(),
715
+ conversationId: z.string(),
716
+ workspaceId: z.string(),
717
+ suspension: z.object({ commandId: z.string(), wakeAt: z.string() }).optional()
718
+ }));
719
+ const built = builder.run(
720
+ (value) => runDefinition(definition, route, value)
721
+ );
722
+ return built;
723
+ }
724
+ function compileAgentModule(route, module) {
725
+ return compileAgentDefinition(defineAgentFromModule(route, module), route);
726
+ }
727
+
728
+ export {
729
+ compileAgentModule
730
+ };