@treeseed/sdk 0.1.1 → 0.3.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.
Files changed (228) hide show
  1. package/README.md +97 -494
  2. package/dist/{src/cli-tools.d.ts → cli-tools.d.ts} +1 -1
  3. package/dist/cli-tools.js +5 -3
  4. package/dist/{src/content-store.d.ts → content-store.d.ts} +3 -2
  5. package/dist/content-store.js +52 -20
  6. package/dist/{src/d1-store.d.ts → d1-store.d.ts} +62 -1
  7. package/dist/d1-store.js +625 -65
  8. package/dist/field-aliases.d.ts +11 -0
  9. package/dist/field-aliases.js +41 -0
  10. package/dist/graph/build.d.ts +19 -0
  11. package/dist/graph/build.js +949 -0
  12. package/dist/graph/dsl.d.ts +2 -0
  13. package/dist/graph/dsl.js +243 -0
  14. package/dist/graph/query.d.ts +47 -0
  15. package/dist/graph/query.js +447 -0
  16. package/dist/graph/ranking.d.ts +3 -0
  17. package/dist/graph/ranking.js +483 -0
  18. package/dist/graph/schema.d.ts +142 -0
  19. package/dist/graph/schema.js +133 -0
  20. package/dist/graph.d.ts +52 -0
  21. package/dist/graph.js +133 -0
  22. package/dist/index.d.ts +27 -0
  23. package/dist/index.js +90 -2
  24. package/dist/model-registry.d.ts +8 -0
  25. package/dist/model-registry.js +351 -25
  26. package/dist/operations/providers/default.d.ts +10 -0
  27. package/dist/operations/providers/default.js +514 -0
  28. package/dist/operations/runtime.d.ts +7 -0
  29. package/dist/operations/runtime.js +60 -0
  30. package/dist/operations/services/config-runtime.d.ts +269 -0
  31. package/dist/operations/services/config-runtime.js +1397 -0
  32. package/dist/operations/services/d1-migration.d.ts +6 -0
  33. package/dist/operations/services/d1-migration.js +89 -0
  34. package/dist/operations/services/deploy.d.ts +371 -0
  35. package/dist/operations/services/deploy.js +981 -0
  36. package/dist/operations/services/git-workflow.d.ts +49 -0
  37. package/dist/operations/services/git-workflow.js +218 -0
  38. package/dist/operations/services/github-automation.d.ts +156 -0
  39. package/dist/operations/services/github-automation.js +256 -0
  40. package/dist/operations/services/local-dev.d.ts +9 -0
  41. package/dist/operations/services/local-dev.js +106 -0
  42. package/dist/operations/services/mailpit-runtime.d.ts +4 -0
  43. package/dist/operations/services/mailpit-runtime.js +59 -0
  44. package/dist/operations/services/railway-deploy.d.ts +53 -0
  45. package/dist/operations/services/railway-deploy.js +123 -0
  46. package/dist/operations/services/runtime-paths.d.ts +19 -0
  47. package/dist/operations/services/runtime-paths.js +54 -0
  48. package/dist/operations/services/runtime-tools.d.ts +117 -0
  49. package/dist/operations/services/runtime-tools.js +358 -0
  50. package/dist/operations/services/save-deploy-preflight.d.ts +34 -0
  51. package/dist/operations/services/save-deploy-preflight.js +76 -0
  52. package/dist/operations/services/template-registry.d.ts +88 -0
  53. package/dist/operations/services/template-registry.js +407 -0
  54. package/dist/operations/services/watch-dev.d.ts +21 -0
  55. package/dist/operations/services/watch-dev.js +284 -0
  56. package/dist/operations/services/workspace-preflight.d.ts +40 -0
  57. package/dist/operations/services/workspace-preflight.js +165 -0
  58. package/dist/operations/services/workspace-save.d.ts +42 -0
  59. package/dist/operations/services/workspace-save.js +235 -0
  60. package/dist/operations/services/workspace-tools.d.ts +16 -0
  61. package/dist/operations/services/workspace-tools.js +270 -0
  62. package/dist/operations-registry.d.ts +5 -0
  63. package/dist/operations-registry.js +68 -0
  64. package/dist/operations-types.d.ts +71 -0
  65. package/dist/operations-types.js +17 -0
  66. package/dist/operations.d.ts +6 -0
  67. package/dist/operations.js +16 -0
  68. package/dist/platform/books-data.d.ts +1 -0
  69. package/dist/platform/books-data.js +1 -0
  70. package/dist/platform/contracts.d.ts +158 -0
  71. package/dist/platform/contracts.js +0 -0
  72. package/dist/platform/deploy/config.d.ts +4 -0
  73. package/dist/platform/deploy/config.js +222 -0
  74. package/dist/platform/deploy-config.d.ts +1 -0
  75. package/dist/platform/deploy-config.js +1 -0
  76. package/dist/platform/env.yaml +394 -0
  77. package/dist/platform/environment.d.ts +130 -0
  78. package/dist/platform/environment.js +331 -0
  79. package/dist/platform/plugin.d.ts +2 -0
  80. package/dist/platform/plugin.js +4 -0
  81. package/dist/platform/plugins/constants.d.ts +22 -0
  82. package/dist/platform/plugins/constants.js +29 -0
  83. package/dist/platform/plugins/plugin.d.ts +51 -0
  84. package/dist/platform/plugins/plugin.js +6 -0
  85. package/dist/platform/plugins/runtime.d.ts +35 -0
  86. package/dist/platform/plugins/runtime.js +142 -0
  87. package/dist/platform/plugins.d.ts +5 -0
  88. package/dist/platform/plugins.js +16 -0
  89. package/dist/platform/site-config-schema.js +1 -0
  90. package/dist/platform/tenant/config.d.ts +9 -0
  91. package/dist/platform/tenant/config.js +154 -0
  92. package/dist/platform/tenant/runtime-config.d.ts +4 -0
  93. package/dist/platform/tenant/runtime-config.js +20 -0
  94. package/dist/platform/tenant-config.d.ts +1 -0
  95. package/dist/platform/tenant-config.js +1 -0
  96. package/dist/platform/utils/books-data.d.ts +29 -0
  97. package/dist/platform/utils/books-data.js +82 -0
  98. package/dist/platform/utils/site-config-schema.js +321 -0
  99. package/dist/remote.d.ts +175 -0
  100. package/dist/remote.js +202 -0
  101. package/dist/runtime.js +50 -3
  102. package/dist/scripts/aggregate-book.js +121 -0
  103. package/dist/scripts/build-dist.js +57 -13
  104. package/dist/scripts/build-tenant-worker.js +36 -0
  105. package/dist/scripts/cleanup-markdown.js +373 -0
  106. package/dist/scripts/cli-test-fixtures.js +48 -0
  107. package/dist/scripts/config-treeseed.js +95 -0
  108. package/dist/scripts/ensure-mailpit.js +29 -0
  109. package/dist/scripts/local-dev.js +129 -0
  110. package/dist/scripts/logs-mailpit.js +2 -0
  111. package/dist/scripts/patch-starlight-content-path.js +172 -0
  112. package/dist/scripts/release-verify.js +34 -5
  113. package/dist/scripts/run-fixture-astro-command.js +18 -0
  114. package/dist/scripts/scaffold-site.js +65 -0
  115. package/dist/scripts/stop-mailpit.js +5 -0
  116. package/dist/scripts/sync-dev-vars.js +6 -0
  117. package/dist/scripts/sync-template.js +20 -0
  118. package/dist/scripts/template-catalog.test.js +100 -0
  119. package/dist/scripts/template-command.js +31 -0
  120. package/dist/scripts/tenant-astro-command.js +3 -0
  121. package/dist/scripts/tenant-build.js +16 -0
  122. package/dist/scripts/tenant-check.js +7 -0
  123. package/dist/scripts/tenant-d1-migrate-local.js +11 -0
  124. package/dist/scripts/tenant-deploy.js +180 -0
  125. package/dist/scripts/tenant-destroy.js +104 -0
  126. package/dist/scripts/tenant-dev.js +171 -0
  127. package/dist/scripts/tenant-lint.js +4 -0
  128. package/dist/scripts/tenant-test.js +4 -0
  129. package/dist/scripts/test-cloudflare-local.js +212 -0
  130. package/dist/scripts/test-scaffold.js +314 -0
  131. package/dist/scripts/test-smoke.js +71 -13
  132. package/dist/scripts/treeseed-assert-release-tag-version.js +21 -0
  133. package/dist/scripts/treeseed-build-dist.js +134 -0
  134. package/dist/scripts/treeseed-publish-package.js +19 -0
  135. package/dist/scripts/treeseed-release-verify.js +131 -0
  136. package/dist/scripts/treeseed-run-ts.js +45 -0
  137. package/dist/scripts/validate-templates.js +6 -0
  138. package/dist/scripts/verify-driver.js +29 -0
  139. package/dist/scripts/workflow-commands.test.js +39 -0
  140. package/dist/scripts/workspace-close.js +24 -0
  141. package/dist/scripts/workspace-command-e2e.js +718 -0
  142. package/dist/scripts/workspace-lint.js +9 -0
  143. package/dist/scripts/workspace-preflight.js +22 -0
  144. package/dist/scripts/workspace-publish-changed-packages.js +16 -0
  145. package/dist/scripts/workspace-release-verify.js +81 -0
  146. package/dist/scripts/workspace-release.js +42 -0
  147. package/dist/scripts/workspace-save.js +124 -0
  148. package/dist/scripts/workspace-start-warning.js +3 -0
  149. package/dist/scripts/workspace-start.js +71 -0
  150. package/dist/scripts/workspace-test-unit.js +4 -0
  151. package/dist/scripts/workspace-test.js +11 -0
  152. package/dist/sdk-fields.d.ts +11 -0
  153. package/dist/sdk-fields.js +169 -0
  154. package/dist/sdk-filters.d.ts +4 -0
  155. package/dist/sdk-filters.js +12 -15
  156. package/dist/sdk-types.d.ts +796 -0
  157. package/dist/sdk-types.js +7 -1
  158. package/dist/sdk-version.d.ts +2 -0
  159. package/dist/sdk-version.js +42 -0
  160. package/dist/sdk.d.ts +215 -0
  161. package/dist/sdk.js +235 -11
  162. package/dist/stores/cursor-store.js +9 -3
  163. package/dist/stores/lease-store.js +8 -2
  164. package/dist/{src/stores → stores}/message-store.d.ts +1 -1
  165. package/dist/stores/message-store.js +27 -3
  166. package/dist/stores/operational-store.d.ts +24 -0
  167. package/dist/stores/operational-store.js +279 -0
  168. package/dist/stores/run-store.js +8 -1
  169. package/dist/stores/subscription-store.js +7 -5
  170. package/dist/template-catalog.d.ts +13 -0
  171. package/dist/template-catalog.js +141 -0
  172. package/dist/treeseed/services/compose.yml +7 -0
  173. package/dist/treeseed/template-catalog/catalog.fixture.json +55 -0
  174. package/dist/treeseed/template-catalog/templates/starter-basic/template/astro.config.d.ts +2 -0
  175. package/dist/treeseed/template-catalog/templates/starter-basic/template/astro.config.ts +3 -0
  176. package/dist/treeseed/template-catalog/templates/starter-basic/template/package.json +32 -0
  177. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/config.yaml +40 -0
  178. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/empty/.gitkeep +1 -0
  179. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/knowledge/handbook/index.mdx +11 -0
  180. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content/pages/welcome.mdx +11 -0
  181. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content.config.d.ts +1 -0
  182. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/content.config.ts +3 -0
  183. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/env.yaml +1 -0
  184. package/dist/treeseed/template-catalog/templates/starter-basic/template/src/manifest.yaml +19 -0
  185. package/dist/treeseed/template-catalog/templates/starter-basic/template/treeseed.site.yaml +26 -0
  186. package/dist/treeseed/template-catalog/templates/starter-basic/template/tsconfig.json +9 -0
  187. package/dist/treeseed/template-catalog/templates/starter-basic/template.config.json +90 -0
  188. package/dist/verification.d.ts +20 -0
  189. package/dist/verification.js +98 -0
  190. package/dist/workflow/operations.d.ts +396 -0
  191. package/dist/workflow/operations.js +841 -0
  192. package/dist/workflow-state.d.ts +56 -0
  193. package/dist/workflow-state.js +195 -0
  194. package/dist/workflow-support.d.ts +9 -0
  195. package/dist/workflow-support.js +176 -0
  196. package/dist/workflow.d.ts +111 -0
  197. package/dist/workflow.js +97 -0
  198. package/package.json +97 -5
  199. package/scripts/verify-driver.mjs +29 -0
  200. package/dist/scripts/.ts-run-1775616845195-odh4xzphk3l.js +0 -22
  201. package/dist/scripts/.ts-run-1775616848931-9386s6kwrl.js +0 -126
  202. package/dist/scripts/assert-release-tag-version.d.ts +0 -1
  203. package/dist/scripts/build-dist.d.ts +0 -1
  204. package/dist/scripts/package-tools.d.ts +0 -15
  205. package/dist/scripts/publish-package.d.ts +0 -1
  206. package/dist/scripts/release-verify.d.ts +0 -1
  207. package/dist/scripts/test-smoke.d.ts +0 -1
  208. package/dist/src/index.d.ts +0 -6
  209. package/dist/src/model-registry.d.ts +0 -4
  210. package/dist/src/sdk-filters.d.ts +0 -4
  211. package/dist/src/sdk-types.d.ts +0 -285
  212. package/dist/src/sdk.d.ts +0 -109
  213. package/dist/test/test-fixture.d.ts +0 -1
  214. package/dist/test/utils/envelopes.test.d.ts +0 -1
  215. package/dist/test/utils/sdk.test.d.ts +0 -1
  216. package/dist/vitest.config.d.ts +0 -2
  217. /package/dist/{src/frontmatter.d.ts → frontmatter.d.ts} +0 -0
  218. /package/dist/{src/git-runtime.d.ts → git-runtime.d.ts} +0 -0
  219. /package/dist/{src/runtime.d.ts → runtime.d.ts} +0 -0
  220. /package/dist/{src/stores → stores}/cursor-store.d.ts +0 -0
  221. /package/dist/{src/stores → stores}/envelopes.d.ts +0 -0
  222. /package/dist/{src/stores → stores}/helpers.d.ts +0 -0
  223. /package/dist/{src/stores → stores}/lease-store.d.ts +0 -0
  224. /package/dist/{src/stores → stores}/run-store.d.ts +0 -0
  225. /package/dist/{src/stores → stores}/subscription-store.d.ts +0 -0
  226. /package/dist/{src/types → types}/agents.d.ts +0 -0
  227. /package/dist/{src/types → types}/cloudflare.d.ts +0 -0
  228. /package/dist/{src/wrangler-d1.d.ts → wrangler-d1.d.ts} +0 -0
package/dist/d1-store.js CHANGED
@@ -1,8 +1,12 @@
1
1
  import crypto from "node:crypto";
2
2
  import { applyFilters, applySort } from "./sdk-filters.js";
3
+ import { normalizeFilterFields, normalizeMutationData, normalizeRecordToCanonicalShape, normalizeSortFields } from "./sdk-fields.js";
4
+ import { assertExpectedVersion } from "./sdk-version.js";
5
+ import { resolveModelDefinition } from "./model-registry.js";
3
6
  import { CursorStore } from "./stores/cursor-store.js";
4
7
  import { LeaseStore } from "./stores/lease-store.js";
5
8
  import { MessageStore } from "./stores/message-store.js";
9
+ import { OperationalStore } from "./stores/operational-store.js";
6
10
  import { RunStore } from "./stores/run-store.js";
7
11
  import { SubscriptionStore } from "./stores/subscription-store.js";
8
12
  function nowIso() {
@@ -11,6 +15,16 @@ function nowIso() {
11
15
  function nextLeaseToken() {
12
16
  return crypto.randomUUID();
13
17
  }
18
+ function pickSortForRequest(request, defaultField) {
19
+ switch (request.strategy) {
20
+ case "oldest":
21
+ return [{ field: defaultField, direction: "asc" }];
22
+ case "highest_priority":
23
+ case "latest":
24
+ default:
25
+ return [{ field: defaultField, direction: "desc" }];
26
+ }
27
+ }
14
28
  function filterSinceField(model) {
15
29
  switch (model) {
16
30
  case "message":
@@ -32,6 +46,12 @@ class MemoryAgentDatabase {
32
46
  runs = /* @__PURE__ */ new Map();
33
47
  contentLeases = /* @__PURE__ */ new Map();
34
48
  cursors = /* @__PURE__ */ new Map();
49
+ workDays = /* @__PURE__ */ new Map();
50
+ tasks = /* @__PURE__ */ new Map();
51
+ taskEvents = /* @__PURE__ */ new Map();
52
+ taskOutputs = /* @__PURE__ */ new Map();
53
+ graphRuns = /* @__PURE__ */ new Map();
54
+ reports = /* @__PURE__ */ new Map();
35
55
  messageId = 0;
36
56
  constructor(seed) {
37
57
  for (const item of seed?.subscriptions ?? []) {
@@ -82,6 +102,18 @@ class MemoryAgentDatabase {
82
102
  token: lease.token
83
103
  }));
84
104
  }
105
+ if (model === "work_day") {
106
+ return [...this.workDays.values()];
107
+ }
108
+ if (model === "task") {
109
+ return [...this.tasks.values()];
110
+ }
111
+ if (model === "graph_run") {
112
+ return [...this.graphRuns.values()];
113
+ }
114
+ if (model === "report") {
115
+ return [...this.reports.values()];
116
+ }
85
117
  throw new Error(`Unsupported D1 model "${model}".`);
86
118
  }
87
119
  async get(request) {
@@ -110,13 +142,29 @@ class MemoryAgentDatabase {
110
142
  token: lease.token
111
143
  } : null;
112
144
  }
145
+ if (request.model === "work_day") {
146
+ return this.workDays.get(key) ?? null;
147
+ }
148
+ if (request.model === "task") {
149
+ return this.tasks.get(key) ?? null;
150
+ }
151
+ if (request.model === "graph_run") {
152
+ return this.graphRuns.get(key) ?? null;
153
+ }
154
+ if (request.model === "report") {
155
+ return this.reports.get(key) ?? null;
156
+ }
113
157
  return this.rowsForModel(request.model).find(
114
158
  (row) => [row.id, row.email, row.runId].map((value) => String(value ?? "")).includes(key)
115
159
  ) ?? null;
116
160
  }
117
161
  async search(request) {
118
- const filtered = applyFilters(this.rowsForModel(request.model), request.filters);
119
- const sorted = applySort(filtered, request.sort);
162
+ const definition = resolveModelDefinition(request.model);
163
+ const rows = this.rowsForModel(request.model).map(
164
+ (row) => normalizeRecordToCanonicalShape(definition, row)
165
+ );
166
+ const filtered = applyFilters(rows, normalizeFilterFields(definition, request.filters), definition);
167
+ const sorted = applySort(filtered, normalizeSortFields(definition, request.sort), definition);
120
168
  return sorted.slice(0, request.limit ?? sorted.length);
121
169
  }
122
170
  async follow(request) {
@@ -138,14 +186,35 @@ class MemoryAgentDatabase {
138
186
  }
139
187
  async pick(request) {
140
188
  if (request.model === "message") {
141
- const item = await this.claimMessage({
142
- workerId: request.workerId,
143
- messageTypes: request.filters?.filter((filter) => filter.field === "type" && filter.op === "in").flatMap((filter) => Array.isArray(filter.value) ? filter.value.map(String) : []),
144
- leaseSeconds: request.leaseSeconds
189
+ const candidates = [...this.messages.values()].filter(
190
+ (message) => (message.status === "pending" || message.status === "failed") && new Date(message.availableAt).valueOf() <= Date.now() && (!request.filters?.filter((filter) => filter.field === "type" && filter.op === "in").flatMap((filter) => Array.isArray(filter.value) ? filter.value.map(String) : []).length || request.filters.filter((filter) => filter.field === "type" && filter.op === "in").flatMap((filter) => Array.isArray(filter.value) ? filter.value.map(String) : []).includes(message.type))
191
+ ).sort((left, right) => {
192
+ if (request.strategy === "oldest") {
193
+ return left.availableAt.localeCompare(right.availableAt) || right.priority - left.priority;
194
+ }
195
+ if (request.strategy === "latest") {
196
+ return right.availableAt.localeCompare(left.availableAt) || right.priority - left.priority;
197
+ }
198
+ return right.priority - left.priority || left.availableAt.localeCompare(right.availableAt);
145
199
  });
200
+ const pending = candidates[0];
201
+ if (!pending) {
202
+ return { item: null, leaseToken: null };
203
+ }
204
+ const claimedAt = nowIso();
205
+ const next = {
206
+ ...pending,
207
+ status: "claimed",
208
+ claimedBy: request.workerId,
209
+ claimedAt,
210
+ leaseExpiresAt: new Date(Date.now() + request.leaseSeconds * 1e3).toISOString(),
211
+ attempts: pending.attempts + 1,
212
+ updatedAt: claimedAt
213
+ };
214
+ this.messages.set(next.id, next);
146
215
  return {
147
- item,
148
- leaseToken: item ? nextLeaseToken() : null
216
+ item: next,
217
+ leaseToken: nextLeaseToken()
149
218
  };
150
219
  }
151
220
  if (request.model === "content_lease") {
@@ -163,7 +232,7 @@ class MemoryAgentDatabase {
163
232
  const items = await this.search({
164
233
  model: request.model,
165
234
  filters: request.filters,
166
- sort: [{ field: filterSinceField(request.model), direction: "desc" }]
235
+ sort: pickSortForRequest(request, filterSinceField(request.model))
167
236
  });
168
237
  return {
169
238
  item: items[0] ?? null,
@@ -171,38 +240,40 @@ class MemoryAgentDatabase {
171
240
  };
172
241
  }
173
242
  async create(request) {
243
+ const definition = resolveModelDefinition(request.model);
244
+ const data = normalizeMutationData(definition, request.data);
174
245
  switch (request.model) {
175
246
  case "message":
176
247
  return await this.createMessage({
177
- type: String(request.data.type ?? "message.created"),
178
- payload: request.data.payload ?? request.data,
179
- relatedModel: typeof request.data.relatedModel === "string" ? request.data.relatedModel : null,
180
- relatedId: typeof request.data.relatedId === "string" ? request.data.relatedId : null,
181
- priority: Number(request.data.priority ?? 0),
182
- maxAttempts: Number(request.data.maxAttempts ?? 3),
248
+ type: String(data.type ?? "message.created"),
249
+ payload: data.payload ?? data,
250
+ relatedModel: typeof data.related_model === "string" ? data.related_model : null,
251
+ relatedId: typeof data.related_id === "string" ? data.related_id : null,
252
+ priority: Number(data.priority ?? 0),
253
+ maxAttempts: Number(data.maxAttempts ?? 3),
183
254
  actor: request.actor
184
255
  });
185
256
  case "subscription": {
186
257
  const record = {
187
258
  id: this.subscriptions.size + 1,
188
- email: String(request.data.email ?? ""),
189
- name: request.data.name ? String(request.data.name) : null,
190
- status: String(request.data.status ?? "active"),
191
- source: String(request.data.source ?? "sdk"),
192
- consent_at: String(request.data.consent_at ?? nowIso()),
193
- created_at: String(request.data.created_at ?? nowIso()),
194
- updated_at: String(request.data.updated_at ?? nowIso()),
195
- ip_hash: String(request.data.ip_hash ?? "")
259
+ email: String(data.email ?? ""),
260
+ name: data.name ? String(data.name) : null,
261
+ status: String(data.status ?? "active"),
262
+ source: String(data.source ?? "sdk"),
263
+ consent_at: String(data.consent_at ?? nowIso()),
264
+ created_at: String(data.created_at ?? nowIso()),
265
+ updated_at: String(data.updated_at ?? nowIso()),
266
+ ip_hash: String(data.ip_hash ?? "")
196
267
  };
197
268
  this.subscriptions.set(String(record.id), record);
198
269
  return record;
199
270
  }
200
271
  case "agent_run":
201
- return this.recordRun({ run: request.data });
272
+ return this.recordRun({ run: data });
202
273
  case "agent_cursor": {
203
- const agentSlug = String(request.data.agentSlug ?? "");
204
- const cursorKey = String(request.data.cursorKey ?? "");
205
- const cursorValue = String(request.data.cursorValue ?? "");
274
+ const agentSlug = String(data.agent_slug ?? "");
275
+ const cursorKey = String(data.cursor_key ?? "");
276
+ const cursorValue = String(data.cursor_value ?? "");
206
277
  this.cursors.set(`${agentSlug}:${cursorKey}`, cursorValue);
207
278
  return {
208
279
  agentSlug,
@@ -213,68 +284,182 @@ class MemoryAgentDatabase {
213
284
  }
214
285
  case "content_lease": {
215
286
  const token = await this.tryClaimContentLease({
216
- model: String(request.data.model ?? ""),
217
- itemKey: String(request.data.itemKey ?? ""),
218
- claimedBy: String(request.data.claimedBy ?? request.actor),
219
- leaseSeconds: Number(request.data.leaseSeconds ?? 300)
287
+ model: String(data.model ?? ""),
288
+ itemKey: String(data.item_key ?? ""),
289
+ claimedBy: String(data.claimed_by ?? request.actor),
290
+ leaseSeconds: Number(data.leaseSeconds ?? 300)
220
291
  });
221
- const lease = this.contentLeases.get(`${request.data.model}:${request.data.itemKey}`);
292
+ const lease = this.contentLeases.get(`${data.model}:${data.item_key}`);
222
293
  return {
223
- model: String(request.data.model ?? ""),
224
- itemKey: String(request.data.itemKey ?? ""),
225
- claimedBy: String(request.data.claimedBy ?? request.actor),
294
+ model: String(data.model ?? ""),
295
+ itemKey: String(data.item_key ?? ""),
296
+ claimedBy: String(data.claimed_by ?? request.actor),
226
297
  claimedAt: String(lease?.claimedAt ?? nowIso()),
227
298
  leaseExpiresAt: String(lease?.leaseExpiresAt ?? nowIso()),
228
299
  token: String(token ?? lease?.token ?? "")
229
300
  };
230
301
  }
302
+ case "work_day":
303
+ return this.startWorkDay({
304
+ id: typeof data.id === "string" ? data.id : void 0,
305
+ projectId: String(data.projectId ?? data.project_id ?? ""),
306
+ capacityBudget: Number(data.capacityBudget ?? data.capacity_budget ?? 0),
307
+ graphVersion: typeof (data.graphVersion ?? data.graph_version) === "string" ? String(data.graphVersion ?? data.graph_version) : null,
308
+ summary: data.summary ?? null,
309
+ actor: request.actor
310
+ });
311
+ case "task":
312
+ return this.createTask({
313
+ id: typeof data.id === "string" ? data.id : void 0,
314
+ workDayId: String(data.workDayId ?? data.work_day_id ?? ""),
315
+ agentId: String(data.agentId ?? data.agent_id ?? ""),
316
+ type: String(data.type ?? ""),
317
+ state: typeof data.state === "string" ? data.state : "pending",
318
+ priority: Number(data.priority ?? 0),
319
+ idempotencyKey: String(data.idempotencyKey ?? data.idempotency_key ?? ""),
320
+ payload: data.payload ?? data,
321
+ payloadHash: typeof (data.payloadHash ?? data.payload_hash) === "string" ? String(data.payloadHash ?? data.payload_hash) : null,
322
+ maxAttempts: Number(data.maxAttempts ?? data.max_attempts ?? 3),
323
+ availableAt: typeof (data.availableAt ?? data.available_at) === "string" ? String(data.availableAt ?? data.available_at) : void 0,
324
+ graphVersion: typeof (data.graphVersion ?? data.graph_version) === "string" ? String(data.graphVersion ?? data.graph_version) : null,
325
+ parentTaskId: typeof (data.parentTaskId ?? data.parent_task_id) === "string" ? String(data.parentTaskId ?? data.parent_task_id) : null,
326
+ actor: request.actor
327
+ });
328
+ case "graph_run": {
329
+ const record = {
330
+ id: String(data.id ?? crypto.randomUUID()),
331
+ workDayId: String(data.workDayId ?? data.work_day_id ?? ""),
332
+ corpusHash: String(data.corpusHash ?? data.corpus_hash ?? ""),
333
+ graphVersion: String(data.graphVersion ?? data.graph_version ?? ""),
334
+ queryJson: typeof (data.queryJson ?? data.query_json) === "string" ? String(data.queryJson ?? data.query_json) : null,
335
+ seedIdsJson: typeof (data.seedIdsJson ?? data.seed_ids_json) === "string" ? String(data.seedIdsJson ?? data.seed_ids_json) : null,
336
+ selectedNodeIdsJson: typeof (data.selectedNodeIdsJson ?? data.selected_node_ids_json) === "string" ? String(data.selectedNodeIdsJson ?? data.selected_node_ids_json) : null,
337
+ statsJson: typeof (data.statsJson ?? data.stats_json) === "string" ? String(data.statsJson ?? data.stats_json) : null,
338
+ snapshotRef: typeof (data.snapshotRef ?? data.snapshot_ref) === "string" ? String(data.snapshotRef ?? data.snapshot_ref) : null,
339
+ createdAt: String(data.createdAt ?? data.created_at ?? nowIso())
340
+ };
341
+ this.graphRuns.set(record.id, record);
342
+ return record;
343
+ }
344
+ case "report":
345
+ return this.createReport({
346
+ id: typeof data.id === "string" ? data.id : void 0,
347
+ workDayId: String(data.workDayId ?? data.work_day_id ?? ""),
348
+ kind: String(data.kind ?? "workday_summary"),
349
+ body: data.body ?? data,
350
+ renderedRef: typeof (data.renderedRef ?? data.rendered_ref) === "string" ? String(data.renderedRef ?? data.rendered_ref) : null,
351
+ sentAt: typeof (data.sentAt ?? data.sent_at) === "string" ? String(data.sentAt ?? data.sent_at) : null,
352
+ actor: request.actor
353
+ });
231
354
  default:
232
355
  throw new Error(`Unsupported D1 create model "${request.model}".`);
233
356
  }
234
357
  }
235
358
  async update(request) {
359
+ const definition = resolveModelDefinition(request.model);
360
+ const data = normalizeMutationData(definition, request.data);
236
361
  switch (request.model) {
237
362
  case "message": {
238
- const current = this.messages.get(Number(request.id ?? request.key ?? request.data.id ?? 0));
363
+ const current = this.messages.get(Number(request.id ?? request.key ?? data.id ?? 0));
239
364
  if (!current) {
240
365
  return null;
241
366
  }
367
+ assertExpectedVersion(request.expectedVersion, current, `message ${current.id}`);
242
368
  const next = {
243
369
  ...current,
244
- ...request.data,
370
+ ...data,
245
371
  updatedAt: nowIso()
246
372
  };
247
373
  this.messages.set(next.id, next);
248
374
  return next;
249
375
  }
250
376
  case "subscription": {
251
- const key = String(request.id ?? request.key ?? request.data.email ?? "");
377
+ const key = String(request.id ?? request.key ?? data.email ?? "");
252
378
  const current = await this.get({ model: "subscription", key });
253
379
  if (!current) {
254
380
  return null;
255
381
  }
382
+ assertExpectedVersion(request.expectedVersion, current, `subscription "${current.email}"`);
256
383
  const next = {
257
384
  ...current,
258
- ...request.data,
385
+ ...data,
259
386
  updated_at: nowIso()
260
387
  };
261
388
  this.subscriptions.set(String(next.id ?? next.email), next);
262
389
  return next;
263
390
  }
264
391
  case "agent_run":
265
- return this.recordRun({ run: { ...request.data, runId: request.id ?? request.key ?? request.data.runId } });
392
+ assertExpectedVersion(
393
+ request.expectedVersion,
394
+ await this.get({ model: "agent_run", key: String(request.id ?? request.key ?? data.run_id ?? "") }),
395
+ `agent_run "${String(request.id ?? request.key ?? data.run_id ?? "")}"`
396
+ );
397
+ return this.recordRun({ run: { ...data, runId: request.id ?? request.key ?? data.run_id } });
266
398
  case "agent_cursor":
399
+ assertExpectedVersion(
400
+ request.expectedVersion,
401
+ await this.get({
402
+ model: "agent_cursor",
403
+ key: `${String(data.agent_slug ?? request.id ?? request.key ?? "")}:${String(data.cursor_key ?? request.slug ?? "")}`
404
+ }),
405
+ `agent_cursor "${String(data.agent_slug ?? request.id ?? request.key ?? "")}:${String(data.cursor_key ?? request.slug ?? "")}"`
406
+ );
267
407
  return this.create({
268
408
  model: "agent_cursor",
269
- data: request.data,
409
+ data,
270
410
  actor: request.actor
271
411
  });
272
412
  case "content_lease":
413
+ assertExpectedVersion(
414
+ request.expectedVersion,
415
+ await this.get({
416
+ model: "content_lease",
417
+ key: `${String(data.model ?? request.id ?? "")}:${String(data.item_key ?? request.slug ?? request.key ?? "")}`
418
+ }),
419
+ `content_lease "${String(data.model ?? request.id ?? "")}:${String(data.item_key ?? request.slug ?? request.key ?? "")}"`
420
+ );
273
421
  return this.create({
274
422
  model: "content_lease",
275
- data: request.data,
423
+ data,
276
424
  actor: request.actor
277
425
  });
426
+ case "work_day":
427
+ return this.closeWorkDay({
428
+ id: String(request.id ?? request.key ?? data.id ?? ""),
429
+ state: data.state ?? "completed",
430
+ summary: data.summary ?? null,
431
+ actor: request.actor
432
+ });
433
+ case "task": {
434
+ const taskId = String(request.id ?? request.key ?? data.id ?? "");
435
+ if (data.state === "completed") {
436
+ return this.completeTask({
437
+ id: taskId,
438
+ output: data.output ?? null,
439
+ outputRef: typeof data.outputRef === "string" ? data.outputRef : null,
440
+ summary: data.summary ?? null,
441
+ actor: request.actor
442
+ });
443
+ }
444
+ if (data.state === "failed") {
445
+ return this.failTask({
446
+ id: taskId,
447
+ errorCode: typeof data.errorCode === "string" ? data.errorCode : null,
448
+ errorMessage: String(data.errorMessage ?? "Task failed"),
449
+ retryable: Boolean(data.retryable),
450
+ nextVisibleAt: typeof data.nextVisibleAt === "string" ? data.nextVisibleAt : null,
451
+ actor: request.actor
452
+ });
453
+ }
454
+ return this.recordTaskProgress({
455
+ id: taskId,
456
+ workerId: typeof data.workerId === "string" ? data.workerId : null,
457
+ state: typeof data.state === "string" ? data.state : void 0,
458
+ appendEvent: data.appendEvent,
459
+ patch: data.patch ?? void 0,
460
+ actor: request.actor
461
+ });
462
+ }
278
463
  default:
279
464
  throw new Error(`Unsupported D1 update model "${request.model}".`);
280
465
  }
@@ -374,6 +559,197 @@ class MemoryAgentDatabase {
374
559
  inspectLeases() {
375
560
  return [...this.contentLeases.values()];
376
561
  }
562
+ async startWorkDay(request) {
563
+ const timestamp = nowIso();
564
+ const record = {
565
+ id: request.id ?? crypto.randomUUID(),
566
+ projectId: request.projectId,
567
+ state: "active",
568
+ capacityBudget: Number(request.capacityBudget ?? 0),
569
+ capacityUsed: 0,
570
+ graphVersion: request.graphVersion ?? null,
571
+ summaryJson: request.summary ? JSON.stringify(request.summary) : null,
572
+ startedAt: timestamp,
573
+ endedAt: null,
574
+ createdAt: timestamp,
575
+ updatedAt: timestamp
576
+ };
577
+ this.workDays.set(record.id, record);
578
+ return record;
579
+ }
580
+ async closeWorkDay(request) {
581
+ const existing = this.workDays.get(request.id);
582
+ if (!existing) return null;
583
+ const next = {
584
+ ...existing,
585
+ state: request.state ?? "completed",
586
+ summaryJson: request.summary ? JSON.stringify(request.summary) : existing.summaryJson,
587
+ endedAt: nowIso(),
588
+ updatedAt: nowIso()
589
+ };
590
+ this.workDays.set(next.id, next);
591
+ return next;
592
+ }
593
+ async createTask(request) {
594
+ const timestamp = nowIso();
595
+ const record = {
596
+ id: request.id ?? crypto.randomUUID(),
597
+ workDayId: request.workDayId,
598
+ agentId: request.agentId,
599
+ type: request.type,
600
+ state: request.state ?? "pending",
601
+ priority: Number(request.priority ?? 0),
602
+ idempotencyKey: request.idempotencyKey,
603
+ payloadJson: JSON.stringify(request.payload),
604
+ payloadHash: request.payloadHash ?? null,
605
+ attemptCount: 0,
606
+ maxAttempts: Number(request.maxAttempts ?? 3),
607
+ claimedBy: null,
608
+ leaseExpiresAt: null,
609
+ availableAt: request.availableAt ?? timestamp,
610
+ lastErrorCode: null,
611
+ lastErrorMessage: null,
612
+ graphVersion: request.graphVersion ?? null,
613
+ parentTaskId: request.parentTaskId ?? null,
614
+ createdAt: timestamp,
615
+ startedAt: null,
616
+ completedAt: null,
617
+ updatedAt: timestamp
618
+ };
619
+ this.tasks.set(record.id, record);
620
+ return record;
621
+ }
622
+ async claimTask(request) {
623
+ const existing = this.tasks.get(request.id);
624
+ if (!existing) return null;
625
+ const next = {
626
+ ...existing,
627
+ state: "claimed",
628
+ claimedBy: request.workerId,
629
+ leaseExpiresAt: new Date(Date.now() + request.leaseSeconds * 1e3).toISOString(),
630
+ attemptCount: existing.attemptCount + 1,
631
+ startedAt: existing.startedAt ?? nowIso(),
632
+ updatedAt: nowIso()
633
+ };
634
+ this.tasks.set(next.id, next);
635
+ return next;
636
+ }
637
+ async recordTaskProgress(request) {
638
+ const existing = this.tasks.get(request.id);
639
+ if (!existing) return null;
640
+ const nextPayload = {
641
+ ...JSON.parse(existing.payloadJson),
642
+ ...request.patch ?? {}
643
+ };
644
+ const next = {
645
+ ...existing,
646
+ state: request.state ?? existing.state,
647
+ claimedBy: request.workerId ?? existing.claimedBy,
648
+ payloadJson: JSON.stringify(nextPayload),
649
+ updatedAt: nowIso()
650
+ };
651
+ this.tasks.set(next.id, next);
652
+ if (request.appendEvent?.kind) {
653
+ await this.appendTaskEvent({
654
+ taskId: request.id,
655
+ kind: request.appendEvent.kind,
656
+ data: request.appendEvent.data,
657
+ actor: request.actor
658
+ });
659
+ }
660
+ return next;
661
+ }
662
+ async completeTask(request) {
663
+ const existing = this.tasks.get(request.id);
664
+ if (!existing) return null;
665
+ const next = {
666
+ ...existing,
667
+ state: "completed",
668
+ completedAt: nowIso(),
669
+ leaseExpiresAt: null,
670
+ updatedAt: nowIso()
671
+ };
672
+ this.tasks.set(next.id, next);
673
+ if (request.output) {
674
+ const outputs = this.taskOutputs.get(request.id) ?? [];
675
+ outputs.push({
676
+ id: crypto.randomUUID(),
677
+ taskId: request.id,
678
+ outputJson: JSON.stringify(request.output),
679
+ outputRef: request.outputRef ?? null,
680
+ createdAt: nowIso()
681
+ });
682
+ this.taskOutputs.set(request.id, outputs);
683
+ }
684
+ if (request.summary) {
685
+ await this.appendTaskEvent({
686
+ taskId: request.id,
687
+ kind: "completed",
688
+ data: request.summary,
689
+ actor: request.actor
690
+ });
691
+ }
692
+ return next;
693
+ }
694
+ async failTask(request) {
695
+ const existing = this.tasks.get(request.id);
696
+ if (!existing) return null;
697
+ const next = {
698
+ ...existing,
699
+ state: request.retryable ? "pending" : "failed",
700
+ availableAt: request.nextVisibleAt ?? existing.availableAt,
701
+ lastErrorCode: request.errorCode ?? null,
702
+ lastErrorMessage: request.errorMessage,
703
+ leaseExpiresAt: null,
704
+ updatedAt: nowIso()
705
+ };
706
+ this.tasks.set(next.id, next);
707
+ return next;
708
+ }
709
+ async appendTaskEvent(request) {
710
+ const events = this.taskEvents.get(request.taskId) ?? [];
711
+ const next = {
712
+ id: crypto.randomUUID(),
713
+ taskId: request.taskId,
714
+ seq: events.length + 1,
715
+ kind: request.kind,
716
+ dataJson: JSON.stringify({ ...request.data ?? {}, actor: request.actor }),
717
+ createdAt: nowIso()
718
+ };
719
+ events.push(next);
720
+ this.taskEvents.set(request.taskId, events);
721
+ return next;
722
+ }
723
+ async searchTasks(request) {
724
+ return [...this.tasks.values()].filter((task) => !request.workDayId || task.workDayId === request.workDayId).filter((task) => !request.agentId || task.agentId === request.agentId).filter((task) => {
725
+ if (!request.state) return true;
726
+ const states = Array.isArray(request.state) ? request.state : [request.state];
727
+ return states.includes(task.state);
728
+ }).sort((left, right) => right.priority - left.priority || left.availableAt.localeCompare(right.availableAt)).slice(0, request.limit ?? 50);
729
+ }
730
+ async createReport(request) {
731
+ const record = {
732
+ id: request.id ?? crypto.randomUUID(),
733
+ workDayId: request.workDayId,
734
+ kind: request.kind,
735
+ bodyJson: JSON.stringify(request.body),
736
+ renderedRef: request.renderedRef ?? null,
737
+ sentAt: request.sentAt ?? null,
738
+ createdAt: nowIso()
739
+ };
740
+ this.reports.set(record.id, record);
741
+ return record;
742
+ }
743
+ async getManagerContext(taskId) {
744
+ const task = this.tasks.get(taskId) ?? null;
745
+ const workDay = task ? this.workDays.get(task.workDayId) ?? null : null;
746
+ return {
747
+ task,
748
+ workDay,
749
+ agent: null,
750
+ graph: workDay?.graphVersion ? { graphVersion: workDay.graphVersion } : null
751
+ };
752
+ }
377
753
  }
378
754
  class CloudflareD1AgentDatabase {
379
755
  constructor(db) {
@@ -383,6 +759,7 @@ class CloudflareD1AgentDatabase {
383
759
  this.runs = new RunStore(db);
384
760
  this.cursors = new CursorStore(db);
385
761
  this.leases = new LeaseStore(db);
762
+ this.operational = new OperationalStore(db);
386
763
  }
387
764
  db;
388
765
  subscriptions;
@@ -390,6 +767,7 @@ class CloudflareD1AgentDatabase {
390
767
  runs;
391
768
  cursors;
392
769
  leases;
770
+ operational;
393
771
  async get(request) {
394
772
  if (request.model === "subscription") {
395
773
  return this.subscriptions.getByKey(String(request.id ?? request.slug ?? request.key ?? ""));
@@ -406,23 +784,52 @@ class CloudflareD1AgentDatabase {
406
784
  if (request.model === "content_lease") {
407
785
  return this.leases.getByKey(String(request.id ?? request.key ?? request.slug ?? ""));
408
786
  }
787
+ if (request.model === "work_day") {
788
+ return this.operational.getWorkDay(String(request.id ?? request.key ?? request.slug ?? ""));
789
+ }
790
+ if (request.model === "task") {
791
+ return this.operational.getTask(String(request.id ?? request.key ?? request.slug ?? ""));
792
+ }
793
+ if (request.model === "report") {
794
+ return this.operational.getReport(String(request.id ?? request.key ?? request.slug ?? ""));
795
+ }
409
796
  throw new Error(`Unsupported D1 get model "${request.model}".`);
410
797
  }
411
798
  async search(request) {
799
+ const definition = resolveModelDefinition(request.model);
800
+ const normalizedRequest = {
801
+ ...request,
802
+ filters: normalizeFilterFields(definition, request.filters),
803
+ sort: normalizeSortFields(definition, request.sort)
804
+ };
412
805
  if (request.model === "subscription") {
413
- return this.subscriptions.search(request);
806
+ return this.subscriptions.search(normalizedRequest);
414
807
  }
415
808
  if (request.model === "message") {
416
- return this.messages.search(request);
809
+ return this.messages.search(normalizedRequest);
417
810
  }
418
811
  if (request.model === "agent_run") {
419
- return this.runs.search(request);
812
+ return this.runs.search(normalizedRequest);
420
813
  }
421
814
  if (request.model === "agent_cursor") {
422
- return this.cursors.search(request);
815
+ return this.cursors.search(normalizedRequest);
423
816
  }
424
817
  if (request.model === "content_lease") {
425
- return this.leases.search(request);
818
+ return this.leases.search(normalizedRequest);
819
+ }
820
+ if (request.model === "work_day") {
821
+ return this.operational.searchWorkDays(request.limit);
822
+ }
823
+ if (request.model === "task") {
824
+ return this.operational.searchTasks({
825
+ workDayId: request.filters?.find((entry) => entry.field === "workDayId" || entry.field === "work_day_id")?.value,
826
+ agentId: request.filters?.find((entry) => entry.field === "agentId" || entry.field === "agent_id")?.value,
827
+ state: request.filters?.find((entry) => entry.field === "state")?.value,
828
+ limit: request.limit
829
+ });
830
+ }
831
+ if (request.model === "report") {
832
+ return [];
426
833
  }
427
834
  throw new Error(`Unsupported D1 search model "${request.model}".`);
428
835
  }
@@ -442,7 +849,7 @@ class CloudflareD1AgentDatabase {
442
849
  workerId: request.workerId,
443
850
  messageTypes: request.filters?.filter((filter) => filter.field === "type" && filter.op === "in").flatMap((filter) => Array.isArray(filter.value) ? filter.value.map(String) : []),
444
851
  leaseSeconds: request.leaseSeconds
445
- });
852
+ }, request.strategy);
446
853
  return {
447
854
  item: claimed,
448
855
  leaseToken: claimed ? nextLeaseToken() : null
@@ -452,7 +859,7 @@ class CloudflareD1AgentDatabase {
452
859
  const items = await this.leases.search({
453
860
  model: "content_lease",
454
861
  filters: request.filters,
455
- sort: [{ field: "lease_expires_at", direction: "desc" }],
862
+ sort: pickSortForRequest(request, "lease_expires_at"),
456
863
  limit: 1
457
864
  });
458
865
  return {
@@ -460,58 +867,171 @@ class CloudflareD1AgentDatabase {
460
867
  leaseToken: items[0]?.token ?? null
461
868
  };
462
869
  }
870
+ if (request.model === "task") {
871
+ const items = await this.operational.searchTasks({
872
+ state: "pending",
873
+ limit: 1
874
+ });
875
+ return { item: items[0] ?? null, leaseToken: null };
876
+ }
463
877
  return {
464
- item: null,
878
+ item: (await this.search({
879
+ model: request.model,
880
+ filters: request.filters,
881
+ sort: pickSortForRequest(request, filterSinceField(request.model)),
882
+ limit: 1
883
+ }))[0] ?? null,
465
884
  leaseToken: null
466
885
  };
467
886
  }
468
887
  async create(request) {
888
+ const definition = resolveModelDefinition(request.model);
889
+ const normalizedRequest = {
890
+ ...request,
891
+ data: normalizeMutationData(definition, request.data)
892
+ };
469
893
  if (request.model === "message") {
470
894
  return await this.createMessage({
471
- type: String(request.data.type ?? "message.created"),
472
- payload: request.data.payload ?? request.data,
473
- relatedModel: typeof request.data.relatedModel === "string" ? request.data.relatedModel : null,
474
- relatedId: typeof request.data.relatedId === "string" ? request.data.relatedId : null,
475
- priority: Number(request.data.priority ?? 0),
476
- maxAttempts: Number(request.data.maxAttempts ?? 3),
895
+ type: String(normalizedRequest.data.type ?? "message.created"),
896
+ payload: normalizedRequest.data.payload ?? normalizedRequest.data,
897
+ relatedModel: typeof normalizedRequest.data.related_model === "string" ? normalizedRequest.data.related_model : null,
898
+ relatedId: typeof normalizedRequest.data.related_id === "string" ? normalizedRequest.data.related_id : null,
899
+ priority: Number(normalizedRequest.data.priority ?? 0),
900
+ maxAttempts: Number(normalizedRequest.data.maxAttempts ?? 3),
477
901
  actor: request.actor
478
902
  });
479
903
  }
480
904
  if (request.model === "subscription") {
481
- return await this.subscriptions.create(request);
905
+ return await this.subscriptions.create(normalizedRequest);
482
906
  }
483
907
  if (request.model === "agent_run") {
484
- return await this.runs.record({ run: request.data });
908
+ return await this.runs.record({ run: normalizedRequest.data });
485
909
  }
486
910
  if (request.model === "agent_cursor") {
487
911
  return await this.cursors.update({
488
- ...request,
912
+ ...normalizedRequest,
489
913
  model: "agent_cursor"
490
914
  });
491
915
  }
492
916
  if (request.model === "content_lease") {
493
917
  return await this.leases.update({
494
- ...request,
918
+ ...normalizedRequest,
495
919
  model: "content_lease"
496
920
  });
497
921
  }
922
+ if (request.model === "work_day") {
923
+ return await this.startWorkDay({
924
+ id: typeof normalizedRequest.data.id === "string" ? normalizedRequest.data.id : void 0,
925
+ projectId: String(normalizedRequest.data.projectId ?? normalizedRequest.data.project_id ?? ""),
926
+ capacityBudget: Number(normalizedRequest.data.capacityBudget ?? normalizedRequest.data.capacity_budget ?? 0),
927
+ graphVersion: typeof (normalizedRequest.data.graphVersion ?? normalizedRequest.data.graph_version) === "string" ? String(normalizedRequest.data.graphVersion ?? normalizedRequest.data.graph_version) : null,
928
+ summary: normalizedRequest.data.summary,
929
+ actor: request.actor
930
+ });
931
+ }
932
+ if (request.model === "task") {
933
+ return await this.createTask({
934
+ id: typeof normalizedRequest.data.id === "string" ? normalizedRequest.data.id : void 0,
935
+ workDayId: String(normalizedRequest.data.workDayId ?? normalizedRequest.data.work_day_id ?? ""),
936
+ agentId: String(normalizedRequest.data.agentId ?? normalizedRequest.data.agent_id ?? ""),
937
+ type: String(normalizedRequest.data.type ?? ""),
938
+ state: typeof normalizedRequest.data.state === "string" ? normalizedRequest.data.state : "pending",
939
+ priority: Number(normalizedRequest.data.priority ?? 0),
940
+ idempotencyKey: String(normalizedRequest.data.idempotencyKey ?? normalizedRequest.data.idempotency_key ?? ""),
941
+ payload: normalizedRequest.data.payload ?? normalizedRequest.data,
942
+ payloadHash: typeof (normalizedRequest.data.payloadHash ?? normalizedRequest.data.payload_hash) === "string" ? String(normalizedRequest.data.payloadHash ?? normalizedRequest.data.payload_hash) : null,
943
+ maxAttempts: Number(normalizedRequest.data.maxAttempts ?? normalizedRequest.data.max_attempts ?? 3),
944
+ availableAt: typeof (normalizedRequest.data.availableAt ?? normalizedRequest.data.available_at) === "string" ? String(normalizedRequest.data.availableAt ?? normalizedRequest.data.available_at) : void 0,
945
+ graphVersion: typeof (normalizedRequest.data.graphVersion ?? normalizedRequest.data.graph_version) === "string" ? String(normalizedRequest.data.graphVersion ?? normalizedRequest.data.graph_version) : null,
946
+ parentTaskId: typeof (normalizedRequest.data.parentTaskId ?? normalizedRequest.data.parent_task_id) === "string" ? String(normalizedRequest.data.parentTaskId ?? normalizedRequest.data.parent_task_id) : null,
947
+ actor: request.actor
948
+ });
949
+ }
950
+ if (request.model === "graph_run") {
951
+ return await this.operational.createGraphRun({
952
+ id: String(normalizedRequest.data.id ?? crypto.randomUUID()),
953
+ workDayId: String(normalizedRequest.data.workDayId ?? normalizedRequest.data.work_day_id ?? ""),
954
+ corpusHash: String(normalizedRequest.data.corpusHash ?? normalizedRequest.data.corpus_hash ?? ""),
955
+ graphVersion: String(normalizedRequest.data.graphVersion ?? normalizedRequest.data.graph_version ?? ""),
956
+ queryJson: typeof (normalizedRequest.data.queryJson ?? normalizedRequest.data.query_json) === "string" ? String(normalizedRequest.data.queryJson ?? normalizedRequest.data.query_json) : null,
957
+ seedIdsJson: typeof (normalizedRequest.data.seedIdsJson ?? normalizedRequest.data.seed_ids_json) === "string" ? String(normalizedRequest.data.seedIdsJson ?? normalizedRequest.data.seed_ids_json) : null,
958
+ selectedNodeIdsJson: typeof (normalizedRequest.data.selectedNodeIdsJson ?? normalizedRequest.data.selected_node_ids_json) === "string" ? String(normalizedRequest.data.selectedNodeIdsJson ?? normalizedRequest.data.selected_node_ids_json) : null,
959
+ statsJson: typeof (normalizedRequest.data.statsJson ?? normalizedRequest.data.stats_json) === "string" ? String(normalizedRequest.data.statsJson ?? normalizedRequest.data.stats_json) : null,
960
+ snapshotRef: typeof (normalizedRequest.data.snapshotRef ?? normalizedRequest.data.snapshot_ref) === "string" ? String(normalizedRequest.data.snapshotRef ?? normalizedRequest.data.snapshot_ref) : null,
961
+ createdAt: typeof (normalizedRequest.data.createdAt ?? normalizedRequest.data.created_at) === "string" ? String(normalizedRequest.data.createdAt ?? normalizedRequest.data.created_at) : void 0
962
+ });
963
+ }
964
+ if (request.model === "report") {
965
+ return await this.createReport({
966
+ id: typeof normalizedRequest.data.id === "string" ? normalizedRequest.data.id : void 0,
967
+ workDayId: String(normalizedRequest.data.workDayId ?? normalizedRequest.data.work_day_id ?? ""),
968
+ kind: String(normalizedRequest.data.kind ?? "workday_summary"),
969
+ body: normalizedRequest.data.body ?? normalizedRequest.data,
970
+ renderedRef: typeof (normalizedRequest.data.renderedRef ?? normalizedRequest.data.rendered_ref) === "string" ? String(normalizedRequest.data.renderedRef ?? normalizedRequest.data.rendered_ref) : null,
971
+ sentAt: typeof (normalizedRequest.data.sentAt ?? normalizedRequest.data.sent_at) === "string" ? String(normalizedRequest.data.sentAt ?? normalizedRequest.data.sent_at) : null,
972
+ actor: request.actor
973
+ });
974
+ }
498
975
  throw new Error(`Unsupported D1 create model "${request.model}".`);
499
976
  }
500
977
  async update(request) {
978
+ const definition = resolveModelDefinition(request.model);
979
+ const normalizedRequest = {
980
+ ...request,
981
+ data: normalizeMutationData(definition, request.data)
982
+ };
501
983
  if (request.model === "message") {
502
- return this.messages.update(request);
984
+ return this.messages.update(normalizedRequest);
503
985
  }
504
986
  if (request.model === "subscription") {
505
- return this.subscriptions.update(request);
987
+ return this.subscriptions.update(normalizedRequest);
506
988
  }
507
989
  if (request.model === "agent_run") {
508
- return this.runs.update(request);
990
+ return this.runs.update(normalizedRequest);
509
991
  }
510
992
  if (request.model === "agent_cursor") {
511
- return this.cursors.update(request);
993
+ return this.cursors.update(normalizedRequest);
512
994
  }
513
995
  if (request.model === "content_lease") {
514
- return this.leases.update(request);
996
+ return this.leases.update(normalizedRequest);
997
+ }
998
+ if (request.model === "work_day") {
999
+ return this.closeWorkDay({
1000
+ id: String(request.id ?? request.key ?? normalizedRequest.data.id ?? ""),
1001
+ state: normalizedRequest.data.state ?? "completed",
1002
+ summary: normalizedRequest.data.summary,
1003
+ actor: request.actor
1004
+ });
1005
+ }
1006
+ if (request.model === "task") {
1007
+ const taskId = String(request.id ?? request.key ?? normalizedRequest.data.id ?? "");
1008
+ if (normalizedRequest.data.state === "completed") {
1009
+ return this.completeTask({
1010
+ id: taskId,
1011
+ output: normalizedRequest.data.output,
1012
+ outputRef: typeof normalizedRequest.data.outputRef === "string" ? normalizedRequest.data.outputRef : null,
1013
+ summary: normalizedRequest.data.summary,
1014
+ actor: request.actor
1015
+ });
1016
+ }
1017
+ if (normalizedRequest.data.state === "failed") {
1018
+ return this.failTask({
1019
+ id: taskId,
1020
+ errorCode: typeof normalizedRequest.data.errorCode === "string" ? normalizedRequest.data.errorCode : null,
1021
+ errorMessage: String(normalizedRequest.data.errorMessage ?? "Task failed"),
1022
+ retryable: Boolean(normalizedRequest.data.retryable),
1023
+ nextVisibleAt: typeof normalizedRequest.data.nextVisibleAt === "string" ? normalizedRequest.data.nextVisibleAt : null,
1024
+ actor: request.actor
1025
+ });
1026
+ }
1027
+ return this.recordTaskProgress({
1028
+ id: taskId,
1029
+ workerId: typeof normalizedRequest.data.workerId === "string" ? normalizedRequest.data.workerId : null,
1030
+ state: typeof normalizedRequest.data.state === "string" ? normalizedRequest.data.state : void 0,
1031
+ appendEvent: normalizedRequest.data.appendEvent,
1032
+ patch: normalizedRequest.data.patch,
1033
+ actor: request.actor
1034
+ });
515
1035
  }
516
1036
  throw new Error(`Unsupported D1 update model "${request.model}".`);
517
1037
  }
@@ -542,6 +1062,46 @@ class CloudflareD1AgentDatabase {
542
1062
  releaseAllLeases() {
543
1063
  return this.leases.releaseAll();
544
1064
  }
1065
+ startWorkDay(request) {
1066
+ return this.operational.startWorkDay(request);
1067
+ }
1068
+ closeWorkDay(request) {
1069
+ return this.operational.closeWorkDay(request);
1070
+ }
1071
+ createTask(request) {
1072
+ return this.operational.createTask(request);
1073
+ }
1074
+ claimTask(request) {
1075
+ return this.operational.claimTask(request);
1076
+ }
1077
+ recordTaskProgress(request) {
1078
+ return this.operational.recordTaskProgress(request);
1079
+ }
1080
+ completeTask(request) {
1081
+ return this.operational.completeTask(request);
1082
+ }
1083
+ failTask(request) {
1084
+ return this.operational.failTask(request);
1085
+ }
1086
+ appendTaskEvent(request) {
1087
+ return this.operational.appendTaskEvent(request);
1088
+ }
1089
+ searchTasks(request) {
1090
+ return this.operational.searchTasks(request);
1091
+ }
1092
+ createReport(request) {
1093
+ return this.operational.createReport(request);
1094
+ }
1095
+ async getManagerContext(taskId) {
1096
+ const task = await this.operational.getTask(taskId);
1097
+ const workDay = task ? await this.operational.getWorkDay(task.workDayId) : null;
1098
+ return {
1099
+ task,
1100
+ workDay,
1101
+ agent: null,
1102
+ graph: workDay?.graphVersion ? { graphVersion: workDay.graphVersion } : null
1103
+ };
1104
+ }
545
1105
  }
546
1106
  export {
547
1107
  CloudflareD1AgentDatabase,