@nylorun/runtime 0.27.0-beta → 0.29.0-beta

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 (160) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/README.md +1 -1
  3. package/dist/api/a2a/card.d.ts +4 -3
  4. package/dist/api/a2a/card.js +3 -3
  5. package/dist/api/a2a/routes.js +18 -7
  6. package/dist/api/ag-ui/routes.js +4 -7
  7. package/dist/api/components.d.ts +5854 -2718
  8. package/dist/api/components.js +39 -30
  9. package/dist/api/http/app.js +9 -4
  10. package/dist/api/http/body.d.ts +2 -0
  11. package/dist/api/http/body.js +20 -0
  12. package/dist/api/http/define.d.ts +4 -0
  13. package/dist/api/http/define.js +20 -9
  14. package/dist/api/http/routes/agent-manifests.d.ts +10 -0
  15. package/dist/api/http/routes/agent-manifests.js +135 -0
  16. package/dist/api/http/routes/agents.d.ts +11 -0
  17. package/dist/api/http/routes/agents.js +418 -0
  18. package/dist/api/http/routes/artifacts.js +2 -2
  19. package/dist/api/http/routes/coverage.d.ts +4 -4
  20. package/dist/api/http/routes/coverage.js +12 -6
  21. package/dist/api/http/routes/files.js +1 -1
  22. package/dist/api/http/routes/mcp.js +2 -2
  23. package/dist/api/http/routes/me.d.ts +1 -1
  24. package/dist/api/http/routes/me.js +1 -2
  25. package/dist/api/http/routes/memories.d.ts +9 -0
  26. package/dist/api/http/routes/memories.js +152 -0
  27. package/dist/api/http/routes/reads.d.ts +1 -137
  28. package/dist/api/http/routes/reads.js +31 -12
  29. package/dist/api/http/routes/sessions.js +21 -50
  30. package/dist/api/http/routes/tenant.js +13 -10
  31. package/dist/api/http/routes/triggers.d.ts +10 -0
  32. package/dist/api/http/routes/triggers.js +183 -0
  33. package/dist/api/openapi.js +69 -47
  34. package/dist/artifacts/disk.d.ts +10 -10
  35. package/dist/artifacts/disk.js +27 -27
  36. package/dist/artifacts/quota.d.ts +1 -1
  37. package/dist/artifacts/quota.js +2 -2
  38. package/dist/artifacts/service.js +2 -2
  39. package/dist/core/flow-host.d.ts +0 -1
  40. package/dist/gates/egress-credentials.js +1 -1
  41. package/dist/gates/egress.d.ts +5 -5
  42. package/dist/gates/egress.js +6 -6
  43. package/dist/gates/http-tool.js +2 -2
  44. package/dist/gates/meter.js +22 -5
  45. package/dist/gates/policy.d.ts +8 -3
  46. package/dist/gates/policy.js +7 -2
  47. package/dist/gates/tenant-vaults.d.ts +1 -1
  48. package/dist/harness/pod.d.ts +2 -0
  49. package/dist/harness/setup.js +17 -6
  50. package/dist/harness-api/record.js +11 -0
  51. package/dist/harness-api/server.js +4 -0
  52. package/dist/harness-api/start.d.ts +11 -7
  53. package/dist/harness-api/start.js +49 -5
  54. package/dist/harness-api/workspace.js +2 -2
  55. package/dist/host/config-for.d.ts +2 -0
  56. package/dist/host/config-for.js +1 -0
  57. package/dist/host/http.d.ts +2 -2
  58. package/dist/host/http.js +5 -2
  59. package/dist/host/main.js +1 -0
  60. package/dist/keys/keys.d.ts +15 -4
  61. package/dist/keys/keys.js +16 -0
  62. package/dist/keys/webhooks.d.ts +25 -0
  63. package/dist/keys/webhooks.js +62 -0
  64. package/dist/management-openapi.json +313 -133
  65. package/dist/mcp/connect.d.ts +2 -2
  66. package/dist/mcp/connect.js +3 -3
  67. package/dist/mcp/preview.js +7 -7
  68. package/dist/memory/service.d.ts +97 -0
  69. package/dist/memory/service.js +335 -0
  70. package/dist/memory/tool.d.ts +36 -0
  71. package/dist/memory/tool.js +84 -0
  72. package/dist/model/pi-model.js +7 -0
  73. package/dist/openapi.json +13120 -9034
  74. package/dist/reads/types.d.ts +3 -3
  75. package/dist/record/agent.d.ts +27 -0
  76. package/dist/record/agent.js +46 -0
  77. package/dist/record/index.d.ts +1 -1
  78. package/dist/record/index.js +1 -1
  79. package/dist/sandbox/join.js +5 -5
  80. package/dist/sandbox/placement.d.ts +1 -1
  81. package/dist/sandbox/placement.js +3 -3
  82. package/dist/sandbox/pods/lifecycle.d.ts +6 -6
  83. package/dist/sandbox/pods/lifecycle.js +6 -6
  84. package/dist/sandbox/pods/reconcile.js +10 -2
  85. package/dist/sandbox/resolve.d.ts +3 -3
  86. package/dist/sandbox/resolve.js +7 -7
  87. package/dist/sandbox/setup.d.ts +3 -1
  88. package/dist/sandbox/setup.js +14 -4
  89. package/dist/store/postgres/drizzle/0032_agents.sql +54 -0
  90. package/dist/store/postgres/drizzle/0033_agent_versions.sql +7 -0
  91. package/dist/store/postgres/drizzle/0034_protocol_17_session_queue.sql +13 -0
  92. package/dist/store/postgres/drizzle/0035_t4_triggers.sql +41 -0
  93. package/dist/store/postgres/drizzle/0036_t5_memories.sql +30 -0
  94. package/dist/store/postgres/drizzle/0037_model_usage_cost_split.sql +4 -0
  95. package/dist/store/postgres/drizzle/meta/_journal.json +42 -0
  96. package/dist/store/postgres/reads.js +44 -87
  97. package/dist/store/postgres/record-writer.d.ts +4 -4
  98. package/dist/store/postgres/record-writer.js +9 -9
  99. package/dist/store/postgres/schema.d.ts +1408 -123
  100. package/dist/store/postgres/schema.js +194 -38
  101. package/dist/store/postgres/store.js +329 -79
  102. package/dist/store/postgres/tenant.js +1 -2
  103. package/dist/store/types.d.ts +155 -50
  104. package/dist/store/types.js +0 -1
  105. package/dist/tenant/advance.js +20 -8
  106. package/dist/tenant/agent-manifests.d.ts +72 -0
  107. package/dist/tenant/agent-manifests.js +359 -0
  108. package/dist/tenant/agent-versions.d.ts +126 -0
  109. package/dist/tenant/agent-versions.js +389 -0
  110. package/dist/tenant/agents.d.ts +230 -0
  111. package/dist/tenant/{environments.js → agents.js} +464 -320
  112. package/dist/tenant/auth.d.ts +1 -1
  113. package/dist/tenant/auth.js +3 -3
  114. package/dist/tenant/commands.d.ts +63 -2
  115. package/dist/tenant/commands.js +240 -83
  116. package/dist/tenant/context.d.ts +46 -19
  117. package/dist/tenant/context.js +6 -2
  118. package/dist/tenant/effects.js +7 -16
  119. package/dist/tenant/identity-file.d.ts +6 -6
  120. package/dist/tenant/identity-file.js +12 -10
  121. package/dist/tenant/issuers.js +3 -3
  122. package/dist/tenant/limits.d.ts +0 -3
  123. package/dist/tenant/limits.js +0 -3
  124. package/dist/tenant/memories.d.ts +38 -0
  125. package/dist/tenant/memories.js +119 -0
  126. package/dist/tenant/reset.js +2 -2
  127. package/dist/tenant/run-grants.d.ts +6 -0
  128. package/dist/tenant/run-grants.js +4 -0
  129. package/dist/tenant/runtime.d.ts +1 -1
  130. package/dist/tenant/runtime.js +8 -0
  131. package/dist/tenant/sessions.d.ts +28 -45
  132. package/dist/tenant/sessions.js +85 -208
  133. package/dist/tenant/status.js +6 -7
  134. package/dist/tenant/sweep.js +12 -3
  135. package/dist/tenant/transcript.d.ts +16 -16
  136. package/dist/tenant/triggers.d.ts +143 -0
  137. package/dist/tenant/triggers.js +715 -0
  138. package/dist/tenant/turn-timing.d.ts +11 -1
  139. package/dist/tenant/turn-timing.js +3 -1
  140. package/dist/tenant/types.d.ts +5 -0
  141. package/dist/tenant/worker.d.ts +2 -0
  142. package/dist/tenant/worker.js +5 -0
  143. package/dist/traces/map.d.ts +1 -1
  144. package/dist/traces/map.js +7 -1
  145. package/dist/tuning.d.ts +7 -0
  146. package/dist/tuning.js +19 -0
  147. package/dist/vault/service.d.ts +13 -8
  148. package/dist/vault/service.js +61 -17
  149. package/dist/version.d.ts +1 -1
  150. package/dist/version.js +1 -1
  151. package/package.json +13 -12
  152. package/dist/api/http/routes/environment-manifests.d.ts +0 -9
  153. package/dist/api/http/routes/environment-manifests.js +0 -118
  154. package/dist/api/http/routes/environments.d.ts +0 -11
  155. package/dist/api/http/routes/environments.js +0 -332
  156. package/dist/record/environment.d.ts +0 -27
  157. package/dist/record/environment.js +0 -46
  158. package/dist/tenant/environment-manifests.d.ts +0 -57
  159. package/dist/tenant/environment-manifests.js +0 -208
  160. package/dist/tenant/environments.d.ts +0 -172
@@ -51,7 +51,7 @@
51
51
  import { AsyncLocalStorage } from "node:async_hooks";
52
52
  import { randomUUID } from "node:crypto";
53
53
  import { and, count, desc, eq, getTableColumns, gte, gt, inArray, isNotNull, isNull, lt, lte, ne, or, sql, } from "drizzle-orm";
54
- import { appendEnvironmentEvent, appendEvent } from "../../record/index.js";
54
+ import { appendAgentEvent, appendEvent } from "../../record/index.js";
55
55
  import { readRuntimeLimits } from "../../tenant/runtime-limits.js";
56
56
  import { OwnershipLostError, PrincipalRoleConflict } from "../ownership.js";
57
57
  import { followControlSignals, pruneSignals, writeSignal } from "./control.js";
@@ -59,8 +59,8 @@ import { database, driverError } from "./db.js";
59
59
  import { expectedSchemaVersion, readSchemaVersion } from "./migrate.js";
60
60
  import { hostTuning } from "../../tuning.js";
61
61
  import { createPostgresRecordReader } from "./record.js";
62
- import { postgresEnvironmentRecordWriter, postgresRecordWriter } from "./record-writer.js";
63
- import { artifacts, artifactVersions, artifactContent, definitionFiles, definitionFileUses, commands, definitions, effects, links, modelBudgets, modelUsage, principals, sandboxes, environmentEvents, environments, environmentManifests, sessionEvents, sessionLogHeads, sessions, toJson, toolCrossings, signingKeys, tenant, tenantSettings, vaultAudit, vaultCredentials, vaultIdempotency, vaults, sandboxSignals, wakes, } from "./schema.js";
62
+ import { postgresAgentRecordWriter, postgresRecordWriter } from "./record-writer.js";
63
+ import { artifacts, artifactVersions, artifactContent, definitionFiles, definitionFileUses, commands, effects, links, modelBudgets, modelUsage, principals, sandboxes, agentEvents, agents, agentManifests, sessionEvents, sessionLogHeads, sessions, sessionQueue, agentTriggers, triggerRuns, memories, memoryVersions, toJson, toolCrossings, signingKeys, tenant, tenantSettings, vaultAudit, vaultCredentials, vaultIdempotency, vaults, sandboxSignals, wakes, } from "./schema.js";
64
64
  export function createPostgresSessionStore(options) {
65
65
  return new PostgresSessionStore(options);
66
66
  }
@@ -68,7 +68,6 @@ const OPEN_SESSION = ["running", "runnable"];
68
68
  /** Rows per statement when a folder version or a definition names many files (Host tuning). */
69
69
  const contentBatch = () => hostTuning().postgres.contentBatchRows;
70
70
  const DOCUMENTS = {
71
- definitions,
72
71
  sessions: sessions,
73
72
  commands,
74
73
  effects: effects,
@@ -257,10 +256,15 @@ function environmentOf(row) {
257
256
  updatedAt: row.updatedAt,
258
257
  ...(row.diskOp ? { diskOp: row.diskOp } : {}),
259
258
  ...(row.diskSeed ? { diskSeed: row.diskSeed } : {}),
260
- ...(row.manifestName !== null ? { manifestName: row.manifestName } : {}),
261
- ...(row.manifestVersion !== null ? { manifestVersion: row.manifestVersion } : {}),
262
- ...(row.manifestHash !== null ? { manifestHash: row.manifestHash } : {}),
259
+ manifestName: row.manifestName,
260
+ manifestVersion: row.manifestVersion,
261
+ manifestRef: row.manifestRef,
262
+ manifestHash: row.manifestHash,
263
+ desiredState: row.desiredState,
263
264
  ...(row.forkedFrom ? { forkedFrom: row.forkedFrom } : {}),
265
+ ...(row.targetVersion !== null ? { targetVersion: row.targetVersion } : {}),
266
+ ...(row.failedVersion !== null ? { failedVersion: row.failedVersion } : {}),
267
+ ...(row.startCheck ? { startCheck: row.startCheck } : {}),
264
268
  ...(row.k8sName !== null && row.desired !== null && row.observed !== null
265
269
  ? {
266
270
  pod: {
@@ -283,7 +287,7 @@ function environmentOf(row) {
283
287
  : {}),
284
288
  };
285
289
  }
286
- function environmentManifestOf(row) {
290
+ function agentManifestOf(row) {
287
291
  return {
288
292
  name: row.name,
289
293
  version: row.version,
@@ -322,7 +326,7 @@ const SIGNING_KEY_STAMP = {
322
326
  };
323
327
  /** The audit columns a row has (`ord` only orders them). */
324
328
  const { ord: _ord, ...AUDIT } = getTableColumns(vaultAudit);
325
- const SESSION_TABLES = [sessions, commands, effects, links, wakes];
329
+ const SESSION_TABLES = [sessions, commands, effects, links, wakes, sessionQueue];
326
330
  /**
327
331
  * The outbox's tables, by the kind of request each holds. Their delivery columns (`id`,
328
332
  * `created_at`, `attempts`, `retry_at`, `parked_at`) are the same.
@@ -629,44 +633,40 @@ class PostgresTx {
629
633
  const rows = await this.db.select({ body: table.body }).from(table).orderBy(table.id);
630
634
  return rows.map((row) => row.body);
631
635
  }
632
- async listDefinitions() {
633
- this.check();
634
- return this.bodies(definitions);
635
- }
636
636
  async listSandboxes() {
637
637
  this.check();
638
638
  return this.bodies(sandboxes);
639
639
  }
640
- // --- Environments ----------------------------------------------------------
640
+ // --- Agents ----------------------------------------------------------------
641
641
  async environment(id, options = {}) {
642
642
  this.check();
643
- const query = this.db.select().from(environments).where(eq(environments.id, id));
643
+ const query = this.db.select().from(agents).where(eq(agents.id, id));
644
644
  const [row] = options.lock ? await query.for("update") : await query;
645
645
  return row && environmentOf(row);
646
646
  }
647
647
  async createEnvironment(row, limit) {
648
648
  this.check();
649
649
  // Every create takes this lock, so two never both see room for one more.
650
- await this.db.execute(sql `SELECT pg_advisory_xact_lock(hashtext('nylorun.environments'))`);
650
+ await this.db.execute(sql `SELECT pg_advisory_xact_lock(hashtext('nylorun.agents'))`);
651
651
  const [found] = await this.db
652
- .select({ id: environments.id })
653
- .from(environments)
654
- .where(eq(environments.id, row.id));
652
+ .select({ id: agents.id })
653
+ .from(agents)
654
+ .where(eq(agents.id, row.id));
655
655
  if (found)
656
656
  return "exists";
657
- const [counted] = await this.db.select({ n: count() }).from(environments);
657
+ const [counted] = await this.db.select({ n: count() }).from(agents);
658
658
  if ((counted?.n ?? 0) >= limit)
659
659
  return "limit";
660
- const { pod, ownerUserId, diskOp, diskSeed, manifestName, manifestVersion, manifestHash, forkedFrom, ...environment } = row;
661
- await this.db.insert(environments).values({
660
+ const { pod, ownerUserId, diskOp, diskSeed, forkedFrom, targetVersion, failedVersion, startCheck, ...environment } = row;
661
+ await this.db.insert(agents).values({
662
662
  ...environment,
663
663
  ownerUserId: ownerUserId ?? null,
664
664
  diskOp: diskOp ?? null,
665
665
  diskSeed: diskSeed ?? null,
666
- manifestName: manifestName ?? null,
667
- manifestVersion: manifestVersion ?? null,
668
- manifestHash: manifestHash ?? null,
669
666
  forkedFrom: forkedFrom ?? null,
667
+ targetVersion: targetVersion ?? null,
668
+ failedVersion: failedVersion ?? null,
669
+ startCheck: startCheck ?? null,
670
670
  ...(pod ? podColumns(pod) : {}),
671
671
  });
672
672
  return "created";
@@ -675,88 +675,88 @@ class PostgresTx {
675
675
  this.check();
676
676
  const columns = Object.fromEntries(Object.entries(patch).filter(([, value]) => value !== undefined));
677
677
  await this.db
678
- .update(environments)
678
+ .update(agents)
679
679
  .set({ ...columns, updatedAt })
680
- .where(eq(environments.id, id));
680
+ .where(eq(agents.id, id));
681
681
  }
682
682
  async updateEnvironmentPod(id, patch, updatedAt) {
683
683
  this.check();
684
684
  await this.db
685
- .update(environments)
685
+ .update(agents)
686
686
  .set({ ...podColumns(patch), updatedAt })
687
- .where(eq(environments.id, id));
687
+ .where(eq(agents.id, id));
688
688
  }
689
689
  async deleteEnvironment(id) {
690
690
  this.check();
691
691
  // Its vault and credentials go with it (ON DELETE CASCADE).
692
- await this.db.delete(environments).where(eq(environments.id, id));
692
+ await this.db.delete(agents).where(eq(agents.id, id));
693
693
  }
694
694
  async listEnvironments(filter = {}) {
695
695
  this.check();
696
696
  const labels = filter.labels;
697
697
  const rows = await this.db
698
698
  .select()
699
- .from(environments)
699
+ .from(agents)
700
700
  .where(labels === undefined || Object.keys(labels).length === 0
701
701
  ? undefined
702
- : sql `nylorun.doc(${environments.labels}) @> ${toJson(labels)}::jsonb`)
703
- .orderBy(environments.id);
702
+ : sql `nylorun.doc(${agents.labels}) @> ${toJson(labels)}::jsonb`)
703
+ .orderBy(agents.id);
704
704
  return rows.map(environmentOf);
705
705
  }
706
- // --- Environment manifests (D63) -----------------------------------------------
707
- async lockEnvironmentManifest(name) {
706
+ // --- Agent manifests (protocol 16) ---------------------------------------------
707
+ async lockAgentManifest(name) {
708
708
  this.check();
709
- await this.db.execute(sql `SELECT pg_advisory_xact_lock(hashtext(${`nylorun.environment_manifests:${name}`}))`);
709
+ await this.db.execute(sql `SELECT pg_advisory_xact_lock(hashtext(${`nylorun.agent_manifests:${name}`}))`);
710
710
  }
711
- async environmentManifest(name, version) {
711
+ async agentManifest(name, version) {
712
712
  this.check();
713
713
  const [row] = await this.db
714
714
  .select()
715
- .from(environmentManifests)
715
+ .from(agentManifests)
716
716
  .where(version === undefined
717
- ? eq(environmentManifests.name, name)
718
- : and(eq(environmentManifests.name, name), eq(environmentManifests.version, version)))
719
- .orderBy(desc(environmentManifests.version))
717
+ ? eq(agentManifests.name, name)
718
+ : and(eq(agentManifests.name, name), eq(agentManifests.version, version)))
719
+ .orderBy(desc(agentManifests.version))
720
720
  .limit(1);
721
- return row && environmentManifestOf(row);
721
+ return row && agentManifestOf(row);
722
722
  }
723
- async insertEnvironmentManifest(row) {
723
+ async insertAgentManifest(row) {
724
724
  this.check();
725
- await this.db.insert(environmentManifests).values(row);
725
+ await this.db.insert(agentManifests).values(row);
726
726
  }
727
- async listEnvironmentManifests() {
727
+ async listAgentManifests() {
728
728
  this.check();
729
729
  const rows = await this.db
730
- .selectDistinctOn([environmentManifests.name])
731
- .from(environmentManifests)
732
- .orderBy(environmentManifests.name, desc(environmentManifests.version));
733
- return rows.map(environmentManifestOf);
730
+ .selectDistinctOn([agentManifests.name])
731
+ .from(agentManifests)
732
+ .orderBy(agentManifests.name, desc(agentManifests.version));
733
+ return rows.map(agentManifestOf);
734
734
  }
735
- async environmentManifestVersions(name) {
735
+ async agentManifestVersions(name) {
736
736
  this.check();
737
737
  const rows = await this.db
738
738
  .select()
739
- .from(environmentManifests)
740
- .where(eq(environmentManifests.name, name))
741
- .orderBy(desc(environmentManifests.version));
742
- return rows.map(environmentManifestOf);
739
+ .from(agentManifests)
740
+ .where(eq(agentManifests.name, name))
741
+ .orderBy(desc(agentManifests.version));
742
+ return rows.map(agentManifestOf);
743
743
  }
744
- async deleteEnvironmentManifest(name) {
744
+ async deleteAgentManifest(name) {
745
745
  this.check();
746
746
  const deleted = await this.db
747
- .delete(environmentManifests)
748
- .where(eq(environmentManifests.name, name))
749
- .returning({ version: environmentManifests.version });
747
+ .delete(agentManifests)
748
+ .where(eq(agentManifests.name, name))
749
+ .returning({ version: agentManifests.version });
750
750
  return deleted.length;
751
751
  }
752
- async environmentsOfManifest(name) {
752
+ async agentsOfManifest(name) {
753
753
  this.check();
754
754
  const rows = await this.db
755
- .select({ version: environments.manifestVersion, n: count() })
756
- .from(environments)
757
- .where(eq(environments.manifestName, name))
758
- .groupBy(environments.manifestVersion);
759
- return new Map(rows.filter((row) => row.version !== null).map((row) => [row.version, row.n]));
755
+ .select({ version: agents.manifestVersion, n: count() })
756
+ .from(agents)
757
+ .where(eq(agents.manifestName, name))
758
+ .groupBy(agents.manifestVersion);
759
+ return new Map(rows.map((row) => [row.version, row.n]));
760
760
  }
761
761
  async sessionsOnEnvironment(environmentId) {
762
762
  this.check();
@@ -765,11 +765,11 @@ class PostgresTx {
765
765
  .orderBy(sessions.id);
766
766
  return rows.map((row) => storedSession(row));
767
767
  }
768
- async environmentEvent(environmentId, type, payload) {
768
+ async agentEvent(agentId, type, payload) {
769
769
  this.check();
770
- return appendEnvironmentEvent(postgresEnvironmentRecordWriter(this.db), {
770
+ return appendAgentEvent(postgresAgentRecordWriter(this.db), {
771
771
  tenantId: this.tenantId,
772
- environmentId,
772
+ agentId,
773
773
  time: this.now(),
774
774
  type,
775
775
  payload,
@@ -780,13 +780,13 @@ class PostgresTx {
780
780
  async maxEntryBytes() {
781
781
  return (await readRuntimeLimits(this)).recordEntryBytes;
782
782
  }
783
- async environmentEvents(environmentId, options = {}) {
783
+ async agentEvents(agentId, options = {}) {
784
784
  this.check();
785
785
  const query = this.db
786
- .select({ body: environmentEvents.body })
787
- .from(environmentEvents)
788
- .where(and(eq(environmentEvents.environmentId, environmentId), options.fromSeq === undefined ? undefined : gte(environmentEvents.seq, options.fromSeq), options.types === undefined ? undefined : inArray(environmentEvents.type, [...options.types]), options.since === undefined ? undefined : gte(environmentEvents.committedAt, options.since), options.until === undefined ? undefined : lt(environmentEvents.committedAt, options.until)))
789
- .orderBy(environmentEvents.seq)
786
+ .select({ body: agentEvents.body })
787
+ .from(agentEvents)
788
+ .where(and(eq(agentEvents.agentId, agentId), options.fromSeq === undefined ? undefined : gte(agentEvents.seq, options.fromSeq), options.types === undefined ? undefined : inArray(agentEvents.type, [...options.types]), options.since === undefined ? undefined : gte(agentEvents.committedAt, options.since), options.until === undefined ? undefined : lt(agentEvents.committedAt, options.until)))
789
+ .orderBy(agentEvents.seq)
790
790
  .$dynamic();
791
791
  const rows = await (options.limit === undefined ? query : query.limit(options.limit));
792
792
  return rows.map((row) => row.body);
@@ -836,13 +836,13 @@ class PostgresTx {
836
836
  WHERE ${sessions.status} IN ('running', 'runnable'))::int AS running,
837
837
  (SELECT count(*) FROM ${effects} WHERE ${effects.status} = 'uncertain')::int AS uncertain,
838
838
  (SELECT count(*) FROM ${sandboxes})::int AS sandboxes,
839
- (SELECT count(*) FROM ${definitions})::int AS definitions`);
839
+ (SELECT count(*) FROM ${agentManifests})::int AS manifests`);
840
840
  return {
841
841
  sessions: row.sessions,
842
842
  runningSessions: row.running,
843
843
  uncertainEffects: row.uncertain,
844
844
  sandboxes: row.sandboxes,
845
- definitions: row.definitions,
845
+ agentManifests: row.manifests,
846
846
  };
847
847
  }
848
848
  // --- control bus (D21) ---------------------------------------------------
@@ -1089,7 +1089,7 @@ class PostgresTx {
1089
1089
  costUsd: sql `coalesce(sum(${modelUsage.costUsd}), 0)::double precision`.mapWith(Number),
1090
1090
  })
1091
1091
  .from(modelUsage)
1092
- .where(and(query.scope === "agent" ? eq(modelUsage.agentId, query.id ?? "") : undefined, query.scope === "turn" ? eq(modelUsage.turnId, query.id ?? "") : undefined, query.since !== undefined ? gte(modelUsage.createdAt, query.since) : undefined));
1092
+ .where(and(query.scope === "manifest" ? eq(modelUsage.manifestName, query.id ?? "") : undefined, query.scope === "turn" ? eq(modelUsage.turnId, query.id ?? "") : undefined, query.since !== undefined ? gte(modelUsage.createdAt, query.since) : undefined));
1093
1093
  return row;
1094
1094
  }
1095
1095
  async listModelBudgets() {
@@ -1105,6 +1105,249 @@ class PostgresTx {
1105
1105
  if (rows.length > 0)
1106
1106
  await this.db.insert(modelBudgets).values([...rows]);
1107
1107
  }
1108
+ // --- session queues (protocol 17) -------------------------------------------
1109
+ async enqueueMessage(row) {
1110
+ this.check();
1111
+ const [last] = await this.db
1112
+ .select({ seq: sql `max(${sessionQueue.seq})` })
1113
+ .from(sessionQueue)
1114
+ .where(eq(sessionQueue.sessionId, row.sessionId));
1115
+ const seq = Number(last?.seq ?? 0) + 1;
1116
+ await this.db.insert(sessionQueue).values({ ...row, seq });
1117
+ return seq;
1118
+ }
1119
+ async queuedMessages(sessionId) {
1120
+ this.check();
1121
+ return this.db
1122
+ .select()
1123
+ .from(sessionQueue)
1124
+ .where(eq(sessionQueue.sessionId, sessionId))
1125
+ .orderBy(sessionQueue.seq);
1126
+ }
1127
+ async countQueuedMessages(sessionId) {
1128
+ this.check();
1129
+ const [row] = await this.db
1130
+ .select({ n: count() })
1131
+ .from(sessionQueue)
1132
+ .where(eq(sessionQueue.sessionId, sessionId));
1133
+ return Number(row?.n ?? 0);
1134
+ }
1135
+ async deleteQueuedMessages(ids) {
1136
+ this.check();
1137
+ if (ids.length > 0)
1138
+ await this.db.delete(sessionQueue).where(inArray(sessionQueue.id, [...ids]));
1139
+ }
1140
+ // --- triggers (track T4) ----------------------------------------------------
1141
+ async agentTriggers(agentId) {
1142
+ this.check();
1143
+ return this.db
1144
+ .select()
1145
+ .from(agentTriggers)
1146
+ .where(eq(agentTriggers.agentId, agentId))
1147
+ .orderBy(agentTriggers.triggerId);
1148
+ }
1149
+ async agentTrigger(agentId, triggerId, options = {}) {
1150
+ this.check();
1151
+ const query = this.db
1152
+ .select()
1153
+ .from(agentTriggers)
1154
+ .where(and(eq(agentTriggers.agentId, agentId), eq(agentTriggers.triggerId, triggerId)));
1155
+ const [row] = options.lock ? await query.for("update") : await query;
1156
+ return row;
1157
+ }
1158
+ async putAgentTrigger(row) {
1159
+ this.check();
1160
+ const { agentId: _a, triggerId: _t, createdAt: _c, ...set } = row;
1161
+ await this.db
1162
+ .insert(agentTriggers)
1163
+ .values(row)
1164
+ .onConflictDoUpdate({ target: [agentTriggers.agentId, agentTriggers.triggerId], set });
1165
+ }
1166
+ async deleteAgentTrigger(agentId, triggerId) {
1167
+ this.check();
1168
+ await this.db
1169
+ .delete(agentTriggers)
1170
+ .where(and(eq(agentTriggers.agentId, agentId), eq(agentTriggers.triggerId, triggerId)));
1171
+ }
1172
+ async deleteAgentTriggers(agentId) {
1173
+ this.check();
1174
+ await this.db.delete(agentTriggers).where(eq(agentTriggers.agentId, agentId));
1175
+ await this.db.delete(triggerRuns).where(eq(triggerRuns.agentId, agentId));
1176
+ }
1177
+ async activeTriggers(options) {
1178
+ this.check();
1179
+ const conditions = [eq(agentTriggers.status, "active"), isNotNull(agentTriggers.nextFireAt)];
1180
+ if (options.dueBefore !== undefined)
1181
+ conditions.push(lte(agentTriggers.nextFireAt, options.dueBefore));
1182
+ if (options.changedSince !== undefined)
1183
+ conditions.push(gte(agentTriggers.updatedAt, options.changedSince));
1184
+ if (options.after)
1185
+ conditions.push(or(gt(agentTriggers.agentId, options.after.agentId), and(eq(agentTriggers.agentId, options.after.agentId), gt(agentTriggers.triggerId, options.after.triggerId))));
1186
+ return this.db
1187
+ .select()
1188
+ .from(agentTriggers)
1189
+ .where(and(...conditions))
1190
+ .orderBy(agentTriggers.agentId, agentTriggers.triggerId)
1191
+ .limit(options.limit);
1192
+ }
1193
+ async agentTriggerByEndpoint(endpointId) {
1194
+ this.check();
1195
+ const [row] = await this.db.select().from(agentTriggers).where(eq(agentTriggers.endpointId, endpointId));
1196
+ return row;
1197
+ }
1198
+ async nextWakeAt(agentId) {
1199
+ this.check();
1200
+ const [row] = await this.db
1201
+ .select({ at: sql `min(${agentTriggers.nextFireAt})` })
1202
+ .from(agentTriggers)
1203
+ .where(and(eq(agentTriggers.agentId, agentId), eq(agentTriggers.status, "active")));
1204
+ return row?.at ?? null;
1205
+ }
1206
+ async insertTriggerRun(row) {
1207
+ this.check();
1208
+ const inserted = await this.db
1209
+ .insert(triggerRuns)
1210
+ .values(row)
1211
+ .onConflictDoNothing()
1212
+ .returning({ id: triggerRuns.id });
1213
+ return inserted.length === 1;
1214
+ }
1215
+ async triggerRunByKey(agentId, runKey) {
1216
+ this.check();
1217
+ const [row] = await this.db
1218
+ .select()
1219
+ .from(triggerRuns)
1220
+ .where(and(eq(triggerRuns.agentId, agentId), eq(triggerRuns.runKey, runKey)));
1221
+ return row;
1222
+ }
1223
+ async updateTriggerRun(id, patch) {
1224
+ this.check();
1225
+ await this.db.update(triggerRuns).set(patch).where(eq(triggerRuns.id, id));
1226
+ }
1227
+ async countTriggerRuns(agentId, since, statuses) {
1228
+ this.check();
1229
+ const [row] = await this.db
1230
+ .select({ n: count() })
1231
+ .from(triggerRuns)
1232
+ .where(and(eq(triggerRuns.agentId, agentId), gte(triggerRuns.firedAt, since), inArray(triggerRuns.status, [...statuses])));
1233
+ return Number(row?.n ?? 0);
1234
+ }
1235
+ async listTriggerRuns(agentId, options) {
1236
+ this.check();
1237
+ const conditions = [eq(triggerRuns.agentId, agentId)];
1238
+ if (options.triggerId !== undefined)
1239
+ conditions.push(eq(triggerRuns.triggerId, options.triggerId));
1240
+ if (options.before !== undefined)
1241
+ conditions.push(lt(triggerRuns.id, options.before));
1242
+ return this.db
1243
+ .select()
1244
+ .from(triggerRuns)
1245
+ .where(and(...conditions))
1246
+ .orderBy(desc(triggerRuns.id))
1247
+ .limit(options.limit);
1248
+ }
1249
+ async pruneTriggerRuns(before) {
1250
+ this.check();
1251
+ const deleted = await this.db
1252
+ .delete(triggerRuns)
1253
+ .where(lt(triggerRuns.firedAt, before))
1254
+ .returning({ id: triggerRuns.id });
1255
+ return deleted.length;
1256
+ }
1257
+ // --- memory (track T5) ------------------------------------------------------
1258
+ async memory(agentId, path, options = {}) {
1259
+ this.check();
1260
+ // The path's own lock, held whether or not a row has it, so two writes creating it queue.
1261
+ if (options.lock)
1262
+ await this.db.execute(sql `SELECT pg_advisory_xact_lock(hashtext(${`nylorun.memories:${agentId}:${path}`}))`);
1263
+ const query = this.db
1264
+ .select()
1265
+ .from(memories)
1266
+ .where(and(eq(memories.agentId, agentId), eq(memories.path, path)));
1267
+ const [row] = options.lock ? await query.for("update") : await query;
1268
+ return row;
1269
+ }
1270
+ async memories(agentId, options) {
1271
+ this.check();
1272
+ const conditions = [eq(memories.agentId, agentId)];
1273
+ // `starts_with`, not LIKE: a path may hold `%` or `_`.
1274
+ if (options.folder !== undefined)
1275
+ conditions.push(sql `starts_with(${memories.path}, ${`${options.folder}/`})`);
1276
+ if (options.after !== undefined)
1277
+ conditions.push(gt(memories.path, options.after));
1278
+ const ordered = this.db
1279
+ .select()
1280
+ .from(memories)
1281
+ .where(and(...conditions))
1282
+ .orderBy(memories.path);
1283
+ const limited = options.limit === undefined ? ordered : ordered.limit(options.limit);
1284
+ return options.lock ? limited.for("update") : limited;
1285
+ }
1286
+ async countMemories(agentId) {
1287
+ this.check();
1288
+ const [row] = await this.db.select({ n: count() }).from(memories).where(eq(memories.agentId, agentId));
1289
+ return Number(row?.n ?? 0);
1290
+ }
1291
+ async recentMemories(agentId, limit) {
1292
+ this.check();
1293
+ return this.db
1294
+ .select({ path: memories.path, description: memories.description, bytes: memories.bytes })
1295
+ .from(memories)
1296
+ .where(eq(memories.agentId, agentId))
1297
+ .orderBy(desc(memories.updatedAt), memories.path)
1298
+ .limit(limit);
1299
+ }
1300
+ async putMemory(row) {
1301
+ this.check();
1302
+ const { agentId: _a, path: _p, ...set } = row;
1303
+ await this.db
1304
+ .insert(memories)
1305
+ .values(row)
1306
+ .onConflictDoUpdate({ target: [memories.agentId, memories.path], set });
1307
+ }
1308
+ async deleteMemory(agentId, path) {
1309
+ this.check();
1310
+ await this.db.delete(memories).where(and(eq(memories.agentId, agentId), eq(memories.path, path)));
1311
+ }
1312
+ async insertMemoryVersion(row) {
1313
+ this.check();
1314
+ await this.db.insert(memoryVersions).values(row);
1315
+ }
1316
+ async memoryVersions(agentId, options) {
1317
+ this.check();
1318
+ const conditions = [eq(memoryVersions.agentId, agentId)];
1319
+ if (options.path !== undefined)
1320
+ conditions.push(eq(memoryVersions.path, options.path));
1321
+ if (options.before !== undefined)
1322
+ conditions.push(lt(memoryVersions.id, options.before));
1323
+ return this.db
1324
+ .select()
1325
+ .from(memoryVersions)
1326
+ .where(and(...conditions))
1327
+ .orderBy(desc(memoryVersions.id))
1328
+ .limit(options.limit);
1329
+ }
1330
+ async memoryVersion(agentId, id) {
1331
+ this.check();
1332
+ const [row] = await this.db
1333
+ .select()
1334
+ .from(memoryVersions)
1335
+ .where(and(eq(memoryVersions.agentId, agentId), eq(memoryVersions.id, id)));
1336
+ return row;
1337
+ }
1338
+ async copyMemories(from, to, now) {
1339
+ this.check();
1340
+ const copied = await this.db.execute(sql `
1341
+ INSERT INTO ${memories} (agent_id, path, content, content_sha256, bytes, description, version, updated_at)
1342
+ SELECT ${to}, path, content, content_sha256, bytes, description, 1, ${now}
1343
+ FROM ${memories} WHERE agent_id = ${from}`);
1344
+ return Number(copied.count ?? 0);
1345
+ }
1346
+ async deleteAgentMemories(agentId) {
1347
+ this.check();
1348
+ await this.db.delete(memories).where(eq(memories.agentId, agentId));
1349
+ await this.db.delete(memoryVersions).where(eq(memoryVersions.agentId, agentId));
1350
+ }
1108
1351
  // --- tool crossings --------------------------------------------------------
1109
1352
  async toolCrossing(key) {
1110
1353
  this.check();
@@ -1373,6 +1616,8 @@ class PostgresTx {
1373
1616
  if (scope === "sessions" || scope === "all") {
1374
1617
  for (const table of SESSION_TABLES)
1375
1618
  await db.delete(table);
1619
+ // A session's booked wake (T4) goes with it.
1620
+ await db.delete(agentTriggers).where(eq(agentTriggers.kind, "wake"));
1376
1621
  await db.delete(toolCrossings);
1377
1622
  // A session's artifacts go with it (their versions by cascade).
1378
1623
  await db.delete(artifacts).where(isNotNull(artifacts.sessionId));
@@ -1385,15 +1630,20 @@ class PostgresTx {
1385
1630
  basinGeneration: sql `${tenant.basinGeneration} + 1`,
1386
1631
  });
1387
1632
  }
1388
- if (scope === "environments" || scope === "all") {
1633
+ if (scope === "agents" || scope === "all") {
1389
1634
  await db.delete(sandboxes);
1390
1635
  // Their vaults and credentials go with them (ON DELETE CASCADE).
1391
- await db.delete(environments);
1392
- await db.delete(environmentEvents);
1636
+ await db.delete(agents);
1637
+ await db.delete(agentEvents);
1638
+ await db.delete(agentTriggers);
1639
+ await db.delete(triggerRuns);
1640
+ // Memories belong to the Agents (D72).
1641
+ await db.delete(memories);
1642
+ await db.delete(memoryVersions);
1393
1643
  await db.delete(sandboxSignals);
1394
1644
  }
1395
1645
  if (scope === "all") {
1396
- await db.delete(definitions);
1646
+ await db.delete(agentManifests);
1397
1647
  // The files stay, as their bytes do; only what used them goes.
1398
1648
  await db.delete(definitionFileUses);
1399
1649
  await db.delete(modelUsage);
@@ -4,7 +4,7 @@ import { TenantEnvelopeSchema, } from "@nylorun/core/contracts";
4
4
  import { openError, TenantOpenError } from "../../tenant/cause.js";
5
5
  import { database, driverError } from "./db.js";
6
6
  import { applyMigrations, assertCurrentLayout, isStatementError, lockMigrations, shippedMigrations, } from "./migrate.js";
7
- import { definitions, principals, sessions, signingKeys, TENANT_SCHEMA, tenant, vaultAudit, vaults, } from "./schema.js";
7
+ import { principals, sessions, signingKeys, TENANT_SCHEMA, tenant, vaultAudit, vaults, } from "./schema.js";
8
8
  import { createPostgresSessionStore } from "./store.js";
9
9
  /** The migration that deletes the vault's `oauth` credentials, each with an audit row. */
10
10
  const OAUTH_REMOVED_MIGRATION = "0016_mcp_oauth_removed";
@@ -114,7 +114,6 @@ async function ensureTenant(tx, create, migrated, now) {
114
114
  const [data] = await tx.execute(sql `
115
115
  SELECT EXISTS (SELECT 1 FROM ${principals})
116
116
  OR EXISTS (SELECT 1 FROM ${sessions})
117
- OR EXISTS (SELECT 1 FROM ${definitions})
118
117
  OR EXISTS (SELECT 1 FROM ${vaults})
119
118
  OR EXISTS (SELECT 1 FROM ${signingKeys}) AS held`);
120
119
  if (data?.held)