@desplega.ai/agent-swarm 1.51.2 → 1.52.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 (55) hide show
  1. package/README.md +131 -0
  2. package/openapi.json +767 -4
  3. package/package.json +3 -1
  4. package/src/be/db.ts +669 -0
  5. package/src/be/migrations/019_skills.sql +65 -0
  6. package/src/be/migrations/020_approval_requests.sql +41 -0
  7. package/src/be/migrations/runner.ts +4 -4
  8. package/src/be/skill-parser.ts +70 -0
  9. package/src/be/skill-sync.ts +106 -0
  10. package/src/commands/runner.ts +299 -52
  11. package/src/http/agents.ts +29 -0
  12. package/src/http/approval-requests.ts +310 -0
  13. package/src/http/config.ts +3 -3
  14. package/src/http/index.ts +26 -2
  15. package/src/http/poll.ts +15 -0
  16. package/src/http/skills.ts +479 -0
  17. package/src/http/tasks.ts +94 -0
  18. package/src/linear/outbound.ts +12 -12
  19. package/src/prompts/base-prompt.ts +8 -0
  20. package/src/providers/claude-adapter.ts +19 -3
  21. package/src/scheduler/scheduler.ts +24 -1
  22. package/src/server.ts +29 -0
  23. package/src/slack/blocks.ts +1 -1
  24. package/src/tests/approval-requests.test.ts +948 -0
  25. package/src/tests/skill-parser.test.ts +178 -0
  26. package/src/tests/skill-sync.test.ts +171 -0
  27. package/src/tests/slack-blocks.test.ts +3 -2
  28. package/src/tests/structured-output.test.ts +1 -0
  29. package/src/tests/tool-annotations.test.ts +2 -1
  30. package/src/tests/tool-call-progress.test.ts +207 -0
  31. package/src/tests/tool-registrar-no-input.test.ts +114 -0
  32. package/src/tests/update-profile-auth.test.ts +1 -0
  33. package/src/tests/workflow-executors.test.ts +4 -2
  34. package/src/tools/request-human-input.ts +117 -0
  35. package/src/tools/skills/index.ts +11 -0
  36. package/src/tools/skills/skill-create.ts +105 -0
  37. package/src/tools/skills/skill-delete.ts +67 -0
  38. package/src/tools/skills/skill-get.ts +75 -0
  39. package/src/tools/skills/skill-install-remote.ts +152 -0
  40. package/src/tools/skills/skill-install.ts +101 -0
  41. package/src/tools/skills/skill-list.ts +77 -0
  42. package/src/tools/skills/skill-publish.ts +123 -0
  43. package/src/tools/skills/skill-search.ts +43 -0
  44. package/src/tools/skills/skill-sync-remote.ts +128 -0
  45. package/src/tools/skills/skill-uninstall.ts +60 -0
  46. package/src/tools/skills/skill-update.ts +128 -0
  47. package/src/tools/store-progress.ts +31 -0
  48. package/src/tools/templates.ts +28 -0
  49. package/src/tools/tool-config.ts +16 -0
  50. package/src/tools/utils.ts +9 -7
  51. package/src/types.ts +54 -0
  52. package/src/workflows/executors/human-in-the-loop.ts +273 -0
  53. package/src/workflows/executors/registry.ts +2 -0
  54. package/src/workflows/recovery.ts +72 -0
  55. package/src/workflows/resume.ts +65 -1
@@ -1,5 +1,5 @@
1
1
  import { unlink, writeFile } from "node:fs/promises";
2
- import { join } from "node:path";
2
+ import { dirname, join } from "node:path";
3
3
  import { validateClaudeCredentials } from "../utils/credentials";
4
4
  import {
5
5
  parseStderrForErrors,
@@ -48,10 +48,26 @@ async function cleanupTaskFile(pid: number): Promise<void> {
48
48
  * Returns the path to the per-session config, or null if no config exists.
49
49
  */
50
50
  async function createSessionMcpConfig(cwd: string, taskId: string): Promise<string | null> {
51
- const mcpJsonPath = join(cwd, ".mcp.json");
51
+ // Walk up from cwd to find .mcp.json (mirrors Claude CLI's project-level config discovery).
52
+ // In Docker, .mcp.json lives at /workspace/.mcp.json but tasks often run with cwd set to
53
+ // a subdirectory like /workspace/repos/<repo>, so a single-directory check misses it.
54
+ let searchDir = cwd;
55
+ let mcpJsonPath: string | null = null;
56
+ while (true) {
57
+ const candidate = join(searchDir, ".mcp.json");
58
+ if (await Bun.file(candidate).exists()) {
59
+ mcpJsonPath = candidate;
60
+ break;
61
+ }
62
+ const parent = dirname(searchDir);
63
+ if (parent === searchDir) break; // reached filesystem root
64
+ searchDir = parent;
65
+ }
66
+
67
+ if (!mcpJsonPath) return null;
68
+
52
69
  try {
53
70
  const file = Bun.file(mcpJsonPath);
54
- if (!(await file.exists())) return null;
55
71
 
56
72
  const config = await file.json();
57
73
  const servers = config?.mcpServers;
@@ -1,3 +1,4 @@
1
+ import { ensure } from "@desplega.ai/business-use";
1
2
  import { CronExpressionParser } from "cron-parser";
2
3
  import {
3
4
  createTaskExtended,
@@ -239,7 +240,11 @@ async function executeSchedule(schedule: ScheduledTask): Promise<void> {
239
240
  * @param registry ExecutorRegistry for triggering workflows linked to schedules
240
241
  * @param intervalMs Polling interval in milliseconds (default: 10000)
241
242
  */
242
- export function startScheduler(registry: ExecutorRegistry, intervalMs = 10000): void {
243
+ export function startScheduler(
244
+ registry: ExecutorRegistry,
245
+ intervalMs = 10000,
246
+ opts?: { runId?: string },
247
+ ): void {
243
248
  if (schedulerInterval) {
244
249
  console.log("[Scheduler] Already running");
245
250
  return;
@@ -254,6 +259,24 @@ export function startScheduler(registry: ExecutorRegistry, intervalMs = 10000):
254
259
  schedulerInterval = setInterval(async () => {
255
260
  await processSchedules();
256
261
  }, intervalMs);
262
+
263
+ ensure({
264
+ id: "scheduler_started",
265
+ flow: "api",
266
+ runId: opts?.runId ?? "",
267
+ depIds: ["listen"],
268
+ data: {},
269
+ // biome-ignore lint/correctness/noEmptyPattern: data unused, ctx needed
270
+ filter: ({}, ctx) => {
271
+ const start = ctx.deps.find((d) => d.id === "listen");
272
+ return !!start && start.data?.capabilities?.includes("scheduling");
273
+ },
274
+ // biome-ignore lint/correctness/noEmptyPattern: data unused, ctx needed
275
+ validator: ({}, ctx) => {
276
+ const start = ctx.deps.find((d) => d.id === "listen");
277
+ return !!start && start.data?.capabilities?.includes("scheduling");
278
+ },
279
+ });
257
280
  }
258
281
 
259
282
  /**
package/src/server.ts CHANGED
@@ -43,6 +43,7 @@ import { registerReadMessagesTool } from "./tools/read-messages";
43
43
  import { registerRegisterAgentMailInboxTool } from "./tools/register-agentmail-inbox";
44
44
  // Services capability
45
45
  import { registerRegisterServiceTool } from "./tools/register-service";
46
+ import { registerRequestHumanInputTool } from "./tools/request-human-input";
46
47
  // Scheduling capability
47
48
  import {
48
49
  registerCreateScheduleTool,
@@ -52,6 +53,20 @@ import {
52
53
  registerUpdateScheduleTool,
53
54
  } from "./tools/schedules";
54
55
  import { registerSendTaskTool } from "./tools/send-task";
56
+ // Skills capability
57
+ import {
58
+ registerSkillCreateTool,
59
+ registerSkillDeleteTool,
60
+ registerSkillGetTool,
61
+ registerSkillInstallRemoteTool,
62
+ registerSkillInstallTool,
63
+ registerSkillListTool,
64
+ registerSkillPublishTool,
65
+ registerSkillSearchTool,
66
+ registerSkillSyncRemoteTool,
67
+ registerSkillUninstallTool,
68
+ registerSkillUpdateTool,
69
+ } from "./tools/skills";
55
70
  import { registerSlackDownloadFileTool } from "./tools/slack-download-file";
56
71
  import { registerSlackListChannelsTool } from "./tools/slack-list-channels";
57
72
  import { registerSlackPostTool } from "./tools/slack-post";
@@ -241,7 +256,21 @@ export function createServer() {
241
256
  registerListWorkflowRunsTool(server);
242
257
  registerGetWorkflowRunTool(server);
243
258
  registerRetryWorkflowRunTool(server);
259
+ registerRequestHumanInputTool(server);
244
260
  }
245
261
 
262
+ // Skills - always registered (skill management is available to all agents)
263
+ registerSkillCreateTool(server);
264
+ registerSkillUpdateTool(server);
265
+ registerSkillDeleteTool(server);
266
+ registerSkillGetTool(server);
267
+ registerSkillListTool(server);
268
+ registerSkillSearchTool(server);
269
+ registerSkillInstallTool(server);
270
+ registerSkillUninstallTool(server);
271
+ registerSkillInstallRemoteTool(server);
272
+ registerSkillSyncRemoteTool(server);
273
+ registerSkillPublishTool(server);
274
+
246
275
  return server;
247
276
  }
@@ -179,7 +179,7 @@ export function buildProgressBlocks(opts: {
179
179
  }): SlackBlock[] {
180
180
  const shortId = opts.taskId.slice(0, 8);
181
181
  return [
182
- sectionBlock(`⏳ *${opts.agentName}* (\`${shortId}\`): ${opts.progress}`),
182
+ sectionBlock(`*${opts.agentName}* (\`${shortId}\`): ${opts.progress}`),
183
183
  cancelActionBlock(opts.taskId),
184
184
  ];
185
185
  }