glove-foundry 0.5.0 → 0.5.2

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.
Files changed (39) hide show
  1. package/README.md +27 -15
  2. package/dist/{chunk-KBMD4RYU.js → chunk-6Q2LGPSC.js} +49 -198
  3. package/dist/{chunk-GKZLWD5M.js → chunk-7F7QVO6I.js} +4 -1
  4. package/dist/{chunk-SGF3CFUR.js → chunk-D2AHSYOB.js} +71 -8
  5. package/dist/{chunk-TH5ETCG2.js → chunk-MABLKZVO.js} +13 -4
  6. package/dist/{chunk-LW5PJ2FN.js → chunk-NHV64WNO.js} +1 -1
  7. package/dist/{chunk-5NFLGHOC.js → chunk-PVOKR4CN.js} +211 -29
  8. package/dist/cli.js +7 -5
  9. package/dist/{client-DcsnudMI.d.ts → client-CLTds1uV.d.ts} +13 -1
  10. package/dist/client.d.ts +1 -1
  11. package/dist/client.js +1 -1
  12. package/dist/execution-agent.js +4 -4
  13. package/dist/execution-daemon.js +1 -1
  14. package/dist/execution-loader.js +4 -4
  15. package/dist/index.d.ts +2 -2
  16. package/dist/index.js +14 -14
  17. package/docs/building-with-foundry.md +4 -2
  18. package/docs/release-verification.md +1 -1
  19. package/package.json +9 -9
  20. package/templates/minimal/README.md +34 -8
  21. package/templates/minimal/agents/assistant/agent.ts +24 -10
  22. package/templates/minimal/foundry.application.ts +11 -3
  23. package/templates/minimal/gitignore +1 -0
  24. package/templates/minimal/lib/file-store.ts +95 -0
  25. package/templates/travel-concierge/README.md +46 -12
  26. package/templates/travel-concierge/agents/concierge/agent.ts +10 -4
  27. package/templates/travel-concierge/agents/concierge/composition.ts +9 -2
  28. package/templates/travel-concierge/agents/concierge/flights.ts +43 -0
  29. package/templates/travel-concierge/agents/concierge/instances.ts +42 -0
  30. package/templates/travel-concierge/agents/concierge/memory/traveller.memory.ts +13 -8
  31. package/templates/travel-concierge/agents/concierge/tools/convert-currency.tool.ts +34 -0
  32. package/templates/travel-concierge/agents/concierge/workbench.ts +4 -1
  33. package/templates/travel-concierge/foundry.application.ts +15 -6
  34. package/templates/travel-concierge/gitignore +1 -0
  35. package/templates/travel-concierge/lib/demo-model.ts +89 -25
  36. package/templates/travel-concierge/lib/file-context.ts +60 -0
  37. package/templates/travel-concierge/lib/file-store.ts +95 -0
  38. package/templates/minimal/agents/assistant/tools/current-time.tool.ts +0 -17
  39. package/templates/travel-concierge/agents/concierge/tools/find-flights.tool.ts +0 -49
package/README.md CHANGED
@@ -71,13 +71,15 @@ If installation fails, your generated project remains available with retry steps
71
71
 
72
72
  ### Before deploying
73
73
 
74
- Persist **three separate things**: Foundry instance/activation data, Glove
75
- conversation history, and structured memory/VFS state. The demo's in-memory
76
- adapters intentionally reset and must not be mistaken for production persistence.
77
- Use `FileFoundryDataAdapter` for single-host runtime data, a durable conversation
78
- store, and `glove-memory/sqlite` or your own native memory adapters. Add VFS
79
- persistence when agents work on documents. Multi-host deployments need shared,
80
- transactional adapters. See [Building with Foundry](./docs/building-with-foundry.md).
74
+ Every run executes in its own process, so nothing the next message needs can live
75
+ only in memory. Persist **four separate things**: Foundry runtime data
76
+ (instances, conversations, activations, workspace), Glove conversation
77
+ transcripts, structured memory, and working-environment files. Persisting one does
78
+ not persist the others. The starters keep all of them on disk under `.data/` with
79
+ single-host adapters (`FileFoundryDataAdapter`, a file-backed transcript store in
80
+ `lib/file-store.ts`, and — in the concierge — file-backed memory and VFS
81
+ persistence). Multi-host deployments need shared, transactional adapters. See
82
+ [Persistence](https://glove.dterminal.net/foundry/docs/persistence).
81
83
 
82
84
  **Troubleshooting:** check `node --version` for engine errors, add a provider key
83
85
  for the minimal starter, choose another `--port` if 4141 is occupied, and inspect a
@@ -317,21 +319,31 @@ projection is resolved only when the subagent is called, after instance
317
319
  installations and message-dependent assembly have completed.
318
320
 
319
321
  ```ts
322
+ import { getToolJsonSchema } from "glove-core"
323
+
324
+ // Names of tools the parent has mounted that the delegate may use.
325
+ const READ_ONLY = new Set(["web_search", "web_read", "workspace_read_file"])
326
+
320
327
  defineSubagent({
321
328
  name: "researcher",
322
329
  description: "Research one bounded question",
323
330
  systemPrompt: "Return evidence, uncertainty, and a concise conclusion.",
324
- tools: ({ parent }) => projectTools(parent, [
325
- webSearchToolName,
326
- webReadToolName,
327
- "workspace_read_file",
328
- ]),
331
+ tools: ({ parent }) =>
332
+ parent.tools
333
+ .filter((tool) => READ_ONLY.has(tool.name))
334
+ .map((tool) => ({
335
+ name: tool.name,
336
+ description: tool.description,
337
+ jsonSchema: getToolJsonSchema(tool),
338
+ do: (input, _display, _agent, signal) => tool.run(input, undefined, signal),
339
+ })),
329
340
  })
330
341
  ```
331
342
 
332
- The child keeps its isolated store, compaction policy, model, prompt, skills,
333
- layers, and subscribers. Parent subscribers still receive the subagent lifecycle
334
- bracket, so delegation remains visible in the same run trace.
343
+ The child keeps its isolated store, compaction policy, model, prompt and skills.
344
+ Its `layers` and `subscribers` mount when the subagent is invoked and are
345
+ disposed when its request ends. Parent subscribers still receive the subagent
346
+ lifecycle bracket, so delegation remains visible in the same run trace.
335
347
 
336
348
  ## Programmatic tool workflows
337
349
 
@@ -1,11 +1,14 @@
1
1
  import {
2
+ EMPTY_NATIVE_REGISTRY,
3
+ FOUNDRY_LAYER_BRAND,
4
+ FOUNDRY_SUBSCRIBER_BRAND,
2
5
  bindFileIdentity,
3
6
  defineAgentFromModule,
4
7
  fileDefinitionKey,
5
8
  fileDefinitionLabel,
6
9
  fileIdentified,
7
10
  internalAgentName
8
- } from "./chunk-5NFLGHOC.js";
11
+ } from "./chunk-PVOKR4CN.js";
9
12
 
10
13
  // src/application.ts
11
14
  var FOUNDRY_APPLICATION_BRAND = /* @__PURE__ */ Symbol.for(
@@ -408,149 +411,6 @@ function isFoundryCapability(value) {
408
411
  return object[FOUNDRY_SHARED_TOOL_BRAND] === true || object[FOUNDRY_AGENT_APPLICATION_BRAND] === true || object[FOUNDRY_MCP_BRAND] === true || object[FOUNDRY_MEMORY_BRAND] === true;
409
412
  }
410
413
 
411
- // src/surfaces.ts
412
- import { Effect as Effect2 } from "effect";
413
- var FOUNDRY_LAYER_BRAND = /* @__PURE__ */ Symbol.for("glove-foundry-layer");
414
- var FOUNDRY_SUBSCRIBER_BRAND = /* @__PURE__ */ Symbol.for(
415
- "glove-foundry-subscriber"
416
- );
417
- var SURFACE_ID = /^[a-z][a-z0-9-]*(?:\/[a-z][a-z0-9-]*)*$/;
418
- function assertSurfaceId(id2, label) {
419
- if (!SURFACE_ID.test(id2)) {
420
- throw new Error(
421
- `Invalid Foundry ${label} id "${id2}". Use lowercase path segments containing letters, digits, and hyphens.`
422
- );
423
- }
424
- }
425
- function defineLayer(options) {
426
- if (options.id) assertSurfaceId(options.id, "layer");
427
- const { id: id2, ...definition } = options;
428
- return Object.freeze(fileIdentified({
429
- ...definition,
430
- [FOUNDRY_LAYER_BRAND]: true
431
- }, "layer", id2));
432
- }
433
- function configureLayer(layer, config) {
434
- return Object.freeze({ layer, config });
435
- }
436
- function defineSubscriber(options) {
437
- if (options.id) assertSurfaceId(options.id, "subscriber");
438
- const { id: id2, ...definition } = options;
439
- return Object.freeze(fileIdentified({
440
- ...definition,
441
- [FOUNDRY_SUBSCRIBER_BRAND]: true
442
- }, "subscriber", id2));
443
- }
444
- var EMPTY_NATIVE_REGISTRY = Object.freeze({
445
- layers: Object.freeze([]),
446
- subscribers: Object.freeze([])
447
- });
448
- function indexById(values, label) {
449
- const indexed = /* @__PURE__ */ new Map();
450
- for (const value of values) {
451
- if (indexed.has(value.id)) {
452
- throw new Error(`Duplicate Foundry ${label} id "${value.id}".`);
453
- }
454
- indexed.set(value.id, value);
455
- }
456
- return indexed;
457
- }
458
- async function mountFoundrySurfaces(options) {
459
- const layers = indexById(options.registry.layers, "layer");
460
- const subscribers = indexById(options.registry.subscribers, "subscriber");
461
- const cleanup = [];
462
- const disposeAll = async () => {
463
- const failures = [];
464
- for (const dispose of cleanup.reverse()) {
465
- try {
466
- const result = dispose();
467
- if (Effect2.isEffect(result)) await Effect2.runPromise(result);
468
- else await Promise.resolve(result);
469
- } catch (cause) {
470
- failures.push(cause);
471
- }
472
- }
473
- if (failures.length > 0) {
474
- throw new AggregateError(failures, "Foundry surface cleanup failed.");
475
- }
476
- };
477
- try {
478
- for (const selected of options.subscribers ?? []) {
479
- let definition = selected;
480
- if (typeof definition === "object" && definition !== null && FOUNDRY_SUBSCRIBER_BRAND in definition) {
481
- const registered = subscribers.get(definition.id);
482
- if (!registered) {
483
- throw new Error(
484
- `Agent "${options.context.agentId}" references unknown subscriber "${definition.id}".`
485
- );
486
- }
487
- definition = registered;
488
- }
489
- let subscriber;
490
- let subscriberId = "inline";
491
- if (typeof definition === "object" && definition !== null && definition[FOUNDRY_SUBSCRIBER_BRAND] === true) {
492
- const foundrySubscriber = definition;
493
- const created = typeof foundrySubscriber.create === "function" ? foundrySubscriber.create(options.context) : foundrySubscriber.create;
494
- subscriber = Effect2.isEffect(created) ? await Effect2.runPromise(created) : await Promise.resolve(created);
495
- subscriberId = foundrySubscriber.id;
496
- } else {
497
- subscriber = definition;
498
- }
499
- options.context.glove.addSubscriber(subscriber);
500
- cleanup.push(() => options.context.glove.removeSubscriber(subscriber));
501
- options.context.emit({
502
- type: "foundry.subscriber.mounted",
503
- data: { id: subscriberId }
504
- });
505
- }
506
- for (const selected of options.layers ?? []) {
507
- const reference = FOUNDRY_LAYER_BRAND in selected ? { layer: selected } : selected;
508
- const definition = layers.get(reference.layer.id);
509
- if (!definition) {
510
- throw new Error(
511
- `Agent "${options.context.agentId}" references unknown layer "${reference.layer.id}".`
512
- );
513
- }
514
- const referenceConfig = "config" in reference ? reference.config : void 0;
515
- const parsed = definition.config ? definition.config.safeParse(referenceConfig ?? {}) : { success: true, data: referenceConfig };
516
- if (!parsed.success) {
517
- throw new Error(
518
- `Invalid config for layer "${definition.id}": ${parsed.error.message}`
519
- );
520
- }
521
- const dispose = await Effect2.runPromise(
522
- definition.setup({ ...options.context, config: parsed.data })
523
- );
524
- if (dispose) cleanup.push(dispose);
525
- options.context.emit({
526
- type: "foundry.layer.mounted",
527
- data: { id: definition.id }
528
- });
529
- }
530
- } catch (cause) {
531
- try {
532
- await disposeAll();
533
- } catch (cleanupCause) {
534
- throw new AggregateError(
535
- [cause, cleanupCause],
536
- "Foundry surface mount and cleanup failed."
537
- );
538
- }
539
- throw cause;
540
- }
541
- return disposeAll;
542
- }
543
- function isFoundryLayer(value) {
544
- return Boolean(
545
- value && typeof value === "object" && value[FOUNDRY_LAYER_BRAND] === true
546
- );
547
- }
548
- function isFoundrySubscriber(value) {
549
- return Boolean(
550
- value && typeof value === "object" && value[FOUNDRY_SUBSCRIBER_BRAND] === true
551
- );
552
- }
553
-
554
414
  // src/composition.ts
555
415
  var composedToolBodies = /* @__PURE__ */ new WeakMap();
556
416
  function isToolBody(value) {
@@ -1274,7 +1134,7 @@ function createManifest(agents) {
1274
1134
 
1275
1135
  // src/primitives.ts
1276
1136
  import { randomUUID } from "node:crypto";
1277
- import { Effect as Effect4 } from "effect";
1137
+ import { Effect as Effect3 } from "effect";
1278
1138
  function toGloveMessage(input) {
1279
1139
  if (typeof input === "string") {
1280
1140
  return freezeGloveMessage({ sender: "user", text: input });
@@ -1346,13 +1206,13 @@ var MemoryFoundryDataAdapter = class {
1346
1206
  this.pendingSubscriptions = [];
1347
1207
  }
1348
1208
  getAgent(id2) {
1349
- return Effect4.sync(() => {
1209
+ return Effect3.sync(() => {
1350
1210
  this.materializeSeeds();
1351
1211
  return this.agents.get(id2) ?? null;
1352
1212
  });
1353
1213
  }
1354
1214
  putAgent(agent) {
1355
- return Effect4.sync(() => {
1215
+ return Effect3.sync(() => {
1356
1216
  this.materializeSeeds();
1357
1217
  const reconstructed = reconstructAgentInstance(agent);
1358
1218
  const prior = this.agents.get(agent.id);
@@ -1366,13 +1226,13 @@ var MemoryFoundryDataAdapter = class {
1366
1226
  });
1367
1227
  }
1368
1228
  listAgents(definitionId) {
1369
- return Effect4.sync(() => {
1229
+ return Effect3.sync(() => {
1370
1230
  this.materializeSeeds();
1371
1231
  return [...this.agents.values()].filter((item) => !definitionId || item.definitionId === definitionId);
1372
1232
  });
1373
1233
  }
1374
1234
  provisionAgent(input) {
1375
- return Effect4.sync(() => {
1235
+ return Effect3.sync(() => {
1376
1236
  this.materializeSeeds();
1377
1237
  const existingId = this.agentsByProvisioningKey.get(input.provisioningKey);
1378
1238
  if (existingId) return this.agents.get(existingId);
@@ -1386,34 +1246,34 @@ var MemoryFoundryDataAdapter = class {
1386
1246
  });
1387
1247
  }
1388
1248
  getPlaybookSubscription(id2) {
1389
- return Effect4.sync(() => {
1249
+ return Effect3.sync(() => {
1390
1250
  this.materializeSeeds();
1391
1251
  return this.subscriptions.get(id2) ?? null;
1392
1252
  });
1393
1253
  }
1394
1254
  putPlaybookSubscription(subscription) {
1395
- return Effect4.sync(() => {
1255
+ return Effect3.sync(() => {
1396
1256
  this.materializeSeeds();
1397
1257
  this.subscriptions.set(subscription.id, reconstructPlaybookSubscription(subscription));
1398
1258
  });
1399
1259
  }
1400
1260
  deletePlaybookSubscription(id2) {
1401
- return Effect4.sync(() => {
1261
+ return Effect3.sync(() => {
1402
1262
  this.materializeSeeds();
1403
1263
  return this.subscriptions.delete(id2);
1404
1264
  });
1405
1265
  }
1406
1266
  listPlaybookSubscriptions(workspaceId) {
1407
- return Effect4.sync(() => {
1267
+ return Effect3.sync(() => {
1408
1268
  this.materializeSeeds();
1409
1269
  return [...this.subscriptions.values()].filter((item) => !workspaceId || item.workspaceId === workspaceId);
1410
1270
  });
1411
1271
  }
1412
1272
  getInboundDelivery(key) {
1413
- return Effect4.succeed(this.inboundDeliveries.get(key) ?? null);
1273
+ return Effect3.succeed(this.inboundDeliveries.get(key) ?? null);
1414
1274
  }
1415
1275
  claimInboundDelivery(key) {
1416
- return Effect4.sync(() => {
1276
+ return Effect3.sync(() => {
1417
1277
  if (this.inboundDeliveries.has(key)) return false;
1418
1278
  this.inboundDeliveries.set(key, Object.freeze({
1419
1279
  key,
@@ -1425,7 +1285,7 @@ var MemoryFoundryDataAdapter = class {
1425
1285
  });
1426
1286
  }
1427
1287
  completeInboundDelivery(key, runIds) {
1428
- return Effect4.sync(() => {
1288
+ return Effect3.sync(() => {
1429
1289
  const prior = this.inboundDeliveries.get(key);
1430
1290
  if (!prior) throw new Error(`Inbound delivery claim "${key}" does not exist.`);
1431
1291
  this.inboundDeliveries.set(key, Object.freeze({
@@ -1437,46 +1297,46 @@ var MemoryFoundryDataAdapter = class {
1437
1297
  });
1438
1298
  }
1439
1299
  releaseInboundDelivery(key) {
1440
- return Effect4.sync(() => {
1300
+ return Effect3.sync(() => {
1441
1301
  if (this.inboundDeliveries.get(key)?.status === "pending") {
1442
1302
  this.inboundDeliveries.delete(key);
1443
1303
  }
1444
1304
  });
1445
1305
  }
1446
1306
  getActivation(id2) {
1447
- return Effect4.succeed(this.activations.get(id2) ?? null);
1307
+ return Effect3.succeed(this.activations.get(id2) ?? null);
1448
1308
  }
1449
1309
  putActivation(activation) {
1450
- return Effect4.sync(() => {
1310
+ return Effect3.sync(() => {
1451
1311
  this.activations.set(activation.id, reconstructActivation(activation));
1452
1312
  });
1453
1313
  }
1454
1314
  listActivations(workspaceId) {
1455
- return Effect4.succeed(
1315
+ return Effect3.succeed(
1456
1316
  [...this.activations.values()].filter((item) => !workspaceId || item.workspaceId === workspaceId)
1457
1317
  );
1458
1318
  }
1459
1319
  getConversation(id2) {
1460
- return Effect4.succeed(this.conversations.get(id2) ?? null);
1320
+ return Effect3.succeed(this.conversations.get(id2) ?? null);
1461
1321
  }
1462
1322
  putConversation(conversation) {
1463
- return Effect4.sync(() => {
1323
+ return Effect3.sync(() => {
1464
1324
  this.conversations.set(conversation.id, Object.freeze({ ...conversation }));
1465
1325
  });
1466
1326
  }
1467
1327
  listConversations(agentId) {
1468
- return Effect4.succeed([...this.conversations.values()].filter((item) => item.agentId === agentId));
1328
+ return Effect3.succeed([...this.conversations.values()].filter((item) => item.agentId === agentId));
1469
1329
  }
1470
1330
  getWorkspaceEntry(workspaceId, key) {
1471
- return Effect4.succeed(this.workspace.get(`${workspaceId}:${key}`) ?? null);
1331
+ return Effect3.succeed(this.workspace.get(`${workspaceId}:${key}`) ?? null);
1472
1332
  }
1473
1333
  putWorkspaceEntry(entry) {
1474
- return Effect4.sync(() => {
1334
+ return Effect3.sync(() => {
1475
1335
  this.workspace.set(`${entry.workspaceId}:${entry.key}`, Object.freeze({ ...entry }));
1476
1336
  });
1477
1337
  }
1478
1338
  compareAndSetWorkspaceEntry(entry, expectedUpdatedAt) {
1479
- return Effect4.sync(() => {
1339
+ return Effect3.sync(() => {
1480
1340
  const key = `${entry.workspaceId}:${entry.key}`;
1481
1341
  const current = this.workspace.get(key);
1482
1342
  if ((current?.updatedAt ?? null) !== expectedUpdatedAt) return false;
@@ -1488,16 +1348,16 @@ var MemoryFoundryDataAdapter = class {
1488
1348
  });
1489
1349
  }
1490
1350
  listWorkspaceEntries(workspaceId) {
1491
- return Effect4.succeed([...this.workspace.values()].filter((item) => item.workspaceId === workspaceId));
1351
+ return Effect3.succeed([...this.workspace.values()].filter((item) => item.workspaceId === workspaceId));
1492
1352
  }
1493
1353
  getWorkingEnvironmentSnapshot(owner) {
1494
- return Effect4.sync(() => {
1354
+ return Effect3.sync(() => {
1495
1355
  const snapshot = this.workingEnvironments.get(workingEnvironmentOwnerKey(owner));
1496
1356
  return snapshot ? structuredClone(snapshot) : null;
1497
1357
  });
1498
1358
  }
1499
1359
  putWorkingEnvironmentSnapshot(owner, snapshot) {
1500
- return Effect4.sync(() => {
1360
+ return Effect3.sync(() => {
1501
1361
  this.workingEnvironments.set(
1502
1362
  workingEnvironmentOwnerKey(owner),
1503
1363
  structuredClone(snapshot)
@@ -1505,23 +1365,23 @@ var MemoryFoundryDataAdapter = class {
1505
1365
  });
1506
1366
  }
1507
1367
  putInboxItem(item) {
1508
- return Effect4.sync(() => {
1368
+ return Effect3.sync(() => {
1509
1369
  this.inbox.set(item.id, Object.freeze({ ...item }));
1510
1370
  });
1511
1371
  }
1512
1372
  listInboxItems(workspaceId) {
1513
- return Effect4.succeed([...this.inbox.values()].filter((item) => item.workspaceId === workspaceId));
1373
+ return Effect3.succeed([...this.inbox.values()].filter((item) => item.workspaceId === workspaceId));
1514
1374
  }
1515
1375
  putTask(task) {
1516
- return Effect4.sync(() => {
1376
+ return Effect3.sync(() => {
1517
1377
  this.tasks.set(task.id, Object.freeze({ ...task }));
1518
1378
  });
1519
1379
  }
1520
1380
  listTasks(workspaceId) {
1521
- return Effect4.succeed([...this.tasks.values()].filter((item) => item.workspaceId === workspaceId));
1381
+ return Effect3.succeed([...this.tasks.values()].filter((item) => item.workspaceId === workspaceId));
1522
1382
  }
1523
1383
  listEnvironment(scope) {
1524
- return Effect4.succeed(this.environment.filter(
1384
+ return Effect3.succeed(this.environment.filter(
1525
1385
  (item) => item.workspaceId === scope.workspaceId && (item.scope === "workspace" || item.scope === "agent" && item.agentId === scope.agentId || item.scope === "conversation" && item.conversationId === scope.conversationId)
1526
1386
  ));
1527
1387
  }
@@ -1676,7 +1536,7 @@ function agentScheduleRevision(schedule) {
1676
1536
 
1677
1537
  // src/core-tools.ts
1678
1538
  import { randomUUID as randomUUID2 } from "node:crypto";
1679
- import { Effect as Effect5, JSONSchema as JSONSchema2, Schema as Schema2 } from "effect";
1539
+ import { Effect as Effect4, JSONSchema as JSONSchema2, Schema as Schema2 } from "effect";
1680
1540
  import { z } from "zod";
1681
1541
 
1682
1542
  // src/core-command-result.ts
@@ -2036,7 +1896,7 @@ function createFoundryCoreTools(context, desiredSchedules = []) {
2036
1896
  };
2037
1897
  const scheduleView = async () => {
2038
1898
  const records = new Map(
2039
- [...context.activations, ...await Effect5.runPromise(context.data.listActivations(context.workspaceId))].filter((item) => item.kind === "scheduled" && item.agentId === context.agentId).map((item) => [item.id, item])
1899
+ [...context.activations, ...await Effect4.runPromise(context.data.listActivations(context.workspaceId))].filter((item) => item.kind === "scheduled" && item.agentId === context.agentId).map((item) => [item.id, item])
2040
1900
  );
2041
1901
  const now = (/* @__PURE__ */ new Date()).toISOString();
2042
1902
  for (const desired of desiredSchedules) {
@@ -2354,7 +2214,7 @@ function createFoundryCoreTools(context, desiredSchedules = []) {
2354
2214
  description: "List the conversations owned by this runtime agent instance.",
2355
2215
  inputSchema: z.object({}),
2356
2216
  async do() {
2357
- return { status: "success", data: await Effect5.runPromise(context.data.listConversations(context.agentId)) };
2217
+ return { status: "success", data: await Effect4.runPromise(context.data.listConversations(context.agentId)) };
2358
2218
  }
2359
2219
  },
2360
2220
  {
@@ -2367,12 +2227,12 @@ function createFoundryCoreTools(context, desiredSchedules = []) {
2367
2227
  ]),
2368
2228
  async do(input) {
2369
2229
  if (input.action === "get") {
2370
- return { status: "success", data: await Effect5.runPromise(context.data.getWorkspaceEntry(context.workspaceId, input.key)) };
2230
+ return { status: "success", data: await Effect4.runPromise(context.data.getWorkspaceEntry(context.workspaceId, input.key)) };
2371
2231
  }
2372
2232
  if (input.action === "list") {
2373
- return { status: "success", data: await Effect5.runPromise(context.data.listWorkspaceEntries(context.workspaceId)) };
2233
+ return { status: "success", data: await Effect4.runPromise(context.data.listWorkspaceEntries(context.workspaceId)) };
2374
2234
  }
2375
- await Effect5.runPromise(context.data.putWorkspaceEntry({
2235
+ await Effect4.runPromise(context.data.putWorkspaceEntry({
2376
2236
  workspaceId: context.workspaceId,
2377
2237
  key: input.key,
2378
2238
  value: input.value,
@@ -2401,13 +2261,13 @@ function createFoundryCoreTools(context, desiredSchedules = []) {
2401
2261
  ]),
2402
2262
  async do(input) {
2403
2263
  if (input.action === "list") {
2404
- return { status: "success", data: await Effect5.runPromise(context.data.listInboxItems(context.workspaceId)) };
2264
+ return { status: "success", data: await Effect4.runPromise(context.data.listInboxItems(context.workspaceId)) };
2405
2265
  }
2406
2266
  if (input.action === "update") {
2407
- const current = (await Effect5.runPromise(context.data.listInboxItems(context.workspaceId))).find((item3) => item3.id === input.itemId);
2267
+ const current = (await Effect4.runPromise(context.data.listInboxItems(context.workspaceId))).find((item3) => item3.id === input.itemId);
2408
2268
  if (!current) return { status: "error", data: null, error: `Shared inbox item "${input.itemId}" was not found.` };
2409
2269
  const item2 = { ...current, status: input.status, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
2410
- await Effect5.runPromise(context.data.putInboxItem(item2));
2270
+ await Effect4.runPromise(context.data.putInboxItem(item2));
2411
2271
  return { status: "success", data: item2 };
2412
2272
  }
2413
2273
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -2422,7 +2282,7 @@ function createFoundryCoreTools(context, desiredSchedules = []) {
2422
2282
  createdAt: now,
2423
2283
  updatedAt: now
2424
2284
  };
2425
- await Effect5.runPromise(context.data.putInboxItem(item));
2285
+ await Effect4.runPromise(context.data.putInboxItem(item));
2426
2286
  return { status: "success", data: item };
2427
2287
  }
2428
2288
  },
@@ -2440,13 +2300,13 @@ function createFoundryCoreTools(context, desiredSchedules = []) {
2440
2300
  ]),
2441
2301
  async do(input) {
2442
2302
  if (input.action === "list") {
2443
- return { status: "success", data: await Effect5.runPromise(context.data.listTasks(context.workspaceId)) };
2303
+ return { status: "success", data: await Effect4.runPromise(context.data.listTasks(context.workspaceId)) };
2444
2304
  }
2445
2305
  if (input.action === "update") {
2446
- const current = (await Effect5.runPromise(context.data.listTasks(context.workspaceId))).find((task3) => task3.id === input.taskId);
2306
+ const current = (await Effect4.runPromise(context.data.listTasks(context.workspaceId))).find((task3) => task3.id === input.taskId);
2447
2307
  if (!current) return { status: "error", data: null, error: `Task "${input.taskId}" was not found.` };
2448
2308
  const task2 = { ...current, status: input.status, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
2449
- await Effect5.runPromise(context.data.putTask(task2));
2309
+ await Effect4.runPromise(context.data.putTask(task2));
2450
2310
  return { status: "success", data: task2 };
2451
2311
  }
2452
2312
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -2461,7 +2321,7 @@ function createFoundryCoreTools(context, desiredSchedules = []) {
2461
2321
  createdAt: now,
2462
2322
  updatedAt: now
2463
2323
  };
2464
- await Effect5.runPromise(context.data.putTask(task));
2324
+ await Effect4.runPromise(context.data.putTask(task));
2465
2325
  return { status: "success", data: task };
2466
2326
  }
2467
2327
  },
@@ -2472,7 +2332,7 @@ function createFoundryCoreTools(context, desiredSchedules = []) {
2472
2332
  async do() {
2473
2333
  return {
2474
2334
  status: "success",
2475
- data: await Effect5.runPromise(context.data.listEnvironment({
2335
+ data: await Effect4.runPromise(context.data.listEnvironment({
2476
2336
  workspaceId: context.workspaceId,
2477
2337
  agentId: context.agentId,
2478
2338
  conversationId: context.conversationId
@@ -2716,15 +2576,6 @@ export {
2716
2576
  mountAgentDefinitionMemory,
2717
2577
  installRegistry,
2718
2578
  isFoundryCapability,
2719
- FOUNDRY_LAYER_BRAND,
2720
- FOUNDRY_SUBSCRIBER_BRAND,
2721
- defineLayer,
2722
- configureLayer,
2723
- defineSubscriber,
2724
- EMPTY_NATIVE_REGISTRY,
2725
- mountFoundrySurfaces,
2726
- isFoundryLayer,
2727
- isFoundrySubscriber,
2728
2579
  composeAgent,
2729
2580
  EMPTY_AGENT_COMPOSITION,
2730
2581
  FOUNDRY_CONNECTION_BRAND,
@@ -81,8 +81,11 @@ var FoundryClient = class {
81
81
  return fetcher(input, { ...init, headers });
82
82
  } : fetcher;
83
83
  }
84
+ /** Resolves with `ok: false` when a subsystem is down (the server answers 503). */
84
85
  async health() {
85
- return readResponse(await this.fetcher(`${this.baseUrl}/health`));
86
+ const response = await this.fetcher(`${this.baseUrl}/health`);
87
+ if (response.status === 503) return await response.json();
88
+ return readResponse(response);
86
89
  }
87
90
  agent(route) {
88
91
  return {