@desplega.ai/agent-swarm 1.55.0 → 1.56.3
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/openapi.json +26 -1
- package/package.json +1 -1
- package/src/be/db.ts +9 -1
- package/src/be/migrations/025_workflow_run_cancelled_status.sql +0 -2
- package/src/be/migrations/027_heartbeat_md.sql +1 -0
- package/src/be/migrations/runner.ts +8 -0
- package/src/commands/runner.ts +24 -1
- package/src/github/handlers.ts +122 -406
- package/src/github/index.ts +8 -1
- package/src/github/mentions.ts +10 -0
- package/src/github/templates.ts +55 -0
- package/src/github/types.ts +2 -0
- package/src/heartbeat/heartbeat.ts +201 -92
- package/src/heartbeat/templates.ts +64 -9
- package/src/hooks/hook.ts +11 -1
- package/src/http/agents.ts +5 -2
- package/src/http/heartbeat.ts +29 -1
- package/src/prompts/session-templates.ts +35 -0
- package/src/tests/concurrency.test.ts +3 -3
- package/src/tests/github-event-filter.test.ts +301 -0
- package/src/tests/github-event-labels.test.ts +24 -0
- package/src/tests/heartbeat-checklist.test.ts +417 -0
- package/src/tests/heartbeat.test.ts +2 -57
- package/src/tests/prompt-template-remaining.test.ts +1 -1
- package/src/tools/update-profile.ts +21 -3
- package/src/types.ts +4 -1
- package/templates/official/lead/CLAUDE.md +3 -0
- package/templates/official/lead/HEARTBEAT.md +12 -0
- package/templates/official/lead/config.json +2 -1
- package/templates/schema.ts +2 -0
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.56.3",
|
|
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": [
|
|
@@ -509,6 +509,10 @@
|
|
|
509
509
|
"type": "string",
|
|
510
510
|
"maxLength": 65536
|
|
511
511
|
},
|
|
512
|
+
"heartbeatMd": {
|
|
513
|
+
"type": "string",
|
|
514
|
+
"maxLength": 65536
|
|
515
|
+
},
|
|
512
516
|
"changeSource": {
|
|
513
517
|
"type": "string"
|
|
514
518
|
},
|
|
@@ -1911,6 +1915,27 @@
|
|
|
1911
1915
|
}
|
|
1912
1916
|
}
|
|
1913
1917
|
},
|
|
1918
|
+
"/api/heartbeat/checklist": {
|
|
1919
|
+
"post": {
|
|
1920
|
+
"summary": "Trigger an immediate heartbeat checklist check",
|
|
1921
|
+
"tags": [
|
|
1922
|
+
"Heartbeat"
|
|
1923
|
+
],
|
|
1924
|
+
"security": [
|
|
1925
|
+
{
|
|
1926
|
+
"bearerAuth": []
|
|
1927
|
+
}
|
|
1928
|
+
],
|
|
1929
|
+
"responses": {
|
|
1930
|
+
"200": {
|
|
1931
|
+
"description": "Checklist check completed successfully"
|
|
1932
|
+
},
|
|
1933
|
+
"401": {
|
|
1934
|
+
"description": "Unauthorized"
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
}
|
|
1938
|
+
},
|
|
1914
1939
|
"/api/memory/index": {
|
|
1915
1940
|
"post": {
|
|
1916
1941
|
"summary": "Ingest content into memory system (async embedding)",
|
package/package.json
CHANGED
package/src/be/db.ts
CHANGED
|
@@ -229,6 +229,7 @@ const VERSIONABLE_FIELDS: VersionableField[] = [
|
|
|
229
229
|
"toolsMd",
|
|
230
230
|
"claudeMd",
|
|
231
231
|
"setupScript",
|
|
232
|
+
"heartbeatMd",
|
|
232
233
|
];
|
|
233
234
|
|
|
234
235
|
function ensureAgentProfileColumns(database: Database): void {
|
|
@@ -399,9 +400,10 @@ function seedContextVersions(): void {
|
|
|
399
400
|
toolsMd: string | null;
|
|
400
401
|
claudeMd: string | null;
|
|
401
402
|
setupScript: string | null;
|
|
403
|
+
heartbeatMd: string | null;
|
|
402
404
|
},
|
|
403
405
|
[]
|
|
404
|
-
>(`SELECT id, soulMd, identityMd, toolsMd, claudeMd, setupScript FROM agents`)
|
|
406
|
+
>(`SELECT id, soulMd, identityMd, toolsMd, claudeMd, setupScript, heartbeatMd FROM agents`)
|
|
405
407
|
.all();
|
|
406
408
|
|
|
407
409
|
for (const agent of agents) {
|
|
@@ -450,6 +452,7 @@ type AgentRow = {
|
|
|
450
452
|
identityMd: string | null;
|
|
451
453
|
setupScript: string | null;
|
|
452
454
|
toolsMd: string | null;
|
|
455
|
+
heartbeatMd: string | null;
|
|
453
456
|
lastActivityAt: string | null;
|
|
454
457
|
createdAt: string;
|
|
455
458
|
lastUpdatedAt: string;
|
|
@@ -471,6 +474,7 @@ function rowToAgent(row: AgentRow): Agent {
|
|
|
471
474
|
identityMd: row.identityMd ?? undefined,
|
|
472
475
|
setupScript: row.setupScript ?? undefined,
|
|
473
476
|
toolsMd: row.toolsMd ?? undefined,
|
|
477
|
+
heartbeatMd: row.heartbeatMd ?? undefined,
|
|
474
478
|
lastActivityAt: row.lastActivityAt ?? undefined,
|
|
475
479
|
createdAt: row.createdAt,
|
|
476
480
|
lastUpdatedAt: row.lastUpdatedAt,
|
|
@@ -2259,6 +2263,7 @@ export function updateAgentProfile(
|
|
|
2259
2263
|
identityMd?: string;
|
|
2260
2264
|
setupScript?: string;
|
|
2261
2265
|
toolsMd?: string;
|
|
2266
|
+
heartbeatMd?: string;
|
|
2262
2267
|
},
|
|
2263
2268
|
meta?: VersionMeta,
|
|
2264
2269
|
): Agent | null {
|
|
@@ -2312,6 +2317,7 @@ export function updateAgentProfile(
|
|
|
2312
2317
|
string | null,
|
|
2313
2318
|
string | null,
|
|
2314
2319
|
string | null,
|
|
2320
|
+
string | null,
|
|
2315
2321
|
string,
|
|
2316
2322
|
string,
|
|
2317
2323
|
]
|
|
@@ -2325,6 +2331,7 @@ export function updateAgentProfile(
|
|
|
2325
2331
|
identityMd = COALESCE(?, identityMd),
|
|
2326
2332
|
setupScript = COALESCE(?, setupScript),
|
|
2327
2333
|
toolsMd = COALESCE(?, toolsMd),
|
|
2334
|
+
heartbeatMd = COALESCE(?, heartbeatMd),
|
|
2328
2335
|
lastUpdatedAt = ?
|
|
2329
2336
|
WHERE id = ? RETURNING *`,
|
|
2330
2337
|
)
|
|
@@ -2337,6 +2344,7 @@ export function updateAgentProfile(
|
|
|
2337
2344
|
updates.identityMd ?? null,
|
|
2338
2345
|
updates.setupScript ?? null,
|
|
2339
2346
|
updates.toolsMd ?? null,
|
|
2347
|
+
updates.heartbeatMd ?? null,
|
|
2340
2348
|
now,
|
|
2341
2349
|
id,
|
|
2342
2350
|
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE agents ADD COLUMN heartbeatMd TEXT DEFAULT NULL;
|
|
@@ -152,6 +152,12 @@ export function runMigrations(db: Database): void {
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
// 5. Run pending migrations
|
|
155
|
+
// Disable FK checks for the entire migration pass. Individual migrations
|
|
156
|
+
// (008, 025, 026) need to DROP + recreate tables, which can violate FKs
|
|
157
|
+
// mid-transaction. PRAGMA foreign_keys cannot be changed inside a transaction,
|
|
158
|
+
// so we disable it here, outside any transaction, and re-enable after.
|
|
159
|
+
db.run("PRAGMA foreign_keys = OFF");
|
|
160
|
+
|
|
155
161
|
for (const migration of migrations) {
|
|
156
162
|
const existing = applied.get(migration.version);
|
|
157
163
|
|
|
@@ -184,4 +190,6 @@ export function runMigrations(db: Database): void {
|
|
|
184
190
|
const elapsed = (performance.now() - start).toFixed(1);
|
|
185
191
|
console.debug(`[migrations] Applied: ${migration.name} (${elapsed}ms)`);
|
|
186
192
|
}
|
|
193
|
+
|
|
194
|
+
db.run("PRAGMA foreign_keys = ON");
|
|
187
195
|
}
|
package/src/commands/runner.ts
CHANGED
|
@@ -1991,6 +1991,7 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
1991
1991
|
let agentSetupScript: string | undefined;
|
|
1992
1992
|
let agentToolsMd: string | undefined;
|
|
1993
1993
|
let agentClaudeMd: string | undefined;
|
|
1994
|
+
let agentHeartbeatMd: string | undefined;
|
|
1994
1995
|
let agentProfileName: string | undefined;
|
|
1995
1996
|
let agentDescription: string | undefined;
|
|
1996
1997
|
let agentSkillsSummary: { name: string; description: string }[] | undefined;
|
|
@@ -2170,6 +2171,7 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
2170
2171
|
claudeMd?: string;
|
|
2171
2172
|
setupScript?: string;
|
|
2172
2173
|
toolsMd?: string;
|
|
2174
|
+
heartbeatMd?: string;
|
|
2173
2175
|
name?: string;
|
|
2174
2176
|
description?: string;
|
|
2175
2177
|
};
|
|
@@ -2178,12 +2180,19 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
2178
2180
|
agentSetupScript = profile.setupScript;
|
|
2179
2181
|
agentToolsMd = profile.toolsMd;
|
|
2180
2182
|
agentClaudeMd = profile.claudeMd;
|
|
2183
|
+
agentHeartbeatMd = profile.heartbeatMd;
|
|
2181
2184
|
agentProfileName = profile.name;
|
|
2182
2185
|
agentDescription = profile.description;
|
|
2183
2186
|
|
|
2184
2187
|
// Generate default templates if missing (runner registers via POST /api/agents
|
|
2185
2188
|
// which doesn't generate templates like join-swarm does)
|
|
2186
|
-
if (
|
|
2189
|
+
if (
|
|
2190
|
+
!agentSoulMd ||
|
|
2191
|
+
!agentIdentityMd ||
|
|
2192
|
+
!agentToolsMd ||
|
|
2193
|
+
!agentClaudeMd ||
|
|
2194
|
+
!agentHeartbeatMd
|
|
2195
|
+
) {
|
|
2187
2196
|
// Use already-fetched template (from pre-registration step)
|
|
2188
2197
|
if (cachedTemplate) {
|
|
2189
2198
|
const ctx = {
|
|
@@ -2202,6 +2211,8 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
2202
2211
|
agentClaudeMd = interpolate(cachedTemplate.files.claudeMd, ctx).result;
|
|
2203
2212
|
if (!agentSetupScript)
|
|
2204
2213
|
agentSetupScript = interpolate(cachedTemplate.files.setupScript, ctx).result;
|
|
2214
|
+
if (!agentHeartbeatMd)
|
|
2215
|
+
agentHeartbeatMd = interpolate(cachedTemplate.files.heartbeatMd, ctx).result;
|
|
2205
2216
|
console.log(`[${role}] Applied template: ${templateId}`);
|
|
2206
2217
|
}
|
|
2207
2218
|
|
|
@@ -2226,6 +2237,8 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
2226
2237
|
if (!profile.claudeMd && agentClaudeMd) profileUpdate.claudeMd = agentClaudeMd;
|
|
2227
2238
|
if (!profile.setupScript && agentSetupScript)
|
|
2228
2239
|
profileUpdate.setupScript = agentSetupScript;
|
|
2240
|
+
if (!profile.heartbeatMd && agentHeartbeatMd)
|
|
2241
|
+
profileUpdate.heartbeatMd = agentHeartbeatMd;
|
|
2229
2242
|
|
|
2230
2243
|
await fetch(`${apiUrl}/api/agents/${agentId}/profile`, {
|
|
2231
2244
|
method: "PUT",
|
|
@@ -2364,6 +2377,16 @@ export async function runAgent(config: RunnerConfig, opts: RunnerOptions) {
|
|
|
2364
2377
|
}
|
|
2365
2378
|
}
|
|
2366
2379
|
|
|
2380
|
+
// Write HEARTBEAT.md to workspace (lead's periodic checklist)
|
|
2381
|
+
if (agentHeartbeatMd) {
|
|
2382
|
+
try {
|
|
2383
|
+
await Bun.write("/workspace/HEARTBEAT.md", agentHeartbeatMd);
|
|
2384
|
+
console.log(`[${role}] Wrote HEARTBEAT.md to workspace`);
|
|
2385
|
+
} catch (err) {
|
|
2386
|
+
console.warn(`[${role}] Could not write HEARTBEAT.md: ${(err as Error).message}`);
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2389
|
+
|
|
2367
2390
|
// Write CLAUDE.md to workspace (agent-level instructions)
|
|
2368
2391
|
if (agentClaudeMd) {
|
|
2369
2392
|
try {
|