@desplega.ai/agent-swarm 1.123.1 → 1.124.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/README.md +2 -1
- package/dist/{actions-3ntn8s3f.js → actions-z3d0fk7z.js} +5 -5
- package/dist/{app-pej7g57x.js → app-q2rc9tdr.js} +3 -3
- package/dist/{assistant-pxa36zjn.js → assistant-3stjq7fz.js} +8 -8
- package/dist/{boot-reembed-wdwde4vr.js → boot-reembed-5867whnb.js} +3 -3
- package/dist/{boot-reembed-ybq960bh.js → boot-reembed-v6r1df32.js} +4 -4
- package/dist/{boot-scrub-logs-ndqxg6e3.js → boot-scrub-logs-8b8jegk3.js} +2 -2
- package/dist/{cli-xv09zc8e.js → cli-0925phzv.js} +1 -1
- package/dist/{cli-256kb8p5.js → cli-2yr6edr7.js} +4 -4
- package/dist/{cli-x2hk4m81.js → cli-3z4q09tn.js} +54 -9
- package/dist/{cli-7yn0n4fp.js → cli-5jn6wnd9.js} +8 -8
- package/dist/{cli-82eq5zf5.js → cli-92bqgbgy.js} +1 -1
- package/dist/{cli-r07fhvsk.js → cli-dq2ssyf0.js} +5 -5
- package/dist/{cli-kqgkfpz7.js → cli-gkvf8d83.js} +1 -1
- package/dist/{cli-7qvpf14x.js → cli-gzjsamwc.js} +1 -1
- package/dist/{cli-333x50bh.js → cli-h89g0qrd.js} +1 -1
- package/dist/{cli-g4bfr1e7.js → cli-jp4mdj9d.js} +2 -2
- package/dist/{cli-2e5t0yjj.js → cli-kk58tg33.js} +7 -7
- package/dist/{cli-mb3gz7qr.js → cli-mcez7z4p.js} +1 -1
- package/dist/{cli-ca32n52j.js → cli-mmk5vagg.js} +2 -2
- package/dist/{cli-1kv5sydm.js → cli-p0ec4vv6.js} +1 -1
- package/dist/{cli-zvbxe7pf.js → cli-p0zgv8pj.js} +1 -1
- package/dist/{cli-mntyk3cr.js → cli-perb20ma.js} +1 -1
- package/dist/{cli-7rk0bbfr.js → cli-qf7acvyr.js} +2 -2
- package/dist/{cli-1cah98w1.js → cli-qwsagsmg.js} +1 -1
- package/dist/{cli-pjvdm39a.js → cli-sqv6c9b8.js} +5 -5
- package/dist/{cli-vw0acwe7.js → cli-vm20sh8d.js} +3 -3
- package/dist/{cli-sj43m5z0.js → cli-wn3m6q54.js} +3 -3
- package/dist/{cli-hgkf9zmd.js → cli-x268say8.js} +125 -58
- package/dist/{cli-0pmkqg1d.js → cli-y43n987v.js} +1 -1
- package/dist/{cli-qrnhnhma.js → cli-ykthjw29.js} +4 -4
- package/dist/{cli-k3yfwe8g.js → cli-zxb72ctk.js} +2 -2
- package/dist/cli.js +9 -9
- package/dist/{commands-5p0erxye.js → commands-sda76yn8.js} +2 -2
- package/dist/{db-yp9e9nvs.js → db-vn9e4rqj.js} +6 -2
- package/dist/{handlers-3hqw1dsr.js → handlers-xfja18ac.js} +8 -8
- package/dist/{hook-5981d59r.js → hook-2medrp47.js} +1 -1
- package/dist/{http-ek9ctgth.js → http-937pyjfc.js} +49 -39
- package/dist/{index-33eb3q08.js → index-2bqd2q9v.js} +11 -11
- package/dist/{index-8j9b86c9.js → index-gw4en7jg.js} +9 -9
- package/dist/{index-chcty242.js → index-knqczmnm.js} +10 -10
- package/dist/{index-1cnvzmh4.js → index-vah60vxp.js} +8 -8
- package/dist/{keepalive-rrvxy1fy.js → keepalive-20rd6hxh.js} +5 -5
- package/dist/{lead-jvw8b413.js → lead-7w2k3a49.js} +20 -20
- package/dist/{maintenance-3zjnr2wa.js → maintenance-p3x918yw.js} +4 -4
- package/dist/{oauth-refresh-sweep-vfhvqmby.js → oauth-refresh-sweep-shm0nzm4.js} +4 -4
- package/dist/{onboard-kvntqz8h.js → onboard-py9dnf54.js} +2 -2
- package/dist/{otel-impl-61tsn4bx.js → otel-impl-7yjkfg68.js} +1 -1
- package/dist/{pricing-refresh-jcp6ntbk.js → pricing-refresh-3snb6370.js} +4 -4
- package/dist/{rbac-roles-xcbab18x.js → rbac-roles-5e72bbpk.js} +3 -3
- package/dist/{rbac-roles-r3j4z9vs.js → rbac-roles-gqxdp8st.js} +4 -4
- package/dist/{seed-pricing-bd669a7j.js → seed-pricing-bg42d7h2.js} +3 -3
- package/dist/{setup-pg03xran.js → setup-nzk3kbbq.js} +2 -2
- package/dist/{worker-q5n4qwvq.js → worker-0p1jdzkm.js} +20 -20
- package/openapi.json +23 -1
- package/package.json +1 -1
- package/src/be/db.ts +81 -4
- package/src/be/scripts/typecheck.ts +8 -4
- package/src/be/seed-scripts/catalog/task-context-gathering.ts +1 -1
- package/src/http/workflows.ts +16 -4
- package/src/prompts/session-templates.ts +6 -3
- package/src/scripts-runtime/swarm-sdk.ts +10 -0
- package/src/scripts-runtime/types/stdlib.d.ts +4 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +4 -0
- package/src/telemetry.ts +10 -7
- package/src/tests/mcp-tools.test.ts +2 -2
- package/src/tests/prompt-template-session.test.ts +7 -0
- package/src/tests/scripts-mcp-e2e.test.ts +51 -2
- package/src/tests/scripts-typecheck.test.ts +17 -0
- package/src/tests/sdk-allowlist.test.ts +34 -1
- package/src/tests/seed-scripts.test.ts +43 -0
- package/src/tests/swarm-tool-result-gate.test.ts +35 -0
- package/src/tests/task-tools-ctx.test.ts +29 -0
- package/src/tests/telemetry-init.test.ts +21 -24
- package/src/tests/workflow-http-v2.test.ts +116 -0
- package/src/tools/get-tasks.ts +40 -1
- package/src/tools/script-run.ts +2 -2
- package/src/tools/script-upsert.ts +2 -2
- package/src/tools/utils.ts +14 -8
- package/src/tools/workflows/list-workflow-runs.ts +95 -24
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PermissionVerbSchema
|
|
3
|
-
} from "./cli-
|
|
3
|
+
} from "./cli-y43n987v.js";
|
|
4
4
|
import {
|
|
5
5
|
getDb,
|
|
6
6
|
init_db
|
|
7
|
-
} from "./cli-
|
|
7
|
+
} from "./cli-3z4q09tn.js";
|
|
8
8
|
import"./cli-z2zcxes1.js";
|
|
9
|
-
import"./cli-
|
|
9
|
+
import"./cli-p0zgv8pj.js";
|
|
10
10
|
import"./cli-4j2mrzag.js";
|
|
11
11
|
import"./cli-bw80ck94.js";
|
|
12
12
|
import"./cli-xz9aq0rf.js";
|
|
@@ -7,11 +7,11 @@ import {
|
|
|
7
7
|
getUserGrant,
|
|
8
8
|
listUserRoles,
|
|
9
9
|
runRbacCliCommand
|
|
10
|
-
} from "./cli-
|
|
11
|
-
import"./cli-
|
|
12
|
-
import"./cli-
|
|
10
|
+
} from "./cli-zxb72ctk.js";
|
|
11
|
+
import"./cli-y43n987v.js";
|
|
12
|
+
import"./cli-3z4q09tn.js";
|
|
13
13
|
import"./cli-z2zcxes1.js";
|
|
14
|
-
import"./cli-
|
|
14
|
+
import"./cli-p0zgv8pj.js";
|
|
15
15
|
import"./cli-4j2mrzag.js";
|
|
16
16
|
import"./cli-bw80ck94.js";
|
|
17
17
|
import"./cli-xz9aq0rf.js";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildModelsDevSeedRows,
|
|
3
3
|
seedPricingFromModelsDev
|
|
4
|
-
} from "./cli-
|
|
5
|
-
import"./cli-
|
|
4
|
+
} from "./cli-gzjsamwc.js";
|
|
5
|
+
import"./cli-3z4q09tn.js";
|
|
6
6
|
import"./cli-z2zcxes1.js";
|
|
7
|
-
import"./cli-
|
|
7
|
+
import"./cli-p0zgv8pj.js";
|
|
8
8
|
import"./cli-4j2mrzag.js";
|
|
9
9
|
import"./cli-bw80ck94.js";
|
|
10
10
|
import"./cli-xz9aq0rf.js";
|
|
@@ -4,14 +4,14 @@ import {
|
|
|
4
4
|
createDefaultMcpJson,
|
|
5
5
|
createDefaultSettingsLocal,
|
|
6
6
|
createHooksConfig
|
|
7
|
-
} from "./cli-
|
|
7
|
+
} from "./cli-perb20ma.js";
|
|
8
8
|
import {
|
|
9
9
|
require_jsx_dev_runtime
|
|
10
10
|
} from "./cli-wx82tw1k.js";
|
|
11
11
|
import {
|
|
12
12
|
getApiKey
|
|
13
13
|
} from "./cli-f14fvzag.js";
|
|
14
|
-
import"./cli-
|
|
14
|
+
import"./cli-p0zgv8pj.js";
|
|
15
15
|
import {
|
|
16
16
|
Box_default,
|
|
17
17
|
Spinner,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runAgent
|
|
3
|
-
} from "./cli-
|
|
3
|
+
} from "./cli-ykthjw29.js";
|
|
4
4
|
import"./cli-exfs8aym.js";
|
|
5
5
|
import"./cli-jj1arm18.js";
|
|
6
6
|
import"./cli-07er7wrs.js";
|
|
@@ -14,7 +14,7 @@ import"./cli-d6n0thxw.js";
|
|
|
14
14
|
import"./cli-v1mwc5v2.js";
|
|
15
15
|
import {
|
|
16
16
|
getEnabledCapabilities
|
|
17
|
-
} from "./cli-
|
|
17
|
+
} from "./cli-x268say8.js";
|
|
18
18
|
import"./cli-1z7048dy.js";
|
|
19
19
|
import"./cli-gz9sbyk3.js";
|
|
20
20
|
import"./cli-ftyf58xj.js";
|
|
@@ -25,36 +25,36 @@ import"./cli-tng3131n.js";
|
|
|
25
25
|
import"./cli-zm7njwzd.js";
|
|
26
26
|
import"./cli-cw70hymf.js";
|
|
27
27
|
import"./cli-e61fs2hp.js";
|
|
28
|
-
import"./cli-
|
|
29
|
-
import"./cli-
|
|
30
|
-
import"./cli-
|
|
31
|
-
import"./cli-
|
|
32
|
-
import"./cli-
|
|
33
|
-
import"./cli-
|
|
34
|
-
import"./cli-
|
|
28
|
+
import"./cli-2yr6edr7.js";
|
|
29
|
+
import"./cli-qf7acvyr.js";
|
|
30
|
+
import"./cli-gzjsamwc.js";
|
|
31
|
+
import"./cli-zxb72ctk.js";
|
|
32
|
+
import"./cli-y43n987v.js";
|
|
33
|
+
import"./cli-gkvf8d83.js";
|
|
34
|
+
import"./cli-kk58tg33.js";
|
|
35
35
|
import"./cli-f14fvzag.js";
|
|
36
36
|
import"./cli-3dpj7atn.js";
|
|
37
|
-
import"./cli-
|
|
38
|
-
import"./cli-
|
|
37
|
+
import"./cli-h89g0qrd.js";
|
|
38
|
+
import"./cli-wn3m6q54.js";
|
|
39
39
|
import"./cli-jkhwmmgg.js";
|
|
40
|
-
import"./cli-
|
|
41
|
-
import"./cli-
|
|
40
|
+
import"./cli-mmk5vagg.js";
|
|
41
|
+
import"./cli-p0ec4vv6.js";
|
|
42
42
|
import"./cli-q25ejbyn.js";
|
|
43
|
-
import"./cli-
|
|
43
|
+
import"./cli-mcez7z4p.js";
|
|
44
44
|
import"./cli-fad8m16k.js";
|
|
45
45
|
import"./cli-7zd05xb4.js";
|
|
46
|
-
import"./cli-
|
|
47
|
-
import"./cli-
|
|
48
|
-
import"./cli-
|
|
49
|
-
import"./cli-
|
|
46
|
+
import"./cli-92bqgbgy.js";
|
|
47
|
+
import"./cli-0925phzv.js";
|
|
48
|
+
import"./cli-qwsagsmg.js";
|
|
49
|
+
import"./cli-dq2ssyf0.js";
|
|
50
50
|
import"./cli-rkndnn90.js";
|
|
51
51
|
import"./cli-b0p7rfnd.js";
|
|
52
52
|
import"./cli-5ncdb7ff.js";
|
|
53
53
|
import"./cli-wspgs9bt.js";
|
|
54
54
|
import"./cli-dh55d5fg.js";
|
|
55
|
-
import"./cli-
|
|
55
|
+
import"./cli-3z4q09tn.js";
|
|
56
56
|
import"./cli-z2zcxes1.js";
|
|
57
|
-
import"./cli-
|
|
57
|
+
import"./cli-p0zgv8pj.js";
|
|
58
58
|
import"./cli-4j2mrzag.js";
|
|
59
59
|
import"./cli-bw80ck94.js";
|
|
60
60
|
import"./cli-xz9aq0rf.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": "1.
|
|
5
|
+
"version": "1.124.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": [
|
|
@@ -19728,6 +19728,28 @@
|
|
|
19728
19728
|
"required": false,
|
|
19729
19729
|
"name": "status",
|
|
19730
19730
|
"in": "query"
|
|
19731
|
+
},
|
|
19732
|
+
{
|
|
19733
|
+
"schema": {
|
|
19734
|
+
"type": "integer",
|
|
19735
|
+
"minimum": 1,
|
|
19736
|
+
"maximum": 100
|
|
19737
|
+
},
|
|
19738
|
+
"required": false,
|
|
19739
|
+
"name": "limit",
|
|
19740
|
+
"in": "query"
|
|
19741
|
+
},
|
|
19742
|
+
{
|
|
19743
|
+
"schema": {
|
|
19744
|
+
"type": [
|
|
19745
|
+
"integer",
|
|
19746
|
+
"null"
|
|
19747
|
+
],
|
|
19748
|
+
"minimum": 0
|
|
19749
|
+
},
|
|
19750
|
+
"required": false,
|
|
19751
|
+
"name": "offset",
|
|
19752
|
+
"in": "query"
|
|
19731
19753
|
}
|
|
19732
19754
|
],
|
|
19733
19755
|
"responses": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@desplega.ai/agent-swarm",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.124.0",
|
|
4
4
|
"description": "Multi-agent orchestration for Claude Code, Codex, Gemini CLI, and other AI coding assistants",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "desplega.sh <contact@desplega.sh>",
|
package/src/be/db.ts
CHANGED
|
@@ -8679,15 +8679,92 @@ export function updateWorkflowRun(
|
|
|
8679
8679
|
return run;
|
|
8680
8680
|
}
|
|
8681
8681
|
|
|
8682
|
-
export
|
|
8682
|
+
export type WorkflowRunListOptions = {
|
|
8683
|
+
status?: WorkflowRunStatus;
|
|
8684
|
+
limit?: number;
|
|
8685
|
+
offset?: number;
|
|
8686
|
+
};
|
|
8687
|
+
|
|
8688
|
+
export type WorkflowRunPage = {
|
|
8689
|
+
runs: WorkflowRun[];
|
|
8690
|
+
page: {
|
|
8691
|
+
limit: number;
|
|
8692
|
+
offset: number;
|
|
8693
|
+
total: number;
|
|
8694
|
+
hasMore: boolean;
|
|
8695
|
+
nextOffset?: number;
|
|
8696
|
+
};
|
|
8697
|
+
};
|
|
8698
|
+
|
|
8699
|
+
export function listWorkflowRuns(
|
|
8700
|
+
workflowId: string,
|
|
8701
|
+
options: WorkflowRunListOptions = {},
|
|
8702
|
+
): WorkflowRun[] {
|
|
8703
|
+
const conditions = ["workflowId = ?"];
|
|
8704
|
+
const params: Array<string | number> = [workflowId];
|
|
8705
|
+
if (options.status) {
|
|
8706
|
+
conditions.push("status = ?");
|
|
8707
|
+
params.push(options.status);
|
|
8708
|
+
}
|
|
8709
|
+
|
|
8710
|
+
let pagination = "";
|
|
8711
|
+
if (options.limit !== undefined) {
|
|
8712
|
+
pagination = " LIMIT ? OFFSET ?";
|
|
8713
|
+
params.push(options.limit, options.offset ?? 0);
|
|
8714
|
+
} else if (options.offset !== undefined) {
|
|
8715
|
+
pagination = " LIMIT -1 OFFSET ?";
|
|
8716
|
+
params.push(options.offset);
|
|
8717
|
+
}
|
|
8718
|
+
|
|
8683
8719
|
return getDb()
|
|
8684
|
-
.prepare<WorkflowRunRow,
|
|
8685
|
-
|
|
8720
|
+
.prepare<WorkflowRunRow, Array<string | number>>(
|
|
8721
|
+
`SELECT * FROM workflow_runs
|
|
8722
|
+
WHERE ${conditions.join(" AND ")}
|
|
8723
|
+
ORDER BY startedAt DESC, id DESC${pagination}`,
|
|
8686
8724
|
)
|
|
8687
|
-
.all(
|
|
8725
|
+
.all(...params)
|
|
8688
8726
|
.map(rowToWorkflowRun);
|
|
8689
8727
|
}
|
|
8690
8728
|
|
|
8729
|
+
export function countWorkflowRuns(
|
|
8730
|
+
workflowId: string,
|
|
8731
|
+
options: Pick<WorkflowRunListOptions, "status"> = {},
|
|
8732
|
+
): number {
|
|
8733
|
+
const conditions = ["workflowId = ?"];
|
|
8734
|
+
const params: string[] = [workflowId];
|
|
8735
|
+
if (options.status) {
|
|
8736
|
+
conditions.push("status = ?");
|
|
8737
|
+
params.push(options.status);
|
|
8738
|
+
}
|
|
8739
|
+
const row = getDb()
|
|
8740
|
+
.prepare<{ count: number }, string[]>(
|
|
8741
|
+
`SELECT COUNT(*) AS count FROM workflow_runs WHERE ${conditions.join(" AND ")}`,
|
|
8742
|
+
)
|
|
8743
|
+
.get(...params);
|
|
8744
|
+
return row?.count ?? 0;
|
|
8745
|
+
}
|
|
8746
|
+
|
|
8747
|
+
export function listWorkflowRunsPage(
|
|
8748
|
+
workflowId: string,
|
|
8749
|
+
options: Required<Pick<WorkflowRunListOptions, "limit" | "offset">> &
|
|
8750
|
+
Pick<WorkflowRunListOptions, "status">,
|
|
8751
|
+
): WorkflowRunPage {
|
|
8752
|
+
const runs = listWorkflowRuns(workflowId, options);
|
|
8753
|
+
const total = countWorkflowRuns(workflowId, { status: options.status });
|
|
8754
|
+
const nextOffset = options.offset + runs.length;
|
|
8755
|
+
const hasMore = nextOffset < total;
|
|
8756
|
+
return {
|
|
8757
|
+
runs,
|
|
8758
|
+
page: {
|
|
8759
|
+
limit: options.limit,
|
|
8760
|
+
offset: options.offset,
|
|
8761
|
+
total,
|
|
8762
|
+
hasMore,
|
|
8763
|
+
...(hasMore ? { nextOffset } : {}),
|
|
8764
|
+
},
|
|
8765
|
+
};
|
|
8766
|
+
}
|
|
8767
|
+
|
|
8691
8768
|
// ============================================================================
|
|
8692
8769
|
// Workflow Run Step CRUD
|
|
8693
8770
|
// ============================================================================
|
|
@@ -106,7 +106,7 @@ export interface SwarmSdk {
|
|
|
106
106
|
// --- workflows ---
|
|
107
107
|
workflow_list(args?: { enabled?: boolean; includeFull?: boolean; consecutiveErrorsMin?: number; lastRunStatus?: "running" | "waiting" | "completed" | "failed" | "skipped" | "cancelled" }): Promise<unknown>;
|
|
108
108
|
workflow_get(args: { id: string }): Promise<unknown>;
|
|
109
|
-
workflow_listRuns(args: { workflowId: string; status?: "running" | "waiting" | "completed" | "failed" | "skipped" | "cancelled" }): Promise<unknown>;
|
|
109
|
+
workflow_listRuns(args: { workflowId: string; status?: "running" | "waiting" | "completed" | "failed" | "skipped" | "cancelled"; limit?: number; offset?: number }): Promise<unknown>;
|
|
110
110
|
workflow_getRun(args: { id: string }): Promise<unknown>;
|
|
111
111
|
// --- prompt templates ---
|
|
112
112
|
prompt_list(args?: { eventType?: string; scope?: "global" | "agent" | "repo"; scopeId?: string; isDefault?: boolean }): Promise<unknown>;
|
|
@@ -299,6 +299,8 @@ export interface ScriptContext {
|
|
|
299
299
|
* A swarm script's default export. \`args\` comes FIRST, \`ctx\` second — never swap them.
|
|
300
300
|
*
|
|
301
301
|
* @example
|
|
302
|
+
* import type { ScriptContext } from "swarm-sdk";
|
|
303
|
+
*
|
|
302
304
|
* export default async function (args: { name: string }, ctx: ScriptContext) {
|
|
303
305
|
* await ctx.logger.log(\`hello \${args.name}\`);
|
|
304
306
|
* return { ok: true };
|
|
@@ -887,15 +889,17 @@ void _scriptMain;
|
|
|
887
889
|
|
|
888
890
|
if (diagnostics.length === 0) return { ok: true };
|
|
889
891
|
|
|
890
|
-
const
|
|
892
|
+
const formatHost: ts.FormatDiagnosticsHost = {
|
|
891
893
|
getCanonicalFileName: (fileName) => fileName,
|
|
892
894
|
getCurrentDirectory: () => "/virtual",
|
|
893
895
|
getNewLine: () => "\n",
|
|
894
|
-
}
|
|
896
|
+
};
|
|
895
897
|
|
|
896
898
|
return {
|
|
897
899
|
ok: false,
|
|
898
|
-
diagnostics:
|
|
900
|
+
diagnostics: diagnostics.map((diagnostic) =>
|
|
901
|
+
ts.formatDiagnosticsWithColorAndContext([diagnostic], formatHost).trimEnd(),
|
|
902
|
+
),
|
|
899
903
|
structured: diagnostics.map(toStructured),
|
|
900
904
|
};
|
|
901
905
|
}
|
|
@@ -81,7 +81,7 @@ export default async function taskContextGathering(args: any, ctx: any) {
|
|
|
81
81
|
memories.sort((a: any, b: any) => b.compositeScore - a.compositeScore);
|
|
82
82
|
|
|
83
83
|
return {
|
|
84
|
-
task: slimTask(taskPayload
|
|
84
|
+
task: slimTask(taskPayload),
|
|
85
85
|
requestedBy: taskPayload?.requestedBy,
|
|
86
86
|
attachments: taskPayload?.attachments ?? [],
|
|
87
87
|
queriesRun: queries.length,
|
package/src/http/workflows.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
getWorkflowVersion,
|
|
12
12
|
getWorkflowVersions,
|
|
13
13
|
listWorkflowRuns,
|
|
14
|
+
listWorkflowRunsPage,
|
|
14
15
|
listWorkflows,
|
|
15
16
|
updateWorkflow,
|
|
16
17
|
withFavoriteFlags,
|
|
@@ -209,6 +210,8 @@ const listWorkflowRunsRoute = route({
|
|
|
209
210
|
params: z.object({ id: z.string() }),
|
|
210
211
|
query: z.object({
|
|
211
212
|
status: WorkflowRunStatusSchema.optional(),
|
|
213
|
+
limit: z.coerce.number().int().min(1).max(100).optional(),
|
|
214
|
+
offset: z.coerce.number().int().min(0).optional(),
|
|
212
215
|
}),
|
|
213
216
|
responses: {
|
|
214
217
|
200: { description: "Workflow run list" },
|
|
@@ -754,11 +757,20 @@ export async function handleWorkflows(
|
|
|
754
757
|
if (listWorkflowRunsRoute.match(req.method, pathSegments)) {
|
|
755
758
|
const parsed = await listWorkflowRunsRoute.parse(req, res, pathSegments, queryParams);
|
|
756
759
|
if (!parsed) return true;
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
if (
|
|
760
|
-
|
|
760
|
+
const paginationRequested =
|
|
761
|
+
parsed.query?.limit !== undefined || parsed.query?.offset !== undefined;
|
|
762
|
+
if (paginationRequested) {
|
|
763
|
+
const page = listWorkflowRunsPage(parsed.params.id, {
|
|
764
|
+
status: parsed.query?.status,
|
|
765
|
+
limit: parsed.query?.limit ?? 20,
|
|
766
|
+
offset: parsed.query?.offset ?? 0,
|
|
767
|
+
});
|
|
768
|
+
json(res, page);
|
|
769
|
+
return true;
|
|
761
770
|
}
|
|
771
|
+
// Preserve the pre-pagination response for the UI when limit/offset are
|
|
772
|
+
// omitted: a bare array containing every matching run.
|
|
773
|
+
const runs = listWorkflowRuns(parsed.params.id, { status: parsed.query?.status });
|
|
762
774
|
json(res, runs);
|
|
763
775
|
return true;
|
|
764
776
|
}
|
|
@@ -450,20 +450,23 @@ registerTemplate({
|
|
|
450
450
|
defaultBody: `
|
|
451
451
|
### Script Authoring Contract (read BEFORE writing any script)
|
|
452
452
|
|
|
453
|
-
**Entry point — \`args\` FIRST, \`ctx\` SECOND.** A one-parameter \`function (ctx)\`
|
|
453
|
+
**Entry point — \`args\` FIRST, \`ctx\` SECOND.** A one-parameter \`function (ctx)\` can execute through \`script-run\`, but at runtime that parameter receives \`args\`, so every \`ctx.*\` access throws. \`script-upsert\` also rejects an untyped parameter under strict typechecking. This is the single most common cause of failed script runs.
|
|
454
454
|
|
|
455
455
|
\`\`\`ts
|
|
456
|
+
import type { ScriptContext } from "swarm-sdk";
|
|
456
457
|
import * as z from "zod";
|
|
457
458
|
|
|
458
459
|
export const argsSchema = z.object({ taskId: z.string(), limit: z.number().optional() });
|
|
459
460
|
|
|
460
|
-
export default async function (args: z.infer<typeof argsSchema>, ctx) {
|
|
461
|
+
export default async function (args: z.infer<typeof argsSchema>, ctx: ScriptContext) {
|
|
461
462
|
const res = await ctx.swarm.task_get({ taskId: args.taskId });
|
|
462
|
-
const task = res
|
|
463
|
+
const task = ((res as { data?: unknown }).data ?? res) as { title?: string };
|
|
463
464
|
return { title: task?.title };
|
|
464
465
|
}
|
|
465
466
|
\`\`\`
|
|
466
467
|
|
|
468
|
+
**Typechecking:** inline source passed to \`script-run\` executes without a compile-time typecheck. \`script-upsert\` typechecks before saving, so import \`ScriptContext\` from \`"swarm-sdk"\` as shown above to make inline code promotion-safe. Use \`script-query-types\` for the authoritative SDK and stdlib declarations.
|
|
469
|
+
|
|
467
470
|
**What \`ctx\` actually holds for inline/named scripts (\`script-run\` / \`script-upsert\`) — nothing else:**
|
|
468
471
|
- \`ctx.swarm.*\` — the swarm SDK: \`task_get\`, \`task_send\`, \`task_storeProgress\`, \`task_action\`, \`task_list\`, \`message_post\`, \`message_read\`, \`slack_reply\`, \`memory_search\`, \`kv_get\`/\`kv_set\`/\`kv_del\`/\`kv_incr\`/\`kv_list\`, \`swarm_get\`, \`agent_info\`, and more. Responses are usually wrapped — prefer \`res?.data ?? res\`.
|
|
469
472
|
- \`ctx.swarm.config\` — \`apiKey\`, \`agentId\`, \`mcpBaseUrl\`, plus \`ctx.swarm.config.get("KEY")\` for user values. All are \`Redacted\` wrappers: they stringify to \`<redacted>\`, and you must never unwrap them into a return value, log line, or request body you build by hand.
|
|
@@ -270,10 +270,20 @@ function bridgeRequestFor(name: string, args: unknown): BridgeRequest | null {
|
|
|
270
270
|
case "workflow_listRuns": {
|
|
271
271
|
const wfId = typeof body.workflowId === "string" ? body.workflowId : undefined;
|
|
272
272
|
if (!wfId) throw new Error("workflow_listRuns requires string `workflowId`");
|
|
273
|
+
const limit = body.limit === undefined ? 20 : body.limit;
|
|
274
|
+
const offset = body.offset === undefined ? 0 : body.offset;
|
|
275
|
+
if (!Number.isInteger(limit) || (limit as number) < 1 || (limit as number) > 100) {
|
|
276
|
+
throw new Error("workflow_listRuns `limit` must be an integer between 1 and 100");
|
|
277
|
+
}
|
|
278
|
+
if (!Number.isInteger(offset) || (offset as number) < 0) {
|
|
279
|
+
throw new Error("workflow_listRuns `offset` must be a non-negative integer");
|
|
280
|
+
}
|
|
273
281
|
return {
|
|
274
282
|
method: "GET",
|
|
275
283
|
path: appendQuery(`/api/workflows/${encodeURIComponent(wfId)}/runs`, {
|
|
276
284
|
status: body.status,
|
|
285
|
+
limit,
|
|
286
|
+
offset,
|
|
277
287
|
}),
|
|
278
288
|
};
|
|
279
289
|
}
|
|
@@ -182,6 +182,8 @@ declare module "swarm-sdk" {
|
|
|
182
182
|
workflow_listRuns(args: {
|
|
183
183
|
workflowId: string;
|
|
184
184
|
status?: "running" | "waiting" | "completed" | "failed" | "skipped" | "cancelled";
|
|
185
|
+
limit?: number;
|
|
186
|
+
offset?: number;
|
|
185
187
|
}): Promise<unknown>;
|
|
186
188
|
workflow_getRun(args: { id: string }): Promise<unknown>;
|
|
187
189
|
// --- prompt templates ---
|
|
@@ -442,6 +444,8 @@ declare module "swarm-sdk" {
|
|
|
442
444
|
* A swarm script's default export. `args` comes FIRST, `ctx` second — never swap them.
|
|
443
445
|
*
|
|
444
446
|
* @example
|
|
447
|
+
* import type { ScriptContext } from "swarm-sdk";
|
|
448
|
+
*
|
|
445
449
|
* export default async function (args: { name: string }, ctx: ScriptContext) {
|
|
446
450
|
* await ctx.logger.log(`hello ${args.name}`);
|
|
447
451
|
* return { ok: true };
|
|
@@ -164,6 +164,8 @@ declare module "swarm-sdk" {
|
|
|
164
164
|
workflow_listRuns(args: {
|
|
165
165
|
workflowId: string;
|
|
166
166
|
status?: "running" | "waiting" | "completed" | "failed" | "skipped" | "cancelled";
|
|
167
|
+
limit?: number;
|
|
168
|
+
offset?: number;
|
|
167
169
|
}): Promise<unknown>;
|
|
168
170
|
workflow_getRun(args: { id: string }): Promise<unknown>;
|
|
169
171
|
// --- prompt templates ---
|
|
@@ -424,6 +426,8 @@ declare module "swarm-sdk" {
|
|
|
424
426
|
* A swarm script's default export. `args` comes FIRST, `ctx` second — never swap them.
|
|
425
427
|
*
|
|
426
428
|
* @example
|
|
429
|
+
* import type { ScriptContext } from "swarm-sdk";
|
|
430
|
+
*
|
|
427
431
|
* export default async function (args: { name: string }, ctx: ScriptContext) {
|
|
428
432
|
* await ctx.logger.log(`hello ${args.name}`);
|
|
429
433
|
* return { ok: true };
|
package/src/telemetry.ts
CHANGED
|
@@ -218,16 +218,19 @@ export async function initTelemetry(
|
|
|
218
218
|
const existing = await getConfig("telemetry_installation_id");
|
|
219
219
|
if (existing) {
|
|
220
220
|
installationId = existing;
|
|
221
|
-
//
|
|
222
|
-
//
|
|
223
|
-
//
|
|
224
|
-
//
|
|
225
|
-
//
|
|
221
|
+
// A pre-existing installation ID with no stored anchor means this
|
|
222
|
+
// install predates `telemetry_installed_at` tracking. Do NOT mint
|
|
223
|
+
// now() as a stand-in "install date" here — that back-fills a date
|
|
224
|
+
// that's wrong by however long the install has actually existed
|
|
225
|
+
// (seen: 110 days on our own production install after a routine
|
|
226
|
+
// upgrade). Leave installedAt null so the field is omitted from the
|
|
227
|
+
// payload: absence unambiguously means "pre-existing install, anchor
|
|
228
|
+
// unknown", and consumers can fall back to min(occurred_at) per
|
|
229
|
+
// installation_id in ClickHouse for the real anchor. Only a
|
|
230
|
+
// genuinely new installationId (the branch below) mints one.
|
|
226
231
|
const existingInstalledAt = await getConfig("telemetry_installed_at");
|
|
227
232
|
if (existingInstalledAt) {
|
|
228
233
|
installedAt = existingInstalledAt;
|
|
229
|
-
} else if (generateIfMissing) {
|
|
230
|
-
await tryPersistInstalledAt(setConfig);
|
|
231
234
|
}
|
|
232
235
|
} else if (generateIfMissing) {
|
|
233
236
|
const candidateId = `install_${randomUUID().replace(/-/g, "").slice(0, 16)}`;
|
|
@@ -48,9 +48,9 @@ describe("script MCP tools", () => {
|
|
|
48
48
|
"script-search":
|
|
49
49
|
"Semantic search over swarm-shared TypeScript scripts (catalog persisted in the agent-swarm DB; callable from agents and workflows). For ephemeral throwaway TS on your local machine, use code-mode instead.",
|
|
50
50
|
"script-run":
|
|
51
|
-
"Run a named swarm-shared script (callable across agents and from workflow `swarm-script` nodes), OR inline source (auto-saved as scratch to the catalog). Use for swarm-visible, durable scripts. For local-only throwaway TS, use code-mode `run`.",
|
|
51
|
+
"Run a named swarm-shared script (callable across agents and from workflow `swarm-script` nodes), OR inline source (auto-saved as scratch to the catalog). Inline source executes without the `script-upsert` compile-time typecheck. Use for swarm-visible, durable scripts. For local-only throwaway TS, use code-mode `run`.",
|
|
52
52
|
"script-upsert":
|
|
53
|
-
|
|
53
|
+
'Typecheck and persist a TypeScript script to the swarm catalog under your agent scope (or global if you\'re a lead). Import `ScriptContext` from "swarm-sdk" for a real context type. Other agents and workflow nodes will be able to find and run it. For local-only scripts, use code-mode `save`.',
|
|
54
54
|
"script-delete":
|
|
55
55
|
"Remove a swarm-shared script from the catalog. Versions table preserves history.",
|
|
56
56
|
"script-query-types":
|
|
@@ -220,8 +220,15 @@ describe("Session templates — individual resolution", () => {
|
|
|
220
220
|
const result = resolveTemplate("system.agent.script_authoring_contract", {});
|
|
221
221
|
expect(result.skipped).toBe(false);
|
|
222
222
|
expect(result.text).toContain("`args` FIRST, `ctx` SECOND");
|
|
223
|
+
expect(result.text).toContain('import type { ScriptContext } from "swarm-sdk"');
|
|
223
224
|
expect(result.text).toContain("export default async function (args");
|
|
225
|
+
expect(result.text).toContain("ctx: ScriptContext");
|
|
224
226
|
expect(result.text).toContain("export const argsSchema");
|
|
227
|
+
expect(result.text).toContain(
|
|
228
|
+
"inline source passed to `script-run` executes without a compile-time typecheck",
|
|
229
|
+
);
|
|
230
|
+
expect(result.text).toContain("`script-upsert` typechecks before saving");
|
|
231
|
+
expect(result.text).toContain("`script-query-types`");
|
|
225
232
|
expect(result.text).toContain("ctx.swarm.config");
|
|
226
233
|
expect(result.text).toContain("ctx.api.<slug>");
|
|
227
234
|
expect(result.text).toContain("ctx.stdlib");
|
|
@@ -9,6 +9,7 @@ import { handleCore } from "../http/core";
|
|
|
9
9
|
import { handleScriptRuns } from "../http/script-runs";
|
|
10
10
|
import { handleScripts } from "../http/scripts";
|
|
11
11
|
import { getPathSegments, parseQueryParams } from "../http/utils";
|
|
12
|
+
import { getTemplateDefinition } from "../prompts/registry";
|
|
12
13
|
import { registerScriptDeleteTool } from "../tools/script-delete";
|
|
13
14
|
import { registerScriptRunTool } from "../tools/script-run";
|
|
14
15
|
import { registerScriptRunsTools } from "../tools/script-runs";
|
|
@@ -16,6 +17,8 @@ import { registerScriptSearchTool } from "../tools/script-search";
|
|
|
16
17
|
import { registerScriptUpsertTool } from "../tools/script-upsert";
|
|
17
18
|
import { refreshSecretScrubberCache } from "../utils/secret-scrubber";
|
|
18
19
|
|
|
20
|
+
import "../prompts/session-templates";
|
|
21
|
+
|
|
19
22
|
const TEST_DB_PATH = "./test-scripts-mcp-e2e.sqlite";
|
|
20
23
|
const API_KEY = "test-scripts-mcp-key-1234567890";
|
|
21
24
|
|
|
@@ -207,6 +210,27 @@ beforeEach(() => {
|
|
|
207
210
|
});
|
|
208
211
|
|
|
209
212
|
describe("script_ MCP HTTP proxy tools", () => {
|
|
213
|
+
test("upserts the canonical script authoring contract example verbatim", async () => {
|
|
214
|
+
const tools = buildToolServer();
|
|
215
|
+
const contract = getTemplateDefinition("system.agent.script_authoring_contract");
|
|
216
|
+
const source = contract?.defaultBody.match(/```ts\n([\s\S]*?)\n```/)?.[1];
|
|
217
|
+
expect(source).toBeTruthy();
|
|
218
|
+
|
|
219
|
+
const upsert = (await tools.upsert.handler(
|
|
220
|
+
{
|
|
221
|
+
name: "canonical-authoring-contract",
|
|
222
|
+
source,
|
|
223
|
+
description: "Canonical authoring contract fixture",
|
|
224
|
+
intent: "verify documented source typechecks",
|
|
225
|
+
},
|
|
226
|
+
meta(workerId),
|
|
227
|
+
)) as StructuredResult<{ name: string }>;
|
|
228
|
+
|
|
229
|
+
expect(upsert.isError).toBeFalsy();
|
|
230
|
+
expect(upsert.structuredContent.success).toBe(true);
|
|
231
|
+
expect(upsert.structuredContent.data?.name).toBe("canonical-authoring-contract");
|
|
232
|
+
});
|
|
233
|
+
|
|
210
234
|
test("exercise script-upsert -> script-search -> script-run -> script-delete", async () => {
|
|
211
235
|
const tools = buildToolServer();
|
|
212
236
|
const source = `export default async (args: { value: number }) => ({ result: args.value * 7 });`;
|
|
@@ -462,8 +486,33 @@ describe("script_ MCP HTTP proxy tools", () => {
|
|
|
462
486
|
// summarizes ... details carries the payload the model actually needs").
|
|
463
487
|
expect(bad.isError).toBe(true);
|
|
464
488
|
expect(bad.structuredContent.success).toBe(false);
|
|
465
|
-
expect(bad.structuredContent.message).
|
|
489
|
+
expect(bad.structuredContent.message).toMatch(/^Typecheck failed:/);
|
|
490
|
+
expect(bad.structuredContent.message).not.toContain("(+1 more)");
|
|
466
491
|
expect(bad.structuredContent.details).toBeTruthy();
|
|
467
|
-
expect(bad.content[0]?.text).toContain(
|
|
492
|
+
expect(bad.content[0]?.text).toContain(bad.structuredContent.message);
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
test("reports only remaining typecheck diagnostics in the summary", async () => {
|
|
496
|
+
const tools = buildToolServer();
|
|
497
|
+
const bad = (await tools.upsert.handler(
|
|
498
|
+
{
|
|
499
|
+
name: "two-type-errors",
|
|
500
|
+
source: `
|
|
501
|
+
export default async () => {
|
|
502
|
+
const count: number = "one";
|
|
503
|
+
const enabled: boolean = 1;
|
|
504
|
+
return { count, enabled };
|
|
505
|
+
};
|
|
506
|
+
`,
|
|
507
|
+
description: "Two diagnostic fixture",
|
|
508
|
+
intent: "verify diagnostic summary cardinality",
|
|
509
|
+
},
|
|
510
|
+
meta(workerId),
|
|
511
|
+
)) as StructuredResult<{ diagnostics: string[] }>;
|
|
512
|
+
|
|
513
|
+
expect(bad.isError).toBe(true);
|
|
514
|
+
expect(bad.structuredContent.success).toBe(false);
|
|
515
|
+
expect(bad.structuredContent.message).toMatch(/\(\+1 more\)$/);
|
|
516
|
+
expect(bad.structuredContent.message).not.toContain("(+2 more)");
|
|
468
517
|
});
|
|
469
518
|
});
|
|
@@ -123,6 +123,23 @@ describe("typecheckScript", () => {
|
|
|
123
123
|
expect(d.message).toContain("number");
|
|
124
124
|
});
|
|
125
125
|
|
|
126
|
+
test("returns exactly one formatted entry per compiler diagnostic", () => {
|
|
127
|
+
const result = typecheckScript(`
|
|
128
|
+
export default async () => {
|
|
129
|
+
const count: number = "one";
|
|
130
|
+
const enabled: boolean = 1;
|
|
131
|
+
return { count, enabled };
|
|
132
|
+
};
|
|
133
|
+
`);
|
|
134
|
+
expect(result.ok).toBe(false);
|
|
135
|
+
if (result.ok) return;
|
|
136
|
+
|
|
137
|
+
expect(result.structured).toHaveLength(2);
|
|
138
|
+
expect(result.diagnostics).toHaveLength(result.structured.length);
|
|
139
|
+
expect(result.diagnostics[0]).toContain("Type 'string' is not assignable to type 'number'");
|
|
140
|
+
expect(result.diagnostics[1]).toContain("Type 'number' is not assignable to type 'boolean'");
|
|
141
|
+
});
|
|
142
|
+
|
|
126
143
|
test("captures the offending identifier on TS2304 (Cannot find name)", () => {
|
|
127
144
|
const result = typecheckScript(`
|
|
128
145
|
export default async () => {
|