@desplega.ai/agent-swarm 1.123.0 → 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-e4c9f0xy.js → actions-z3d0fk7z.js} +6 -6
- package/dist/{app-vmvmj2v3.js → app-q2rc9tdr.js} +4 -4
- package/dist/{assistant-yn7a792a.js → assistant-3stjq7fz.js} +9 -9
- package/dist/{boot-reembed-xg1r86h2.js → boot-reembed-5867whnb.js} +3 -3
- package/dist/{boot-reembed-chxty50a.js → boot-reembed-v6r1df32.js} +4 -4
- package/dist/{boot-scrub-logs-exwddvp5.js → boot-scrub-logs-8b8jegk3.js} +2 -2
- package/dist/{cli-1592nfd6.js → cli-0925phzv.js} +1 -1
- package/dist/{cli-hbbxmhec.js → cli-2yr6edr7.js} +4 -4
- package/dist/{cli-8cq4z4x7.js → cli-3z4q09tn.js} +182 -19
- package/dist/{cli-vz9drmce.js → cli-5jn6wnd9.js} +17 -8
- package/dist/{cli-5arfywtm.js → cli-5ncdb7ff.js} +19 -9
- package/dist/{cli-3tv9z4wx.js → cli-92bqgbgy.js} +1 -1
- package/dist/{cli-fjf04hpa.js → cli-dq2ssyf0.js} +48 -56
- package/dist/{cli-mngsj9fx.js → cli-gkvf8d83.js} +1 -1
- package/dist/{cli-mepk1j0t.js → cli-gzjsamwc.js} +2 -2
- package/dist/{cli-c9m59f83.js → cli-h89g0qrd.js} +1 -1
- package/dist/{cli-n8mf7x4b.js → cli-jp4mdj9d.js} +2 -2
- package/dist/{cli-822d4bjk.js → cli-kk58tg33.js} +7 -7
- package/dist/{cli-9hj1adgp.js → cli-mcez7z4p.js} +1 -1
- package/dist/{cli-byv3720g.js → cli-mmk5vagg.js} +2 -2
- package/dist/{cli-zdp11t8m.js → cli-p0ec4vv6.js} +1 -1
- package/dist/{cli-h2say6xk.js → cli-p0zgv8pj.js} +3 -1
- package/dist/{cli-8ef5ky75.js → cli-perb20ma.js} +1 -1
- package/dist/{cli-zkj6f2sk.js → cli-qf7acvyr.js} +90 -4
- package/dist/{cli-kmm1rwmp.js → cli-qwsagsmg.js} +1 -1
- package/dist/{cli-we91ywvy.js → cli-sqv6c9b8.js} +6 -6
- package/dist/{cli-np0yhmmk.js → cli-vm20sh8d.js} +3 -3
- package/dist/{cli-p11rf59d.js → cli-wn3m6q54.js} +3 -3
- package/dist/{cli-mkpf4ndf.js → cli-x268say8.js} +2976 -5621
- package/dist/{cli-ngbsk4yx.js → cli-y43n987v.js} +1 -1
- package/dist/{cli-4509mwm5.js → cli-ykthjw29.js} +8 -8
- package/dist/{cli-9eka6jwv.js → cli-zxb72ctk.js} +2 -2
- package/dist/cli.js +12 -10
- package/dist/{commands-sjk3zfyr.js → commands-sda76yn8.js} +2 -2
- package/dist/{db-2je5agjb.js → db-vn9e4rqj.js} +6 -2
- package/dist/{e2b-2s4psnbf.js → e2b-q345y8s4.js} +0 -4
- package/dist/{handlers-yzv369hf.js → handlers-xfja18ac.js} +9 -9
- package/dist/{hook-rfsj2r8x.js → hook-2medrp47.js} +1 -40
- package/dist/{http-v9rr144m.js → http-937pyjfc.js} +99 -44
- package/dist/{index-nr2199m6.js → index-2bqd2q9v.js} +11 -11
- package/dist/{index-3xtk777g.js → index-gw4en7jg.js} +9 -9
- package/dist/{index-c3tan44f.js → index-knqczmnm.js} +10 -10
- package/dist/{index-smjdc3h9.js → index-vah60vxp.js} +8 -8
- package/dist/{keepalive-5ds53bjd.js → keepalive-20rd6hxh.js} +5 -5
- package/dist/{lead-5xhez25b.js → lead-7w2k3a49.js} +21 -21
- package/dist/{maintenance-b43d24q6.js → maintenance-p3x918yw.js} +4 -4
- package/dist/{oauth-refresh-sweep-qe286vn2.js → oauth-refresh-sweep-shm0nzm4.js} +4 -4
- package/dist/{onboard-c4r3ds3z.js → onboard-py9dnf54.js} +6 -2
- package/dist/{otel-impl-nv3rjw61.js → otel-impl-7yjkfg68.js} +1 -1
- package/dist/{pi-mono-adapter-2syx1x4d.js → pi-mono-adapter-z6h98fva.js} +4 -38
- package/dist/{pricing-refresh-5ct2wp4k.js → pricing-refresh-3snb6370.js} +4 -4
- package/dist/{rbac-roles-m502w0qv.js → rbac-roles-5e72bbpk.js} +3 -3
- package/dist/{rbac-roles-b82cxpxn.js → rbac-roles-gqxdp8st.js} +4 -4
- package/dist/{seed-pricing-jhjphbf0.js → seed-pricing-bg42d7h2.js} +3 -3
- package/dist/{setup-zbaspydq.js → setup-nzk3kbbq.js} +2 -2
- package/dist/{worker-snvhpax5.js → worker-0p1jdzkm.js} +21 -21
- package/openapi.json +146 -1
- package/package.json +3 -1
- package/src/be/db.ts +81 -4
- package/src/be/models-catalog.ts +156 -0
- package/src/be/modelsdev-cache.ts +14 -1
- package/src/be/pricing-refresh.ts +2 -0
- package/src/be/scripts/typecheck.ts +17 -4
- package/src/be/seed-scripts/catalog/task-context-gathering.ts +1 -1
- package/src/commands/onboard/env-generator.ts +12 -0
- package/src/e2b/env.ts +0 -4
- package/src/hooks/hook.ts +0 -67
- package/src/http/all-routes.ts +1 -0
- package/src/http/index.ts +2 -0
- package/src/http/models-catalog.ts +65 -0
- package/src/http/workflows.ts +16 -4
- package/src/prompts/base-prompt.ts +8 -7
- package/src/prompts/session-templates.ts +106 -12
- package/src/providers/pi-mono-adapter.ts +12 -2
- package/src/providers/pi-mono-extension.ts +0 -64
- package/src/providers/pricing-sources.md +16 -1
- package/src/scripts-runtime/eval-harness.ts +18 -1
- package/src/scripts-runtime/swarm-sdk.ts +10 -0
- package/src/scripts-runtime/types/stdlib.d.ts +13 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +13 -0
- package/src/server-user.ts +4 -7
- package/src/slack/blocks.ts +21 -8
- package/src/slack/responses.ts +27 -51
- package/src/slack/watcher.ts +22 -5
- package/src/telemetry.ts +169 -3
- package/src/tests/base-prompt.test.ts +79 -0
- package/src/tests/mcp-tools-user.test.ts +62 -16
- package/src/tests/mcp-tools.test.ts +6 -3
- package/src/tests/memory-edit.test.ts +21 -4
- package/src/tests/model-groups-live-catalog.test.ts +65 -0
- package/src/tests/models-catalog.test.ts +119 -0
- package/src/tests/oauth-access-token-tool.test.ts +71 -1
- package/src/tests/pricing-refresh.test.ts +25 -0
- package/src/tests/prompt-template-session.test.ts +142 -5
- package/src/tests/rbac-charact-skills.test.ts +81 -14
- package/src/tests/script-apis-mcp.test.ts +56 -8
- package/src/tests/scripts-mcp-e2e.test.ts +157 -8
- 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/slack-blocks.test.ts +2 -1
- package/src/tests/slack-inline-output.test.ts +24 -30
- package/src/tests/slack-watcher.test.ts +42 -0
- package/src/tests/steer-task-tool.test.ts +37 -8
- package/src/tests/steering-transport.test.ts +18 -3
- package/src/tests/swarm-tool-result-gate.test.ts +399 -0
- package/src/tests/task-tools-ctx.test.ts +49 -17
- package/src/tests/task-tools-ownership.test.ts +41 -13
- package/src/tests/telemetry-init.test.ts +376 -2
- package/src/tests/tool-output-agent-id.test.ts +14 -2
- package/src/tests/workflow-http-v2.test.ts +116 -0
- package/src/tools/accept-steer.ts +45 -53
- package/src/tools/cancel-task.ts +31 -41
- package/src/tools/context-diff.ts +19 -63
- package/src/tools/context-history.ts +22 -51
- package/src/tools/create-channel.ts +24 -39
- package/src/tools/create-metric.ts +19 -82
- package/src/tools/create-page.ts +20 -81
- package/src/tools/credential-bindings/tool.ts +125 -246
- package/src/tools/db-query.ts +13 -24
- package/src/tools/delete-channel.ts +25 -71
- package/src/tools/delete-page.ts +27 -75
- package/src/tools/get-metrics.ts +29 -22
- package/src/tools/get-swarm.ts +44 -15
- package/src/tools/get-task-details.ts +150 -32
- package/src/tools/get-tasks.ts +63 -29
- package/src/tools/inject-learning.ts +8 -38
- package/src/tools/join-swarm.ts +45 -47
- package/src/tools/kv/kv-delete.ts +13 -37
- package/src/tools/kv/kv-get.ts +38 -29
- package/src/tools/kv/kv-incr.ts +28 -56
- package/src/tools/kv/kv-list.ts +40 -31
- package/src/tools/kv/kv-set.ts +34 -76
- package/src/tools/list-channels.ts +24 -17
- package/src/tools/list-services.ts +37 -45
- package/src/tools/manage-user.ts +53 -66
- package/src/tools/mcp-servers/mcp-server-create.ts +19 -55
- package/src/tools/mcp-servers/mcp-server-delete.ts +9 -39
- package/src/tools/mcp-servers/mcp-server-get.ts +9 -35
- package/src/tools/mcp-servers/mcp-server-install.ts +13 -60
- package/src/tools/mcp-servers/mcp-server-list.ts +28 -26
- package/src/tools/mcp-servers/mcp-server-uninstall.ts +10 -36
- package/src/tools/mcp-servers/mcp-server-update.ts +13 -57
- package/src/tools/memory-delete.ts +16 -46
- package/src/tools/memory-edit.ts +48 -49
- package/src/tools/memory-get.ts +40 -36
- package/src/tools/memory-rate.ts +14 -44
- package/src/tools/memory-search.ts +46 -52
- package/src/tools/my-agent-info.ts +39 -33
- package/src/tools/oauth-access-token.ts +9 -24
- package/src/tools/poll-task.ts +50 -77
- package/src/tools/post-message.ts +24 -38
- package/src/tools/prompt-templates/delete.ts +16 -48
- package/src/tools/prompt-templates/get.ts +45 -42
- package/src/tools/prompt-templates/list.ts +29 -44
- package/src/tools/prompt-templates/preview.ts +14 -40
- package/src/tools/prompt-templates/set.ts +30 -52
- package/src/tools/read-messages.ts +45 -54
- package/src/tools/register-agentmail-inbox.ts +28 -84
- package/src/tools/register-kapso-number.ts +20 -50
- package/src/tools/register-service.ts +36 -44
- package/src/tools/repos/get-repos.ts +29 -21
- package/src/tools/repos/update-repo.ts +30 -27
- package/src/tools/request-human-input.ts +10 -33
- package/src/tools/resolve-user.ts +59 -16
- package/src/tools/schedules/create-schedule.ts +58 -173
- package/src/tools/schedules/delete-schedule.ts +16 -56
- package/src/tools/schedules/list-schedules.ts +41 -67
- package/src/tools/schedules/patch-schedule.ts +57 -153
- package/src/tools/schedules/run-schedule-now.ts +18 -59
- package/src/tools/schedules/update-schedule.ts +57 -153
- package/src/tools/script-apis.ts +46 -28
- package/src/tools/script-common.ts +129 -34
- package/src/tools/script-connections/tool.ts +59 -154
- package/src/tools/script-query-types.ts +43 -3
- package/src/tools/script-run.ts +41 -2
- package/src/tools/script-runs.ts +69 -1
- package/src/tools/script-search.ts +24 -1
- package/src/tools/script-upsert.ts +18 -3
- package/src/tools/send-task.ts +32 -81
- package/src/tools/skills/skill-create.ts +14 -39
- package/src/tools/skills/skill-delete.ts +14 -42
- package/src/tools/skills/skill-get-file.ts +10 -43
- package/src/tools/skills/skill-get.ts +9 -32
- package/src/tools/skills/skill-install-remote.ts +16 -52
- package/src/tools/skills/skill-install.ts +14 -52
- package/src/tools/skills/skill-list.ts +24 -26
- package/src/tools/skills/skill-publish.ts +18 -54
- package/src/tools/skills/skill-search.ts +21 -18
- package/src/tools/skills/skill-sync-remote.ts +12 -24
- package/src/tools/skills/skill-uninstall.ts +10 -26
- package/src/tools/skills/skill-update.ts +24 -81
- package/src/tools/slack-delete.ts +8 -32
- package/src/tools/slack-download-file.ts +17 -57
- package/src/tools/slack-list-channels.ts +16 -43
- package/src/tools/slack-post.ts +11 -40
- package/src/tools/slack-read.ts +33 -103
- package/src/tools/slack-reply.ts +16 -53
- package/src/tools/slack-start-thread.ts +14 -55
- package/src/tools/slack-update.ts +8 -35
- package/src/tools/slack-upload-file.ts +22 -122
- package/src/tools/steer-task.ts +22 -35
- package/src/tools/store-progress.ts +11 -26
- package/src/tools/swarm-config/delete-config.ts +19 -57
- package/src/tools/swarm-config/get-config.ts +36 -44
- package/src/tools/swarm-config/list-config.ts +36 -44
- package/src/tools/swarm-config/set-config.ts +35 -73
- package/src/tools/swarm-x.ts +20 -26
- package/src/tools/task-action.ts +26 -46
- package/src/tools/task-tool-ctx.ts +5 -13
- package/src/tools/tracker/tracker-link-task.ts +8 -22
- package/src/tools/tracker/tracker-map-agent.ts +8 -22
- package/src/tools/tracker/tracker-status.ts +27 -19
- package/src/tools/tracker/tracker-sync-status.ts +8 -18
- package/src/tools/tracker/tracker-unlink.ts +4 -16
- package/src/tools/unregister-service.ts +19 -59
- package/src/tools/update-profile.ts +60 -100
- package/src/tools/update-service-status.ts +42 -67
- package/src/tools/utils.ts +189 -8
- package/src/tools/whatsapp-message.ts +19 -32
- package/src/tools/workflows/cancel-workflow-run.ts +4 -16
- package/src/tools/workflows/create-workflow.ts +9 -38
- package/src/tools/workflows/delete-workflow.ts +5 -17
- package/src/tools/workflows/get-workflow-run.ts +41 -31
- package/src/tools/workflows/get-workflow.ts +10 -21
- package/src/tools/workflows/list-workflow-runs.ts +107 -34
- package/src/tools/workflows/list-workflows.ts +5 -17
- package/src/tools/workflows/patch-workflow-node.ts +11 -39
- package/src/tools/workflows/patch-workflow.ts +11 -36
- package/src/tools/workflows/retry-workflow-run.ts +4 -16
- package/src/tools/workflows/trigger-workflow.ts +22 -58
- package/src/tools/workflows/update-workflow.ts +10 -42
- package/templates/skills/swarm-scripts/SKILL.md +1 -1
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import { mergeScheduleTiming, validateRecurringTiming } from "@/be/schedules/validate";
|
|
14
14
|
import { getScript } from "@/be/scripts/db";
|
|
15
15
|
import { calculateNextRun } from "@/scheduler";
|
|
16
|
-
import { createToolRegistrar } from "@/tools/utils";
|
|
16
|
+
import { createToolRegistrar, swarmToolOutputSchema, toolErr, toolOk } from "@/tools/utils";
|
|
17
17
|
import {
|
|
18
18
|
AssetKeySchema,
|
|
19
19
|
ModelTierSchema,
|
|
@@ -73,6 +73,34 @@ export const updateScheduleInputSchema = z.object({
|
|
|
73
73
|
.describe("Portable model tier for tasks created by this schedule. Set to null to clear."),
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
+
const scheduleDataShape = {
|
|
77
|
+
id: z.string().optional(),
|
|
78
|
+
key: AssetKeySchema.optional(),
|
|
79
|
+
name: z.string().optional(),
|
|
80
|
+
description: z.string().optional(),
|
|
81
|
+
cronExpression: z.string().optional(),
|
|
82
|
+
intervalMs: z.number().optional(),
|
|
83
|
+
taskTemplate: z.string().optional(),
|
|
84
|
+
taskType: z.string().optional(),
|
|
85
|
+
tags: z.array(z.string()).optional(),
|
|
86
|
+
priority: z.number().optional(),
|
|
87
|
+
targetAgentId: z.string().optional(),
|
|
88
|
+
enabled: z.boolean().optional(),
|
|
89
|
+
lastRunAt: z.string().optional(),
|
|
90
|
+
nextRunAt: z.string().optional(),
|
|
91
|
+
createdByAgentId: z.string().optional(),
|
|
92
|
+
timezone: z.string().optional(),
|
|
93
|
+
model: z.string().optional(),
|
|
94
|
+
modelTier: ModelTierSchema.optional(),
|
|
95
|
+
scheduleType: z.string().optional(),
|
|
96
|
+
targetType: ScheduledTaskTargetTypeSchema.optional(),
|
|
97
|
+
workflowId: z.string().optional(),
|
|
98
|
+
scriptName: z.string().optional(),
|
|
99
|
+
scriptArgs: z.record(z.string(), z.unknown()).optional(),
|
|
100
|
+
createdAt: z.string().optional(),
|
|
101
|
+
lastUpdatedAt: z.string().optional(),
|
|
102
|
+
};
|
|
103
|
+
|
|
76
104
|
export const registerUpdateScheduleTool = (server: McpServer) => {
|
|
77
105
|
createToolRegistrar(server)(
|
|
78
106
|
"update-schedule",
|
|
@@ -81,39 +109,9 @@ export const registerUpdateScheduleTool = (server: McpServer) => {
|
|
|
81
109
|
annotations: { idempotentHint: true },
|
|
82
110
|
description: "Update an existing scheduled task. Any registered agent can update schedules.",
|
|
83
111
|
inputSchema: updateScheduleInputSchema,
|
|
84
|
-
outputSchema:
|
|
112
|
+
outputSchema: swarmToolOutputSchema({
|
|
85
113
|
yourAgentId: z.string().optional(),
|
|
86
|
-
|
|
87
|
-
message: z.string(),
|
|
88
|
-
schedule: z
|
|
89
|
-
.object({
|
|
90
|
-
id: z.string(),
|
|
91
|
-
key: AssetKeySchema,
|
|
92
|
-
name: z.string(),
|
|
93
|
-
description: z.string().optional(),
|
|
94
|
-
cronExpression: z.string().optional(),
|
|
95
|
-
intervalMs: z.number().optional(),
|
|
96
|
-
taskTemplate: z.string().optional(),
|
|
97
|
-
taskType: z.string().optional(),
|
|
98
|
-
tags: z.array(z.string()),
|
|
99
|
-
priority: z.number(),
|
|
100
|
-
targetAgentId: z.string().optional(),
|
|
101
|
-
enabled: z.boolean(),
|
|
102
|
-
lastRunAt: z.string().optional(),
|
|
103
|
-
nextRunAt: z.string().optional(),
|
|
104
|
-
createdByAgentId: z.string().optional(),
|
|
105
|
-
timezone: z.string(),
|
|
106
|
-
model: z.string().optional(),
|
|
107
|
-
modelTier: ModelTierSchema.optional(),
|
|
108
|
-
scheduleType: z.string(),
|
|
109
|
-
targetType: ScheduledTaskTargetTypeSchema.optional(),
|
|
110
|
-
workflowId: z.string().optional(),
|
|
111
|
-
scriptName: z.string().optional(),
|
|
112
|
-
scriptArgs: z.record(z.string(), z.unknown()).optional(),
|
|
113
|
-
createdAt: z.string(),
|
|
114
|
-
lastUpdatedAt: z.string(),
|
|
115
|
-
})
|
|
116
|
-
.optional(),
|
|
114
|
+
schedule: z.looseObject(scheduleDataShape).optional(),
|
|
117
115
|
}),
|
|
118
116
|
},
|
|
119
117
|
async (
|
|
@@ -143,13 +141,7 @@ export const registerUpdateScheduleTool = (server: McpServer) => {
|
|
|
143
141
|
_meta,
|
|
144
142
|
) => {
|
|
145
143
|
if (!requestInfo.agentId) {
|
|
146
|
-
return
|
|
147
|
-
content: [{ type: "text", text: 'Agent ID not found. Set the "X-Agent-ID" header.' }],
|
|
148
|
-
structuredContent: {
|
|
149
|
-
success: false,
|
|
150
|
-
message: 'Agent ID not found. Set the "X-Agent-ID" header.',
|
|
151
|
-
},
|
|
152
|
-
};
|
|
144
|
+
return toolErr('Agent ID not found. Set the "X-Agent-ID" header.');
|
|
153
145
|
}
|
|
154
146
|
|
|
155
147
|
// Find the schedule
|
|
@@ -160,40 +152,19 @@ export const registerUpdateScheduleTool = (server: McpServer) => {
|
|
|
160
152
|
: null;
|
|
161
153
|
|
|
162
154
|
if (!schedule) {
|
|
163
|
-
return
|
|
164
|
-
content: [{ type: "text", text: "Schedule not found." }],
|
|
165
|
-
structuredContent: {
|
|
166
|
-
success: false,
|
|
167
|
-
message: "Schedule not found.",
|
|
168
|
-
},
|
|
169
|
-
};
|
|
155
|
+
return toolErr("Schedule not found.");
|
|
170
156
|
}
|
|
171
157
|
|
|
172
158
|
const caller = getAgentById(requestInfo.agentId);
|
|
173
159
|
if (!caller) {
|
|
174
|
-
return
|
|
175
|
-
content: [{ type: "text", text: "Agent not found." }],
|
|
176
|
-
structuredContent: {
|
|
177
|
-
success: false,
|
|
178
|
-
message: "Agent not found.",
|
|
179
|
-
},
|
|
180
|
-
};
|
|
160
|
+
return toolErr("Agent not found.");
|
|
181
161
|
}
|
|
182
162
|
|
|
183
163
|
// Reject updates on completed one-time schedules
|
|
184
164
|
if (schedule.scheduleType === "one_time" && !schedule.enabled && schedule.lastRunAt) {
|
|
185
|
-
return
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
type: "text",
|
|
189
|
-
text: `One-time schedule "${schedule.name}" has already executed. Create a new one instead.`,
|
|
190
|
-
},
|
|
191
|
-
],
|
|
192
|
-
structuredContent: {
|
|
193
|
-
success: false,
|
|
194
|
-
message: `One-time schedule "${schedule.name}" has already executed. Create a new one instead.`,
|
|
195
|
-
},
|
|
196
|
-
};
|
|
165
|
+
return toolErr(
|
|
166
|
+
`One-time schedule "${schedule.name}" has already executed. Create a new one instead.`,
|
|
167
|
+
);
|
|
197
168
|
}
|
|
198
169
|
|
|
199
170
|
// Validate new cron expression if provided
|
|
@@ -204,13 +175,7 @@ export const registerUpdateScheduleTool = (server: McpServer) => {
|
|
|
204
175
|
});
|
|
205
176
|
} catch (err) {
|
|
206
177
|
const message = err instanceof Error ? err.message : "Invalid cron expression";
|
|
207
|
-
return {
|
|
208
|
-
content: [{ type: "text", text: `Invalid cron expression: ${message}` }],
|
|
209
|
-
structuredContent: {
|
|
210
|
-
success: false,
|
|
211
|
-
message: `Invalid cron expression: ${message}`,
|
|
212
|
-
},
|
|
213
|
-
};
|
|
178
|
+
return toolErr(`Invalid cron expression: ${message}`);
|
|
214
179
|
}
|
|
215
180
|
}
|
|
216
181
|
|
|
@@ -218,13 +183,7 @@ export const registerUpdateScheduleTool = (server: McpServer) => {
|
|
|
218
183
|
if (targetAgentId && targetAgentId !== null) {
|
|
219
184
|
const agent = getAgentById(targetAgentId);
|
|
220
185
|
if (!agent) {
|
|
221
|
-
return {
|
|
222
|
-
content: [{ type: "text", text: `Target agent not found: ${targetAgentId}` }],
|
|
223
|
-
structuredContent: {
|
|
224
|
-
success: false,
|
|
225
|
-
message: `Target agent not found: ${targetAgentId}`,
|
|
226
|
-
},
|
|
227
|
-
};
|
|
186
|
+
return toolErr(`Target agent not found: ${targetAgentId}`);
|
|
228
187
|
}
|
|
229
188
|
}
|
|
230
189
|
|
|
@@ -232,13 +191,7 @@ export const registerUpdateScheduleTool = (server: McpServer) => {
|
|
|
232
191
|
if (newName && newName !== schedule.name) {
|
|
233
192
|
const existing = getScheduledTaskByName(newName);
|
|
234
193
|
if (existing) {
|
|
235
|
-
return {
|
|
236
|
-
content: [{ type: "text", text: `Schedule with name "${newName}" already exists.` }],
|
|
237
|
-
structuredContent: {
|
|
238
|
-
success: false,
|
|
239
|
-
message: `Schedule with name "${newName}" already exists.`,
|
|
240
|
-
},
|
|
241
|
-
};
|
|
194
|
+
return toolErr(`Schedule with name "${newName}" already exists.`);
|
|
242
195
|
}
|
|
243
196
|
}
|
|
244
197
|
|
|
@@ -249,42 +202,22 @@ export const registerUpdateScheduleTool = (server: McpServer) => {
|
|
|
249
202
|
const mergedScriptName = scriptName !== undefined ? scriptName : schedule.scriptName;
|
|
250
203
|
|
|
251
204
|
if (mergedTargetType === "agent-task" && !mergedTaskTemplate) {
|
|
252
|
-
|
|
253
|
-
return {
|
|
254
|
-
content: [{ type: "text", text: message }],
|
|
255
|
-
structuredContent: { success: false, message },
|
|
256
|
-
};
|
|
205
|
+
return toolErr("taskTemplate is required when targetType is 'agent-task'.");
|
|
257
206
|
}
|
|
258
207
|
if (mergedTargetType === "workflow") {
|
|
259
208
|
if (!mergedWorkflowId) {
|
|
260
|
-
|
|
261
|
-
return {
|
|
262
|
-
content: [{ type: "text", text: message }],
|
|
263
|
-
structuredContent: { success: false, message },
|
|
264
|
-
};
|
|
209
|
+
return toolErr("workflowId is required when targetType is 'workflow'.");
|
|
265
210
|
}
|
|
266
211
|
if (!getWorkflow(mergedWorkflowId)) {
|
|
267
|
-
|
|
268
|
-
return {
|
|
269
|
-
content: [{ type: "text", text: message }],
|
|
270
|
-
structuredContent: { success: false, message },
|
|
271
|
-
};
|
|
212
|
+
return toolErr(`Workflow not found: ${mergedWorkflowId}`);
|
|
272
213
|
}
|
|
273
214
|
}
|
|
274
215
|
if (mergedTargetType === "script") {
|
|
275
216
|
if (!mergedScriptName) {
|
|
276
|
-
|
|
277
|
-
return {
|
|
278
|
-
content: [{ type: "text", text: message }],
|
|
279
|
-
structuredContent: { success: false, message },
|
|
280
|
-
};
|
|
217
|
+
return toolErr("scriptName is required when targetType is 'script'.");
|
|
281
218
|
}
|
|
282
219
|
if (!getScript({ name: mergedScriptName, scope: "global" })) {
|
|
283
|
-
|
|
284
|
-
return {
|
|
285
|
-
content: [{ type: "text", text: message }],
|
|
286
|
-
structuredContent: { success: false, message },
|
|
287
|
-
};
|
|
220
|
+
return toolErr(`Script not found: ${mergedScriptName}`);
|
|
288
221
|
}
|
|
289
222
|
}
|
|
290
223
|
|
|
@@ -333,19 +266,9 @@ export const registerUpdateScheduleTool = (server: McpServer) => {
|
|
|
333
266
|
);
|
|
334
267
|
const timingError = validateRecurringTiming(timing);
|
|
335
268
|
if (timingError) {
|
|
336
|
-
return
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
type: "text",
|
|
340
|
-
text: "At least one of intervalMs or cronExpression must be set for recurring schedules.",
|
|
341
|
-
},
|
|
342
|
-
],
|
|
343
|
-
structuredContent: {
|
|
344
|
-
success: false,
|
|
345
|
-
message:
|
|
346
|
-
"At least one of intervalMs or cronExpression must be set for recurring schedules.",
|
|
347
|
-
},
|
|
348
|
-
};
|
|
269
|
+
return toolErr(
|
|
270
|
+
"At least one of intervalMs or cronExpression must be set for recurring schedules.",
|
|
271
|
+
);
|
|
349
272
|
}
|
|
350
273
|
|
|
351
274
|
const needsNextRunRecalc =
|
|
@@ -375,39 +298,20 @@ export const registerUpdateScheduleTool = (server: McpServer) => {
|
|
|
375
298
|
const updated = updateScheduledTask(schedule.id, { ...updateData, updatedBy });
|
|
376
299
|
|
|
377
300
|
if (!updated) {
|
|
378
|
-
return
|
|
379
|
-
content: [{ type: "text", text: "Failed to update schedule." }],
|
|
380
|
-
structuredContent: {
|
|
381
|
-
success: false,
|
|
382
|
-
message: "Failed to update schedule.",
|
|
383
|
-
},
|
|
384
|
-
};
|
|
301
|
+
return toolErr("Failed to update schedule.");
|
|
385
302
|
}
|
|
386
303
|
|
|
387
|
-
return
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
text: `Updated schedule "${updated.name}". Next run: ${updated.nextRunAt || "disabled"}`,
|
|
392
|
-
},
|
|
393
|
-
],
|
|
394
|
-
structuredContent: {
|
|
395
|
-
yourAgentId: requestInfo.agentId,
|
|
396
|
-
success: true,
|
|
397
|
-
message: `Updated schedule "${updated.name}".`,
|
|
398
|
-
schedule: updated,
|
|
304
|
+
return toolOk(
|
|
305
|
+
`Updated schedule "${updated.name}". Next run: ${updated.nextRunAt || "disabled"}`,
|
|
306
|
+
{
|
|
307
|
+
data: { yourAgentId: requestInfo.agentId, schedule: updated },
|
|
399
308
|
},
|
|
400
|
-
|
|
309
|
+
);
|
|
401
310
|
} catch (error) {
|
|
402
311
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
403
|
-
return {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
yourAgentId: requestInfo.agentId,
|
|
407
|
-
success: false,
|
|
408
|
-
message: `Failed to update schedule: ${message}`,
|
|
409
|
-
},
|
|
410
|
-
};
|
|
312
|
+
return toolErr(`Failed to update schedule: ${message}`, {
|
|
313
|
+
data: { yourAgentId: requestInfo.agentId },
|
|
314
|
+
});
|
|
411
315
|
}
|
|
412
316
|
},
|
|
413
317
|
);
|
package/src/tools/script-apis.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
3
2
|
import * as z from "zod";
|
|
4
3
|
import { getAgentById } from "@/be/db";
|
|
5
4
|
import { can, type PermissionVerb } from "@/rbac";
|
|
6
|
-
import type { RequestInfo } from "@/tools/utils";
|
|
7
|
-
import { createToolRegistrar } from "@/tools/utils";
|
|
5
|
+
import type { RequestInfo, SwarmToolResult } from "@/tools/utils";
|
|
6
|
+
import { createToolRegistrar, toolErr, toolOk } from "@/tools/utils";
|
|
8
7
|
import type { ScriptApiRecord, ScriptApiWithSecret } from "@/types";
|
|
9
8
|
import { registerVolatileSecret } from "@/utils/secret-scrubber";
|
|
10
9
|
import { proxyScriptsApi, SCRIPT_TRANSPORT_ERROR, scriptToolOutputSchema } from "./script-common";
|
|
@@ -44,20 +43,23 @@ function maskToken(endpoint: RawEndpoint): RawEndpoint {
|
|
|
44
43
|
return { ...rest, token: endpoint.authMode === "bearer" ? "********" : null };
|
|
45
44
|
}
|
|
46
45
|
|
|
47
|
-
function
|
|
48
|
-
return
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
function renderEndpointsList(endpoints: RawEndpoint[]): string | undefined {
|
|
47
|
+
if (endpoints.length === 0) return undefined;
|
|
48
|
+
return endpoints
|
|
49
|
+
.map((endpoint) => {
|
|
50
|
+
const label = endpoint.label ? ` "${endpoint.label}"` : "";
|
|
51
|
+
const token = endpoint.token ? `, token=${endpoint.token}` : "";
|
|
52
|
+
return `- ${endpoint.id}${label}: authMode=${endpoint.authMode}, enabled=${endpoint.enabled}${token}`;
|
|
53
|
+
})
|
|
54
|
+
.join("\n");
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
function requireScriptApiPermission(
|
|
56
58
|
requestInfo: RequestInfo,
|
|
57
59
|
verb: PermissionVerb,
|
|
58
60
|
message: string,
|
|
59
|
-
):
|
|
60
|
-
if (!requestInfo.agentId) return
|
|
61
|
+
): SwarmToolResult | null {
|
|
62
|
+
if (!requestInfo.agentId) return toolErr(SCRIPT_TRANSPORT_ERROR);
|
|
61
63
|
|
|
62
64
|
const agent = getAgentById(requestInfo.agentId);
|
|
63
65
|
const decision = can({
|
|
@@ -70,7 +72,7 @@ function requireScriptApiPermission(
|
|
|
70
72
|
resource: { kind: "none" },
|
|
71
73
|
source: "mcp",
|
|
72
74
|
});
|
|
73
|
-
return decision.allow ? null :
|
|
75
|
+
return decision.allow ? null : toolErr(message, { data: { status: 403 } });
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
export const registerScriptApisTool = (server: McpServer) => {
|
|
@@ -92,8 +94,8 @@ export const registerScriptApisTool = (server: McpServer) => {
|
|
|
92
94
|
requestInfo,
|
|
93
95
|
successMessage: () => "",
|
|
94
96
|
});
|
|
95
|
-
if (result.
|
|
96
|
-
const raw = (result.
|
|
97
|
+
if (!result.ok) return result;
|
|
98
|
+
const raw = (result.data as { data?: { apis?: RawEndpoint[] } } | undefined)?.data;
|
|
97
99
|
let endpoints = (raw?.apis ?? []).map(maskToken);
|
|
98
100
|
|
|
99
101
|
if (args.includeSecrets) {
|
|
@@ -113,8 +115,8 @@ export const registerScriptApisTool = (server: McpServer) => {
|
|
|
113
115
|
requestInfo,
|
|
114
116
|
successMessage: () => "",
|
|
115
117
|
});
|
|
116
|
-
if (secretResult.
|
|
117
|
-
const token = (secretResult.
|
|
118
|
+
if (!secretResult.ok) return endpoint;
|
|
119
|
+
const token = (secretResult.data as { data?: { token?: string | null } } | undefined)
|
|
118
120
|
?.data?.token;
|
|
119
121
|
if (token) registerVolatileSecret(token, `script-api:${endpoint.id}`);
|
|
120
122
|
return { ...endpoint, token: token ?? null };
|
|
@@ -122,10 +124,12 @@ export const registerScriptApisTool = (server: McpServer) => {
|
|
|
122
124
|
);
|
|
123
125
|
}
|
|
124
126
|
|
|
125
|
-
return {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
return toolOk(`Found ${endpoints.length} endpoint(s).`, {
|
|
128
|
+
details: renderEndpointsList(endpoints),
|
|
129
|
+
data: { status: 200, data: { apis: endpoints } },
|
|
130
|
+
// Deliberate reveal path — includeSecrets returns real bearer tokens.
|
|
131
|
+
allowSecretEgress: args.includeSecrets === true,
|
|
132
|
+
});
|
|
129
133
|
}
|
|
130
134
|
|
|
131
135
|
if (args.action === "create") {
|
|
@@ -146,16 +150,23 @@ export const registerScriptApisTool = (server: McpServer) => {
|
|
|
146
150
|
},
|
|
147
151
|
requestInfo,
|
|
148
152
|
successMessage: (data) => `Endpoint ${(data as ScriptApiWithSecret).id} created.`,
|
|
153
|
+
successDetails: (data) => {
|
|
154
|
+
const token = (data as ScriptApiWithSecret).token;
|
|
155
|
+
return token ? `Bearer token (shown once — save it now): ${token}` : undefined;
|
|
156
|
+
},
|
|
149
157
|
});
|
|
150
|
-
if (
|
|
151
|
-
const endpoint = (result.
|
|
158
|
+
if (result.ok) {
|
|
159
|
+
const endpoint = (result.data as { data?: ScriptApiWithSecret } | undefined)?.data;
|
|
152
160
|
if (endpoint?.token) registerVolatileSecret(endpoint.token, `script-api:${endpoint.id}`);
|
|
161
|
+
// Deliberate one-time reveal — the volatile secret registered above
|
|
162
|
+
// would otherwise be redacted by the finalize scrubber.
|
|
163
|
+
return { ...result, allowSecretEgress: true };
|
|
153
164
|
}
|
|
154
165
|
return result;
|
|
155
166
|
}
|
|
156
167
|
|
|
157
168
|
if (args.action === "rotate") {
|
|
158
|
-
if (!args.endpointId) return
|
|
169
|
+
if (!args.endpointId) return toolErr("endpointId is required for rotate.");
|
|
159
170
|
const denied = requireScriptApiPermission(
|
|
160
171
|
requestInfo,
|
|
161
172
|
"script.api.rotate",
|
|
@@ -168,16 +179,23 @@ export const registerScriptApisTool = (server: McpServer) => {
|
|
|
168
179
|
path: `/api/scripts/${args.scriptId}/apis/${args.endpointId}/rotate`,
|
|
169
180
|
requestInfo,
|
|
170
181
|
successMessage: () => "Token rotated.",
|
|
182
|
+
successDetails: (data) => {
|
|
183
|
+
const token = (data as ScriptApiWithSecret).token;
|
|
184
|
+
return token ? `New bearer token (shown once — save it now): ${token}` : undefined;
|
|
185
|
+
},
|
|
171
186
|
});
|
|
172
|
-
if (
|
|
173
|
-
const endpoint = (result.
|
|
187
|
+
if (result.ok) {
|
|
188
|
+
const endpoint = (result.data as { data?: ScriptApiWithSecret } | undefined)?.data;
|
|
174
189
|
if (endpoint?.token) registerVolatileSecret(endpoint.token, `script-api:${endpoint.id}`);
|
|
190
|
+
// Deliberate one-time reveal — the volatile secret registered above
|
|
191
|
+
// would otherwise be redacted by the finalize scrubber.
|
|
192
|
+
return { ...result, allowSecretEgress: true };
|
|
175
193
|
}
|
|
176
194
|
return result;
|
|
177
195
|
}
|
|
178
196
|
|
|
179
197
|
if (args.action === "update") {
|
|
180
|
-
if (!args.endpointId) return
|
|
198
|
+
if (!args.endpointId) return toolErr("endpointId is required for update.");
|
|
181
199
|
const denied = requireScriptApiPermission(
|
|
182
200
|
requestInfo,
|
|
183
201
|
"script.api.update",
|
|
@@ -195,7 +213,7 @@ export const registerScriptApisTool = (server: McpServer) => {
|
|
|
195
213
|
}
|
|
196
214
|
|
|
197
215
|
if (args.action === "delete") {
|
|
198
|
-
if (!args.endpointId) return
|
|
216
|
+
if (!args.endpointId) return toolErr("endpointId is required for delete.");
|
|
199
217
|
const denied = requireScriptApiPermission(
|
|
200
218
|
requestInfo,
|
|
201
219
|
"script.api.delete",
|
|
@@ -211,7 +229,7 @@ export const registerScriptApisTool = (server: McpServer) => {
|
|
|
211
229
|
});
|
|
212
230
|
}
|
|
213
231
|
|
|
214
|
-
return
|
|
232
|
+
return toolErr(`Unknown action: ${args.action}`);
|
|
215
233
|
},
|
|
216
234
|
);
|
|
217
235
|
};
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
1
|
import * as z from "zod";
|
|
3
2
|
import { getApiKey } from "@/utils/api-key";
|
|
4
3
|
import { getMcpBaseUrl } from "@/utils/constants";
|
|
5
|
-
import
|
|
4
|
+
import {
|
|
5
|
+
type RequestInfo,
|
|
6
|
+
type SwarmToolResult,
|
|
7
|
+
swarmToolOutputSchema,
|
|
8
|
+
toolErr,
|
|
9
|
+
toolOk,
|
|
10
|
+
} from "./utils";
|
|
6
11
|
|
|
7
12
|
export const SCRIPT_TRANSPORT_ERROR =
|
|
8
13
|
"script_* tools require HTTP MCP transport — agent identity is not available over stdio in this build. Switch to MCP_BASE_URL=http://... or invoke the HTTP API directly.";
|
|
@@ -11,29 +16,108 @@ export const scriptNameSchema = z.string().min(1).max(200);
|
|
|
11
16
|
export const scriptScopeSchema = z.enum(["agent", "global"]);
|
|
12
17
|
export const scriptFsModeSchema = z.enum(["none", "workspace-rw"]);
|
|
13
18
|
|
|
14
|
-
export const scriptToolOutputSchema =
|
|
15
|
-
|
|
16
|
-
status: z.number(),
|
|
19
|
+
export const scriptToolOutputSchema = swarmToolOutputSchema({
|
|
20
|
+
status: z.number().optional(),
|
|
17
21
|
data: z.unknown().optional(),
|
|
18
|
-
error: z.string().optional(),
|
|
19
22
|
});
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
const DETAILS_CAP = 16_000;
|
|
25
|
+
|
|
26
|
+
function stripAnsi(text: string): string {
|
|
27
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: stripping terminal color codes
|
|
28
|
+
return text.replace(/\x1b\[[0-9;]*m/g, "");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function capDetails(text: string | undefined): string | undefined {
|
|
32
|
+
if (!text) return undefined;
|
|
33
|
+
if (text.length <= DETAILS_CAP) return text;
|
|
34
|
+
return `${text.slice(0, DETAILS_CAP)}\n… [truncated ${text.length - DETAILS_CAP} chars]`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
38
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
39
|
+
}
|
|
22
40
|
|
|
23
41
|
function apiBaseUrl(): string {
|
|
24
42
|
return getMcpBaseUrl();
|
|
25
43
|
}
|
|
26
44
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
45
|
+
type ScriptFailure = { message: string; details?: string };
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Honest failure detection for the scripts API. The API returns HTTP 200 for
|
|
49
|
+
* script runs that failed at runtime (error / runtimeError / exitCode live in
|
|
50
|
+
* the body) and durable runs carry `run.status` / `run.error` — trusting
|
|
51
|
+
* `res.ok` alone reports failures as successes.
|
|
52
|
+
*/
|
|
53
|
+
function describeScriptFailure(
|
|
54
|
+
resOk: boolean,
|
|
55
|
+
status: number,
|
|
56
|
+
data: unknown,
|
|
57
|
+
): ScriptFailure | undefined {
|
|
58
|
+
const body = isRecord(data) ? data : undefined;
|
|
59
|
+
|
|
60
|
+
if (!resOk) {
|
|
61
|
+
const error = body && "error" in body ? String(body.error) : undefined;
|
|
62
|
+
|
|
63
|
+
// Typecheck rejection: fold real diagnostics instead of the literal "typecheck_failed".
|
|
64
|
+
const diagnostics =
|
|
65
|
+
body && Array.isArray(body.diagnostics)
|
|
66
|
+
? (body.diagnostics as unknown[]).map((d) => stripAnsi(String(d)))
|
|
67
|
+
: undefined;
|
|
68
|
+
if (error === "typecheck_failed" && diagnostics && diagnostics.length > 0) {
|
|
69
|
+
const more = diagnostics.length > 1 ? ` (+${diagnostics.length - 1} more)` : "";
|
|
70
|
+
const firstLine = diagnostics[0]?.split("\n")[0] ?? "unknown diagnostic";
|
|
71
|
+
return {
|
|
72
|
+
message: `Typecheck failed: ${firstLine}${more}`,
|
|
73
|
+
details: capDetails(diagnostics.join("\n\n")),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Label-lint / policy rejections: fold violation detail.
|
|
78
|
+
const violations =
|
|
79
|
+
body && Array.isArray(body.violations) ? (body.violations as unknown[]) : undefined;
|
|
80
|
+
if (violations && violations.length > 0) {
|
|
81
|
+
return {
|
|
82
|
+
message: `${error ?? `Scripts API request failed with ${status}`} — ${violations.length} violation(s)`,
|
|
83
|
+
details: capDetails(
|
|
84
|
+
violations.map((v) => (typeof v === "string" ? v : JSON.stringify(v))).join("\n"),
|
|
85
|
+
),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return { message: error ?? `Scripts API request failed with ${status}` };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// HTTP 200 inline-run body: failure signalled inside the payload.
|
|
93
|
+
if (body && ("exitCode" in body || "runtimeError" in body || "stderr" in body)) {
|
|
94
|
+
const runtimeError = isRecord(body.runtimeError)
|
|
95
|
+
? `${String(body.runtimeError.name ?? "Error")}: ${String(body.runtimeError.message ?? "")}`
|
|
96
|
+
: undefined;
|
|
97
|
+
const error = typeof body.error === "string" && body.error ? body.error : undefined;
|
|
98
|
+
const exitCode = typeof body.exitCode === "number" ? body.exitCode : 0;
|
|
99
|
+
if (error || runtimeError || exitCode !== 0) {
|
|
100
|
+
const reason =
|
|
101
|
+
[error, runtimeError].filter(Boolean).join(" — ") || `script exited with code ${exitCode}`;
|
|
102
|
+
const stderr =
|
|
103
|
+
typeof body.stderr === "string" && body.stderr.trim() ? body.stderr.trim() : undefined;
|
|
104
|
+
return {
|
|
105
|
+
message: `Script run failed: ${reason}`,
|
|
106
|
+
details: capDetails(stderr ? `stderr:\n${stderr}` : undefined),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Durable run body: { run: { status, error, ... } }.
|
|
112
|
+
if (body && isRecord(body.run) && body.run.status === "failed") {
|
|
113
|
+
const runError =
|
|
114
|
+
typeof body.run.error === "string" && body.run.error ? body.run.error : "unknown error";
|
|
115
|
+
return {
|
|
116
|
+
message: `Script run ${String(body.run.id ?? "")} failed: ${runError}`.replace(" ", " "),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return undefined;
|
|
37
121
|
}
|
|
38
122
|
|
|
39
123
|
export async function proxyScriptsApi(args: {
|
|
@@ -42,8 +126,22 @@ export async function proxyScriptsApi(args: {
|
|
|
42
126
|
body?: unknown;
|
|
43
127
|
requestInfo: RequestInfo;
|
|
44
128
|
successMessage: (data: unknown) => string;
|
|
45
|
-
|
|
46
|
-
|
|
129
|
+
/** Optional model-facing rendering of the success payload (appended to the text channel). */
|
|
130
|
+
successDetails?: (data: unknown) => string | undefined;
|
|
131
|
+
/**
|
|
132
|
+
* Optional model-facing rendering of the payload when the call fails, used
|
|
133
|
+
* when the failure itself carries no details (e.g. a failed durable run whose
|
|
134
|
+
* journal holds the step errors).
|
|
135
|
+
*/
|
|
136
|
+
failureDetails?: (data: unknown) => string | undefined;
|
|
137
|
+
/**
|
|
138
|
+
* Skip the generic details cap. Only for payloads that are authoritative in
|
|
139
|
+
* full (e.g. script-query-types' type blobs, which exceed the cap and have
|
|
140
|
+
* no pagination) — everything else stays capped.
|
|
141
|
+
*/
|
|
142
|
+
uncappedDetails?: boolean;
|
|
143
|
+
}): Promise<SwarmToolResult> {
|
|
144
|
+
if (!args.requestInfo.agentId) return toolErr(SCRIPT_TRANSPORT_ERROR);
|
|
47
145
|
|
|
48
146
|
const apiKey = getApiKey();
|
|
49
147
|
const headers: Record<string, string> = {
|
|
@@ -70,21 +168,18 @@ export async function proxyScriptsApi(args: {
|
|
|
70
168
|
}
|
|
71
169
|
}
|
|
72
170
|
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
171
|
+
const toolData = { status: res.status, data };
|
|
172
|
+
const failure = describeScriptFailure(res.ok, res.status, data);
|
|
173
|
+
if (failure) {
|
|
174
|
+
return toolErr(failure.message, {
|
|
175
|
+
details: failure.details ?? capDetails(args.failureDetails?.(data)),
|
|
176
|
+
data: toolData,
|
|
177
|
+
});
|
|
80
178
|
}
|
|
81
179
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
data,
|
|
88
|
-
} satisfies ScriptToolStructuredContent,
|
|
89
|
-
};
|
|
180
|
+
const successDetails = args.successDetails?.(data);
|
|
181
|
+
return toolOk(args.successMessage(data), {
|
|
182
|
+
details: args.uncappedDetails ? successDetails : capDetails(successDetails),
|
|
183
|
+
data: toolData,
|
|
184
|
+
});
|
|
90
185
|
}
|