@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.
- package/README.md +3 -0
- package/TRADEMARKS.md +22 -0
- package/apps/README.md +3 -0
- package/apps/cad-creator/LICENSE +21 -0
- package/apps/cad-creator/README.md +4 -1
- package/apps/cad-creator/shared/cad/package.json +1 -1
- package/apps/client-cms-editor/LICENSE +21 -0
- package/apps/client-cms-editor/README.md +3 -0
- package/apps/client-cms-editor/backend/package.json +2 -2
- package/apps/client-cms-editor/frontend/package.json +3 -3
- package/apps/client-cms-editor/package-lock.json +43 -43
- package/apps/client-cms-editor/package.json +3 -3
- package/apps/client-cms-editor/reference/harvest/HARVEST_RECEIPT.json +1 -1
- package/apps/client-cms-editor/reference/harvest/README.md +1 -1
- package/apps/client-cms-editor/reference/harvest/plans/ARCHIVE-INTAKE.md +1 -1
- package/apps/client-cms-editor/reference/harvest/plans/HARVEST-INDEX.md +1 -1
- package/apps/client-cms-editor/reference/harvest/plans/TOOLING-LAB.md +1 -1
- package/apps/client-cms-editor/shared/cms/package.json +1 -1
- package/docs/MINI.md +4 -2
- package/docs/REPO_FILE_MAP.txt +0 -1
- package/docs/SOURCE_ARCHITECTURE.md +1 -1
- package/docs/architecture/DUAL_ANALYTICS_PRODUCT.md +140 -0
- package/docs/content-studio/REVISION_GATE_2026-09-27.md +1 -1
- package/docs/engineering/go-portability/01-product-project-deployment-authority.md +69 -0
- package/docs/engineering/provider-internal-renames/01-lane-initialization.md +20 -0
- package/docs/engineering/provider-internal-renames/01a-runtime-environment-contract.md +115 -0
- package/docs/engineering/provider-internal-renames/02-cfoa.md +57 -0
- package/docs/engineering/provider-internal-renames/03-gclioa.md +32 -0
- package/docs/engineering/provider-internal-renames/04-goaude.md +50 -0
- package/docs/engineering/provider-internal-renames/05-gdrv.md +33 -0
- package/docs/engineering/provider-internal-renames/06-verification.md +103 -0
- package/docs/engineering/provider-internal-renames/README.md +77 -0
- package/docs/engineering/provider-internal-renames/runtime-environment-contract.json +220 -0
- package/docs/engineering/test-diagnostics/go-cli-test-hang-20261003.md +49 -0
- package/docs/engineering/test-diagnostics/go-skip-deploy-docker-fix.md +90 -0
- package/docs/knowledge-service-verification.md +3 -3
- package/docs/plans/AGENTSAM-SUSPEND-QUEUE-KNOWLEDGE-RDP-2026-10-03.md +870 -0
- package/docs/plans/LOCAL-STUDIO-GRADUATION-2026-09-26.md +9 -9
- package/docs/plans/MACHINE-FIRST-APPS-TUI-2026-09-24.md +11 -11
- package/docs/plans/RECONCILIATION-2026-09-19.md +6 -6
- package/docs/plans/SAM_WORK_PROTOCOL.md +667 -0
- package/docs/plans/TOMORROW-EXTENSIVE-TODO-2026-09-26.md +2 -2
- package/docs/plans/UNIVERSAL-INGEST-MACHINE-FIRST-2026-09-24.md +3 -3
- package/examples/hyperspace-demo/src/main.tsx +227 -110
- package/migrations/d1/0020_agentsam_receipt_catalog.sql +35 -0
- package/migrations/runtime/0006_agent_run_suspend_activity.sql +53 -0
- package/migrations/runtime/0007_queue_control.sql +40 -0
- package/migrations/runtime/0008_agent_run_dependencies.sql +24 -0
- package/migrations/runtime/0008_analytics_legacy_bootstrap.sql +43 -0
- package/migrations/runtime/0009_analytics_authority.sql +108 -0
- package/package.json +26 -11
- package/packages/agentsam-brand/README.md +3 -0
- package/packages/agentsam-brand/package.json +2 -2
- package/packages/agentsam-contracts/dist/adapter.d.ts +22 -0
- package/packages/agentsam-contracts/dist/adapter.js +0 -0
- package/packages/agentsam-contracts/dist/agent.d.ts +66 -0
- package/packages/agentsam-contracts/dist/agent.js +15 -0
- package/packages/agentsam-contracts/dist/artifacts.d.ts +70 -0
- package/packages/agentsam-contracts/dist/artifacts.js +0 -0
- package/packages/agentsam-contracts/dist/authority.d.ts +21 -0
- package/packages/agentsam-contracts/dist/authority.js +0 -0
- package/packages/agentsam-contracts/dist/context.d.ts +14 -0
- package/packages/agentsam-contracts/dist/context.js +0 -0
- package/packages/agentsam-contracts/dist/errors.d.ts +121 -0
- package/packages/agentsam-contracts/dist/errors.js +5 -0
- package/packages/agentsam-contracts/dist/events.d.ts +53 -0
- package/packages/agentsam-contracts/dist/events.js +0 -0
- package/packages/agentsam-contracts/dist/execution.d.ts +38 -0
- package/packages/agentsam-contracts/dist/execution.js +0 -0
- package/packages/agentsam-contracts/dist/hooks.d.ts +31 -0
- package/packages/agentsam-contracts/dist/hooks.js +0 -0
- package/packages/agentsam-contracts/dist/identity.d.ts +15 -0
- package/packages/agentsam-contracts/dist/identity.js +0 -0
- package/packages/agentsam-contracts/dist/index.d.ts +16 -0
- package/packages/agentsam-contracts/dist/index.js +164 -0
- package/packages/agentsam-contracts/dist/models.d.ts +9 -0
- package/packages/agentsam-contracts/dist/models.js +0 -0
- package/packages/agentsam-contracts/dist/providers.d.ts +27 -0
- package/packages/agentsam-contracts/dist/providers.js +0 -0
- package/packages/agentsam-contracts/dist/repository.d.ts +56 -0
- package/packages/agentsam-contracts/dist/repository.js +15 -0
- package/packages/agentsam-contracts/dist/run.d.ts +113 -0
- package/packages/agentsam-contracts/dist/run.js +132 -0
- package/packages/agentsam-contracts/dist/tools.d.ts +82 -0
- package/packages/agentsam-contracts/dist/tools.js +0 -0
- package/packages/agentsam-contracts/dist/widgets.d.ts +38 -0
- package/packages/agentsam-contracts/dist/widgets.js +0 -0
- package/packages/agentsam-contracts/package.json +9 -1
- package/packages/agentsam-contracts/scripts/build.mjs +1 -1
- package/packages/agentsam-contracts/src/agent.ts +78 -3
- package/packages/agentsam-contracts/src/index.ts +2 -0
- package/packages/agentsam-contracts/src/run.ts +320 -0
- package/packages/agentsam-contracts/src/widgets.ts +58 -0
- package/packages/agentsam-contracts/test/contracts.test.mjs +1 -1
- package/packages/agentsam-contracts/test/run-contract.test.mjs +94 -0
- package/packages/agentsam-errors/package.json +1 -1
- package/packages/agentsam-goap/README.md +3 -0
- package/packages/agentsam-goap/package.json +2 -2
- package/packages/agentsam-hooks/package.json +2 -2
- package/packages/agentsam-hooks/src/adapters/agents.js +48 -22
- package/packages/agentsam-hooks/src/index.d.ts +16 -0
- package/packages/agentsam-knowledge/package.json +1 -1
- package/packages/agentsam-knowledge/src/backends/index.js +1 -1
- package/packages/agentsam-merch/README.md +62 -0
- package/packages/agentsam-merch/bin/agentsam-merch.mjs +16 -0
- package/packages/agentsam-merch/package.json +65 -0
- package/packages/agentsam-merch/profiles/completeful/dtg-back-large.json +42 -0
- package/packages/agentsam-merch/profiles/completeful/laser-engraving.json +39 -0
- package/packages/agentsam-merch/profiles/generic/embroidery-digitization.json +22 -0
- package/packages/agentsam-merch/schemas/collection-candidate.schema.json +66 -0
- package/packages/agentsam-merch/schemas/manufacturing-profile.schema.json +221 -0
- package/packages/agentsam-merch/src/adapters-completeful.js +50 -0
- package/packages/agentsam-merch/src/cli.js +93 -0
- package/packages/agentsam-merch/src/collection-lab.js +60 -0
- package/packages/agentsam-merch/src/compatibility.js +501 -0
- package/packages/agentsam-merch/src/derivatives.js +112 -0
- package/packages/agentsam-merch/src/index.d.ts +316 -0
- package/packages/agentsam-merch/src/index.js +46 -0
- package/packages/agentsam-merch/src/node/index.d.ts +58 -0
- package/packages/agentsam-merch/src/node/index.js +6 -0
- package/packages/agentsam-merch/src/node/raster.js +142 -0
- package/packages/agentsam-merch/src/node/vector.js +239 -0
- package/packages/agentsam-merch/src/product-concepts.js +118 -0
- package/packages/agentsam-merch/src/profile-registry.js +104 -0
- package/packages/agentsam-merch/src/profile.js +158 -0
- package/packages/agentsam-merch/src/transforms.js +215 -0
- package/packages/agentsam-merch/test/merch.test.mjs +332 -0
- package/packages/agentsam-merch/test/node-transforms.test.mjs +149 -0
- package/packages/agentsam-nav/dist/browser.global.js +71 -34
- package/packages/agentsam-nav/dist/browser.js +3179 -781
- package/packages/agentsam-nav/dist/index.js +3171 -773
- package/packages/agentsam-nav/package.json +1 -1
- package/packages/agentsam-queue-control/README.md +4 -1
- package/packages/agentsam-queue-control/package.json +4 -3
- package/packages/agentsam-queue-control/schemas/job-envelope.schema.json +111 -11
- package/packages/agentsam-queue-control/src/adapters/cloudflare.js +34 -6
- package/packages/agentsam-queue-control/src/adapters/memory.js +11 -2
- package/packages/agentsam-queue-control/src/adapters/sqlite.js +259 -0
- package/packages/agentsam-queue-control/src/contracts.js +207 -3
- package/packages/agentsam-queue-control/src/control-plane.js +62 -2
- package/packages/agentsam-queue-control/src/index.js +1 -0
- package/packages/agentsam-queue-control/test/queue-control.test.mjs +310 -0
- package/packages/agentsam-queue-control/test/sqlite-adapter.test.mjs +91 -0
- package/packages/agentsam-rapid-rust/README.md +3 -0
- package/packages/agentsam-repository/README.md +3 -0
- package/packages/agentsam-repository/package.json +1 -1
- package/packages/agentsam-vault/package.json +1 -1
- package/packages/agentsam-workbench/README.md +43 -0
- package/packages/agentsam-workbench/package.json +13 -3
- package/packages/agentsam-workbench/src/agent/AgentConversationSurface.tsx +108 -0
- package/packages/agentsam-workbench/src/agent/AgentPanel.tsx +25 -8
- package/packages/agentsam-workbench/src/agent/AgentRuntimeField.tsx +152 -0
- package/packages/agentsam-workbench/src/agent/Composer.tsx +10 -1
- package/packages/agentsam-workbench/src/agent/RunMode.ts +26 -0
- package/packages/agentsam-workbench/src/agent/Thread.tsx +18 -3
- package/packages/agentsam-workbench/src/agent/index.ts +3 -0
- package/packages/agentsam-workbench/src/index.ts +4 -0
- package/packages/agentsam-workbench/src/manufacturing/PreflightIndicator.tsx +203 -0
- package/packages/agentsam-workbench/src/manufacturing/index.ts +2 -0
- package/packages/agentsam-workbench/src/manufacturing/loading.ts +147 -0
- package/packages/agentsam-workbench/src/widgets/BuiltinWidget.tsx +22 -0
- package/packages/agentsam-workbench/src/widgets/CountdownWidget.tsx +68 -0
- package/packages/agentsam-workbench/src/widgets/WidgetFrame.tsx +56 -0
- package/packages/agentsam-workbench/src/widgets/countdown.ts +25 -0
- package/packages/agentsam-workbench/src/widgets/index.ts +6 -0
- package/packages/agentsam-workbench/src/widgets/registry.ts +13 -0
- package/packages/agentsam-workbench/src/widgets/useCountdown.ts +128 -0
- package/packages/agentsam-workbench/src/widgets/widgets.css +102 -0
- package/packages/connectors/{cloudflare → cfoa}/package.json +3 -3
- package/packages/heuristic-theme/package.json +1 -1
- package/packages/identity/README.md +3 -0
- package/packages/identity/backend/README.md +3 -0
- package/packages/identity/package.json +1 -1
- package/packages/identity/src/frontend/auth-portal/README.md +3 -0
- package/packages/identity/src/index.js +1 -1
- package/packages/identity/src/oauth/README.md +4 -1
- package/packages/identity/src/oauth/credentials.js +1 -1
- package/packages/identity/src/server/worker-router.js +1 -1
- package/packages/identity/tests/google-desktop-identity-login.test.mjs +1 -1
- package/packages/identity/tests/lane1-packed-consumer.test.mjs +1 -1
- package/packages/identity/tests/oauth-presets-accounts-ssot.test.mjs +1 -1
- package/packages/providers/completeful/package.json +1 -1
- package/packages/theme-church-site/package.json +1 -1
- package/packages/theme-companions-site/package.json +1 -1
- package/packages/theme-floors-site/package.json +1 -1
- package/packages/theme-fuelnfree-site/package.json +1 -1
- package/packages/theme-handyman-site/package.json +1 -1
- package/packages/theme-insurance-site/package.json +1 -1
- package/packages/theme-scenes/package.json +1 -1
- package/packages/theme-shinshu-site/package.json +1 -1
- package/packages/work-graph/package.json +1 -1
- package/protocol/models/README.md +3 -0
- package/protocol/receipts/agentsam.receipt.v1.json +95 -0
- package/protocol/theme-refinery/receipts/products-registry-batch-20260924.json +6 -6
- package/protocol/theme-refinery/receipts/theme-harvest-20260924.json +6 -6
- package/skills/README.md +3 -0
- package/src/acp/agent-executor.js +106 -0
- package/src/acp/client.js +316 -0
- package/src/acp/dependencies.js +426 -0
- package/src/acp/http.js +207 -0
- package/src/acp/index.js +22 -0
- package/src/acp/runs.js +125 -0
- package/src/acp/runtime-selection.js +180 -0
- package/src/cli/command-catalog.js +3 -0
- package/src/cli.js +24 -0
- package/src/commands/cloudflare-login.js +1 -1
- package/src/commands/cloudflare.js +2 -2
- package/src/commands/connections.js +1 -1
- package/src/commands/go.js +76 -6
- package/src/commands/merch.js +5 -0
- package/src/commands/mini.js +1 -1
- package/src/commands/receipts.js +140 -0
- package/src/commands/run.js +253 -0
- package/src/go/container.js +1 -1
- package/src/go/contract.js +61 -18
- package/src/go/discover.js +0 -4
- package/src/go/index.js +13 -1
- package/src/go/probe.js +109 -0
- package/src/go/{cloudflare.js → providers/cloudflare.js} +36 -136
- package/src/go/verify.js +1 -1
- package/src/indexing/ingest/inventory.js +1 -1
- package/src/lib/deploy/local-studio.js +2 -2
- package/src/lib/mini/scaffold.js +1 -1
- package/src/lib/whoami-capabilities.js +1 -1
- package/src/local/runtime-store.js +8 -0
- package/src/mcp/cloudflare-bundles.js +1 -1
- package/src/plugins/index.js +1 -0
- package/src/plugins/registry.js +59 -6
- package/src/receipts/contract.js +68 -0
- package/src/receipts/index.js +20 -0
- package/src/receipts/prune.js +64 -0
- package/src/receipts/sinks.js +285 -0
- package/templates/mini/gadget/app.js +15 -40
- package/templates/mini/gadget/index.html +7 -7
- package/templates/mini/shared/style.css +1 -1
- package/packages/agentsam-repository/src/goap.js.bak-20260922011251 +0 -670
- /package/packages/connectors/{cloudflare → cfoa}/OAUTH_STORAGE_AUDIT.md +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/src/api-client.js +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/src/capabilities.js +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/src/credential.js +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/src/families/brand-protection.js +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/src/families/keyless.js +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/src/families/pages.js +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/src/families/scanner.js +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/src/families/snippets.js +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/src/families/tag-gateway.js +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/src/families/tags.js +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/src/families/token-validation.js +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/src/families/vectorize.js +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/src/families/workflows.js +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/src/index.js +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/src/oauth-persist.js +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/src/owner.js +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/src/permission-options.js +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/src/routes.js +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/src/scope-catalog.js +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/src/vault.js +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/tests/capabilities.test.mjs +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/tests/connector.test.mjs +0 -0
- /package/packages/connectors/{cloudflare → cfoa}/tests/oauth-persist.test.mjs +0 -0
- /package/packages/identity/src/oauth/{google-desktop-exchange.js → goaude.js} +0 -0
|
@@ -11,7 +11,7 @@ The package deliberately separates four concerns:
|
|
|
11
11
|
|
|
12
12
|
## Goals
|
|
13
13
|
|
|
14
|
-
- Cloudflare
|
|
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.
|
|
4
|
-
"description": "Portable AgentSam queue, job-routing,
|
|
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": {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"
|
|
21
|
-
|
|
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": {
|
|
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": {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
|
|
24
|
-
|
|
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) =>
|
|
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) =>
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
}
|