@desplega.ai/agent-swarm 1.91.0 → 1.92.1

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.
Files changed (114) hide show
  1. package/README.md +3 -2
  2. package/openapi.json +1005 -152
  3. package/package.json +6 -6
  4. package/plugin/skills/pages/SKILL.md +5 -2
  5. package/src/be/db.ts +662 -19
  6. package/src/be/memory/constants.ts +2 -1
  7. package/src/be/memory/providers/openai-embedding.ts +2 -5
  8. package/src/be/memory/providers/sqlite-store.ts +293 -76
  9. package/src/be/memory/types.ts +35 -0
  10. package/src/be/migrations/083_script_workflows.sql +51 -0
  11. package/src/be/migrations/084_script_run_journal_duration.sql +5 -0
  12. package/src/be/migrations/085_script_runs_kind.sql +9 -0
  13. package/src/be/migrations/086_pages_default_authed.sql +64 -0
  14. package/src/be/migrations/087_skill_files.sql +19 -0
  15. package/src/be/modelsdev-cache.json +42310 -38617
  16. package/src/be/scripts/typecheck.ts +49 -0
  17. package/src/be/seed-scripts/catalog/boot-triage.ts +221 -0
  18. package/src/be/seed-scripts/catalog/catalog-report.ts +457 -0
  19. package/src/be/seed-scripts/catalog/compound-insights.ts +310 -6
  20. package/src/be/seed-scripts/catalog/gh-pr-snapshot.ts +1 -1
  21. package/src/be/seed-scripts/catalog/memory-eval.ts +1059 -0
  22. package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +506 -0
  23. package/src/be/seed-scripts/catalog/schedule-health.ts +78 -2
  24. package/src/be/seed-scripts/catalog/task-context-gathering.ts +92 -0
  25. package/src/be/seed-scripts/catalog/task-failure-audit.ts +48 -1
  26. package/src/be/seed-scripts/catalog/tool-usage.ts +6 -3
  27. package/src/be/seed-scripts/index.ts +51 -5
  28. package/src/be/seed-skills/index.ts +3 -3
  29. package/src/be/skill-sync.ts +91 -7
  30. package/src/be/swarm-config-guard.ts +17 -0
  31. package/src/commands/runner.ts +49 -4
  32. package/src/heartbeat/templates.ts +20 -16
  33. package/src/http/db-query.ts +20 -5
  34. package/src/http/index.ts +51 -7
  35. package/src/http/mcp-user.ts +23 -0
  36. package/src/http/mcp.ts +58 -0
  37. package/src/http/memory.ts +58 -0
  38. package/src/http/pages.ts +1 -1
  39. package/src/http/script-runs.ts +557 -0
  40. package/src/http/scripts.ts +39 -2
  41. package/src/http/skills.ts +225 -0
  42. package/src/prompts/session-templates.ts +24 -4
  43. package/src/providers/claude-adapter.ts +107 -28
  44. package/src/script-workflows/executor.ts +110 -0
  45. package/src/script-workflows/harness.ts +73 -0
  46. package/src/script-workflows/label-lint.ts +51 -0
  47. package/src/script-workflows/limits.ts +22 -0
  48. package/src/script-workflows/supervisor.ts +139 -0
  49. package/src/script-workflows/workflow-ctx.ts +209 -0
  50. package/src/scripts-runtime/sdk-allowlist.ts +4 -0
  51. package/src/scripts-runtime/swarm-sdk.ts +13 -0
  52. package/src/scripts-runtime/types/stdlib.d.ts +61 -0
  53. package/src/scripts-runtime/types/swarm-sdk.d.ts +61 -0
  54. package/src/server.ts +4 -0
  55. package/src/slack/handlers.ts +11 -4
  56. package/src/slack/message-text.ts +98 -0
  57. package/src/slack/thread-buffer.ts +5 -3
  58. package/src/tests/claude-adapter-binary.test.ts +271 -74
  59. package/src/tests/create-page-tool.test.ts +19 -2
  60. package/src/tests/db-query.test.ts +28 -0
  61. package/src/tests/error-tracker.test.ts +121 -0
  62. package/src/tests/harness-provider-resolution.test.ts +33 -0
  63. package/src/tests/heartbeat-checklist.test.ts +36 -0
  64. package/src/tests/mcp-tools.test.ts +6 -0
  65. package/src/tests/mcp-transport-gc.test.ts +58 -0
  66. package/src/tests/memory-health-endpoint.test.ts +78 -0
  67. package/src/tests/memory-store.test.ts +221 -1
  68. package/src/tests/pages-http.test.ts +20 -2
  69. package/src/tests/pages-storage.test.ts +26 -0
  70. package/src/tests/prompt-template-session.test.ts +34 -5
  71. package/src/tests/script-runs-http.test.ts +278 -0
  72. package/src/tests/script-workflows-label-lint.test.ts +43 -0
  73. package/src/tests/script-workflows-runtime-e2e.test.ts +170 -0
  74. package/src/tests/scripts-mcp-e2e.test.ts +102 -2
  75. package/src/tests/seed-scripts.test.ts +468 -3
  76. package/src/tests/skill-files-http.test.ts +171 -0
  77. package/src/tests/skill-files.test.ts +162 -0
  78. package/src/tests/skill-get-file-tool.test.ts +110 -0
  79. package/src/tests/skill-sync.test.ts +125 -6
  80. package/src/tests/slack-message-text.test.ts +250 -0
  81. package/src/tests/system-default-skills.test.ts +40 -0
  82. package/src/tools/create-page.ts +2 -2
  83. package/src/tools/db-query.ts +16 -6
  84. package/src/tools/script-runs.ts +123 -0
  85. package/src/tools/skills/index.ts +1 -0
  86. package/src/tools/skills/skill-get-file.ts +80 -0
  87. package/src/tools/slack-read.ts +12 -3
  88. package/src/tools/tool-config.ts +6 -2
  89. package/src/types.ts +72 -0
  90. package/src/utils/error-tracker.ts +40 -1
  91. package/src/utils/internal-ai/complete-structured.ts +10 -4
  92. package/src/workflows/executors/raw-llm.ts +76 -59
  93. package/templates/schedules/daily-blocker-digest/content.md +68 -54
  94. package/templates/schedules/daily-compounding-reflection/content.md +4 -4
  95. package/templates/schedules/daily-hn-briefing/content.md +5 -5
  96. package/templates/schedules/daily-workflow-health-audit/content.md +6 -6
  97. package/templates/schedules/gtm-weekly-review/content.md +9 -9
  98. package/templates/schedules/weekly-dependabot-triage/content.md +24 -20
  99. package/templates/skills/agentmail-sending/content.md +6 -7
  100. package/templates/skills/desloppify/content.md +8 -9
  101. package/templates/skills/jira-interaction/content.md +25 -33
  102. package/templates/skills/kapso-whatsapp/content.md +29 -30
  103. package/templates/skills/linear-interaction/content.md +8 -9
  104. package/templates/skills/pages/content.md +205 -55
  105. package/templates/skills/profile-corruption-escalation/content.md +44 -85
  106. package/templates/skills/script-workflows/config.json +14 -0
  107. package/templates/skills/script-workflows/content.md +68 -0
  108. package/templates/skills/sprite-cli/content.md +4 -5
  109. package/templates/skills/swarm-scripts/content.md +2 -3
  110. package/templates/skills/turso-interaction/content.md +14 -17
  111. package/templates/skills/workflow-iterate/content.md +38 -391
  112. package/templates/skills/x-api-interactions/content.md +4 -6
  113. package/templates/skills/scheduled-task-resilience/config.json +0 -14
  114. package/templates/skills/scheduled-task-resilience/content.md +0 -95
package/src/server.ts CHANGED
@@ -78,6 +78,7 @@ import {
78
78
  import { registerScriptDeleteTool } from "./tools/script-delete";
79
79
  import { registerScriptQueryTypesTool } from "./tools/script-query-types";
80
80
  import { registerScriptRunTool } from "./tools/script-run";
81
+ import { registerScriptRunsTools } from "./tools/script-runs";
81
82
  import { registerScriptSearchTool } from "./tools/script-search";
82
83
  import { registerScriptUpsertTool } from "./tools/script-upsert";
83
84
  import { registerSendTaskTool } from "./tools/send-task";
@@ -85,6 +86,7 @@ import { registerSendTaskTool } from "./tools/send-task";
85
86
  import {
86
87
  registerSkillCreateTool,
87
88
  registerSkillDeleteTool,
89
+ registerSkillGetFileTool,
88
90
  registerSkillGetTool,
89
91
  registerSkillInstallRemoteTool,
90
92
  registerSkillInstallTool,
@@ -227,6 +229,7 @@ export function createServer() {
227
229
  registerScriptUpsertTool(server);
228
230
  registerScriptDeleteTool(server);
229
231
  registerScriptQueryTypesTool(server);
232
+ registerScriptRunsTools(server);
230
233
 
231
234
  // External command routes - mirrors the `agent-swarm x ...` CLI surface.
232
235
  registerSwarmXTool(server);
@@ -327,6 +330,7 @@ export function createServer() {
327
330
  registerSkillUpdateTool(server);
328
331
  registerSkillDeleteTool(server);
329
332
  registerSkillGetTool(server);
333
+ registerSkillGetFileTool(server);
330
334
  registerSkillListTool(server);
331
335
  registerSkillSearchTool(server);
332
336
  registerSkillInstallTool(server);
@@ -18,6 +18,7 @@ import type { SlackFile } from "./files";
18
18
  import { extractTaskFromMessage, hasOtherUserMention, routeMessage } from "./router";
19
19
  // Side-effect import: registers all Slack event templates in the in-memory registry
20
20
  import "./templates";
21
+ import { extractSlackMessageText } from "./message-text";
21
22
  import { bufferThreadMessage, getBufferMessageCount, instantFlush } from "./thread-buffer";
22
23
  import { registerTreeMessage } from "./watcher";
23
24
 
@@ -173,6 +174,8 @@ interface ThreadMessage {
173
174
  subtype?: string;
174
175
  text?: string;
175
176
  ts: string;
177
+ attachments?: Array<{ fallback?: string; text?: string; title?: string; pretext?: string }>;
178
+ blocks?: unknown[];
176
179
  }
177
180
 
178
181
  // Cache for bot's own user ID (avoids redundant auth.test calls)
@@ -286,8 +289,11 @@ async function getThreadContext(
286
289
  });
287
290
 
288
291
  const messages = (result.messages || []) as ThreadMessage[];
289
- // Filter out the current message only (keep bot messages for context)
290
- const previousMessages = messages.filter((m) => m.ts !== currentTs && m.text);
292
+ // Filter out the current message; include any message with extractable text
293
+ const previousMessages = messages.filter((m) => {
294
+ if (m.ts === currentTs) return false;
295
+ return extractSlackMessageText(m) !== "";
296
+ });
291
297
 
292
298
  if (previousMessages.length === 0) return "";
293
299
 
@@ -298,13 +304,14 @@ async function getThreadContext(
298
304
  const isBotMessage =
299
305
  m.user === botUserId || m.bot_id !== undefined || m.subtype === "bot_message";
300
306
 
307
+ const text = extractSlackMessageText(m);
301
308
  if (isBotMessage) {
302
309
  // Bot/agent message - truncate if too long
303
- const truncatedText = m.text && m.text.length > 500 ? `${m.text.slice(0, 500)}...` : m.text;
310
+ const truncatedText = text.length > 500 ? `${text.slice(0, 500)}...` : text;
304
311
  formattedMessages.push(`[Agent]: ${truncatedText}`);
305
312
  } else {
306
313
  const userName = m.user ? await getUserDisplayName(client, m.user) : "Unknown";
307
- formattedMessages.push(`${userName}: ${m.text}`);
314
+ formattedMessages.push(`${userName}: ${text}`);
308
315
  }
309
316
  }
310
317
 
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Shared utility for extracting displayable text from a Slack message.
3
+ *
4
+ * Slack integration/alert apps (Datadog, PagerDuty, GitHub) often post with
5
+ * an empty top-level `text` field and put all content in legacy `attachments`
6
+ * or Block Kit `blocks`. This helper falls back through those layers so callers
7
+ * never silently drop those messages.
8
+ */
9
+
10
+ interface SlackAttachment {
11
+ fallback?: string;
12
+ text?: string;
13
+ title?: string;
14
+ pretext?: string;
15
+ }
16
+
17
+ // Internal shape used only inside the helper; callers pass `blocks?: unknown[]`
18
+ interface SlackBlockInternal {
19
+ type?: string;
20
+ text?: { type?: string; text?: string };
21
+ /** section blocks may use fields[] instead of (or alongside) a top-level text object */
22
+ fields?: Array<{ type?: string; text?: string }>;
23
+ elements?: unknown[];
24
+ }
25
+
26
+ export interface SlackMessageLike {
27
+ text?: string;
28
+ attachments?: SlackAttachment[];
29
+ /** Typed as unknown[] so any Slack SDK block variant is accepted without casting. */
30
+ blocks?: unknown[];
31
+ }
32
+
33
+ /**
34
+ * Recursively collect plain text from a Slack rich_text node tree.
35
+ *
36
+ * Handles text leaf nodes plus all container types that carry child elements:
37
+ * rich_text_section, rich_text_list, rich_text_quote, rich_text_preformatted.
38
+ */
39
+ function collectRichTextParts(node: unknown, parts: string[]): void {
40
+ if (node == null || typeof node !== "object") return;
41
+ const n = node as { type?: string; text?: string; elements?: unknown[] };
42
+ if (n.type === "text" && n.text) {
43
+ parts.push(n.text);
44
+ }
45
+ if (Array.isArray(n.elements)) {
46
+ for (const child of n.elements) {
47
+ collectRichTextParts(child, parts);
48
+ }
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Return the best displayable text for a Slack message.
54
+ *
55
+ * Priority:
56
+ * 1. `msg.text` (non-empty)
57
+ * 2. `msg.attachments[]` — joins `fallback || text || title || pretext` for each
58
+ * 3. `msg.blocks[]` — extracts text from section (text + fields) and rich_text blocks
59
+ * 4. `""` if nothing found
60
+ */
61
+ export function extractSlackMessageText(msg: SlackMessageLike): string {
62
+ if (msg.text?.trim()) return msg.text;
63
+
64
+ // Legacy attachments (Datadog, PagerDuty, GitHub alert apps)
65
+ if (Array.isArray(msg.attachments) && msg.attachments.length > 0) {
66
+ const parts = msg.attachments
67
+ .filter((a): a is SlackAttachment => a != null && typeof a === "object")
68
+ .map((a) => a.fallback || a.text || a.title || a.pretext || "")
69
+ .filter(Boolean);
70
+ if (parts.length > 0) return parts.join("\n");
71
+ }
72
+
73
+ // Block Kit blocks
74
+ if (Array.isArray(msg.blocks) && msg.blocks.length > 0) {
75
+ const parts: string[] = [];
76
+ for (const rawBlock of msg.blocks) {
77
+ if (rawBlock == null || typeof rawBlock !== "object") continue;
78
+ const block = rawBlock as SlackBlockInternal;
79
+ if (block.type === "section") {
80
+ if (block.text?.text) parts.push(block.text.text);
81
+ if (Array.isArray(block.fields)) {
82
+ for (const field of block.fields) {
83
+ if (field != null && typeof field === "object" && field.text) {
84
+ parts.push(field.text);
85
+ }
86
+ }
87
+ }
88
+ } else if (block.type === "rich_text" && Array.isArray(block.elements)) {
89
+ for (const el of block.elements) {
90
+ collectRichTextParts(el, parts);
91
+ }
92
+ }
93
+ }
94
+ if (parts.length > 0) return parts.join("\n");
95
+ }
96
+
97
+ return "";
98
+ }
@@ -4,6 +4,7 @@ import { slackContextKey } from "../tasks/context-key";
4
4
  import { createTaskWithSiblingAwareness } from "../tasks/sibling-awareness";
5
5
  import { getSlackApp } from "./app";
6
6
  import { buildBufferFlushBlocks } from "./blocks";
7
+ import { extractSlackMessageText } from "./message-text";
7
8
  import { registerTreeMessage } from "./watcher";
8
9
 
9
10
  interface BufferedMessage {
@@ -93,15 +94,16 @@ async function getThreadContextForBuffer(channelId: string, threadTs: string): P
93
94
  if (messages.length === 0) return "";
94
95
 
95
96
  const formatted = messages
96
- .filter((m) => m.text)
97
+ .filter((m) => extractSlackMessageText(m) !== "")
97
98
  .map((m) => {
98
99
  const msg = m as Record<string, unknown>;
99
100
  const isBotMessage = msg.bot_id !== undefined || msg.subtype === "bot_message";
101
+ const text = extractSlackMessageText(m);
100
102
  if (isBotMessage) {
101
- const truncated = m.text && m.text.length > 500 ? `${m.text.slice(0, 500)}...` : m.text;
103
+ const truncated = text.length > 500 ? `${text.slice(0, 500)}...` : text;
102
104
  return `[Agent]: ${truncated}`;
103
105
  }
104
- return `<@${m.user}>: ${m.text}`;
106
+ return `<@${m.user}>: ${text}`;
105
107
  })
106
108
  .join("\n");
107
109