@inneranimalmedia/agentsam-sdk 2.6.10 → 2.6.11

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 (261) hide show
  1. package/README.md +3 -0
  2. package/TRADEMARKS.md +22 -0
  3. package/apps/README.md +3 -0
  4. package/apps/cad-creator/LICENSE +21 -0
  5. package/apps/cad-creator/README.md +4 -1
  6. package/apps/cad-creator/shared/cad/package.json +1 -1
  7. package/apps/client-cms-editor/LICENSE +21 -0
  8. package/apps/client-cms-editor/README.md +3 -0
  9. package/apps/client-cms-editor/backend/package.json +2 -2
  10. package/apps/client-cms-editor/frontend/package.json +3 -3
  11. package/apps/client-cms-editor/package-lock.json +43 -43
  12. package/apps/client-cms-editor/package.json +3 -3
  13. package/apps/client-cms-editor/reference/harvest/HARVEST_RECEIPT.json +1 -1
  14. package/apps/client-cms-editor/reference/harvest/README.md +1 -1
  15. package/apps/client-cms-editor/reference/harvest/plans/ARCHIVE-INTAKE.md +1 -1
  16. package/apps/client-cms-editor/reference/harvest/plans/HARVEST-INDEX.md +1 -1
  17. package/apps/client-cms-editor/reference/harvest/plans/TOOLING-LAB.md +1 -1
  18. package/apps/client-cms-editor/shared/cms/package.json +1 -1
  19. package/docs/MINI.md +4 -2
  20. package/docs/REPO_FILE_MAP.txt +0 -1
  21. package/docs/SOURCE_ARCHITECTURE.md +1 -1
  22. package/docs/architecture/DUAL_ANALYTICS_PRODUCT.md +140 -0
  23. package/docs/content-studio/REVISION_GATE_2026-09-27.md +1 -1
  24. package/docs/engineering/go-portability/01-product-project-deployment-authority.md +69 -0
  25. package/docs/engineering/provider-internal-renames/01-lane-initialization.md +20 -0
  26. package/docs/engineering/provider-internal-renames/01a-runtime-environment-contract.md +115 -0
  27. package/docs/engineering/provider-internal-renames/02-cfoa.md +57 -0
  28. package/docs/engineering/provider-internal-renames/03-gclioa.md +32 -0
  29. package/docs/engineering/provider-internal-renames/04-goaude.md +50 -0
  30. package/docs/engineering/provider-internal-renames/05-gdrv.md +33 -0
  31. package/docs/engineering/provider-internal-renames/06-verification.md +103 -0
  32. package/docs/engineering/provider-internal-renames/README.md +77 -0
  33. package/docs/engineering/provider-internal-renames/runtime-environment-contract.json +220 -0
  34. package/docs/engineering/test-diagnostics/go-cli-test-hang-20261003.md +49 -0
  35. package/docs/engineering/test-diagnostics/go-skip-deploy-docker-fix.md +90 -0
  36. package/docs/knowledge-service-verification.md +3 -3
  37. package/docs/plans/AGENTSAM-SUSPEND-QUEUE-KNOWLEDGE-RDP-2026-10-03.md +870 -0
  38. package/docs/plans/LOCAL-STUDIO-GRADUATION-2026-09-26.md +9 -9
  39. package/docs/plans/MACHINE-FIRST-APPS-TUI-2026-09-24.md +11 -11
  40. package/docs/plans/RECONCILIATION-2026-09-19.md +6 -6
  41. package/docs/plans/SAM_WORK_PROTOCOL.md +667 -0
  42. package/docs/plans/TOMORROW-EXTENSIVE-TODO-2026-09-26.md +2 -2
  43. package/docs/plans/UNIVERSAL-INGEST-MACHINE-FIRST-2026-09-24.md +3 -3
  44. package/examples/hyperspace-demo/src/main.tsx +227 -110
  45. package/migrations/d1/0020_agentsam_receipt_catalog.sql +35 -0
  46. package/migrations/runtime/0006_agent_run_suspend_activity.sql +53 -0
  47. package/migrations/runtime/0007_queue_control.sql +40 -0
  48. package/migrations/runtime/0008_agent_run_dependencies.sql +24 -0
  49. package/migrations/runtime/0008_analytics_legacy_bootstrap.sql +43 -0
  50. package/migrations/runtime/0009_analytics_authority.sql +108 -0
  51. package/package.json +26 -11
  52. package/packages/agentsam-brand/README.md +3 -0
  53. package/packages/agentsam-brand/package.json +2 -2
  54. package/packages/agentsam-contracts/dist/adapter.d.ts +22 -0
  55. package/packages/agentsam-contracts/dist/adapter.js +0 -0
  56. package/packages/agentsam-contracts/dist/agent.d.ts +66 -0
  57. package/packages/agentsam-contracts/dist/agent.js +15 -0
  58. package/packages/agentsam-contracts/dist/artifacts.d.ts +70 -0
  59. package/packages/agentsam-contracts/dist/artifacts.js +0 -0
  60. package/packages/agentsam-contracts/dist/authority.d.ts +21 -0
  61. package/packages/agentsam-contracts/dist/authority.js +0 -0
  62. package/packages/agentsam-contracts/dist/context.d.ts +14 -0
  63. package/packages/agentsam-contracts/dist/context.js +0 -0
  64. package/packages/agentsam-contracts/dist/errors.d.ts +121 -0
  65. package/packages/agentsam-contracts/dist/errors.js +5 -0
  66. package/packages/agentsam-contracts/dist/events.d.ts +53 -0
  67. package/packages/agentsam-contracts/dist/events.js +0 -0
  68. package/packages/agentsam-contracts/dist/execution.d.ts +38 -0
  69. package/packages/agentsam-contracts/dist/execution.js +0 -0
  70. package/packages/agentsam-contracts/dist/hooks.d.ts +31 -0
  71. package/packages/agentsam-contracts/dist/hooks.js +0 -0
  72. package/packages/agentsam-contracts/dist/identity.d.ts +15 -0
  73. package/packages/agentsam-contracts/dist/identity.js +0 -0
  74. package/packages/agentsam-contracts/dist/index.d.ts +16 -0
  75. package/packages/agentsam-contracts/dist/index.js +164 -0
  76. package/packages/agentsam-contracts/dist/models.d.ts +9 -0
  77. package/packages/agentsam-contracts/dist/models.js +0 -0
  78. package/packages/agentsam-contracts/dist/providers.d.ts +27 -0
  79. package/packages/agentsam-contracts/dist/providers.js +0 -0
  80. package/packages/agentsam-contracts/dist/repository.d.ts +56 -0
  81. package/packages/agentsam-contracts/dist/repository.js +15 -0
  82. package/packages/agentsam-contracts/dist/run.d.ts +113 -0
  83. package/packages/agentsam-contracts/dist/run.js +132 -0
  84. package/packages/agentsam-contracts/dist/tools.d.ts +82 -0
  85. package/packages/agentsam-contracts/dist/tools.js +0 -0
  86. package/packages/agentsam-contracts/dist/widgets.d.ts +38 -0
  87. package/packages/agentsam-contracts/dist/widgets.js +0 -0
  88. package/packages/agentsam-contracts/package.json +9 -1
  89. package/packages/agentsam-contracts/scripts/build.mjs +1 -1
  90. package/packages/agentsam-contracts/src/agent.ts +78 -3
  91. package/packages/agentsam-contracts/src/index.ts +2 -0
  92. package/packages/agentsam-contracts/src/run.ts +320 -0
  93. package/packages/agentsam-contracts/src/widgets.ts +58 -0
  94. package/packages/agentsam-contracts/test/contracts.test.mjs +1 -1
  95. package/packages/agentsam-contracts/test/run-contract.test.mjs +94 -0
  96. package/packages/agentsam-errors/package.json +1 -1
  97. package/packages/agentsam-goap/README.md +3 -0
  98. package/packages/agentsam-goap/package.json +2 -2
  99. package/packages/agentsam-hooks/package.json +2 -2
  100. package/packages/agentsam-hooks/src/adapters/agents.js +48 -22
  101. package/packages/agentsam-hooks/src/index.d.ts +16 -0
  102. package/packages/agentsam-knowledge/package.json +1 -1
  103. package/packages/agentsam-knowledge/src/backends/index.js +1 -1
  104. package/packages/agentsam-merch/README.md +62 -0
  105. package/packages/agentsam-merch/bin/agentsam-merch.mjs +16 -0
  106. package/packages/agentsam-merch/package.json +65 -0
  107. package/packages/agentsam-merch/profiles/completeful/dtg-back-large.json +42 -0
  108. package/packages/agentsam-merch/profiles/completeful/laser-engraving.json +39 -0
  109. package/packages/agentsam-merch/profiles/generic/embroidery-digitization.json +22 -0
  110. package/packages/agentsam-merch/schemas/collection-candidate.schema.json +66 -0
  111. package/packages/agentsam-merch/schemas/manufacturing-profile.schema.json +221 -0
  112. package/packages/agentsam-merch/src/adapters-completeful.js +50 -0
  113. package/packages/agentsam-merch/src/cli.js +93 -0
  114. package/packages/agentsam-merch/src/collection-lab.js +60 -0
  115. package/packages/agentsam-merch/src/compatibility.js +501 -0
  116. package/packages/agentsam-merch/src/derivatives.js +112 -0
  117. package/packages/agentsam-merch/src/index.d.ts +316 -0
  118. package/packages/agentsam-merch/src/index.js +46 -0
  119. package/packages/agentsam-merch/src/node/index.d.ts +58 -0
  120. package/packages/agentsam-merch/src/node/index.js +6 -0
  121. package/packages/agentsam-merch/src/node/raster.js +142 -0
  122. package/packages/agentsam-merch/src/node/vector.js +239 -0
  123. package/packages/agentsam-merch/src/product-concepts.js +118 -0
  124. package/packages/agentsam-merch/src/profile-registry.js +104 -0
  125. package/packages/agentsam-merch/src/profile.js +158 -0
  126. package/packages/agentsam-merch/src/transforms.js +215 -0
  127. package/packages/agentsam-merch/test/merch.test.mjs +332 -0
  128. package/packages/agentsam-merch/test/node-transforms.test.mjs +149 -0
  129. package/packages/agentsam-nav/dist/browser.global.js +71 -34
  130. package/packages/agentsam-nav/dist/browser.js +3179 -781
  131. package/packages/agentsam-nav/dist/index.js +3171 -773
  132. package/packages/agentsam-nav/package.json +1 -1
  133. package/packages/agentsam-queue-control/README.md +4 -1
  134. package/packages/agentsam-queue-control/package.json +4 -3
  135. package/packages/agentsam-queue-control/schemas/job-envelope.schema.json +111 -11
  136. package/packages/agentsam-queue-control/src/adapters/cloudflare.js +34 -6
  137. package/packages/agentsam-queue-control/src/adapters/memory.js +11 -2
  138. package/packages/agentsam-queue-control/src/adapters/sqlite.js +259 -0
  139. package/packages/agentsam-queue-control/src/contracts.js +207 -3
  140. package/packages/agentsam-queue-control/src/control-plane.js +62 -2
  141. package/packages/agentsam-queue-control/src/index.js +1 -0
  142. package/packages/agentsam-queue-control/test/queue-control.test.mjs +310 -0
  143. package/packages/agentsam-queue-control/test/sqlite-adapter.test.mjs +91 -0
  144. package/packages/agentsam-rapid-rust/README.md +3 -0
  145. package/packages/agentsam-repository/README.md +3 -0
  146. package/packages/agentsam-repository/package.json +1 -1
  147. package/packages/agentsam-vault/package.json +1 -1
  148. package/packages/agentsam-workbench/README.md +43 -0
  149. package/packages/agentsam-workbench/package.json +13 -3
  150. package/packages/agentsam-workbench/src/agent/AgentConversationSurface.tsx +108 -0
  151. package/packages/agentsam-workbench/src/agent/AgentPanel.tsx +25 -8
  152. package/packages/agentsam-workbench/src/agent/AgentRuntimeField.tsx +152 -0
  153. package/packages/agentsam-workbench/src/agent/Composer.tsx +10 -1
  154. package/packages/agentsam-workbench/src/agent/RunMode.ts +26 -0
  155. package/packages/agentsam-workbench/src/agent/Thread.tsx +18 -3
  156. package/packages/agentsam-workbench/src/agent/index.ts +3 -0
  157. package/packages/agentsam-workbench/src/index.ts +4 -0
  158. package/packages/agentsam-workbench/src/manufacturing/PreflightIndicator.tsx +203 -0
  159. package/packages/agentsam-workbench/src/manufacturing/index.ts +2 -0
  160. package/packages/agentsam-workbench/src/manufacturing/loading.ts +147 -0
  161. package/packages/agentsam-workbench/src/widgets/BuiltinWidget.tsx +22 -0
  162. package/packages/agentsam-workbench/src/widgets/CountdownWidget.tsx +68 -0
  163. package/packages/agentsam-workbench/src/widgets/WidgetFrame.tsx +56 -0
  164. package/packages/agentsam-workbench/src/widgets/countdown.ts +25 -0
  165. package/packages/agentsam-workbench/src/widgets/index.ts +6 -0
  166. package/packages/agentsam-workbench/src/widgets/registry.ts +13 -0
  167. package/packages/agentsam-workbench/src/widgets/useCountdown.ts +128 -0
  168. package/packages/agentsam-workbench/src/widgets/widgets.css +102 -0
  169. package/packages/connectors/{cloudflare → cfoa}/package.json +3 -3
  170. package/packages/heuristic-theme/package.json +1 -1
  171. package/packages/identity/README.md +3 -0
  172. package/packages/identity/backend/README.md +3 -0
  173. package/packages/identity/package.json +1 -1
  174. package/packages/identity/src/frontend/auth-portal/README.md +3 -0
  175. package/packages/identity/src/index.js +1 -1
  176. package/packages/identity/src/oauth/README.md +4 -1
  177. package/packages/identity/src/oauth/credentials.js +1 -1
  178. package/packages/identity/src/server/worker-router.js +1 -1
  179. package/packages/identity/tests/google-desktop-identity-login.test.mjs +1 -1
  180. package/packages/identity/tests/lane1-packed-consumer.test.mjs +1 -1
  181. package/packages/identity/tests/oauth-presets-accounts-ssot.test.mjs +1 -1
  182. package/packages/providers/completeful/package.json +1 -1
  183. package/packages/theme-church-site/package.json +1 -1
  184. package/packages/theme-companions-site/package.json +1 -1
  185. package/packages/theme-floors-site/package.json +1 -1
  186. package/packages/theme-fuelnfree-site/package.json +1 -1
  187. package/packages/theme-handyman-site/package.json +1 -1
  188. package/packages/theme-insurance-site/package.json +1 -1
  189. package/packages/theme-scenes/package.json +1 -1
  190. package/packages/theme-shinshu-site/package.json +1 -1
  191. package/packages/work-graph/package.json +1 -1
  192. package/protocol/models/README.md +3 -0
  193. package/protocol/receipts/agentsam.receipt.v1.json +95 -0
  194. package/protocol/theme-refinery/receipts/products-registry-batch-20260924.json +6 -6
  195. package/protocol/theme-refinery/receipts/theme-harvest-20260924.json +6 -6
  196. package/skills/README.md +3 -0
  197. package/src/acp/agent-executor.js +106 -0
  198. package/src/acp/client.js +316 -0
  199. package/src/acp/dependencies.js +426 -0
  200. package/src/acp/http.js +207 -0
  201. package/src/acp/index.js +22 -0
  202. package/src/acp/runs.js +125 -0
  203. package/src/acp/runtime-selection.js +180 -0
  204. package/src/cli/command-catalog.js +3 -0
  205. package/src/cli.js +24 -0
  206. package/src/commands/cloudflare-login.js +1 -1
  207. package/src/commands/cloudflare.js +2 -2
  208. package/src/commands/connections.js +1 -1
  209. package/src/commands/go.js +76 -6
  210. package/src/commands/merch.js +5 -0
  211. package/src/commands/mini.js +1 -1
  212. package/src/commands/receipts.js +140 -0
  213. package/src/commands/run.js +253 -0
  214. package/src/go/container.js +1 -1
  215. package/src/go/contract.js +61 -18
  216. package/src/go/discover.js +0 -4
  217. package/src/go/index.js +13 -1
  218. package/src/go/probe.js +109 -0
  219. package/src/go/{cloudflare.js → providers/cloudflare.js} +36 -136
  220. package/src/go/verify.js +1 -1
  221. package/src/indexing/ingest/inventory.js +1 -1
  222. package/src/lib/deploy/local-studio.js +2 -2
  223. package/src/lib/mini/scaffold.js +1 -1
  224. package/src/lib/whoami-capabilities.js +1 -1
  225. package/src/local/runtime-store.js +8 -0
  226. package/src/mcp/cloudflare-bundles.js +1 -1
  227. package/src/plugins/index.js +1 -0
  228. package/src/plugins/registry.js +59 -6
  229. package/src/receipts/contract.js +68 -0
  230. package/src/receipts/index.js +20 -0
  231. package/src/receipts/prune.js +64 -0
  232. package/src/receipts/sinks.js +285 -0
  233. package/templates/mini/gadget/app.js +15 -40
  234. package/templates/mini/gadget/index.html +7 -7
  235. package/templates/mini/shared/style.css +1 -1
  236. package/packages/agentsam-repository/src/goap.js.bak-20260922011251 +0 -670
  237. /package/packages/connectors/{cloudflare → cfoa}/OAUTH_STORAGE_AUDIT.md +0 -0
  238. /package/packages/connectors/{cloudflare → cfoa}/src/api-client.js +0 -0
  239. /package/packages/connectors/{cloudflare → cfoa}/src/capabilities.js +0 -0
  240. /package/packages/connectors/{cloudflare → cfoa}/src/credential.js +0 -0
  241. /package/packages/connectors/{cloudflare → cfoa}/src/families/brand-protection.js +0 -0
  242. /package/packages/connectors/{cloudflare → cfoa}/src/families/keyless.js +0 -0
  243. /package/packages/connectors/{cloudflare → cfoa}/src/families/pages.js +0 -0
  244. /package/packages/connectors/{cloudflare → cfoa}/src/families/scanner.js +0 -0
  245. /package/packages/connectors/{cloudflare → cfoa}/src/families/snippets.js +0 -0
  246. /package/packages/connectors/{cloudflare → cfoa}/src/families/tag-gateway.js +0 -0
  247. /package/packages/connectors/{cloudflare → cfoa}/src/families/tags.js +0 -0
  248. /package/packages/connectors/{cloudflare → cfoa}/src/families/token-validation.js +0 -0
  249. /package/packages/connectors/{cloudflare → cfoa}/src/families/vectorize.js +0 -0
  250. /package/packages/connectors/{cloudflare → cfoa}/src/families/workflows.js +0 -0
  251. /package/packages/connectors/{cloudflare → cfoa}/src/index.js +0 -0
  252. /package/packages/connectors/{cloudflare → cfoa}/src/oauth-persist.js +0 -0
  253. /package/packages/connectors/{cloudflare → cfoa}/src/owner.js +0 -0
  254. /package/packages/connectors/{cloudflare → cfoa}/src/permission-options.js +0 -0
  255. /package/packages/connectors/{cloudflare → cfoa}/src/routes.js +0 -0
  256. /package/packages/connectors/{cloudflare → cfoa}/src/scope-catalog.js +0 -0
  257. /package/packages/connectors/{cloudflare → cfoa}/src/vault.js +0 -0
  258. /package/packages/connectors/{cloudflare → cfoa}/tests/capabilities.test.mjs +0 -0
  259. /package/packages/connectors/{cloudflare → cfoa}/tests/connector.test.mjs +0 -0
  260. /package/packages/connectors/{cloudflare → cfoa}/tests/oauth-persist.test.mjs +0 -0
  261. /package/packages/identity/src/oauth/{google-desktop-exchange.js → goaude.js} +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inneranimalmedia/agentsam-nav",
3
- "version": "2.6.10",
3
+ "version": "2.6.11",
4
4
  "private": false,
5
5
  "description": "Reusable responsive navigation primitives for AgentSam dashboard-family applications.",
6
6
  "type": "module",
@@ -11,7 +11,7 @@ The package deliberately separates four concerns:
11
11
 
12
12
  ## Goals
13
13
 
14
- - Cloudflare-first without Cloudflare lock-in.
14
+ - Runs well on Cloudflare without Cloudflare lock-in.
15
15
  - One stable job envelope across CAD, code indexing, CMS, commerce, deployment, webhook, batch-AI, and future worker types.
16
16
  - Logical queues stay stable while physical topology can start compact and split later.
17
17
  - Deterministic routing keeps LLMs out of timers, polling loops, retries, and ordinary scheduling.
@@ -105,3 +105,6 @@ Queue Control does not replace `@inneranimalmedia/agentsam-work-graph`. A WorkGr
105
105
  ## Relationship to AgentSam tools and MCP
106
106
 
107
107
  The canonical capability/tool contract should sit above transports. A tool may be called inline, queued, from a WorkGraph, from a hook, from CLI, or exposed through MCP. Queue Control only owns execution routing and job lifecycle semantics.
108
+
109
+ <!-- agentsam:trademark-notice -->
110
+ > Independent project. Not affiliated with, endorsed by, or sponsored by Cloudflare, Inc. or by any other company whose products are named here. Cloudflare is a registered trademark of Cloudflare, Inc. Other names are trademarks of their respective owners. See [TRADEMARKS](https://github.com/SamPrimeaux/agentsam-sdk/blob/main/TRADEMARKS.md).
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@inneranimalmedia/agentsam-queue-control",
3
- "version": "2.6.10",
4
- "description": "Portable AgentSam queue, job-routing, batching, and execution-control primitives with Cloudflare-first adapters.",
3
+ "version": "2.6.11",
4
+ "description": "Portable AgentSam queue, job-routing, retry, scheduling, and execution-control primitives with provider adapters.",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
7
7
  "exports": {
@@ -11,7 +11,8 @@
11
11
  "./topology": "./src/topology.js",
12
12
  "./dispatch": "./src/dispatch.js",
13
13
  "./adapters/memory": "./src/adapters/memory.js",
14
- "./adapters/cloudflare": "./src/adapters/cloudflare.js"
14
+ "./adapters/cloudflare": "./src/adapters/cloudflare.js",
15
+ "./adapters/sqlite": "./src/adapters/sqlite.js"
15
16
  },
16
17
  "files": [
17
18
  "src",
@@ -14,11 +14,27 @@
14
14
  "created_at"
15
15
  ],
16
16
  "properties": {
17
- "schema_version": { "const": "1" },
18
- "id": { "type": "string", "minLength": 1 },
19
- "account_id": { "type": "string", "minLength": 1 },
20
- "kind": { "type": "string", "minLength": 1 },
21
- "logical_queue": { "type": ["string", "null"] },
17
+ "schema_version": {
18
+ "const": "1"
19
+ },
20
+ "id": {
21
+ "type": "string",
22
+ "minLength": 1
23
+ },
24
+ "account_id": {
25
+ "type": "string",
26
+ "minLength": 1
27
+ },
28
+ "kind": {
29
+ "type": "string",
30
+ "minLength": 1
31
+ },
32
+ "logical_queue": {
33
+ "type": [
34
+ "string",
35
+ "null"
36
+ ]
37
+ },
22
38
  "executor": {
23
39
  "enum": [
24
40
  "inline",
@@ -31,7 +47,14 @@
31
47
  "external"
32
48
  ]
33
49
  },
34
- "priority": { "enum": ["low", "normal", "high", "urgent"] },
50
+ "priority": {
51
+ "enum": [
52
+ "low",
53
+ "normal",
54
+ "high",
55
+ "urgent"
56
+ ]
57
+ },
35
58
  "status": {
36
59
  "enum": [
37
60
  "queued",
@@ -40,17 +63,94 @@
40
63
  "waiting",
41
64
  "batch_waiting",
42
65
  "awaiting_input",
66
+ "retry_scheduled",
43
67
  "completed",
44
68
  "failed",
45
69
  "cancelled"
46
70
  ]
47
71
  },
48
72
  "payload": {},
49
- "payload_ref": { "type": ["string", "null"] },
50
- "metadata": { "type": "object" },
51
- "retry": { "type": "object" },
52
- "attempt": { "type": "integer", "minimum": 0 },
53
- "created_at": { "type": "integer", "minimum": 0 }
73
+ "payload_ref": {
74
+ "type": [
75
+ "string",
76
+ "null"
77
+ ]
78
+ },
79
+ "metadata": {
80
+ "type": "object"
81
+ },
82
+ "retry": {
83
+ "type": "object",
84
+ "properties": {
85
+ "max_attempts": {
86
+ "type": "integer",
87
+ "minimum": 1
88
+ },
89
+ "backoff": {
90
+ "enum": [
91
+ "fixed",
92
+ "exponential"
93
+ ]
94
+ },
95
+ "initial_delay_ms": {
96
+ "type": "integer",
97
+ "minimum": 0
98
+ },
99
+ "max_delay_ms": {
100
+ "type": "integer",
101
+ "minimum": 0
102
+ },
103
+ "jitter": {
104
+ "type": "boolean"
105
+ }
106
+ },
107
+ "additionalProperties": true
108
+ },
109
+ "attempt": {
110
+ "type": "integer",
111
+ "minimum": 0
112
+ },
113
+ "created_at": {
114
+ "type": "integer",
115
+ "minimum": 0
116
+ },
117
+ "available_at": {
118
+ "type": "integer",
119
+ "minimum": 0
120
+ },
121
+ "source_run_id": {
122
+ "type": [
123
+ "string",
124
+ "null"
125
+ ]
126
+ },
127
+ "step_id": {
128
+ "type": [
129
+ "string",
130
+ "null"
131
+ ]
132
+ },
133
+ "idempotency_key": {
134
+ "type": "string",
135
+ "minLength": 1
136
+ },
137
+ "lease_owner": {
138
+ "type": [
139
+ "string",
140
+ "null"
141
+ ]
142
+ },
143
+ "lease_expires_at": {
144
+ "type": [
145
+ "integer",
146
+ "null"
147
+ ],
148
+ "minimum": 0
149
+ },
150
+ "lease_generation": {
151
+ "type": "integer",
152
+ "minimum": 0
153
+ }
54
154
  },
55
155
  "additionalProperties": true
56
156
  }
@@ -6,6 +6,19 @@ function uniquePhysicalQueueNames(topology) {
6
6
  return [...new Set(Object.values(topology?.routes || {}).filter(Boolean))];
7
7
  }
8
8
 
9
+ const MAX_CLOUDFLARE_DELAY_SECONDS = 86_400;
10
+
11
+ export function delaySecondsForAvailableAt(availableAt, now = Math.floor(Date.now() / 1000)) {
12
+ if (availableAt == null) return 0;
13
+ const delay = Math.max(0, Math.ceil(Number(availableAt) - Number(now)));
14
+ if (delay > MAX_CLOUDFLARE_DELAY_SECONDS) {
15
+ const error = new RangeError('cloudflare_queue_delay_exceeds_24h');
16
+ error.code = 'delay_exceeds_provider_limit';
17
+ throw error;
18
+ }
19
+ return delay;
20
+ }
21
+
9
22
  export class CloudflareQueueBindingAdapter {
10
23
  constructor({ bindings = {} } = {}) {
11
24
  this.bindings = bindings;
@@ -20,16 +33,25 @@ export class CloudflareQueueBindingAdapter {
20
33
  }
21
34
 
22
35
  async publish(queue, job, options = {}) {
23
- await this.resolve(queue).send(job, options.send_options);
24
- return { provider: 'cloudflare-binding', queue, accepted: 1 };
36
+ const sendOptions = { ...(options.send_options || {}) };
37
+ const delaySeconds = delaySecondsForAvailableAt(job.available_at, options.now);
38
+ if (delaySeconds > 0) sendOptions.delaySeconds = delaySeconds;
39
+ await this.resolve(queue).send(job, Object.keys(sendOptions).length ? sendOptions : undefined);
40
+ return { provider: 'cloudflare-binding', queue, accepted: 1, delay_seconds: delaySeconds };
25
41
  }
26
42
 
27
- async publishBatch(queue, jobs) {
43
+ async publishBatch(queue, jobs, options = {}) {
28
44
  const binding = this.resolve(queue);
29
45
  if (typeof binding.sendBatch === 'function') {
30
- await binding.sendBatch(jobs.map((body) => ({ body })));
46
+ await binding.sendBatch(jobs.map((body) => {
47
+ const delaySeconds = delaySecondsForAvailableAt(body.available_at, options.now);
48
+ return delaySeconds > 0 ? { body, delaySeconds } : { body };
49
+ }));
31
50
  } else {
32
- await Promise.all(jobs.map((job) => binding.send(job)));
51
+ await Promise.all(jobs.map((job) => {
52
+ const delaySeconds = delaySecondsForAvailableAt(job.available_at, options.now);
53
+ return binding.send(job, delaySeconds > 0 ? { delaySeconds } : undefined);
54
+ }));
33
55
  }
34
56
  return { provider: 'cloudflare-binding', queue, accepted: jobs.length };
35
57
  }
@@ -91,6 +113,7 @@ export class CloudflareQueueApiAdapter {
91
113
  max_retries = 3,
92
114
  retry_delay = 5,
93
115
  max_concurrency,
116
+ dead_letter_queue = null,
94
117
  } = {}) {
95
118
  if (!script_name) throw new TypeError('script_name is required');
96
119
  const settings = {
@@ -109,6 +132,7 @@ export class CloudflareQueueApiAdapter {
109
132
  body: JSON.stringify({
110
133
  type: 'worker',
111
134
  script_name,
135
+ ...(dead_letter_queue ? { dead_letter_queue } : {}),
112
136
  settings,
113
137
  }),
114
138
  });
@@ -134,7 +158,11 @@ export class CloudflareQueueApiAdapter {
134
158
  if (consumer?.script_name) {
135
159
  const queueId = queue.queue_id ?? queue.id;
136
160
  if (!queueId) throw new Error(`cloudflare_queue_id_missing:${queueName}`);
137
- await this.attachWorkerConsumer(queueId, consumer);
161
+ const physical = Object.values(topology.physical || {}).find((entry) => entry?.name === queueName);
162
+ await this.attachWorkerConsumer(queueId, {
163
+ ...consumer,
164
+ dead_letter_queue: consumer.dead_letter_queue || physical?.dead_letter || null,
165
+ });
138
166
  }
139
167
  }
140
168
 
@@ -18,8 +18,17 @@ export class MemoryQueueAdapter {
18
18
  return { provider: 'memory', queue, accepted: jobs.length };
19
19
  }
20
20
 
21
- async pull(queue, max = 1) {
22
- return this.#queue(queue).splice(0, Math.max(0, Number(max) || 1));
21
+ async pull(queue, max = 1, { now = Math.floor(Date.now() / 1000) } = {}) {
22
+ const items = this.#queue(queue);
23
+ const limit = Math.max(0, Number(max) || 1);
24
+ const ready = [];
25
+ const pending = [];
26
+ for (const item of items) {
27
+ if (ready.length < limit && (item.available_at ?? 0) <= now) ready.push(item);
28
+ else pending.push(item);
29
+ }
30
+ this.queues.set(queue, pending);
31
+ return ready;
23
32
  }
24
33
 
25
34
  async ensureTopology(topology) {
@@ -0,0 +1,259 @@
1
+ import { assertJobEnvelope } from '../contracts.js';
2
+
3
+ function rows(result) {
4
+ if (Array.isArray(result)) return result;
5
+ if (Array.isArray(result?.results)) return result.results;
6
+ return [];
7
+ }
8
+
9
+ function changes(result) {
10
+ if (Number.isFinite(Number(result?.changes))) return Number(result.changes);
11
+ if (Number.isFinite(Number(result?.meta?.changes))) return Number(result.meta.changes);
12
+ return 0;
13
+ }
14
+
15
+ function clean(value) {
16
+ return value == null ? '' : String(value).trim();
17
+ }
18
+
19
+ function parseJob(row) {
20
+ if (!row) return null;
21
+ const body = JSON.parse(row.job_json);
22
+ return {
23
+ ...body,
24
+ status: row.status,
25
+ available_at: Number(row.available_at),
26
+ attempt: Number(row.attempt),
27
+ lease_owner: row.lease_owner || null,
28
+ lease_expires_at: row.lease_expires_at == null ? null : Number(row.lease_expires_at),
29
+ lease_generation: Number(row.lease_generation || 0),
30
+ };
31
+ }
32
+
33
+ const PRIORITY_SQL = "CASE priority WHEN 'urgent' THEN 4 WHEN 'high' THEN 3 WHEN 'normal' THEN 2 ELSE 1 END";
34
+
35
+ /**
36
+ * Durable provider-neutral queue adapter over AgentSam's D1-shaped DB contract.
37
+ * Local SQLite is the reference host; other hosts may supply the same prepare/bind API.
38
+ */
39
+ export class SqliteQueueAdapter {
40
+ constructor({
41
+ database,
42
+ leaseOwner = 'sqlite-' + process.pid,
43
+ leaseTtlSeconds = 60,
44
+ } = {}) {
45
+ if (!database || typeof database.prepare !== 'function') {
46
+ throw new TypeError('database with prepare() is required');
47
+ }
48
+ this.database = database;
49
+ this.leaseOwner = clean(leaseOwner) || ('sqlite-' + process.pid);
50
+ this.leaseTtlSeconds = Math.max(1, Number(leaseTtlSeconds) || 60);
51
+ }
52
+
53
+ async publish(queue, job) {
54
+ assertJobEnvelope(job);
55
+ const physicalQueue = clean(queue);
56
+ if (!physicalQueue) throw new TypeError('queue is required');
57
+
58
+ const existing = await this.database.prepare(
59
+ 'SELECT id, status FROM agentsam_queue_job WHERE account_id = ? AND idempotency_key = ? LIMIT 1'
60
+ ).bind(job.account_id, job.idempotency_key).first();
61
+
62
+ if (existing && existing.id !== job.id) {
63
+ return {
64
+ provider: 'sqlite',
65
+ queue: physicalQueue,
66
+ accepted: 0,
67
+ deduplicated: true,
68
+ existing_job_id: existing.id,
69
+ existing_status: existing.status,
70
+ };
71
+ }
72
+
73
+ const maxAttempts = Math.max(1, Number(job.retry?.max_attempts) || 3);
74
+ const now = Math.floor(Date.now() / 1000);
75
+ const sql = [
76
+ 'INSERT INTO agentsam_queue_job (',
77
+ 'id, account_id, physical_queue, logical_queue, kind, status, priority,',
78
+ 'available_at, attempt, max_attempts, idempotency_key, source_run_id,',
79
+ 'step_id, lease_owner, lease_expires_at, lease_generation, job_json,',
80
+ 'created_at_unix, updated_at_unix',
81
+ ') VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
82
+ 'ON CONFLICT(id) DO UPDATE SET',
83
+ 'physical_queue = excluded.physical_queue,',
84
+ 'logical_queue = excluded.logical_queue,',
85
+ 'kind = excluded.kind,',
86
+ 'status = excluded.status,',
87
+ 'priority = excluded.priority,',
88
+ 'available_at = excluded.available_at,',
89
+ 'attempt = excluded.attempt,',
90
+ 'max_attempts = excluded.max_attempts,',
91
+ 'source_run_id = excluded.source_run_id,',
92
+ 'step_id = excluded.step_id,',
93
+ 'lease_owner = excluded.lease_owner,',
94
+ 'lease_expires_at = excluded.lease_expires_at,',
95
+ 'lease_generation = excluded.lease_generation,',
96
+ 'job_json = excluded.job_json,',
97
+ 'result_json = NULL, error_json = NULL, completed_at_unix = NULL,',
98
+ 'updated_at_unix = excluded.updated_at_unix'
99
+ ].join(' ');
100
+
101
+ await this.database.prepare(sql).bind(
102
+ job.id,
103
+ job.account_id,
104
+ physicalQueue,
105
+ job.logical_queue,
106
+ job.kind,
107
+ job.status,
108
+ job.priority,
109
+ job.available_at,
110
+ job.attempt,
111
+ maxAttempts,
112
+ job.idempotency_key,
113
+ job.source_run_id,
114
+ job.step_id,
115
+ job.lease_owner,
116
+ job.lease_expires_at,
117
+ job.lease_generation || 0,
118
+ JSON.stringify(job),
119
+ job.created_at || now,
120
+ now,
121
+ ).run();
122
+
123
+ return { provider: 'sqlite', queue: physicalQueue, accepted: 1, deduplicated: false };
124
+ }
125
+
126
+ async publishBatch(queue, jobs) {
127
+ let accepted = 0;
128
+ let deduplicated = 0;
129
+ for (const job of jobs) {
130
+ const result = await this.publish(queue, job);
131
+ accepted += Number(result.accepted || 0);
132
+ if (result.deduplicated) deduplicated += 1;
133
+ }
134
+ return { provider: 'sqlite', queue, accepted, deduplicated };
135
+ }
136
+
137
+ async pull(queue, max = 1, {
138
+ now = Math.floor(Date.now() / 1000),
139
+ owner = this.leaseOwner,
140
+ ttl_seconds = this.leaseTtlSeconds,
141
+ } = {}) {
142
+ const physicalQueue = clean(queue);
143
+ const leaseOwner = clean(owner);
144
+ if (!physicalQueue) throw new TypeError('queue is required');
145
+ if (!leaseOwner) throw new TypeError('lease owner is required');
146
+
147
+ const limit = Math.max(1, Math.floor(Number(max) || 1));
148
+ const ttl = Math.max(1, Math.floor(Number(ttl_seconds) || this.leaseTtlSeconds));
149
+ const selectSql = [
150
+ 'SELECT * FROM agentsam_queue_job',
151
+ 'WHERE physical_queue = ?',
152
+ "AND status IN ('queued','retry_scheduled','waiting','claimed')",
153
+ 'AND available_at <= ?',
154
+ 'AND (lease_expires_at IS NULL OR lease_expires_at <= ?)',
155
+ 'ORDER BY ' + PRIORITY_SQL + ' DESC, available_at ASC, created_at_unix ASC',
156
+ 'LIMIT ?'
157
+ ].join(' ');
158
+
159
+ const result = await this.database.prepare(selectSql).bind(
160
+ physicalQueue, now, now, limit
161
+ ).all();
162
+
163
+ const claimed = [];
164
+ for (const row of rows(result)) {
165
+ const leaseExpiresAt = now + ttl;
166
+ const updateSql = [
167
+ "UPDATE agentsam_queue_job SET status = 'claimed',",
168
+ 'lease_owner = ?, lease_expires_at = ?,',
169
+ 'lease_generation = lease_generation + 1, updated_at_unix = ?',
170
+ 'WHERE id = ?',
171
+ "AND status IN ('queued','retry_scheduled','waiting','claimed')",
172
+ 'AND available_at <= ?',
173
+ 'AND (lease_expires_at IS NULL OR lease_expires_at <= ?)'
174
+ ].join(' ');
175
+ const update = await this.database.prepare(updateSql).bind(
176
+ leaseOwner, leaseExpiresAt, now, row.id, now, now
177
+ ).run();
178
+
179
+ if (changes(update) !== 1) continue;
180
+ const current = await this.database.prepare(
181
+ 'SELECT * FROM agentsam_queue_job WHERE id = ? LIMIT 1'
182
+ ).bind(row.id).first();
183
+ if (current) claimed.push(parseJob(current));
184
+ }
185
+ return claimed;
186
+ }
187
+
188
+ async ack(jobOrId, {
189
+ status = 'completed',
190
+ result = null,
191
+ error = null,
192
+ now = Math.floor(Date.now() / 1000),
193
+ } = {}) {
194
+ const id = typeof jobOrId === 'string' ? jobOrId : jobOrId?.id;
195
+ if (!clean(id)) throw new TypeError('job id is required');
196
+ const sql = [
197
+ 'UPDATE agentsam_queue_job SET status = ?,',
198
+ 'lease_owner = NULL, lease_expires_at = NULL,',
199
+ 'result_json = ?, error_json = ?, completed_at_unix = ?, updated_at_unix = ?',
200
+ 'WHERE id = ?'
201
+ ].join(' ');
202
+ const update = await this.database.prepare(sql).bind(
203
+ status,
204
+ result == null ? null : JSON.stringify(result),
205
+ error == null ? null : JSON.stringify(error),
206
+ now,
207
+ now,
208
+ id,
209
+ ).run();
210
+ return { provider: 'sqlite', job_id: id, status, updated: changes(update) };
211
+ }
212
+
213
+ async release(jobOrId, {
214
+ status = 'queued',
215
+ available_at = Math.floor(Date.now() / 1000),
216
+ now = Math.floor(Date.now() / 1000),
217
+ } = {}) {
218
+ const id = typeof jobOrId === 'string' ? jobOrId : jobOrId?.id;
219
+ if (!clean(id)) throw new TypeError('job id is required');
220
+ const sql = [
221
+ 'UPDATE agentsam_queue_job SET status = ?, available_at = ?,',
222
+ 'lease_owner = NULL, lease_expires_at = NULL, updated_at_unix = ?',
223
+ 'WHERE id = ?'
224
+ ].join(' ');
225
+ const update = await this.database.prepare(sql).bind(
226
+ status, available_at, now, id
227
+ ).run();
228
+ return { provider: 'sqlite', job_id: id, status, updated: changes(update), available_at };
229
+ }
230
+
231
+ async get(id) {
232
+ const row = await this.database.prepare(
233
+ 'SELECT * FROM agentsam_queue_job WHERE id = ? LIMIT 1'
234
+ ).bind(id).first();
235
+ return parseJob(row);
236
+ }
237
+
238
+ async depth(queue, { now = null, includeTerminal = false } = {}) {
239
+ const clauses = ['physical_queue = ?'];
240
+ const values = [queue];
241
+ if (!includeTerminal) clauses.push("status NOT IN ('completed','failed','cancelled')");
242
+ if (now != null) {
243
+ clauses.push('available_at <= ?');
244
+ values.push(now);
245
+ }
246
+ const sql = 'SELECT COUNT(*) AS count FROM agentsam_queue_job WHERE ' + clauses.join(' AND ');
247
+ const row = await this.database.prepare(sql).bind(...values).first();
248
+ return Number(row?.count || 0);
249
+ }
250
+
251
+ async ensureTopology(topology) {
252
+ await this.database.prepare('SELECT id FROM agentsam_queue_job LIMIT 1').all();
253
+ return {
254
+ provider: 'sqlite',
255
+ created: [],
256
+ existing: [...new Set(Object.values(topology?.routes || {}))],
257
+ };
258
+ }
259
+ }