@desplega.ai/agent-swarm 1.147.0 → 1.149.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 +13 -1
- package/dist/{acp-adapter-9n319wqc.js → acp-adapter-4jncb126.js} +12 -5
- package/dist/{actions-2vxqvpr9.js → actions-31vp3ae7.js} +10 -9
- package/dist/{app-w066xfy0.js → app-1hh67x8w.js} +6 -6
- package/dist/{assistant-kt31dj2h.js → assistant-z66dmz6p.js} +13 -11
- package/dist/{boot-reembed-az5rassp.js → boot-reembed-fqzxxzjh.js} +7 -7
- package/dist/{boot-reembed-j3mm3rfz.js → boot-reembed-wxa8ya0s.js} +8 -8
- package/dist/{boot-scrub-logs-b6h54817.js → boot-scrub-logs-jnyndh79.js} +5 -5
- package/dist/{claude-adapter-w1z04ann.js → claude-adapter-3qpa9w0j.js} +9 -9
- package/dist/{claude-managed-adapter-sactwn31.js → claude-managed-adapter-qvsmh6mv.js} +2 -2
- package/dist/{claude-sdk-session-f0cc1kec.js → claude-sdk-session-2yxgjs5d.js} +9 -9
- package/dist/{cli-y6b6fb76.js → cli-08b07b4r.js} +1 -1
- package/dist/{cli-8fc8de14.js → cli-0z2v4nhw.js} +1 -1
- package/dist/{cli-de14znh8.js → cli-19f354qr.js} +2 -2
- package/dist/{cli-hbv0kq6w.js → cli-2qts1hys.js} +3 -3
- package/dist/{cli-kpv03zhj.js → cli-3apbzgyk.js} +27 -15
- package/dist/{cli-1th1728g.js → cli-3q5ejx9p.js} +2 -2
- package/dist/{cli-d8brzxjb.js → cli-4wtq5jjv.js} +2 -2
- package/dist/{cli-ct0et58h.js → cli-5my3bjsd.js} +1 -1
- package/dist/{cli-cn6mmc7f.js → cli-6664w7y4.js} +1 -1
- package/dist/{cli-yz3djrm0.js → cli-6pqcb4q0.js} +53 -13
- package/dist/{cli-719k9j2c.js → cli-7smrsr25.js} +3 -3
- package/dist/{cli-rw51bq3j.js → cli-9fy6nk6g.js} +1 -1
- package/dist/{cli-zhjmqxzh.js → cli-9hspd3dp.js} +2 -2
- package/dist/{cli-3tgwnf43.js → cli-aae6hz6a.js} +4 -4
- package/dist/{cli-89xfd7f9.js → cli-cr12paw2.js} +5 -5
- package/dist/{cli-b5bq9crk.js → cli-d8ftsp62.js} +8 -8
- package/dist/{cli-4nr988h6.js → cli-e95cx1eb.js} +3 -3
- package/dist/{cli-n8508nre.js → cli-gjhjfeeg.js} +1 -1
- package/dist/{cli-p1d5b073.js → cli-gv88e1vf.js} +1 -1
- package/dist/{cli-rvqz34y5.js → cli-jecc01cb.js} +1 -1
- package/dist/{cli-8v0g1yc8.js → cli-k0cr4kat.js} +1 -1
- package/dist/{cli-mmemxxdc.js → cli-kgz4np97.js} +4 -4
- package/dist/{cli-w9kb3bk1.js → cli-kjwt6hdf.js} +3 -1
- package/dist/{cli-f7dsy61y.js → cli-mnmsfd1w.js} +6 -2
- package/dist/{cli-54wwve05.js → cli-n3dz2942.js} +37 -26
- package/dist/{cli-12fz972k.js → cli-nye12xk5.js} +8 -5
- package/dist/{cli-tzvk9haz.js → cli-phsxnkp6.js} +20 -20
- package/dist/{cli-53s590z8.js → cli-q50ef8g0.js} +1 -1
- package/dist/{cli-f146mn5s.js → cli-qaacms9y.js} +7 -6
- package/dist/{cli-xqcq9y5e.js → cli-r2ap2czm.js} +1 -0
- package/dist/{cli-m8yrsg97.js → cli-sd5pv3b1.js} +3 -3
- package/dist/{cli-0b6y7kxm.js → cli-xm87hzbw.js} +1 -1
- package/dist/{cli-ftht3zzj.js → cli-yab68w40.js} +285 -11
- package/dist/{cli-atcve9y8.js → cli-yb9qhqam.js} +227 -59
- package/dist/{cli-smby5m17.js → cli-ygweqcn4.js} +133 -22
- package/dist/{cli-dttph1bw.js → cli-ykxrnd1q.js} +2 -2
- package/dist/{cli-m9sxbkhm.js → cli-zvz62chv.js} +3 -3
- package/dist/cli.js +16 -14
- package/dist/{codex-adapter-zw4dwsx7.js → codex-adapter-8meawydj.js} +4 -4
- package/dist/{codex-hook-bw8p5nh4.js → codex-hook-hfrt9shr.js} +2 -2
- package/dist/{codex-session-runner-k981s65v.js → codex-session-runner-gjgxyp5j.js} +4 -4
- package/dist/{commands-sykrxx7e.js → commands-hz3nb95f.js} +5 -5
- package/dist/{db-sfbsc8wt.js → db-ggz97zbm.js} +5 -5
- package/dist/{e2b-6hb103d8.js → e2b-p04vmtx0.js} +1 -1
- package/dist/{handlers-0aspcejm.js → handlers-nbzdzn9k.js} +14 -11
- package/dist/{hook-hxccs7m5.js → hook-bks2q1f6.js} +7 -7
- package/dist/{hook-4nvqj2sb.js → hook-kq9wp0ep.js} +8 -8
- package/dist/{http-y06z517d.js → http-hrf77v87.js} +96 -45
- package/dist/{index-tce1rss4.js → index-6nsbg88z.js} +443 -144
- package/dist/{index-x5j894zf.js → index-8hmeg8j1.js} +14 -14
- package/dist/{index-k8znfx0z.js → index-cqtebbhb.js} +13 -13
- package/dist/{index-hssww7kj.js → index-n28pw1zt.js} +15 -15
- package/dist/{keepalive-w733ax66.js → keepalive-dxc12gvg.js} +7 -7
- package/dist/{lead-75bjqa9d.js → lead-yckfn18d.js} +32 -32
- package/dist/{maintenance-w4f1zjck.js → maintenance-6kfb2m5e.js} +8 -8
- package/dist/{oauth-refresh-sweep-wdetky26.js → oauth-refresh-sweep-1x1ac722.js} +6 -6
- package/dist/{onboard-bb5net8s.js → onboard-dcyt1609.js} +4 -3
- package/dist/{opencode-adapter-fef1mrn2.js → opencode-adapter-dce4wskd.js} +2 -2
- package/dist/{otel-impl-0w7c14ap.js → otel-impl-tbk3e5dr.js} +2 -2
- package/dist/{pi-mono-adapter-2has4gnp.js → pi-mono-adapter-zvshk5cj.js} +2 -2
- package/dist/{pricing-refresh-9nzsrgcq.js → pricing-refresh-kaqg567e.js} +7 -7
- package/dist/{rbac-roles-z1jrffbt.js → rbac-roles-ammq6rd2.js} +5 -5
- package/dist/{rbac-roles-r3hqjp09.js → rbac-roles-cf97v1vd.js} +6 -6
- package/dist/{render-v2-vbr89fnb.js → render-v2-80w603vy.js} +6 -6
- package/dist/{seed-pricing-g62hy1pk.js → seed-pricing-zbrn83xv.js} +6 -6
- package/dist/{setup-gnfqnptp.js → setup-fe66kczs.js} +2 -2
- package/dist/{worker-kznxp4qm.js → worker-qmb2d1e2.js} +32 -32
- package/dist/{x-n2phr5vm.js → x-n3e0v3xa.js} +2 -2
- package/openapi.json +46 -4
- package/package.json +3 -1
- package/src/agentmail/handlers.ts +5 -0
- package/src/automation-preflight-alert.ts +41 -0
- package/src/be/automation-preflight.ts +3 -3
- package/src/be/budget-refusal-notify.ts +1 -0
- package/src/be/db/tasks/read.ts +5 -0
- package/src/be/db.ts +132 -2
- package/src/be/migrations/150_deferred_task_waits.sql +18 -0
- package/src/be/migrations/151_repair_scheduled_task_required_params.sql +39 -0
- package/src/be/migrations/152_routing_decisions.sql +44 -0
- package/src/be/scripts/typecheck.ts +33 -22
- package/src/be/seed-scripts/catalog/delegate.ts +5 -1
- package/src/be/seed-skills/bundled-files.generated.json +10 -0
- package/src/be/seed-skills/index.ts +3 -0
- package/src/be/steering.ts +1 -0
- package/src/be/swarm-config-guard.ts +11 -0
- package/src/commands/onboard/steps/post-task.tsx +1 -0
- package/src/github/handlers.ts +9 -0
- package/src/gitlab/handlers.ts +4 -0
- package/src/heartbeat/heartbeat.ts +8 -0
- package/src/http/approval-requests.ts +1 -0
- package/src/http/apps.ts +1 -0
- package/src/http/config.ts +15 -6
- package/src/http/mcp.ts +31 -4
- package/src/http/script-runs.ts +6 -0
- package/src/http/tasks.ts +52 -30
- package/src/integrations/kapso/inbound.ts +1 -0
- package/src/jira/sync.ts +2 -0
- package/src/linear/sync.ts +2 -0
- package/src/prompts/session-templates.ts +29 -15
- package/src/scheduler/deferred-task-waits.ts +123 -0
- package/src/scheduler/schedule-task.ts +42 -0
- package/src/scheduler/scheduler.ts +22 -31
- package/src/script-workflows/workflow-ctx.ts +2 -0
- package/src/scripts-runtime/types/stdlib.d.ts +38 -24
- package/src/scripts-runtime/types/swarm-sdk.d.ts +38 -24
- package/src/server.ts +10 -1
- package/src/slack/actions.ts +1 -0
- package/src/slack/assistant.ts +2 -0
- package/src/slack/handlers.ts +3 -0
- package/src/slack/thread-buffer.ts +2 -0
- package/src/tasks/worker-follow-up.ts +9 -0
- package/src/tests/acp-adapter.test.ts +35 -6
- package/src/tests/acp-session-token.test.ts +67 -0
- package/src/tests/asset-key-api.test.ts +15 -2
- package/src/tests/asset-key-mcp.test.ts +2 -0
- package/src/tests/automation-preflight-alert.test.ts +91 -0
- package/src/tests/claude-worker-parity.test.ts +3 -0
- package/src/tests/config-session-auth.test.ts +143 -0
- package/src/tests/defer-task.test.ts +117 -6
- package/src/tests/deferred-task-wake.test.ts +456 -0
- package/src/tests/heartbeat-reroute-decision.test.ts +1 -0
- package/src/tests/http-api-integration.test.ts +33 -4
- package/src/tests/mcp-input-ergonomics.test.ts +386 -0
- package/src/tests/model-control.test.ts +18 -5
- package/src/tests/opencode-adapter.test.ts +2 -2
- package/src/tests/promote-draft-task-route.test.ts +4 -0
- package/src/tests/prompt-template-session.test.ts +13 -4
- package/src/tests/rbac-wire-e2e.test.ts +2 -2
- package/src/tests/routing-decision-persistence.test.ts +520 -0
- package/src/tests/routing-reason-contract.test.ts +89 -0
- package/src/tests/routing-reason-inventory.test.ts +55 -0
- package/src/tests/schedule-target-type.test.ts +48 -1
- package/src/tests/scheduled-task-required-params-migration.test.ts +182 -0
- package/src/tests/scheduled-tasks.test.ts +9 -5
- package/src/tests/script-connections.test.ts +4 -0
- package/src/tests/script-runs-http.test.ts +31 -0
- package/src/tests/scripts-typecheck.test.ts +11 -0
- package/src/tests/secret-scrubber.test.ts +12 -0
- package/src/tests/send-task-output-schema.test.ts +66 -1
- package/src/tests/send-task-requested-by.test.ts +1 -0
- package/src/tests/send-task-slack-routing-guard.test.ts +2 -0
- package/src/tests/store-progress-blocked-waiting-gate.test.ts +151 -0
- package/src/tests/swarm-tool-result-gate.test.ts +24 -0
- package/src/tests/task-tool-manifest.test.ts +47 -0
- package/src/tests/task-tool-preload-mcp.test.ts +125 -0
- package/src/tests/task-tools-ctx.test.ts +2 -0
- package/src/tests/tool-output-agent-id.test.ts +1 -0
- package/src/tests/ui-followup-lead-delegation.test.ts +6 -1
- package/src/tests/workflow-agent-task.test.ts +24 -1
- package/src/tests/workflow-engine-v2.test.ts +58 -2
- package/src/tools/accept-steer.ts +0 -1
- package/src/tools/defer-task.ts +73 -21
- package/src/tools/memory-get.ts +10 -3
- package/src/tools/memory-rate.ts +19 -7
- package/src/tools/memory-search.ts +2 -1
- package/src/tools/memory-store.ts +25 -5
- package/src/tools/send-task.ts +40 -2
- package/src/tools/skills/skill-publish.ts +1 -0
- package/src/tools/store-progress.ts +78 -4
- package/src/tools/templates.ts +2 -1
- package/src/tools/utils.ts +33 -2
- package/src/types.ts +14 -1
- package/src/utils/acp-session-token.ts +14 -4
- package/src/utils/secret-scrubber.ts +2 -0
- package/src/utils/task-tool-manifest.ts +33 -0
- package/src/workflows/engine.ts +4 -1
- package/src/workflows/executors/agent-task.ts +7 -1
- package/templates/ai-toolbox.manifest.json +6 -1
- package/templates/skills/comms/config.json +18 -0
- package/templates/skills/comms/content.md +74 -0
- package/templates/skills/comms/files/references/ste-rules.md +73 -0
- package/templates/skills/comms/files/references/visual-shapes.md +112 -0
- package/templates/skills/swarm-scripts/SKILL.md +3 -2
- package/templates/skills/swarm-scripts/content.md +3 -2
package/src/tools/utils.ts
CHANGED
|
@@ -246,6 +246,23 @@ const slackReadNudge = (r: SwarmToolResult): string | undefined => {
|
|
|
246
246
|
: undefined;
|
|
247
247
|
};
|
|
248
248
|
|
|
249
|
+
// Sole caller (storeProgressBlockedWaitingNudge) only reaches this once ms is
|
|
250
|
+
// past BLOCKED_WAITING_MIN_ELAPSED_MS (3 minutes), so there's no sub-minute case.
|
|
251
|
+
function formatIdleDuration(ms: number): string {
|
|
252
|
+
const minutes = Math.round(ms / 60_000);
|
|
253
|
+
if (minutes < 60) return `${minutes}m`;
|
|
254
|
+
const hours = Math.floor(minutes / 60);
|
|
255
|
+
const remMinutes = minutes % 60;
|
|
256
|
+
return remMinutes > 0 ? `${hours}h${remMinutes}m` : `${hours}h`;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const storeProgressBlockedWaitingNudge = (r: SwarmToolResult): string | undefined => {
|
|
260
|
+
if (!r.ok) return undefined;
|
|
261
|
+
const ms = (r.data as { blockedWaitingElapsedMs?: unknown } | undefined)?.blockedWaitingElapsedMs;
|
|
262
|
+
if (typeof ms !== "number") return undefined;
|
|
263
|
+
return `That reads as blocked-waiting, ${formatIdleDuration(ms)} since your last update — call defer-task so a wake-up task resumes you instead of polling manually.`;
|
|
264
|
+
};
|
|
265
|
+
|
|
249
266
|
const workflowLongScriptTimeoutNudge = (r: SwarmToolResult): string | undefined => {
|
|
250
267
|
if (!r.ok) return undefined;
|
|
251
268
|
const hint = (r.data as { longScriptTimeoutHint?: unknown } | undefined)?.longScriptTimeoutHint;
|
|
@@ -260,6 +277,7 @@ const workflowLongScriptTimeoutNudge = (r: SwarmToolResult): string | undefined
|
|
|
260
277
|
export const NUDGES: Record<string, (result: SwarmToolResult) => string | undefined> = {
|
|
261
278
|
"defer-task": (r) =>
|
|
262
279
|
r.ok ? "Stop working on this task now; the wake-up task will carry your note." : undefined,
|
|
280
|
+
"store-progress": storeProgressBlockedWaitingNudge,
|
|
263
281
|
"script-run": scriptRunNudge,
|
|
264
282
|
"script-upsert": scriptAuthoringNudge,
|
|
265
283
|
"launch-script-run": scriptAuthoringNudge,
|
|
@@ -745,6 +763,13 @@ type ToolConfig<
|
|
|
745
763
|
_meta?: Record<string, unknown>;
|
|
746
764
|
};
|
|
747
765
|
|
|
766
|
+
const preloadedToolsByServer = new WeakMap<McpServer, ReadonlySet<string>>();
|
|
767
|
+
|
|
768
|
+
/** Configure before registration. The set belongs to one MCP session, never the fleet. */
|
|
769
|
+
export function setPreloadedTools(server: McpServer, names: readonly string[]): void {
|
|
770
|
+
preloadedToolsByServer.set(server, new Set(names));
|
|
771
|
+
}
|
|
772
|
+
|
|
748
773
|
/**
|
|
749
774
|
* Creates a tool registration helper that automatically extracts request info
|
|
750
775
|
* and passes it as the second parameter to the callback.
|
|
@@ -770,10 +795,13 @@ export const createToolRegistrar = (server: McpServer) => {
|
|
|
770
795
|
config: ToolConfig<InputArgs, OutputArgs>,
|
|
771
796
|
cb: ToolCallbackWithInfo<InputArgs>,
|
|
772
797
|
) => {
|
|
798
|
+
const toolConfig = preloadedToolsByServer.get(server)?.has(name)
|
|
799
|
+
? { ...config, _meta: { ...config._meta, "anthropic/alwaysLoad": true } }
|
|
800
|
+
: config;
|
|
773
801
|
// When inputSchema is undefined, the MCP SDK calls handler(extra) with a single arg.
|
|
774
802
|
// When inputSchema is defined, it calls handler(args, extra) with two args.
|
|
775
803
|
if (config.inputSchema === undefined) {
|
|
776
|
-
return server.registerTool(name,
|
|
804
|
+
return server.registerTool(name, toolConfig, (async (meta: Meta) => {
|
|
777
805
|
const requestInfo = getRequestInfo(meta);
|
|
778
806
|
return withSpan(
|
|
779
807
|
"mcp.tool",
|
|
@@ -793,7 +821,10 @@ export const createToolRegistrar = (server: McpServer) => {
|
|
|
793
821
|
}) as Parameters<typeof server.registerTool>[2]);
|
|
794
822
|
}
|
|
795
823
|
|
|
796
|
-
return server.registerTool(name,
|
|
824
|
+
return server.registerTool(name, toolConfig, (async (
|
|
825
|
+
args: InferInput<InputArgs>,
|
|
826
|
+
meta: Meta,
|
|
827
|
+
) => {
|
|
797
828
|
const requestInfo = getRequestInfo(meta);
|
|
798
829
|
return withSpan(
|
|
799
830
|
// Span name carries the tool: a static `mcp.tool` is unreadable in a
|
package/src/types.ts
CHANGED
|
@@ -340,6 +340,15 @@ export const AgentTaskSourceSchema = z.enum([
|
|
|
340
340
|
]);
|
|
341
341
|
export type AgentTaskSource = z.infer<typeof AgentTaskSourceSchema>;
|
|
342
342
|
|
|
343
|
+
export const RoutingReasonSchema = z.enum([
|
|
344
|
+
"skill",
|
|
345
|
+
"continuity",
|
|
346
|
+
"overflow",
|
|
347
|
+
"human_pinned",
|
|
348
|
+
"reroute_fault",
|
|
349
|
+
]);
|
|
350
|
+
export type RoutingReason = z.infer<typeof RoutingReasonSchema>;
|
|
351
|
+
|
|
343
352
|
// ---------------------------------------------------------------------------
|
|
344
353
|
// Harness Provider
|
|
345
354
|
// ---------------------------------------------------------------------------
|
|
@@ -504,6 +513,8 @@ export const AgentTaskSchema = z
|
|
|
504
513
|
title: z.string().optional(), // Human-facing display title override (e.g. session rename); falls back to `task` when unset
|
|
505
514
|
status: AgentTaskStatusSchema,
|
|
506
515
|
source: AgentTaskSourceSchema.default("mcp"),
|
|
516
|
+
routingReason: RoutingReasonSchema.optional(),
|
|
517
|
+
routingNote: z.string().max(200).optional(),
|
|
507
518
|
|
|
508
519
|
// Task metadata
|
|
509
520
|
taskType: z.string().max(50).optional(), // e.g., "bug", "feature", "chore"
|
|
@@ -664,6 +675,8 @@ export const CreateTaskOptionsSchema = z.object({
|
|
|
664
675
|
agentId: z.string().nullable().optional(),
|
|
665
676
|
creatorAgentId: z.string().optional(),
|
|
666
677
|
source: AgentTaskSourceSchema.optional(),
|
|
678
|
+
routingReason: RoutingReasonSchema.optional(),
|
|
679
|
+
routingNote: z.string().max(200).optional(),
|
|
667
680
|
taskType: z.string().max(50).optional(),
|
|
668
681
|
tags: z.array(z.string()).optional(),
|
|
669
682
|
priority: z.number().int().min(0).max(100).optional(),
|
|
@@ -1936,7 +1949,7 @@ export const WorkflowNodeSchema = z
|
|
|
1936
1949
|
config: z
|
|
1937
1950
|
.record(z.string(), z.unknown())
|
|
1938
1951
|
.describe(
|
|
1939
|
-
"Executor-specific config. For agent-task: { template, outputSchema?, agentId?, tags?, priority?, dir?, vcsRepo?, model? }. " +
|
|
1952
|
+
"Executor-specific config. For agent-task: { template, outputSchema?, agentId?, routingReason?, routingNote?, tags?, priority?, dir?, vcsRepo?, model? }; configured agentId defaults routingReason to human_pinned. " +
|
|
1940
1953
|
"For script: { runtime, script, args?, timeout? }. " +
|
|
1941
1954
|
"For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode?, timeoutMs? (1000-300000) }. " +
|
|
1942
1955
|
"Agent-task templates and ordinary config values support {{interpolation}} from the node's inputs context, including trigger and declared upstream aliases. " +
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
* key for a short-lived aseph_ bearer before handing credentials to the
|
|
6
6
|
* ACP target process.
|
|
7
7
|
*/
|
|
8
|
+
import { scrubSecrets } from "./secret-scrubber";
|
|
9
|
+
|
|
10
|
+
const REVOKE_TIMEOUT_MS = 5000;
|
|
8
11
|
|
|
9
12
|
/** Wall-clock TTL for a session token: 24 hours. Long enough for any realistic
|
|
10
13
|
* ACP session; the token is actively revoked when the session finishes anyway. */
|
|
@@ -38,7 +41,8 @@ export async function mintAcpSessionToken(
|
|
|
38
41
|
|
|
39
42
|
/**
|
|
40
43
|
* Ask the swarm API to revoke a previously-minted `aseph_` token. Best-effort:
|
|
41
|
-
* errors are logged but never propagated to the
|
|
44
|
+
* the request is bounded, and errors are logged but never propagated to the
|
|
45
|
+
* caller. ACP completion does not wait for this cleanup.
|
|
42
46
|
*/
|
|
43
47
|
export async function revokeAcpSessionToken(
|
|
44
48
|
apiUrl: string,
|
|
@@ -46,11 +50,17 @@ export async function revokeAcpSessionToken(
|
|
|
46
50
|
tokenId: string,
|
|
47
51
|
): Promise<void> {
|
|
48
52
|
try {
|
|
49
|
-
await fetch(`${apiUrl.replace(/\/+$/, "")}/api/sessions/tokens/${tokenId}`, {
|
|
53
|
+
const res = await fetch(`${apiUrl.replace(/\/+$/, "")}/api/sessions/tokens/${tokenId}`, {
|
|
50
54
|
method: "DELETE",
|
|
51
55
|
headers: { Authorization: `Bearer ${apiKey}` },
|
|
56
|
+
signal: AbortSignal.timeout(REVOKE_TIMEOUT_MS),
|
|
52
57
|
});
|
|
53
|
-
|
|
54
|
-
|
|
58
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.warn(
|
|
61
|
+
scrubSecrets(
|
|
62
|
+
`[acp] Session token revoke failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
63
|
+
),
|
|
64
|
+
);
|
|
55
65
|
}
|
|
56
66
|
}
|
|
@@ -104,6 +104,8 @@ const TOKEN_REGEXES: ReadonlyArray<{ name: string; re: RegExp }> = [
|
|
|
104
104
|
{ name: "github_pat", re: /github_pat_[A-Za-z0-9_]{20,}/g },
|
|
105
105
|
// GitHub classic/OAuth tokens (ghp_, gho_, ghu_, ghs_, ghr_)
|
|
106
106
|
{ name: "github_token", re: new RegExp(String.raw`${TB}gh[pousr]_[A-Za-z0-9]{20,}\b`, "g") },
|
|
107
|
+
// ACP ephemeral session tokens (base62 payload)
|
|
108
|
+
{ name: "acp_session_token", re: new RegExp(String.raw`${TB}aseph_[A-Za-z0-9]{20,}\b`, "g") },
|
|
107
109
|
// GitLab personal access tokens
|
|
108
110
|
{ name: "gitlab_pat", re: new RegExp(String.raw`${TB}glpat-[A-Za-z0-9_-]{20,}\b`, "g") },
|
|
109
111
|
// Anthropic API keys (must match before the generic sk- rule below)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { ALL_TOOLS } from "../tools/tool-config";
|
|
3
|
+
|
|
4
|
+
const toolNames = z
|
|
5
|
+
.array(z.string().refine((name) => ALL_TOOLS.has(name), "Unknown swarm tool"))
|
|
6
|
+
.max(16);
|
|
7
|
+
|
|
8
|
+
/** Exact task-type and schedule keys; a schedule entry overrides its task type. */
|
|
9
|
+
export const taskToolManifestSchema = z.strictObject({
|
|
10
|
+
taskTypes: z.record(z.string().min(1).max(50), toolNames).optional(),
|
|
11
|
+
schedules: z.record(z.uuid(), toolNames).optional(),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export function parseTaskToolManifest(value: string) {
|
|
15
|
+
return taskToolManifestSchema.parse(JSON.parse(value));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function selectTaskTools(
|
|
19
|
+
manifest: z.infer<typeof taskToolManifestSchema>,
|
|
20
|
+
task: { taskType?: string; scheduleId?: string; slackChannelId?: string },
|
|
21
|
+
): string[] {
|
|
22
|
+
const fromSchedule =
|
|
23
|
+
task.scheduleId && Object.hasOwn(manifest.schedules ?? {}, task.scheduleId)
|
|
24
|
+
? manifest.schedules?.[task.scheduleId]
|
|
25
|
+
: undefined;
|
|
26
|
+
const fromType =
|
|
27
|
+
task.taskType && Object.hasOwn(manifest.taskTypes ?? {}, task.taskType)
|
|
28
|
+
? manifest.taskTypes?.[task.taskType]
|
|
29
|
+
: undefined;
|
|
30
|
+
return [...new Set(fromSchedule ?? fromType ?? [])].filter(
|
|
31
|
+
(name) => !name.startsWith("slack-") || Boolean(task.slackChannelId),
|
|
32
|
+
);
|
|
33
|
+
}
|
package/src/workflows/engine.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { notifyAutomationPreflightFailure } from "../automation-preflight-alert";
|
|
1
2
|
import {
|
|
2
3
|
getAutomationSetupStates,
|
|
3
4
|
preflightAutomation,
|
|
@@ -91,13 +92,15 @@ export async function startWorkflowExecution(
|
|
|
91
92
|
await getAutomationSetupStates(),
|
|
92
93
|
);
|
|
93
94
|
if (preflight.state === "needs_setup") {
|
|
94
|
-
|
|
95
|
+
const { runId, recorded } = await recordWorkflowPreflightFailure({
|
|
95
96
|
workflowId: workflow.id,
|
|
96
97
|
triggerType: options.triggerType ?? "manual",
|
|
97
98
|
triggerData,
|
|
98
99
|
failureReason: preflight.failureReason!,
|
|
99
100
|
createdBy: options.requestedByUserId,
|
|
100
101
|
});
|
|
102
|
+
if (recorded) await notifyAutomationPreflightFailure(preflight);
|
|
103
|
+
return runId;
|
|
101
104
|
}
|
|
102
105
|
|
|
103
106
|
// Templates can consume install params outside the graph definition (most
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
FollowUpConfigSchema,
|
|
7
7
|
ModelTierSchema,
|
|
8
8
|
ReasoningEffortSchema,
|
|
9
|
+
RoutingReasonSchema,
|
|
9
10
|
splitLegacyModelAlias,
|
|
10
11
|
} from "../../types";
|
|
11
12
|
import type { ExecutorResult } from "./base";
|
|
@@ -13,11 +14,13 @@ import { BaseExecutor } from "./base";
|
|
|
13
14
|
|
|
14
15
|
// ─── Config / Output Schemas ────────────────────────────────
|
|
15
16
|
|
|
16
|
-
const AgentTaskConfigSchema = z.object({
|
|
17
|
+
export const AgentTaskConfigSchema = z.object({
|
|
17
18
|
template: z.string(),
|
|
18
19
|
// Plain string, NOT .uuid(): agents may join with custom IDs (AGENT_ID env /
|
|
19
20
|
// join-swarm agentId), so a UUID filter would reject legitimate agents.
|
|
20
21
|
agentId: z.string().optional(),
|
|
22
|
+
routingReason: RoutingReasonSchema.optional(),
|
|
23
|
+
routingNote: z.string().max(200).optional(),
|
|
21
24
|
tags: z.array(z.string()).optional(),
|
|
22
25
|
priority: z.number().int().min(0).max(100).optional(),
|
|
23
26
|
offerMode: z.boolean().optional(),
|
|
@@ -98,6 +101,9 @@ export class AgentTaskExecutor extends BaseExecutor<
|
|
|
98
101
|
{
|
|
99
102
|
key: effectiveKey,
|
|
100
103
|
agentId: config.agentId ?? null,
|
|
104
|
+
// A configured workflow target is an author pin, including existing definitions.
|
|
105
|
+
routingReason: config.routingReason ?? (config.agentId ? "human_pinned" : undefined),
|
|
106
|
+
routingNote: config.routingNote,
|
|
101
107
|
source: "workflow",
|
|
102
108
|
tags: config.tags,
|
|
103
109
|
priority: config.priority,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"commit": "
|
|
2
|
+
"commit": "9748aabf7252c258378302240d73f7516d113777",
|
|
3
3
|
"excludedSkills": [
|
|
4
4
|
"feedback"
|
|
5
5
|
],
|
|
@@ -11,6 +11,10 @@
|
|
|
11
11
|
"templates/skills/brainstorming/files/template.md": "ae0aabc02a307db0550f9026aca33fb471608c31f7a0b65ecc781073f17cc953",
|
|
12
12
|
"templates/skills/code-reviewing/config.json": "dde1298b15d55428b898a0421033d1aa140ef152d335d49345059e29deab96f2",
|
|
13
13
|
"templates/skills/code-reviewing/content.md": "85e9aa3b276384ab3f3bc570aece2e8c103a8614c19129378cf4dfec3457a18b",
|
|
14
|
+
"templates/skills/comms/config.json": "5561ee129f68a03e89b21458afebcd79afd2a8c177c0ba5dad00ffa21ee57bc3",
|
|
15
|
+
"templates/skills/comms/content.md": "bd1d33b4af13eb36dfd87552bb35ecd200ac0a0dd40d409b50dff448708ce5ea",
|
|
16
|
+
"templates/skills/comms/files/references/ste-rules.md": "6ee2ed5d6b49d2e421b6c9d22310a5b589fa1abe81de06213e4b89fbc1271e74",
|
|
17
|
+
"templates/skills/comms/files/references/visual-shapes.md": "5e07e9250ad4cdc877af2281525185f0de89c01f90a077463a2c77c8a7b998e8",
|
|
14
18
|
"templates/skills/delegate-work/config.json": "5b1542eb0be359bb8a17117fcf87917e0607d1b939ae3266ddffacdc14efb281",
|
|
15
19
|
"templates/skills/delegate-work/content.md": "c9562bd17846d3595d40172ecfdc6f85bb99eaf23597eb9d5aa9635d5c14d079",
|
|
16
20
|
"templates/skills/delegate-work/files/scripts/codex-exec.sh": "c2222986c46ac608403f28f201230cb34c7d7ac41a2262dc2c8dbd99c8645dbb",
|
|
@@ -74,6 +78,7 @@
|
|
|
74
78
|
"ask-user",
|
|
75
79
|
"brainstorming",
|
|
76
80
|
"code-reviewing",
|
|
81
|
+
"comms",
|
|
77
82
|
"delegate-work",
|
|
78
83
|
"design-docs",
|
|
79
84
|
"engineering-standards",
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"category": "skills",
|
|
3
|
+
"description": "Re-express something so it lands — re-explain your last reply in plain casual language, show the current topic visually (diagram, code-shape sketch, HTML artifact), do both at once, or rewrite artifact text into unambiguous ASD-STE100 English. Use when the user runs /desplega:comms, types /bro, says 'say it simpler', 'bro what', 'I don't follow', 'show me', 'draw this', 'visualize', 'disambiguate this', or 'STE100 rewrite'. Not for creative or marketing copy.",
|
|
4
|
+
"displayName": "Comms",
|
|
5
|
+
"kind": "skill",
|
|
6
|
+
"name": "comms",
|
|
7
|
+
"placeholders": [],
|
|
8
|
+
"runAllSeedersCandidate": true,
|
|
9
|
+
"slug": "comms",
|
|
10
|
+
"systemDefault": true,
|
|
11
|
+
"tags": [
|
|
12
|
+
"ai-toolbox",
|
|
13
|
+
"agents",
|
|
14
|
+
"workflow"
|
|
15
|
+
],
|
|
16
|
+
"title": "Comms",
|
|
17
|
+
"version": "1.0.0"
|
|
18
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# /comms — make it land
|
|
2
|
+
|
|
3
|
+
Merged from three MIT sources: [bro-skill](https://github.com/luchasarie/bro-skill) (Simpler), the local show-me skill (Visual), and [asd-ste100-skill](https://github.com/desplega-ai/asd-ste100-skill) (Precise).
|
|
4
|
+
|
|
5
|
+
One skill, three base modes plus a joint one. Pick from the **target** of the request, not from the wording alone.
|
|
6
|
+
|
|
7
|
+
## Dispatch
|
|
8
|
+
|
|
9
|
+
| Target of the request | Mode |
|
|
10
|
+
|---|---|
|
|
11
|
+
| Your own previous message — "simpler", "bro what", "didn't get it", "rephrase" | **Simpler** |
|
|
12
|
+
| A concept, flow, architecture, or change — "show me", "draw", "diagram", "what does this look like" | **Visual** |
|
|
13
|
+
| Your previous message AND it describes structure (a flow, a tree, an architecture, a sequence) — or the user asks for both ("simpler, and draw it") | **Joint** |
|
|
14
|
+
| Artifact text a machine or reader must parse without a back-channel — tool description, error message, prompt, doc paragraph — "disambiguate", "rewrite", "STE" | **Precise** |
|
|
15
|
+
|
|
16
|
+
Dispatch rules:
|
|
17
|
+
|
|
18
|
+
- If the request names a mode, obey it.
|
|
19
|
+
- If the target is your previous message and it is plain prose, use Simpler. If it describes structure, prefer Joint — a small visual usually lands faster than more words.
|
|
20
|
+
- Never mix registers: no casual flavor in Precise output, no STE flatness in Simpler output. Precise never combines with the other modes.
|
|
21
|
+
- If there is nothing to re-express (no previous message, no artifact, no topic), say so in one line.
|
|
22
|
+
|
|
23
|
+
## Mode: Simpler
|
|
24
|
+
|
|
25
|
+
Re-explain YOUR most recent assistant message like you're explaining it to a smart friend over a beer.
|
|
26
|
+
|
|
27
|
+
1. **Re-explain, don't re-answer.** Never answer a new question, never add new information, never use tools. You are only re-expressing what you already said.
|
|
28
|
+
2. **Simpler, not necessarily shorter.** The goal is "impossible to misunderstand", not "fewer words". Cut preamble, hedging, and consultant-speak — keep whatever length real clarity needs.
|
|
29
|
+
3. **Facts survive verbatim.** Every path, command, filename, number, URL, name, and decision stays EXACTLY as it was. Simplify the explanation around the facts, never the facts themselves.
|
|
30
|
+
4. **Light casual flavor.** Direct and informal ("basically...", "the point is...", "ok so..."). A touch of personality — don't turn it into a meme.
|
|
31
|
+
5. **Same language.** If the original message was in another language, the simpler version stays in that language.
|
|
32
|
+
6. **Flatten structure.** Drop headers and ceremony. Tables become plain sentences. Keep a short list only if the original genuinely had multiple parts.
|
|
33
|
+
|
|
34
|
+
## Mode: Visual
|
|
35
|
+
|
|
36
|
+
Help the user understand the current topic visually. Skip the preamble and keep prose brief. Pick the smallest view that makes the key point clear:
|
|
37
|
+
|
|
38
|
+
- **Pseudocode** for logic or an algorithm.
|
|
39
|
+
- **Call tree** for runtime control flow.
|
|
40
|
+
- **Component tree** for UI structure, including the state and module boundaries that matter.
|
|
41
|
+
- **Shallow file tree** for file responsibility or a broad refactor.
|
|
42
|
+
- **Mermaid** for component interaction, control flow, or data flow.
|
|
43
|
+
- **`diff`** when the point is what changes and the surrounding shape already exists — diff the tree or pseudocode itself, not raw code. Match the diff shape to the topic.
|
|
44
|
+
- **Whole code block** when most of it is new, when omitted context would hide ownership or order, or when the user needs a copyable target shape.
|
|
45
|
+
- **One focused HTML file** for a visual UI, layout, state comparison, or concept too dense for Mermaid — a diagram, infographic, or short slide deck. Match the product's colors, type, spacing, and components; use real labels and data; support desktop and mobile. Then `Bash(open path/to/comms-{description}.html)`.
|
|
46
|
+
|
|
47
|
+
Place each visual next to the short text it supports. Keep only the calls, files, props, states, and boundaries needed to answer the current question. Use one shape, maybe several — never all. Concrete example shapes: `references/visual-shapes.md`.
|
|
48
|
+
|
|
49
|
+
**Delivery:** write the visual explanation to `/tmp/YYYY-MM-DD-HHMM-comms-<topic>.md` and open it with `file-review` (via Bash, `run_in_background: true`, `timeout: 600000`) — it rich-renders the markdown and lets the user leave inline comments; process their comments when the window closes. If `file-review` is not on PATH, put the visual in chat instead. Keep `Bash(open ...)` for HTML artifacts. Skip file-review only for a single small visual that reads fine in chat.
|
|
50
|
+
|
|
51
|
+
## Mode: Joint
|
|
52
|
+
|
|
53
|
+
Simpler + Visual in one document: Simpler-mode prose with Visual-mode shapes placed right after the sentence each one supports. Follow both rule sets — casual register for the words, smallest-view discipline for the visuals. Deliver via file-review, like Visual mode.
|
|
54
|
+
|
|
55
|
+
## Mode: Precise
|
|
56
|
+
|
|
57
|
+
Rewrite the given text under ASD-STE100 structural discipline so no reader — human or agent — can misparse it. Full rule tables, sub-mode detail, and process: `references/ste-rules.md`.
|
|
58
|
+
|
|
59
|
+
Core rules:
|
|
60
|
+
|
|
61
|
+
- Active voice. Simple tenses ("we received", not "we have received").
|
|
62
|
+
- One instruction per sentence. ≤20 words for instructions, ≤25 for descriptions.
|
|
63
|
+
- No semicolons. No phrasal verbs ("start", not "spin up"). No noun stacks over 3 words. No dropped words.
|
|
64
|
+
- One name per thing — never rotate synonyms for the same referent.
|
|
65
|
+
- Verb over nominalization ("analyze the log", not "perform an analysis of the log").
|
|
66
|
+
- **Keep every hedge and qualifier.** "May have failed" never becomes "failed". A rewrite that changes confidence is a different claim, not a simplification.
|
|
67
|
+
- Never add a fact the source did not state.
|
|
68
|
+
|
|
69
|
+
Two sub-modes:
|
|
70
|
+
|
|
71
|
+
- **Strict** — tool descriptions, error messages, prompts, procedures, safety text: every rule.
|
|
72
|
+
- **STE-flavored** — READMEs, PR text, explanatory prose: structural rules in full, lexical rules advisory.
|
|
73
|
+
|
|
74
|
+
Output: the rewritten text and nothing else — no preamble, no mode announcement, no change summary. If you deliberately kept a longer phrasing to preserve precision, add one line prefixed `Kept as-is:`. When asked to "show the diff" or "explain the changes", output the before/after rule table from `references/ste-rules.md` instead.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Precise mode — ASD-STE100 rules
|
|
2
|
+
|
|
3
|
+
Condensed from [asd-ste100-skill](https://github.com/desplega-ai/asd-ste100-skill) (MIT), which encodes the rule categories of ASD-STE100 Issue 9 (Jan 2025).
|
|
4
|
+
|
|
5
|
+
This encodes the standard's rule *categories*, not ASD's ~900-word approved dictionary (free to obtain, not free to redistribute). Structural rules are checkable from the description alone — apply them with confidence. Lexical rules depend on the dictionary — apply them as a direction of travel, and never imply dictionary compliance.
|
|
6
|
+
|
|
7
|
+
## Structural rules — apply these
|
|
8
|
+
|
|
9
|
+
| Rule | Do | Don't |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| Active voice | "The agent deletes the file." | "The file is deleted (by the agent)." — unless the actor is genuinely unknown or irrelevant |
|
|
12
|
+
| No phrasal verbs | "Remove the panel." / "Start the job." | "Take off the panel." / "Spin up the job." |
|
|
13
|
+
| One instruction per sentence | "Open the file. Read line 3." | "Open the file and read line 3, then check if it matches." |
|
|
14
|
+
| Sentence length | ≤20 words for instructions, ≤25 for descriptions | Long compound/subordinate-clause sentences |
|
|
15
|
+
| No semicolons | Split into separate sentences | Any semicolon at all |
|
|
16
|
+
| Noun clusters | ≤3 words stacked as a noun phrase | 4+ word noun stacks ("high pressure fuel pump inlet valve assembly") |
|
|
17
|
+
| No ellipsis | Keep subject, verb, and article explicit | Drop words to save space ("Files not backed up will be lost" → ambiguous which files) |
|
|
18
|
+
| Keep modality | "The request **may have** failed." stays "may have" | Promote a hedge to a fact, or invent a certainty the source did not state |
|
|
19
|
+
| Paragraph limits | One topic per paragraph, ≤6 sentences | Multi-topic paragraphs |
|
|
20
|
+
| Lists for sequences | Numbered/bulleted list for 3+ steps or conditions | A sequence buried in one prose sentence |
|
|
21
|
+
|
|
22
|
+
## Lexical rules — direction of travel only
|
|
23
|
+
|
|
24
|
+
| Rule | Do | Don't |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| One word, one meaning | Pick one verb for one action and reuse it every time | Rotate synonyms ("check"/"verify"/"confirm") for the same action |
|
|
27
|
+
| One part of speech per word | "Apply oil to the valve" (oil = noun) | "Oil the valve" (oil = verb) |
|
|
28
|
+
| Verb, not noun | "Analyze the log." | "Perform an analysis of the log." |
|
|
29
|
+
| Domain terms | Keep needed technical terms; define each once if not common English | Jargon never defined |
|
|
30
|
+
|
|
31
|
+
## Simple tenses — one exception
|
|
32
|
+
|
|
33
|
+
STE permits infinitive, imperative, simple present, simple past, simple future, and past participle as adjective. It excludes present perfect: "we received the report", not "we have received the report". Exception: where the compound form carries information the simple form cannot — current relevance ("the job has completed" = output available now), or a hedge like "may have failed" — keep it and flag the departure.
|
|
34
|
+
|
|
35
|
+
## Scan checklist
|
|
36
|
+
|
|
37
|
+
Scan for all six before rewriting. Each is mechanical — you can point at the exact word that breaks it.
|
|
38
|
+
|
|
39
|
+
1. **Synonym rotation** — the same thing has several names ("the user", "the customer", "the client"). Fix: one name, every time.
|
|
40
|
+
2. **Hedge stacking** — qualifiers pile up until nothing is asserted ("it is important to note that this may potentially help to improve"). Fix: state the claim or delete it.
|
|
41
|
+
3. **Nominalization** — an action frozen into a noun ("perform an analysis of"). Fix: use the verb.
|
|
42
|
+
4. **Marketing adjectives** — seamless, robust, powerful, blazing-fast. Fix: delete, or replace with the measurement that earns the claim.
|
|
43
|
+
5. **Run-on sentences** — ideas joined by semicolons or em dashes. Fix: one idea per sentence.
|
|
44
|
+
6. **Soft phrasal verbs** — spin up, reach out, dive into, kick off. Fix: the single plain verb (start, contact, read, begin).
|
|
45
|
+
|
|
46
|
+
## Process
|
|
47
|
+
|
|
48
|
+
1. Pick the sub-mode (Strict or STE-flavored). Keep the choice internal unless asked.
|
|
49
|
+
2. Read the input once for meaning before rewriting anything.
|
|
50
|
+
3. Walk it sentence by sentence; flag every violation. In STE-flavored, flag lexical rules but do not enforce them.
|
|
51
|
+
4. Rewrite each flagged sentence, preserving the original meaning exactly. If a rewrite would drop necessary precision (a safety condition, scope qualifier, number), keep the longer phrasing and flag it. Check modality before committing — a shorter sentence that upgrades a hedge to a fact is a different claim. Never add a fact the source did not state.
|
|
52
|
+
5. Output the rewritten text alone. If the input already complies, say so — do not force changes.
|
|
53
|
+
|
|
54
|
+
## Diff table format (on request)
|
|
55
|
+
|
|
56
|
+
When asked to "show the diff" / "which rules did it break" / "before/after":
|
|
57
|
+
|
|
58
|
+
```markdown
|
|
59
|
+
| Rule violated | Original | Simplified |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| Present perfect tense | "We have received your request." | "We received your request." |
|
|
62
|
+
| Noun cluster (4+ words) | "the agent task queue priority handler" | "the handler that sets task-queue priority" |
|
|
63
|
+
|
|
64
|
+
Mode: Strict. 7 violations found.
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Follow with one line naming anything deliberately not simplified, and why.
|
|
68
|
+
|
|
69
|
+
## Boundaries
|
|
70
|
+
|
|
71
|
+
- Not a certified STE authoring tool — a clarity tool inspired by the standard. For aerospace-grade compliance, check word-by-word against the official dictionary from [asd-ste100.org](https://www.asd-ste100.org/STE_downloads.html).
|
|
72
|
+
- Fixes form, not substance: a hollow paragraph rewritten under these rules is a clean hollow paragraph. Say so instead of polishing it.
|
|
73
|
+
- Stop when the sentence is unambiguous, not when it is shortest.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Visual mode — example shapes
|
|
2
|
+
|
|
3
|
+
Concrete examples for each view the Visual mode can produce. Source: the show-me skill (bundled into this skill).
|
|
4
|
+
|
|
5
|
+
Logic or an algorithm as pseudocode:
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
on(save)
|
|
9
|
+
if content is unchanged
|
|
10
|
+
return cached result
|
|
11
|
+
write new content
|
|
12
|
+
return fresh result
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Runtime control flow as a call tree:
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
submitForm
|
|
19
|
+
createSession
|
|
20
|
+
persistPrompt
|
|
21
|
+
launchAgent
|
|
22
|
+
navigateToSession
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
UI structure as a component tree, including state and module boundaries that matter:
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
<SessionPage> (apps/example/src/routes/session.tsx)
|
|
29
|
+
useSessionEvents()
|
|
30
|
+
<SessionToolbar>
|
|
31
|
+
<RunSkillButton> (packages/ui)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
File responsibility or a broad refactor as a shallow file tree:
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
src/
|
|
38
|
+
├── commands/ # parses user actions
|
|
39
|
+
├── sessions/ # owns session state
|
|
40
|
+
└── transport/ # sends API requests
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Component interaction, control flow, or data flow with Mermaid:
|
|
44
|
+
|
|
45
|
+
```mermaid
|
|
46
|
+
sequenceDiagram
|
|
47
|
+
participant User
|
|
48
|
+
participant UI
|
|
49
|
+
participant Daemon
|
|
50
|
+
User->>UI: choose command
|
|
51
|
+
UI->>Daemon: send expanded prompt
|
|
52
|
+
Daemon-->>UI: stream result
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`diff` shapes — match the diff to the topic.
|
|
56
|
+
|
|
57
|
+
Component change:
|
|
58
|
+
|
|
59
|
+
```diff
|
|
60
|
+
<SessionPage>
|
|
61
|
+
useSessionEvents()
|
|
62
|
+
<SessionToolbar>
|
|
63
|
+
+ <RunSkillButton />
|
|
64
|
+
<SessionTimeline>
|
|
65
|
+
+ <SkillResultCard />
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
File-layout change:
|
|
69
|
+
|
|
70
|
+
```diff
|
|
71
|
+
src/
|
|
72
|
+
├── commands/
|
|
73
|
+
+│ └── show-me.ts # expands the slash command
|
|
74
|
+
├── sessions/
|
|
75
|
+
-└── transport.ts
|
|
76
|
+
+└── transport/
|
|
77
|
+
+ ├── client.ts
|
|
78
|
+
+ └── stream.ts
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Call-tree change:
|
|
82
|
+
|
|
83
|
+
```diff
|
|
84
|
+
submitForm
|
|
85
|
+
createSession
|
|
86
|
+
persistPrompt
|
|
87
|
+
+ expandSkillMention
|
|
88
|
+
launchAgent
|
|
89
|
+
- navigateToSession
|
|
90
|
+
+ navigateToSession
|
|
91
|
+
+ subscribeToEvents
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
State or control-flow change:
|
|
95
|
+
|
|
96
|
+
```diff
|
|
97
|
+
on(save)
|
|
98
|
+
- write content
|
|
99
|
+
+ if content is unchanged
|
|
100
|
+
+ return cached result
|
|
101
|
+
+ write new content
|
|
102
|
+
+ invalidate cache
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Whole block when most of it is new or a copyable target shape is needed:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
function expandSkill(command: string): string {
|
|
109
|
+
const skillName = command.slice(1)
|
|
110
|
+
return `use the ${skillName} skill`
|
|
111
|
+
}
|
|
112
|
+
```
|
|
@@ -37,7 +37,7 @@ The swarm ships named scripts at global scope. Each one replaces a multi-step to
|
|
|
37
37
|
| `task-context-gathering` | `{ taskId, queries: [...] }` | the task plus a deduplicated multi-query memory recall |
|
|
38
38
|
| `smart-recall` | `{ queries: [...] }` | multi-query memory recall without the task |
|
|
39
39
|
| `memory-dedup-check` | `{ text, threshold? }` | near-duplicates before you store a memory |
|
|
40
|
-
| `delegate` | `{ agentName, task, parentTaskId? }` | a subtask for an agent by name, returns `{ taskId }` |
|
|
40
|
+
| `delegate` | `{ agentName, task, routingReason, parentTaskId? }` | a subtask for an agent by name, returns `{ taskId }` |
|
|
41
41
|
| `wait-for-task` | `{ taskId }` | waits up to about 25 s for a terminal state, returns `{ done, status, output }`; call again while `done` is false |
|
|
42
42
|
| `get-child-outputs` | `{ parentTaskId }` | every child with status and output |
|
|
43
43
|
| `complete-task` | `{ taskId, output }` | finish a task from inside a script |
|
|
@@ -74,6 +74,7 @@ export default async function (args: z.infer<typeof argsSchema>, ctx: ScriptCont
|
|
|
74
74
|
### What `ctx` holds
|
|
75
75
|
|
|
76
76
|
- `ctx.swarm.*`: the swarm SDK. `task_get`, `task_send`, `task_storeProgress`, `task_action`, `task_list`, `slack_reply`, `memory_search`, `memory_store`, `kv_get`, `kv_getOrNull`, `kv_set`, `kv_delete`, `kv_incr`, `kv_list`, `swarm_get`, `agent_info`, `db_query`, and more. `kv_getOrNull` returns the entry, `null` on a missing key, and throws on other errors.
|
|
77
|
+
- `ctx.swarm.task_send` requires `routingReason` whenever `agentId` is present. Use `human_pinned` for an explicit/configured choice, `skill` for a role or specialization match, `continuity` for the same worker/session, `reroute_fault` for a fault handoff, or `overflow` for capacity/pool escalation. Omit both `agentId` and routing fields for the pool.
|
|
77
78
|
- `ctx.swarm.config`: `apiKey`, `agentId`, `mcpBaseUrl`, and `ctx.swarm.config.get("KEY")` for user config values. All are `Redacted` wrappers that stringify to `<redacted>`. Never unwrap one into a return value, a log line, or a request body you build by hand.
|
|
78
79
|
- `ctx.api.<slug>` and `ctx.mcp.<slug>`: typed clients for registered connections. They exist only for registered connections. Introspect with `Object.keys(ctx.api ?? {})` and `Object.keys(ctx.mcp ?? {})`.
|
|
79
80
|
- `ctx.stdlib`: `fetch`, `fetchJson` (retries, 30 s timeout), `grep`, `glob`, `table`, `Redacted`.
|
|
@@ -81,7 +82,7 @@ export default async function (args: z.infer<typeof argsSchema>, ctx: ScriptCont
|
|
|
81
82
|
|
|
82
83
|
### Durable workflow scripts
|
|
83
84
|
|
|
84
|
-
`launch-script-run` runs a script as a durable, journaled run with a different `ctx`: `ctx.run` (`id`, `agentId`, `args`) and `ctx.step.rawLlm(label, config)`, `ctx.step.agentTask(label, config)`, `ctx.step.swarmScript(label, config)`, plus `ctx.swarm.*`, `ctx.stdlib`, `ctx.logger`. Durable runs have no `ctx.api`, no `ctx.mcp`, and no `ctx.swarm.config`. Call a connection from an inner script through `ctx.step.swarmScript`. See the `script-workflows` skill.
|
|
85
|
+
`launch-script-run` runs a script as a durable, journaled run with a different `ctx`: `ctx.run` (`id`, `agentId`, `args`) and `ctx.step.rawLlm(label, config)`, `ctx.step.agentTask(label, config)`, `ctx.step.swarmScript(label, config)`, plus `ctx.swarm.*`, `ctx.stdlib`, `ctx.logger`. Durable runs have no `ctx.api`, no `ctx.mcp`, and no `ctx.swarm.config`. A configured `ctx.step.agentTask` `agentId` records `human_pinned` unless `routingReason` is supplied. Call a connection from an inner script through `ctx.step.swarmScript`. See the `script-workflows` skill.
|
|
85
86
|
|
|
86
87
|
## Inline script pattern
|
|
87
88
|
|
|
@@ -32,7 +32,7 @@ The swarm ships named scripts at global scope. Each one replaces a multi-step to
|
|
|
32
32
|
| `task-context-gathering` | `{ taskId, queries: [...] }` | the task plus a deduplicated multi-query memory recall |
|
|
33
33
|
| `smart-recall` | `{ queries: [...] }` | multi-query memory recall without the task |
|
|
34
34
|
| `memory-dedup-check` | `{ text, threshold? }` | near-duplicates before you store a memory |
|
|
35
|
-
| `delegate` | `{ agentName, task, parentTaskId? }` | a subtask for an agent by name, returns `{ taskId }` |
|
|
35
|
+
| `delegate` | `{ agentName, task, routingReason, parentTaskId? }` | a subtask for an agent by name, returns `{ taskId }` |
|
|
36
36
|
| `wait-for-task` | `{ taskId }` | waits up to about 25 s for a terminal state, returns `{ done, status, output }`; call again while `done` is false |
|
|
37
37
|
| `get-child-outputs` | `{ parentTaskId }` | every child with status and output |
|
|
38
38
|
| `complete-task` | `{ taskId, output }` | finish a task from inside a script |
|
|
@@ -69,6 +69,7 @@ export default async function (args: z.infer<typeof argsSchema>, ctx: ScriptCont
|
|
|
69
69
|
### What `ctx` holds
|
|
70
70
|
|
|
71
71
|
- `ctx.swarm.*`: the swarm SDK. `task_get`, `task_send`, `task_storeProgress`, `task_action`, `task_list`, `slack_reply`, `memory_search`, `memory_store`, `kv_get`, `kv_getOrNull`, `kv_set`, `kv_delete`, `kv_incr`, `kv_list`, `swarm_get`, `agent_info`, `db_query`, and more. `kv_getOrNull` returns the entry, `null` on a missing key, and throws on other errors.
|
|
72
|
+
- `ctx.swarm.task_send` requires `routingReason` whenever `agentId` is present. Use `human_pinned` for an explicit/configured choice, `skill` for a role or specialization match, `continuity` for the same worker/session, `reroute_fault` for a fault handoff, or `overflow` for capacity/pool escalation. Omit both `agentId` and routing fields for the pool.
|
|
72
73
|
- `ctx.swarm.config`: `apiKey`, `agentId`, `mcpBaseUrl`, and `ctx.swarm.config.get("KEY")` for user config values. All are `Redacted` wrappers that stringify to `<redacted>`. Never unwrap one into a return value, a log line, or a request body you build by hand.
|
|
73
74
|
- `ctx.api.<slug>` and `ctx.mcp.<slug>`: typed clients for registered connections. They exist only for registered connections. Introspect with `Object.keys(ctx.api ?? {})` and `Object.keys(ctx.mcp ?? {})`.
|
|
74
75
|
- `ctx.stdlib`: `fetch`, `fetchJson` (retries, 30 s timeout), `grep`, `glob`, `table`, `Redacted`.
|
|
@@ -76,7 +77,7 @@ export default async function (args: z.infer<typeof argsSchema>, ctx: ScriptCont
|
|
|
76
77
|
|
|
77
78
|
### Durable workflow scripts
|
|
78
79
|
|
|
79
|
-
`launch-script-run` runs a script as a durable, journaled run with a different `ctx`: `ctx.run` (`id`, `agentId`, `args`) and `ctx.step.rawLlm(label, config)`, `ctx.step.agentTask(label, config)`, `ctx.step.swarmScript(label, config)`, plus `ctx.swarm.*`, `ctx.stdlib`, `ctx.logger`. Durable runs have no `ctx.api`, no `ctx.mcp`, and no `ctx.swarm.config`. Call a connection from an inner script through `ctx.step.swarmScript`. See the `script-workflows` skill.
|
|
80
|
+
`launch-script-run` runs a script as a durable, journaled run with a different `ctx`: `ctx.run` (`id`, `agentId`, `args`) and `ctx.step.rawLlm(label, config)`, `ctx.step.agentTask(label, config)`, `ctx.step.swarmScript(label, config)`, plus `ctx.swarm.*`, `ctx.stdlib`, `ctx.logger`. Durable runs have no `ctx.api`, no `ctx.mcp`, and no `ctx.swarm.config`. A configured `ctx.step.agentTask` `agentId` records `human_pinned` unless `routingReason` is supplied. Call a connection from an inner script through `ctx.step.swarmScript`. See the `script-workflows` skill.
|
|
80
81
|
|
|
81
82
|
## Inline script pattern
|
|
82
83
|
|