@desplega.ai/agent-swarm 2.2.0 → 2.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.
- package/dist/{acp-adapter-k0vwfyvn.js → acp-adapter-v85a2bqy.js} +1 -1
- package/dist/{actions-w4pnb8vz.js → actions-zgcxfspj.js} +15 -15
- package/dist/{amp-adapter-0cmxb2t5.js → amp-adapter-jw9xfz42.js} +2 -2
- package/dist/{app-zneem7g9.js → app-4e1s4675.js} +3 -3
- package/dist/{assistant-wbzd2rnr.js → assistant-v238n9dk.js} +16 -16
- package/dist/{boot-reembed-4kx69j3g.js → boot-reembed-p666cw5n.js} +1 -1
- package/dist/{boot-reembed-db0wwgy1.js → boot-reembed-w6pm64j4.js} +1 -1
- package/dist/{boot-scrub-sweep-tfv4d3mm.js → boot-scrub-sweep-jcyjagn3.js} +2 -2
- package/dist/{boot-seeds-w2hmkxn5.js → boot-seeds-gbedmamp.js} +4 -4
- package/dist/{claude-adapter-5qrc2paq.js → claude-adapter-q7wspzt8.js} +2 -2
- package/dist/{claude-managed-setup-7ra32em4.js → claude-managed-setup-wza784fb.js} +1 -1
- package/dist/{claude-sdk-session-cd02gc76.js → claude-sdk-session-yf400ptr.js} +2 -2
- package/dist/{cli-p46xdr1m.js → cli-0rh20bp3.js} +1 -1
- package/dist/{cli-e5y285rg.js → cli-1v8w782f.js} +1 -1
- package/dist/{cli-8c1m9mhy.js → cli-30m5q8mc.js} +5 -5
- package/dist/{cli-xnp2vkx7.js → cli-4hmaheb6.js} +6 -6
- package/dist/{cli-xhgtay7w.js → cli-4s1kqrqg.js} +1 -1
- package/dist/{cli-2jm992rm.js → cli-5d1m1qca.js} +2 -2
- package/dist/{cli-mvsfbbgq.js → cli-65q70v2v.js} +3 -3
- package/dist/{cli-th8krqbf.js → cli-6p7ddg72.js} +2 -2
- package/dist/{cli-6q7pyd3k.js → cli-6vcyw6v7.js} +1 -1
- package/dist/{cli-bddxamg7.js → cli-8qsx817b.js} +23 -22
- package/dist/{cli-ztcxv5nv.js → cli-9e9kjqsj.js} +1 -1
- package/dist/{cli-jrk8mj0t.js → cli-a17tzmn0.js} +1 -1
- package/dist/{cli-raejy0mp.js → cli-d43xqzbe.js} +1 -1
- package/dist/{cli-tba8fxf9.js → cli-dxwh4j32.js} +11 -11
- package/dist/{cli-c9vrwcpb.js → cli-ea7chd26.js} +19 -19
- package/dist/{cli-vmbakbq0.js → cli-fhvqt2fp.js} +1 -1
- package/dist/{cli-z3dk189k.js → cli-fp4xbw07.js} +6 -6
- package/dist/{cli-xx13gqf3.js → cli-g6p7c2my.js} +1 -1
- package/dist/{cli-c0dpzwnx.js → cli-hn3pftj2.js} +2 -2
- package/dist/{cli-h23mr2s6.js → cli-hz64bcnj.js} +2 -2
- package/dist/{cli-dw0njd9q.js → cli-jhmjwqcg.js} +5 -5
- package/dist/{cli-0k9rcwfy.js → cli-ka01m5rb.js} +28 -12
- package/dist/{cli-jhhb2v9n.js → cli-kqypty34.js} +2 -2
- package/dist/{cli-hwc4a9xm.js → cli-q1812jbw.js} +4 -4
- package/dist/{cli-8w65vwee.js → cli-qrwp40st.js} +1 -1
- package/dist/{cli-4c7k75rq.js → cli-re4wkbzx.js} +54 -41
- package/dist/{cli-z1hh99j0.js → cli-tr24eeny.js} +2 -2
- package/dist/{cli-q6gw45wj.js → cli-wtg6edvd.js} +1 -1
- package/dist/{cli-mnry16kh.js → cli-xgn4rwyv.js} +4 -4
- package/dist/{cli-5ks6x36q.js → cli-y3dvz6ge.js} +3 -3
- package/dist/{cli-ksrphveb.js → cli-yv0vgscc.js} +1 -0
- package/dist/{cli-ak4c12mh.js → cli-yv3n83x8.js} +1 -1
- package/dist/{cli-9ac0mkg5.js → cli-zes4tsbb.js} +1 -1
- package/dist/cli.js +14 -14
- package/dist/{codex-adapter-m0fx3v3s.js → codex-adapter-nhjj2veb.js} +1 -1
- package/dist/{codex-session-runner-j9m2gfyy.js → codex-session-runner-6hggrjbx.js} +1 -1
- package/dist/{commands-ktnqwrv4.js → commands-mrw1ph2w.js} +2 -2
- package/dist/{controller-nex2he8v.js → controller-pt1zam5w.js} +2 -2
- package/dist/{controllers-connect-6yhwqv9v.js → controllers-connect-ymw5541d.js} +16 -16
- package/dist/{cursor-adapter-02s5ekva.js → cursor-adapter-cf4zh5x0.js} +1 -1
- package/dist/{db-19tw9r5s.js → db-hhpy6m4x.js} +2 -2
- package/dist/{db-jvr86v7f.js → db-hy80219q.js} +1 -1
- package/dist/{dispatcher-d3mnsg2y.js → dispatcher-6pdjtkr1.js} +14 -14
- package/dist/{dsh-adapter-63rvej88.js → dsh-adapter-fbx06re2.js} +1 -1
- package/dist/{external-channel-44cwer32.js → external-channel-j6vb6ya1.js} +2 -2
- package/dist/{grok-adapter-ysp907f6.js → grok-adapter-1193sprp.js} +2 -2
- package/dist/{handlers-t5pbabwf.js → handlers-tb3xgjnm.js} +17 -17
- package/dist/{heartbeat-2etacsqq.js → heartbeat-h1w1ktce.js} +17 -17
- package/dist/{hook-3kvmax6d.js → hook-ejja4bpe.js} +1 -1
- package/dist/{hook-mzxxs5n2.js → hook-skrbja18.js} +1 -1
- package/dist/{http-fn978m0g.js → http-mzh41mfj.js} +108 -52
- package/dist/{index-039x2sag.js → index-6rmnn89d.js} +40 -12
- package/dist/{index-w2wr89xd.js → index-epr2gnbw.js} +1 -1
- package/dist/{index-qyjbb7br.js → index-nyfcdpky.js} +17 -17
- package/dist/{index-e4tsa1h7.js → index-vjn3wbzf.js} +14 -14
- package/dist/{index-1r8hw4vd.js → index-xmmkyx82.js} +14 -14
- package/dist/{keepalive-d4nzs76x.js → keepalive-4djvbm2j.js} +3 -3
- package/dist/{lead-8h5n9k5f.js → lead-61kqp604.js} +23 -23
- package/dist/{maintenance-ea6jfw42.js → maintenance-f3xhnjsm.js} +1 -1
- package/dist/{oauth-refresh-sweep-3f25djq3.js → oauth-refresh-sweep-fpd6x6rw.js} +2 -2
- package/dist/{onboard-pvk7hdb2.js → onboard-196tjgyn.js} +2 -2
- package/dist/{otel-impl-qb7nhgdp.js → otel-impl-g8fh4c21.js} +1 -1
- package/dist/{pricing-refresh-6ehwkcmp.js → pricing-refresh-sdcf5yaz.js} +3 -3
- package/dist/{rbac-roles-9648nh00.js → rbac-roles-2x4g1wb5.js} +2 -2
- package/dist/{rbac-roles-km0f9cmm.js → rbac-roles-bsp5657v.js} +1 -1
- package/dist/{render-v2-xkze1wef.js → render-v2-0pyb39bb.js} +3 -3
- package/dist/{resume-tq0bbvt5.js → resume-a86tkj6r.js} +5 -5
- package/dist/{setup-rnrazxvd.js → setup-ypbzcapd.js} +1 -1
- package/dist/{work-objects-e75q2rqs.js → work-objects-yjp8de12.js} +17 -17
- package/dist/{worker-4ww4hjef.js → worker-4ptnn1ge.js} +23 -23
- package/openapi.json +168 -6
- package/package.json +2 -2
- package/src/be/asset-key-audit.ts +4 -13
- package/src/be/db.ts +57 -33
- package/src/be/migrations/227_inbox_item_state_last_read_at.sql +1 -0
- package/src/be/seed-scripts/catalog/heartbeat-jev-gate.ts +22 -4
- package/src/heartbeat/heartbeat.ts +25 -7
- package/src/http/assets.ts +26 -4
- package/src/http/inbox-state.ts +58 -8
- package/src/kv-reserved-namespaces.ts +1 -0
- package/src/providers/amp-adapter.ts +1 -1
- package/src/tests/asset-key-api.test.ts +128 -0
- package/src/tests/asset-key-invariants.test.ts +179 -3
- package/src/tests/asset-key-migration.test.ts +35 -0
- package/src/tests/docs-index-footprint.test.js +2 -2
- package/src/tests/heartbeat-checklist.test.ts +88 -0
- package/src/tests/heartbeat-jev-gate.test.ts +394 -10
- package/src/tests/inbox-state.test.ts +167 -0
- package/src/tests/kv-tool.test.ts +15 -0
- package/src/tests/script-connections.test.ts +2 -0
- package/src/types.ts +2 -0
- package/templates/skills/code-quality/content.md +2 -2
- package/templates/skills/pages/content.md +4 -0
- package/templates/skills/swarm-scripts/SKILL.md +6 -0
- package/templates/skills/swarm-scripts/content.md +6 -0
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import"./cli-qz93y3x5.js";
|
|
2
2
|
import {
|
|
3
3
|
getEnabledCapabilities
|
|
4
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-8qsx817b.js";
|
|
5
5
|
import"./cli-v1sjhn52.js";
|
|
6
|
-
import"./cli-
|
|
7
|
-
import"./cli-
|
|
8
|
-
import"./cli-
|
|
9
|
-
import"./cli-
|
|
10
|
-
import"./cli-
|
|
11
|
-
import"./cli-
|
|
12
|
-
import"./cli-
|
|
13
|
-
import"./cli-
|
|
14
|
-
import"./cli-
|
|
6
|
+
import"./cli-re4wkbzx.js";
|
|
7
|
+
import"./cli-6vcyw6v7.js";
|
|
8
|
+
import"./cli-xgn4rwyv.js";
|
|
9
|
+
import"./cli-qrwp40st.js";
|
|
10
|
+
import"./cli-kqypty34.js";
|
|
11
|
+
import"./cli-fhvqt2fp.js";
|
|
12
|
+
import"./cli-jhmjwqcg.js";
|
|
13
|
+
import"./cli-65q70v2v.js";
|
|
14
|
+
import"./cli-g6p7c2my.js";
|
|
15
15
|
import"./cli-3ggwdtb0.js";
|
|
16
|
-
import"./cli-
|
|
17
|
-
import"./cli-
|
|
18
|
-
import"./cli-
|
|
16
|
+
import"./cli-dxwh4j32.js";
|
|
17
|
+
import"./cli-9e9kjqsj.js";
|
|
18
|
+
import"./cli-q1812jbw.js";
|
|
19
19
|
import"./cli-8cvvytad.js";
|
|
20
20
|
import"./cli-kvzgak7c.js";
|
|
21
21
|
import"./cli-445c1vp7.js";
|
|
@@ -23,7 +23,7 @@ import"./cli-vjfpshn3.js";
|
|
|
23
23
|
import"./cli-ptkpaqfy.js";
|
|
24
24
|
import"./cli-7a91w22y.js";
|
|
25
25
|
import"./cli-qje9k2nh.js";
|
|
26
|
-
import"./cli-
|
|
26
|
+
import"./cli-hz64bcnj.js";
|
|
27
27
|
import"./cli-3h26v7yj.js";
|
|
28
28
|
import"./cli-rdr166ht.js";
|
|
29
29
|
import"./cli-665j3feb.js";
|
|
@@ -31,31 +31,31 @@ import"./cli-p22zdvnt.js";
|
|
|
31
31
|
import"./cli-77cd6gy8.js";
|
|
32
32
|
import {
|
|
33
33
|
runAgent
|
|
34
|
-
} from "./cli-
|
|
34
|
+
} from "./cli-ea7chd26.js";
|
|
35
35
|
import"./cli-jhp7w1fy.js";
|
|
36
36
|
import"./cli-gx4rm0qx.js";
|
|
37
37
|
import"./cli-a49vpbf3.js";
|
|
38
38
|
import"./cli-jc1g9ndz.js";
|
|
39
|
-
import"./cli-
|
|
39
|
+
import"./cli-6p7ddg72.js";
|
|
40
40
|
import"./cli-k28p6xh7.js";
|
|
41
41
|
import"./cli-etvn5ej2.js";
|
|
42
42
|
import"./cli-c5sbmw1v.js";
|
|
43
43
|
import"./cli-0726awxw.js";
|
|
44
|
-
import"./cli-
|
|
45
|
-
import"./cli-
|
|
44
|
+
import"./cli-1v8w782f.js";
|
|
45
|
+
import"./cli-hn3pftj2.js";
|
|
46
46
|
import"./cli-4bd1rck6.js";
|
|
47
47
|
import"./cli-vbhgkw9h.js";
|
|
48
48
|
import"./cli-er83cjbn.js";
|
|
49
49
|
import"./cli-j0v75y13.js";
|
|
50
50
|
import"./cli-kr5tjjtz.js";
|
|
51
|
-
import"./cli-
|
|
52
|
-
import"./cli-
|
|
51
|
+
import"./cli-tr24eeny.js";
|
|
52
|
+
import"./cli-4s1kqrqg.js";
|
|
53
53
|
import"./cli-zv4vy2b0.js";
|
|
54
|
-
import"./cli-
|
|
55
|
-
import"./cli-
|
|
54
|
+
import"./cli-zes4tsbb.js";
|
|
55
|
+
import"./cli-a17tzmn0.js";
|
|
56
56
|
import"./cli-9td5ss65.js";
|
|
57
57
|
import"./cli-rc3r0bnh.js";
|
|
58
|
-
import"./cli-
|
|
58
|
+
import"./cli-0rh20bp3.js";
|
|
59
59
|
import"./cli-4zsenjhy.js";
|
|
60
60
|
import"./cli-4g629sgr.js";
|
|
61
61
|
import"./cli-13p25grh.js";
|
package/openapi.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"openapi": "3.1.0",
|
|
3
3
|
"info": {
|
|
4
4
|
"title": "Agent Swarm API",
|
|
5
|
-
"version": "2.
|
|
5
|
+
"version": "2.3.0",
|
|
6
6
|
"description": "Multi-agent orchestration API for Claude Code, Codex, and Gemini CLI. Enables task distribution, agent communication, and service discovery.\n\nMCP tools are documented separately in [MCP.md](./MCP.md)."
|
|
7
7
|
},
|
|
8
8
|
"servers": [
|
|
@@ -2295,6 +2295,9 @@
|
|
|
2295
2295
|
"readAt": {
|
|
2296
2296
|
"type": "string"
|
|
2297
2297
|
},
|
|
2298
|
+
"lastReadAt": {
|
|
2299
|
+
"type": "string"
|
|
2300
|
+
},
|
|
2298
2301
|
"createdAt": {
|
|
2299
2302
|
"type": "string"
|
|
2300
2303
|
},
|
|
@@ -14653,6 +14656,12 @@
|
|
|
14653
14656
|
"minLength": 1,
|
|
14654
14657
|
"maxLength": 255,
|
|
14655
14658
|
"description": "Non-unique asset directory namespace (for example shared/ or personal/<user-id>/drafts/). Runtime write boundaries normalize and validate the canonical form."
|
|
14659
|
+
},
|
|
14660
|
+
"movedTaskIds": {
|
|
14661
|
+
"type": "array",
|
|
14662
|
+
"items": {
|
|
14663
|
+
"type": "string"
|
|
14664
|
+
}
|
|
14656
14665
|
}
|
|
14657
14666
|
},
|
|
14658
14667
|
"required": [
|
|
@@ -14777,6 +14786,12 @@
|
|
|
14777
14786
|
"minLength": 1,
|
|
14778
14787
|
"maxLength": 255,
|
|
14779
14788
|
"description": "Non-unique asset directory namespace (for example shared/ or personal/<user-id>/drafts/). Runtime write boundaries normalize and validate the canonical form."
|
|
14789
|
+
},
|
|
14790
|
+
"movedTaskIds": {
|
|
14791
|
+
"type": "array",
|
|
14792
|
+
"items": {
|
|
14793
|
+
"type": "string"
|
|
14794
|
+
}
|
|
14780
14795
|
}
|
|
14781
14796
|
},
|
|
14782
14797
|
"required": [
|
|
@@ -14882,6 +14897,10 @@
|
|
|
14882
14897
|
"minLength": 1,
|
|
14883
14898
|
"maxLength": 255,
|
|
14884
14899
|
"description": "Non-unique asset directory namespace (for example shared/ or personal/<user-id>/drafts/). Runtime write boundaries normalize and validate the canonical form."
|
|
14900
|
+
},
|
|
14901
|
+
"cascade": {
|
|
14902
|
+
"type": "boolean",
|
|
14903
|
+
"description": "For tasks only, also move every descendant task recursively through parentTaskId."
|
|
14885
14904
|
}
|
|
14886
14905
|
},
|
|
14887
14906
|
"required": [
|
|
@@ -14919,6 +14938,12 @@
|
|
|
14919
14938
|
"minLength": 1,
|
|
14920
14939
|
"maxLength": 255,
|
|
14921
14940
|
"description": "Non-unique asset directory namespace (for example shared/ or personal/<user-id>/drafts/). Runtime write boundaries normalize and validate the canonical form."
|
|
14941
|
+
},
|
|
14942
|
+
"movedTaskIds": {
|
|
14943
|
+
"type": "array",
|
|
14944
|
+
"items": {
|
|
14945
|
+
"type": "string"
|
|
14946
|
+
}
|
|
14922
14947
|
}
|
|
14923
14948
|
},
|
|
14924
14949
|
"required": [
|
|
@@ -20766,9 +20791,6 @@
|
|
|
20766
20791
|
"schema": {
|
|
20767
20792
|
"type": "object",
|
|
20768
20793
|
"properties": {
|
|
20769
|
-
"userId": {
|
|
20770
|
-
"type": "string"
|
|
20771
|
-
},
|
|
20772
20794
|
"itemType": {
|
|
20773
20795
|
"type": "string",
|
|
20774
20796
|
"enum": [
|
|
@@ -20800,13 +20822,24 @@
|
|
|
20800
20822
|
"readAt": {
|
|
20801
20823
|
"type": "string",
|
|
20802
20824
|
"format": "date-time"
|
|
20825
|
+
},
|
|
20826
|
+
"lastReadAt": {
|
|
20827
|
+
"type": [
|
|
20828
|
+
"string",
|
|
20829
|
+
"null"
|
|
20830
|
+
],
|
|
20831
|
+
"format": "date-time",
|
|
20832
|
+
"description": "Omit to preserve the read cursor, send null to clear it, or send a timestamp to set it, including an earlier time."
|
|
20833
|
+
},
|
|
20834
|
+
"userId": {
|
|
20835
|
+
"type": "string"
|
|
20803
20836
|
}
|
|
20804
20837
|
},
|
|
20805
20838
|
"required": [
|
|
20806
|
-
"userId",
|
|
20807
20839
|
"itemType",
|
|
20808
20840
|
"itemId",
|
|
20809
|
-
"status"
|
|
20841
|
+
"status",
|
|
20842
|
+
"userId"
|
|
20810
20843
|
]
|
|
20811
20844
|
}
|
|
20812
20845
|
}
|
|
@@ -20854,6 +20887,135 @@
|
|
|
20854
20887
|
}
|
|
20855
20888
|
}
|
|
20856
20889
|
},
|
|
20890
|
+
"/api/inbox-state/bulk": {
|
|
20891
|
+
"patch": {
|
|
20892
|
+
"summary": "Upsert inbox-item state in one transaction",
|
|
20893
|
+
"tags": [
|
|
20894
|
+
"Inbox State"
|
|
20895
|
+
],
|
|
20896
|
+
"security": [
|
|
20897
|
+
{
|
|
20898
|
+
"bearerAuth": []
|
|
20899
|
+
}
|
|
20900
|
+
],
|
|
20901
|
+
"requestBody": {
|
|
20902
|
+
"content": {
|
|
20903
|
+
"application/json": {
|
|
20904
|
+
"schema": {
|
|
20905
|
+
"type": "object",
|
|
20906
|
+
"properties": {
|
|
20907
|
+
"userId": {
|
|
20908
|
+
"type": "string"
|
|
20909
|
+
},
|
|
20910
|
+
"items": {
|
|
20911
|
+
"type": "array",
|
|
20912
|
+
"items": {
|
|
20913
|
+
"type": "object",
|
|
20914
|
+
"properties": {
|
|
20915
|
+
"itemType": {
|
|
20916
|
+
"type": "string",
|
|
20917
|
+
"enum": [
|
|
20918
|
+
"approval",
|
|
20919
|
+
"credential_missing",
|
|
20920
|
+
"broken_task",
|
|
20921
|
+
"to_read",
|
|
20922
|
+
"to_start_template",
|
|
20923
|
+
"notification"
|
|
20924
|
+
]
|
|
20925
|
+
},
|
|
20926
|
+
"itemId": {
|
|
20927
|
+
"type": "string",
|
|
20928
|
+
"minLength": 1
|
|
20929
|
+
},
|
|
20930
|
+
"status": {
|
|
20931
|
+
"type": "string",
|
|
20932
|
+
"enum": [
|
|
20933
|
+
"open",
|
|
20934
|
+
"snoozed",
|
|
20935
|
+
"dismissed",
|
|
20936
|
+
"done"
|
|
20937
|
+
]
|
|
20938
|
+
},
|
|
20939
|
+
"snoozeUntil": {
|
|
20940
|
+
"type": "string",
|
|
20941
|
+
"format": "date-time"
|
|
20942
|
+
},
|
|
20943
|
+
"readAt": {
|
|
20944
|
+
"type": "string",
|
|
20945
|
+
"format": "date-time"
|
|
20946
|
+
},
|
|
20947
|
+
"lastReadAt": {
|
|
20948
|
+
"type": [
|
|
20949
|
+
"string",
|
|
20950
|
+
"null"
|
|
20951
|
+
],
|
|
20952
|
+
"format": "date-time",
|
|
20953
|
+
"description": "Omit to preserve the read cursor, send null to clear it, or send a timestamp to set it, including an earlier time."
|
|
20954
|
+
}
|
|
20955
|
+
},
|
|
20956
|
+
"required": [
|
|
20957
|
+
"itemType",
|
|
20958
|
+
"itemId",
|
|
20959
|
+
"status"
|
|
20960
|
+
]
|
|
20961
|
+
},
|
|
20962
|
+
"minItems": 1,
|
|
20963
|
+
"maxItems": 200
|
|
20964
|
+
}
|
|
20965
|
+
},
|
|
20966
|
+
"required": [
|
|
20967
|
+
"userId",
|
|
20968
|
+
"items"
|
|
20969
|
+
]
|
|
20970
|
+
}
|
|
20971
|
+
}
|
|
20972
|
+
}
|
|
20973
|
+
},
|
|
20974
|
+
"responses": {
|
|
20975
|
+
"200": {
|
|
20976
|
+
"description": "Upserted inbox state rows in request order",
|
|
20977
|
+
"content": {
|
|
20978
|
+
"application/json": {
|
|
20979
|
+
"schema": {
|
|
20980
|
+
"type": "object",
|
|
20981
|
+
"properties": {
|
|
20982
|
+
"items": {
|
|
20983
|
+
"type": "array",
|
|
20984
|
+
"items": {
|
|
20985
|
+
"$ref": "#/components/schemas/InboxItemState"
|
|
20986
|
+
}
|
|
20987
|
+
}
|
|
20988
|
+
},
|
|
20989
|
+
"required": [
|
|
20990
|
+
"items"
|
|
20991
|
+
]
|
|
20992
|
+
}
|
|
20993
|
+
}
|
|
20994
|
+
}
|
|
20995
|
+
},
|
|
20996
|
+
"400": {
|
|
20997
|
+
"description": "Validation error",
|
|
20998
|
+
"content": {
|
|
20999
|
+
"application/json": {
|
|
21000
|
+
"schema": {
|
|
21001
|
+
"$ref": "#/components/schemas/ErrorResponse"
|
|
21002
|
+
}
|
|
21003
|
+
}
|
|
21004
|
+
}
|
|
21005
|
+
},
|
|
21006
|
+
"401": {
|
|
21007
|
+
"description": "Unauthorized",
|
|
21008
|
+
"content": {
|
|
21009
|
+
"application/json": {
|
|
21010
|
+
"schema": {
|
|
21011
|
+
"$ref": "#/components/schemas/ErrorResponse"
|
|
21012
|
+
}
|
|
21013
|
+
}
|
|
21014
|
+
}
|
|
21015
|
+
}
|
|
21016
|
+
}
|
|
21017
|
+
}
|
|
21018
|
+
},
|
|
20857
21019
|
"/api/integrations/claude-managed/test": {
|
|
20858
21020
|
"post": {
|
|
20859
21021
|
"summary": "Test the claude-managed integration: resolves ANTHROPIC_API_KEY + MANAGED_AGENT_ID from swarm_config and calls beta.agents.retrieve.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@desplega.ai/agent-swarm",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "agent-swarm.dev — an open-source operating system for AI work: a lead agent breaks goals into tasks, routes them to specialized workers such as Claude Code or Codex, runs each worker in an isolated container, and preserves shared memory, tools, schedules, and review gates so delegated work compounds across sessions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-swarm.dev",
|
|
@@ -209,7 +209,7 @@
|
|
|
209
209
|
"@chat-adapter/teams": "4.41.1",
|
|
210
210
|
"@chat-adapter/telegram": "4.41.1",
|
|
211
211
|
"@cursor/sdk": "1.0.38",
|
|
212
|
-
"@desplega.ai/agent-fs-just-bash": "0.
|
|
212
|
+
"@desplega.ai/agent-fs-just-bash": "0.18.4",
|
|
213
213
|
"@desplega.ai/business-use": "^0.4.2",
|
|
214
214
|
"@earendil-works/pi-agent-core": "^1.3.0",
|
|
215
215
|
"@earendil-works/pi-ai": "^1.3.0",
|
|
@@ -90,9 +90,7 @@ function auditKeyRow(
|
|
|
90
90
|
|
|
91
91
|
type AttachmentMappingAuditRow = {
|
|
92
92
|
attachment_id: string;
|
|
93
|
-
task_key: string;
|
|
94
93
|
mapping_id: string | null;
|
|
95
|
-
mapping_key: string | null;
|
|
96
94
|
};
|
|
97
95
|
|
|
98
96
|
type MappingSourceAuditRow = {
|
|
@@ -118,9 +116,7 @@ export function auditAssetKeys(db: Database): AssetKeyAuditResult {
|
|
|
118
116
|
.prepare<AttachmentMappingAuditRow, []>(
|
|
119
117
|
`SELECT
|
|
120
118
|
a.id AS attachment_id,
|
|
121
|
-
|
|
122
|
-
m.id AS mapping_id,
|
|
123
|
-
m."key" AS mapping_key
|
|
119
|
+
m.id AS mapping_id
|
|
124
120
|
FROM task_attachments a
|
|
125
121
|
JOIN agent_tasks t ON t.id = a.task_id
|
|
126
122
|
LEFT JOIN asset_key_mappings m
|
|
@@ -132,6 +128,9 @@ export function auditAssetKeys(db: Database): AssetKeyAuditResult {
|
|
|
132
128
|
AND COALESCE(NULLIF(a.provider_key, ''), a.path) IS NOT NULL`,
|
|
133
129
|
)
|
|
134
130
|
.all();
|
|
131
|
+
// One file has one mapping, which follows its source attachment (checked below). Other
|
|
132
|
+
// tasks may attach the same file from any namespace, and a mapping detached from its
|
|
133
|
+
// deleted source keeps its own namespace, so neither is drift.
|
|
135
134
|
for (const row of attachmentMappings) {
|
|
136
135
|
if (!row.mapping_id) {
|
|
137
136
|
issues.push({
|
|
@@ -141,14 +140,6 @@ export function auditAssetKeys(db: Database): AssetKeyAuditResult {
|
|
|
141
140
|
entityId: row.attachment_id,
|
|
142
141
|
message: "Agent-fs attachment has no logical namespace mapping.",
|
|
143
142
|
});
|
|
144
|
-
} else if (row.mapping_key !== row.task_key) {
|
|
145
|
-
issues.push({
|
|
146
|
-
severity: "warning",
|
|
147
|
-
code: "provider-mapping-drift",
|
|
148
|
-
entityType: "file",
|
|
149
|
-
entityId: row.mapping_id,
|
|
150
|
-
message: "Provider mapping namespace differs from its parent task namespace.",
|
|
151
|
-
});
|
|
152
143
|
}
|
|
153
144
|
}
|
|
154
145
|
|
package/src/be/db.ts
CHANGED
|
@@ -1731,7 +1731,9 @@ export async function moveAssetKey(input: {
|
|
|
1731
1731
|
id: string;
|
|
1732
1732
|
key: string;
|
|
1733
1733
|
changedBy?: string;
|
|
1734
|
-
|
|
1734
|
+
/** Task moves only: descendant task ids the caller already authorized to move with the task. */
|
|
1735
|
+
descendantTaskIds?: readonly string[];
|
|
1736
|
+
}): Promise<false | { movedTaskIds?: string[] }> {
|
|
1735
1737
|
const key = normalizeAssetKey(input.key);
|
|
1736
1738
|
// auditAssetKeys stays sync (shared with the boot audit); run it inside a
|
|
1737
1739
|
// client transaction so this request-path read cannot observe another
|
|
@@ -1746,7 +1748,7 @@ export async function moveAssetKey(input: {
|
|
|
1746
1748
|
}
|
|
1747
1749
|
const previousKey = await currentAssetKey(input.entityType, input.id);
|
|
1748
1750
|
if (!previousKey) return false;
|
|
1749
|
-
if (previousKey === key) return
|
|
1751
|
+
if (previousKey === key && input.entityType !== "task") return {};
|
|
1750
1752
|
if (input.entityType === "file") {
|
|
1751
1753
|
const mapping = await getAssetKeyMapping(input.id);
|
|
1752
1754
|
if (mapping?.sourceEntityType === "task-attachment") {
|
|
@@ -1757,48 +1759,64 @@ export async function moveAssetKey(input: {
|
|
|
1757
1759
|
}
|
|
1758
1760
|
const now = new Date().toISOString();
|
|
1759
1761
|
|
|
1760
|
-
|
|
1762
|
+
return getDbClient().transaction(async (tx) => {
|
|
1761
1763
|
switch (input.entityType) {
|
|
1762
1764
|
case "task": {
|
|
1763
|
-
const
|
|
1764
|
-
|
|
1765
|
+
const root = await getTaskById(input.id);
|
|
1766
|
+
if (!root) return false;
|
|
1767
|
+
const tasks = [root];
|
|
1768
|
+
for (const id of input.descendantTaskIds ?? []) {
|
|
1769
|
+
const task = id === root.id ? null : await getTaskById(id);
|
|
1770
|
+
if (task) tasks.push(task);
|
|
1771
|
+
}
|
|
1772
|
+
const movedTaskIds: string[] = [];
|
|
1773
|
+
for (const task of tasks) {
|
|
1774
|
+
if (task.key === key) continue;
|
|
1775
|
+
// A file shared with another task keeps the namespace of the task whose attachment
|
|
1776
|
+
// sources its mapping. Mappings with no attachment source follow any attaching task.
|
|
1777
|
+
const mappedFiles = await tx.query<{ id: string; key: string }>(
|
|
1778
|
+
`SELECT DISTINCT m.id, m."key" AS key
|
|
1765
1779
|
FROM asset_key_mappings m
|
|
1766
1780
|
JOIN task_attachments a
|
|
1767
1781
|
ON m.provider_id = COALESCE(NULLIF(a.provider_id, ''), 'agent-fs')
|
|
1768
1782
|
AND m.provider_org_id = COALESCE(a.agent_fs_org_id, '')
|
|
1769
1783
|
AND m.provider_drive_id = COALESCE(a.agent_fs_drive_id, '')
|
|
1770
1784
|
AND m.provider_key = COALESCE(NULLIF(a.provider_key, ''), a.path)
|
|
1771
|
-
WHERE a.task_id = ?`,
|
|
1772
|
-
[input.id],
|
|
1773
|
-
);
|
|
1774
|
-
await tx.run(
|
|
1775
|
-
'UPDATE agent_tasks SET "key" = ?, lastUpdatedAt = ?, updated_by = ? WHERE id = ?',
|
|
1776
|
-
[key, now, input.changedBy ?? null, input.id],
|
|
1777
|
-
);
|
|
1778
|
-
await tx.run(
|
|
1779
|
-
`UPDATE asset_key_mappings
|
|
1780
|
-
SET "key" = ?, updated_at = ?, updated_by = ?
|
|
1781
|
-
WHERE EXISTS (
|
|
1782
|
-
SELECT 1 FROM task_attachments a
|
|
1783
1785
|
WHERE a.task_id = ?
|
|
1784
|
-
AND
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1786
|
+
AND (m.source_entity_type IS NOT 'task-attachment'
|
|
1787
|
+
OR m.source_entity_id IN (SELECT id FROM task_attachments WHERE task_id = ?))`,
|
|
1788
|
+
[task.id, task.id],
|
|
1789
|
+
);
|
|
1790
|
+
// The namespace is metadata, and lastUpdatedAt tracks task activity, as in updateTaskTitle.
|
|
1791
|
+
await tx.run('UPDATE agent_tasks SET "key" = ?, updated_by = ? WHERE id = ?', [
|
|
1792
|
+
key,
|
|
1793
|
+
input.changedBy ?? null,
|
|
1794
|
+
task.id,
|
|
1795
|
+
]);
|
|
1796
|
+
for (const mapping of mappedFiles) {
|
|
1797
|
+
if (mapping.key === key) continue;
|
|
1798
|
+
await tx.run(
|
|
1799
|
+
'UPDATE asset_key_mappings SET "key" = ?, updated_at = ?, updated_by = ? WHERE id = ?',
|
|
1800
|
+
[key, now, input.changedBy ?? null, mapping.id],
|
|
1801
|
+
);
|
|
1802
|
+
await insertAssetKeyHistory({
|
|
1803
|
+
entityType: "file",
|
|
1804
|
+
entityId: mapping.id,
|
|
1805
|
+
previousKey: mapping.key,
|
|
1806
|
+
newKey: key,
|
|
1807
|
+
changedBy: input.changedBy,
|
|
1808
|
+
});
|
|
1809
|
+
}
|
|
1793
1810
|
await insertAssetKeyHistory({
|
|
1794
|
-
entityType: "
|
|
1795
|
-
entityId:
|
|
1796
|
-
previousKey:
|
|
1811
|
+
entityType: "task",
|
|
1812
|
+
entityId: task.id,
|
|
1813
|
+
previousKey: task.key,
|
|
1797
1814
|
newKey: key,
|
|
1798
1815
|
changedBy: input.changedBy,
|
|
1799
1816
|
});
|
|
1817
|
+
movedTaskIds.push(task.id);
|
|
1800
1818
|
}
|
|
1801
|
-
|
|
1819
|
+
return { movedTaskIds };
|
|
1802
1820
|
}
|
|
1803
1821
|
case "workflow":
|
|
1804
1822
|
await tx.run(
|
|
@@ -1849,8 +1867,8 @@ export async function moveAssetKey(input: {
|
|
|
1849
1867
|
newKey: key,
|
|
1850
1868
|
changedBy: input.changedBy,
|
|
1851
1869
|
});
|
|
1870
|
+
return {};
|
|
1852
1871
|
});
|
|
1853
|
-
return true;
|
|
1854
1872
|
}
|
|
1855
1873
|
|
|
1856
1874
|
export async function deleteTaskAttachment(id: string): Promise<boolean> {
|
|
@@ -12513,6 +12531,7 @@ interface InboxItemStateRow {
|
|
|
12513
12531
|
dismissedAt: string | null;
|
|
12514
12532
|
doneAt: string | null;
|
|
12515
12533
|
readAt: string | null;
|
|
12534
|
+
lastReadAt: string | null;
|
|
12516
12535
|
createdAt: string;
|
|
12517
12536
|
lastUpdatedAt: string;
|
|
12518
12537
|
}
|
|
@@ -12528,6 +12547,7 @@ function rowToInboxItemState(row: InboxItemStateRow): InboxItemState {
|
|
|
12528
12547
|
dismissedAt: row.dismissedAt ?? undefined,
|
|
12529
12548
|
doneAt: row.doneAt ?? undefined,
|
|
12530
12549
|
readAt: row.readAt ?? undefined,
|
|
12550
|
+
lastReadAt: row.lastReadAt ?? undefined,
|
|
12531
12551
|
createdAt: row.createdAt,
|
|
12532
12552
|
lastUpdatedAt: row.lastUpdatedAt,
|
|
12533
12553
|
};
|
|
@@ -12568,6 +12588,7 @@ export async function upsertInboxState(opts: {
|
|
|
12568
12588
|
doneAt?: string;
|
|
12569
12589
|
/** First-viewed timestamp. Sticky: once set, later calls never clear or move it. */
|
|
12570
12590
|
readAt?: string;
|
|
12591
|
+
lastReadAt?: string | null;
|
|
12571
12592
|
}): Promise<InboxItemState> {
|
|
12572
12593
|
const now = new Date().toISOString();
|
|
12573
12594
|
// Auto-derive timestamps from status when not explicitly provided.
|
|
@@ -12579,14 +12600,15 @@ export async function upsertInboxState(opts: {
|
|
|
12579
12600
|
// SQLite upsert via UNIQUE(userId, itemType, itemId). readAt is sticky: the
|
|
12580
12601
|
// first non-null value written wins on every subsequent conflict.
|
|
12581
12602
|
const row = await getDbClient().get<InboxItemStateRow>(
|
|
12582
|
-
`INSERT INTO inbox_item_state (userId, itemType, itemId, status, snoozeUntil, dismissedAt, doneAt, readAt, createdAt, lastUpdatedAt)
|
|
12583
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
12603
|
+
`INSERT INTO inbox_item_state (userId, itemType, itemId, status, snoozeUntil, dismissedAt, doneAt, readAt, lastReadAt, createdAt, lastUpdatedAt)
|
|
12604
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
12584
12605
|
ON CONFLICT(userId, itemType, itemId) DO UPDATE SET
|
|
12585
12606
|
status = excluded.status,
|
|
12586
12607
|
snoozeUntil = excluded.snoozeUntil,
|
|
12587
12608
|
dismissedAt = excluded.dismissedAt,
|
|
12588
12609
|
doneAt = excluded.doneAt,
|
|
12589
12610
|
readAt = COALESCE(inbox_item_state.readAt, excluded.readAt),
|
|
12611
|
+
lastReadAt = CASE WHEN ? THEN excluded.lastReadAt ELSE inbox_item_state.lastReadAt END,
|
|
12590
12612
|
lastUpdatedAt = excluded.lastUpdatedAt
|
|
12591
12613
|
RETURNING *`,
|
|
12592
12614
|
[
|
|
@@ -12598,8 +12620,10 @@ export async function upsertInboxState(opts: {
|
|
|
12598
12620
|
dismissedAt,
|
|
12599
12621
|
doneAt,
|
|
12600
12622
|
readAt,
|
|
12623
|
+
opts.lastReadAt ?? null,
|
|
12601
12624
|
now,
|
|
12602
12625
|
now,
|
|
12626
|
+
opts.lastReadAt !== undefined ? 1 : 0,
|
|
12603
12627
|
],
|
|
12604
12628
|
);
|
|
12605
12629
|
if (!row) throw new Error("Failed to upsert inbox state");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE inbox_item_state ADD COLUMN lastReadAt TEXT;
|
|
@@ -138,8 +138,7 @@ async function buildState(ctx: any, leadId: string, nowMs: number, timeZone: str
|
|
|
138
138
|
// db_query_concurrency_cap on a busy swarm.
|
|
139
139
|
const lead = await q("SELECT heartbeatMd FROM agents WHERE id = ?", [leadId]);
|
|
140
140
|
const prev = await q(
|
|
141
|
-
`SELECT id, substr(output, 1, 400) AS output
|
|
142
|
-
substr(task, 1, instr(task, '## Your Standing Orders')) AS status
|
|
141
|
+
`SELECT id, substr(output, 1, 400) AS output
|
|
143
142
|
FROM agent_tasks
|
|
144
143
|
WHERE agentId = ? AND taskType = 'heartbeat-checklist' AND status = 'completed'
|
|
145
144
|
ORDER BY createdAt DESC LIMIT 1`,
|
|
@@ -163,9 +162,28 @@ async function buildState(ctx: any, leadId: string, nowMs: number, timeZone: str
|
|
|
163
162
|
"SELECT status, COUNT(*) AS n FROM agents WHERE COALESCE(role, '') != 'extension' GROUP BY status",
|
|
164
163
|
);
|
|
165
164
|
|
|
165
|
+
// Only the producer's receipt proves which full IDs the checklist actually showed.
|
|
166
|
+
// Old checklists and invalid receipts conservatively treat all current failures as new.
|
|
167
|
+
let reportedIds: unknown = [];
|
|
168
|
+
if (prev[0]?.id) {
|
|
169
|
+
try {
|
|
170
|
+
const receipt = await ctx.swarm.kv_getOrNull({
|
|
171
|
+
namespace: "heartbeat-checklist:reported-failures",
|
|
172
|
+
key: prev[0].id,
|
|
173
|
+
});
|
|
174
|
+
reportedIds = typeof receipt?.value === "string" ? JSON.parse(receipt.value) : receipt?.value;
|
|
175
|
+
} catch {
|
|
176
|
+
reportedIds = [];
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const prevIds = new Set(
|
|
180
|
+
Array.isArray(reportedIds) && reportedIds.every((id) => typeof id === "string") ? reportedIds : [],
|
|
181
|
+
);
|
|
166
182
|
const fails = parseFailures(failed.map(renderFailureLine).join("\n"));
|
|
167
|
-
|
|
168
|
-
const newFails =
|
|
183
|
+
// Compare full IDs before rendering the replay's eight-character display IDs.
|
|
184
|
+
const newFails = parseFailures(
|
|
185
|
+
failed.filter((f) => !prevIds.has(f.id)).map(renderFailureLine).join("\n"),
|
|
186
|
+
);
|
|
169
187
|
|
|
170
188
|
const { stamp, zone } = localStamp(nowMs, timeZone);
|
|
171
189
|
const mmdd = new Date(nowMs).toISOString().slice(5, 10);
|