@desplega.ai/agent-swarm 1.9.0 → 1.10.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/Dockerfile +43 -5
- package/README.md +16 -0
- package/UI.md +40 -0
- package/deploy/prod-db.ts +2 -2
- package/docker-compose.example.yml +49 -50
- package/docker-entrypoint.sh +4 -1
- package/package.json +1 -1
- package/plugin/commands/review-offered-task.md +45 -0
- package/plugin/commands/start-leader.md +7 -5
- package/plugin/commands/start-worker.md +5 -0
- package/src/cli.tsx +44 -5
- package/src/commands/lead.ts +2 -0
- package/src/commands/runner.ts +273 -45
- package/src/commands/worker.ts +2 -0
- package/src/http.ts +145 -1
- package/src/prompts/base-prompt.ts +17 -3
- package/src/tests/runner-polling-api.test.ts +456 -0
- package/src/utils/pretty-print.ts +137 -120
- package/thoughts/shared/plans/2025-12-23-runner-level-polling.md +934 -0
- package/thoughts/shared/research/2025-12-22-runner-loop-architecture.md +582 -0
package/Dockerfile
CHANGED
|
@@ -1,16 +1,54 @@
|
|
|
1
|
-
|
|
1
|
+
# Agent Swarm MCP Server Dockerfile
|
|
2
|
+
# Multi-stage build: compiles to standalone binary for minimal image size
|
|
3
|
+
|
|
4
|
+
# Stage 1: Build the binary
|
|
5
|
+
FROM oven/bun:latest AS builder
|
|
6
|
+
|
|
7
|
+
WORKDIR /build
|
|
8
|
+
|
|
9
|
+
# Copy package files first for better layer caching
|
|
10
|
+
COPY package.json bun.lock* ./
|
|
11
|
+
RUN bun install --frozen-lockfile
|
|
12
|
+
|
|
13
|
+
# Copy source files
|
|
14
|
+
COPY src/ ./src/
|
|
15
|
+
COPY tsconfig.json ./
|
|
16
|
+
|
|
17
|
+
# Compile HTTP server to standalone binary
|
|
18
|
+
RUN bun build ./src/http.ts --compile --outfile ./agent-swarm-api
|
|
19
|
+
|
|
20
|
+
# Stage 2: Minimal runtime image
|
|
21
|
+
FROM debian:bookworm-slim
|
|
22
|
+
|
|
23
|
+
# Install minimal dependencies (for bun:sqlite and networking)
|
|
24
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
25
|
+
ca-certificates \
|
|
26
|
+
wget \
|
|
27
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
2
28
|
|
|
3
29
|
WORKDIR /app
|
|
4
30
|
|
|
5
|
-
|
|
6
|
-
|
|
31
|
+
# Copy compiled binary from builder
|
|
32
|
+
COPY --from=builder /build/agent-swarm-api /usr/local/bin/agent-swarm-api
|
|
33
|
+
RUN chmod +x /usr/local/bin/agent-swarm-api
|
|
7
34
|
|
|
8
|
-
|
|
35
|
+
# Copy package.json for version info
|
|
36
|
+
COPY package.json ./
|
|
37
|
+
|
|
38
|
+
# Database will be created in /app (mount /app for persistence)
|
|
39
|
+
VOLUME /app
|
|
9
40
|
|
|
10
41
|
ENV PORT=3013
|
|
42
|
+
|
|
11
43
|
EXPOSE 3013
|
|
12
44
|
|
|
45
|
+
# Health check
|
|
13
46
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
|
14
47
|
CMD wget -qO- http://localhost:3013/health || exit 1
|
|
15
48
|
|
|
16
|
-
|
|
49
|
+
# Print version on startup and run the server
|
|
50
|
+
CMD echo "=== Agent Swarm API v$(cat /app/package.json | grep '\"version\"' | cut -d'"' -f4) ===" && \
|
|
51
|
+
echo "Port: $PORT" && \
|
|
52
|
+
echo "Database: /app/agent-swarm-db.sqlite" && \
|
|
53
|
+
echo "==============================" && \
|
|
54
|
+
exec /usr/local/bin/agent-swarm-api
|
package/README.md
CHANGED
|
@@ -26,6 +26,21 @@ Agent Swarm MCP enables multi-agent coordination for AI coding assistants. It pr
|
|
|
26
26
|
- **Service Discovery** - Register and discover background services
|
|
27
27
|
- **Docker Workers** - Run isolated Claude workers in containers
|
|
28
28
|
- **Lead/Worker Pattern** - Coordinate work with a lead agent and multiple workers
|
|
29
|
+
- **Dashboard UI** - Real-time monitoring dashboard for agents, tasks, and channels
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Dashboard UI
|
|
34
|
+
|
|
35
|
+
A React-based monitoring dashboard is available in the `ui/` directory. See [UI.md](./UI.md) for details.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
cd ui
|
|
39
|
+
pnpm install
|
|
40
|
+
pnpm run dev
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The dashboard runs at `http://localhost:5173` by default.
|
|
29
44
|
|
|
30
45
|
---
|
|
31
46
|
|
|
@@ -166,6 +181,7 @@ Full deployment options are documented in [DEPLOYMENT.md](./DEPLOYMENT.md).
|
|
|
166
181
|
|
|
167
182
|
| Document | Description |
|
|
168
183
|
|----------|-------------|
|
|
184
|
+
| [UI.md](./UI.md) | Dashboard UI overview |
|
|
169
185
|
| [DEPLOYMENT.md](./DEPLOYMENT.md) | Docker, Docker Compose, systemd deployment |
|
|
170
186
|
| [CONTRIBUTING.md](./CONTRIBUTING.md) | Development setup, code quality, project structure |
|
|
171
187
|
| [MCP.md](./MCP.md) | MCP tools reference (auto-generated) |
|
package/UI.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Dashboard UI
|
|
2
|
+
|
|
3
|
+
A React-based monitoring dashboard for Agent Swarm.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
cd ui
|
|
9
|
+
pnpm install
|
|
10
|
+
pnpm run dev
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The dashboard runs at `http://localhost:5173`. Make sure the API server is running (`bun run start:http` on port 3013).
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- Real-time agent and task monitoring
|
|
18
|
+
- Channel-based messaging with threads
|
|
19
|
+
- Service registry and health status
|
|
20
|
+
- Dark/light theme with honeycomb aesthetic
|
|
21
|
+
- Responsive design (desktop and mobile)
|
|
22
|
+
- URL-based state for shareable links
|
|
23
|
+
|
|
24
|
+
## Tabs
|
|
25
|
+
|
|
26
|
+
| Tab | Description |
|
|
27
|
+
|-----|-------------|
|
|
28
|
+
| **Agents** | View agents, their status (idle/busy/offline), and assigned tasks |
|
|
29
|
+
| **Tasks** | Browse and filter tasks by status, agent, or search query |
|
|
30
|
+
| **Chat** | Channel messaging between agents with thread support |
|
|
31
|
+
| **Services** | Monitor registered background services and health checks |
|
|
32
|
+
|
|
33
|
+
## Configuration
|
|
34
|
+
|
|
35
|
+
Click the settings icon in the header to configure:
|
|
36
|
+
|
|
37
|
+
- **API URL** - The Agent Swarm API endpoint (default: `http://localhost:3013`)
|
|
38
|
+
- **API Key** - Optional authentication key (matches your `API_KEY` env var)
|
|
39
|
+
|
|
40
|
+
Settings are stored in localStorage.
|
package/deploy/prod-db.ts
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
import { $ } from "bun";
|
|
4
4
|
import * as readline from "node:readline";
|
|
5
5
|
|
|
6
|
-
const DB_PATH = "/
|
|
7
|
-
const SSH_HOST = process.argv[2] || "
|
|
6
|
+
const DB_PATH = "/var/lib/docker/volumes/agent-swarm-nrz8v0_swarm_api/_data/agent-swarm-db.sqlite";
|
|
7
|
+
const SSH_HOST = process.argv[2] || "swarm";
|
|
8
8
|
|
|
9
9
|
console.log(`Connected to ${SSH_HOST}:${DB_PATH}`);
|
|
10
10
|
console.log("Type SQL queries or .tables, .schema, etc. Ctrl+C to exit.\n");
|
|
@@ -10,16 +10,14 @@
|
|
|
10
10
|
|
|
11
11
|
services:
|
|
12
12
|
api:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
dockerfile: Dockerfile
|
|
13
|
+
image: "ghcr.io/desplega-ai/agent-swarm:latest"
|
|
14
|
+
pull_policy: always
|
|
16
15
|
|
|
17
16
|
environment:
|
|
18
|
-
- ENV=${ENV:-development}
|
|
19
17
|
- API_KEY=${API_KEY}
|
|
20
18
|
|
|
21
|
-
- MCP_BASE_URL=${MCP_BASE_URL
|
|
22
|
-
- APP_URL=${APP_URL
|
|
19
|
+
- MCP_BASE_URL=${MCP_BASE_URL}
|
|
20
|
+
- APP_URL=${APP_URL}
|
|
23
21
|
|
|
24
22
|
# Optional: Enable Slack integration
|
|
25
23
|
- SLACK_DISABLE=${SLACK_DISABLE:-false}
|
|
@@ -30,97 +28,102 @@ services:
|
|
|
30
28
|
- "3013:3013"
|
|
31
29
|
|
|
32
30
|
volumes:
|
|
33
|
-
# For the sqlite database
|
|
34
31
|
- swarm_api:/app
|
|
35
32
|
|
|
36
33
|
restart: unless-stopped
|
|
37
34
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
dockerfile: Dockerfile.worker
|
|
35
|
+
lead:
|
|
36
|
+
image: "ghcr.io/desplega-ai/agent-swarm-worker:latest"
|
|
37
|
+
pull_policy: always
|
|
42
38
|
|
|
43
39
|
environment:
|
|
44
40
|
- CLAUDE_CODE_OAUTH_TOKEN=${CLAUDE_CODE_OAUTH_TOKEN}
|
|
45
41
|
- API_KEY=${API_KEY}
|
|
46
|
-
|
|
47
|
-
-
|
|
42
|
+
# Replace by a valid UUID
|
|
43
|
+
- AGENT_ID=d454d1a5-4df9-49bd-8a89-e58d6a657dc3
|
|
44
|
+
|
|
45
|
+
# Important: Lead agent role
|
|
46
|
+
- AGENT_ROLE=lead
|
|
48
47
|
|
|
49
|
-
- MCP_BASE_URL=${MCP_BASE_URL:-http://api:3013}
|
|
48
|
+
# - MCP_BASE_URL=${MCP_BASE_URL:-http://api:3013}
|
|
49
|
+
# If in the same Docker network, use the service name
|
|
50
|
+
- MCP_BASE_URL=http://api:3013
|
|
50
51
|
|
|
51
|
-
|
|
52
|
-
- SESSION_ID=${SESSION_ID:-}
|
|
53
|
-
- YOLO=${YOLO:-false}
|
|
54
|
-
# GitHub credentials for git push and PR operations
|
|
52
|
+
- YOLO=true
|
|
55
53
|
- GITHUB_TOKEN=${GITHUB_TOKEN:-}
|
|
56
54
|
- GITHUB_EMAIL=${GITHUB_EMAIL:-}
|
|
57
55
|
- GITHUB_NAME=${GITHUB_NAME:-}
|
|
58
|
-
# Service registry URL (for service discovery)
|
|
59
56
|
- SWARM_URL=${SWARM_URL:-localhost}
|
|
60
57
|
|
|
61
58
|
ports:
|
|
62
|
-
|
|
63
|
-
- "${SERVICE_PORT:-3001}:3000"
|
|
59
|
+
- "${SERVICE_PORT:-3020}:3000"
|
|
64
60
|
|
|
65
61
|
volumes:
|
|
66
62
|
- swarm_logs:/logs
|
|
67
|
-
# Optional: mount a workspace directory for persistent work
|
|
68
63
|
- swarm_shared:/workspace/shared
|
|
69
|
-
-
|
|
64
|
+
- swarm_lead:/workspace/personal
|
|
70
65
|
|
|
71
66
|
restart: unless-stopped
|
|
72
67
|
|
|
73
|
-
worker-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
dockerfile: Dockerfile.worker
|
|
68
|
+
worker-1:
|
|
69
|
+
image: "ghcr.io/desplega-ai/agent-swarm-worker:latest"
|
|
70
|
+
pull_policy: always
|
|
77
71
|
|
|
78
72
|
environment:
|
|
79
73
|
- CLAUDE_CODE_OAUTH_TOKEN=${CLAUDE_CODE_OAUTH_TOKEN}
|
|
80
74
|
- API_KEY=${API_KEY}
|
|
81
|
-
|
|
75
|
+
# Replace by a valid UUID
|
|
76
|
+
- AGENT_ID=38d36438-58a0-45b5-8602-a5d52b07c2f1
|
|
82
77
|
- AGENT_ROLE=worker
|
|
83
78
|
|
|
84
|
-
- MCP_BASE_URL=${MCP_BASE_URL:-http://api:3013}
|
|
79
|
+
# - MCP_BASE_URL=${MCP_BASE_URL:-http://api:3013}
|
|
80
|
+
# If in the same Docker network, use the service name
|
|
81
|
+
- MCP_BASE_URL=http://api:3013
|
|
85
82
|
|
|
86
|
-
|
|
83
|
+
- YOLO=true
|
|
84
|
+
- GITHUB_TOKEN=${GITHUB_TOKEN:-}
|
|
85
|
+
- GITHUB_EMAIL=${GITHUB_EMAIL:-}
|
|
86
|
+
- GITHUB_NAME=${GITHUB_NAME:-}
|
|
87
|
+
- SWARM_URL=${SWARM_URL:-localhost}
|
|
87
88
|
|
|
88
89
|
ports:
|
|
89
|
-
|
|
90
|
-
- "${SERVICE_PORT:-3002}:3000"
|
|
90
|
+
- "${SERVICE_PORT:-3021}:3000"
|
|
91
91
|
|
|
92
92
|
volumes:
|
|
93
93
|
- swarm_logs:/logs
|
|
94
94
|
- swarm_shared:/workspace/shared
|
|
95
|
-
-
|
|
95
|
+
- swarm_worker_1:/workspace/personal
|
|
96
96
|
|
|
97
97
|
restart: unless-stopped
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
dockerfile: Dockerfile.worker
|
|
99
|
+
worker-2:
|
|
100
|
+
image: "ghcr.io/desplega-ai/agent-swarm-worker:latest"
|
|
101
|
+
pull_policy: always
|
|
103
102
|
|
|
104
103
|
environment:
|
|
105
104
|
- CLAUDE_CODE_OAUTH_TOKEN=${CLAUDE_CODE_OAUTH_TOKEN}
|
|
106
105
|
- API_KEY=${API_KEY}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
- AGENT_ROLE=lead
|
|
106
|
+
# Replace by a valid UUID
|
|
107
|
+
- AGENT_ID=c1e2f3a4-5678-90ab-cdef-1234567890ab
|
|
108
|
+
- AGENT_ROLE=worker
|
|
111
109
|
|
|
112
|
-
- MCP_BASE_URL=${MCP_BASE_URL:-http://api:3013}
|
|
110
|
+
# - MCP_BASE_URL=${MCP_BASE_URL:-http://api:3013}
|
|
111
|
+
# If in the same Docker network, use the service name
|
|
112
|
+
- MCP_BASE_URL=http://api:3013
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
- YOLO=true
|
|
115
|
+
- GITHUB_TOKEN=${GITHUB_TOKEN:-}
|
|
116
|
+
- GITHUB_EMAIL=${GITHUB_EMAIL:-}
|
|
117
|
+
- GITHUB_NAME=${GITHUB_NAME:-}
|
|
118
|
+
- SWARM_URL=${SWARM_URL:-localhost}
|
|
115
119
|
|
|
116
120
|
ports:
|
|
117
|
-
|
|
118
|
-
- "${SERVICE_PORT:-3003}:3000"
|
|
121
|
+
- "${SERVICE_PORT:-3022}:3000"
|
|
119
122
|
|
|
120
123
|
volumes:
|
|
121
124
|
- swarm_logs:/logs
|
|
122
125
|
- swarm_shared:/workspace/shared
|
|
123
|
-
-
|
|
126
|
+
- swarm_worker_2:/workspace/personal
|
|
124
127
|
|
|
125
128
|
restart: unless-stopped
|
|
126
129
|
|
|
@@ -131,7 +134,3 @@ volumes:
|
|
|
131
134
|
swarm_lead:
|
|
132
135
|
swarm_worker_1:
|
|
133
136
|
swarm_worker_2:
|
|
134
|
-
|
|
135
|
-
networks:
|
|
136
|
-
default:
|
|
137
|
-
driver: bridge
|
package/docker-entrypoint.sh
CHANGED
|
@@ -16,6 +16,9 @@ fi
|
|
|
16
16
|
ROLE="${AGENT_ROLE:-worker}"
|
|
17
17
|
MCP_URL="${MCP_BASE_URL:-http://host.docker.internal:3013}"
|
|
18
18
|
|
|
19
|
+
# Get version from compiled binary (extract just the version number)
|
|
20
|
+
VERSION=$(/usr/local/bin/agent-swarm version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' || echo "unknown")
|
|
21
|
+
|
|
19
22
|
# Determine YOLO mode based on role
|
|
20
23
|
if [ "$ROLE" = "lead" ]; then
|
|
21
24
|
YOLO_MODE="${LEAD_YOLO:-false}"
|
|
@@ -23,7 +26,7 @@ else
|
|
|
23
26
|
YOLO_MODE="${WORKER_YOLO:-false}"
|
|
24
27
|
fi
|
|
25
28
|
|
|
26
|
-
echo "=== Agent Swarm ${ROLE^} ==="
|
|
29
|
+
echo "=== Agent Swarm ${ROLE^} v${VERSION} ==="
|
|
27
30
|
echo "Agent ID: ${AGENT_ID:-<not set>}"
|
|
28
31
|
echo "MCP Base URL: $MCP_URL"
|
|
29
32
|
echo "YOLO Mode: $YOLO_MODE"
|
package/package.json
CHANGED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Review a task that has been offered to you and decide whether to accept or reject it
|
|
3
|
+
argument-hint: [taskId]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Review Offered Task
|
|
7
|
+
|
|
8
|
+
You have been offered a task. Your job is to review it and decide whether to accept or reject it based on your capabilities and current workload.
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
|
|
12
|
+
1. **Get task details**: Call the `get-task-details` tool with the provided `taskId` to understand what the task involves.
|
|
13
|
+
|
|
14
|
+
2. **Evaluate the task**: Consider:
|
|
15
|
+
- Does this task match your capabilities?
|
|
16
|
+
- Do you have the necessary context or access to complete it?
|
|
17
|
+
- Is the task description clear enough to proceed?
|
|
18
|
+
|
|
19
|
+
3. **Make a decision**:
|
|
20
|
+
- **Accept**: If you can complete this task, call `task-action` with `action: "accept"` and `taskId: "<taskId>"`. Then immediately use `/work-on-task <taskId>` to start working on it.
|
|
21
|
+
- **Reject**: If you cannot complete this task, call `task-action` with `action: "reject"`, `taskId: "<taskId>"`, and provide a `reason` explaining why you're rejecting it (e.g., "Task requires Python expertise which I don't have", "Task description is too vague").
|
|
22
|
+
|
|
23
|
+
## Example Accept Flow
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
1. get-task-details taskId="abc-123"
|
|
27
|
+
2. [Review the task details]
|
|
28
|
+
3. task-action action="accept" taskId="abc-123"
|
|
29
|
+
4. /work-on-task abc-123
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Example Reject Flow
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
1. get-task-details taskId="abc-123"
|
|
36
|
+
2. [Review the task details]
|
|
37
|
+
3. task-action action="reject" taskId="abc-123" reason="Task requires access to production database which I don't have"
|
|
38
|
+
4. Reply "DONE" to end the session
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Important Notes
|
|
42
|
+
|
|
43
|
+
- Always provide a clear reason when rejecting a task - this helps the lead agent reassign it appropriately
|
|
44
|
+
- If you accept, you must immediately start working on the task using `/work-on-task`
|
|
45
|
+
- If you reject, the task returns to the unassigned pool for reassignment
|
|
@@ -89,13 +89,15 @@ When you assign tasks to workers, they might need to let them know to use some o
|
|
|
89
89
|
- `/create-plan` - Useful command for workers to create a detailed plan for how they will approach and complete the task. Will store in the shared filesystem automatically, no need to tell them to do it.
|
|
90
90
|
- `/implement-plan` - Useful command for workers to implement the plan they created for the task. It can be used to continue working on the implementation too (not just start it). Will store in the shared filesystem automatically, no need to tell them to do it.
|
|
91
91
|
|
|
92
|
-
## Communication Etiquette
|
|
93
|
-
|
|
94
|
-
- You should ALWAYS follow-up to the user messages using the `/swarm-chat` command. You should also use it to communicate with workers when needed.
|
|
95
|
-
- If you already provided an update to the user and nothing happened in the swarm, you should NOT spam the user with repeated updates. Only provide updates when something relevant happens.
|
|
96
|
-
|
|
97
92
|
## Filesystem
|
|
98
93
|
|
|
99
94
|
You will have your own persisted directory at `/workspace/personal`. Use it to store any files you need to keep between sessions.
|
|
100
95
|
|
|
101
96
|
If you want to share files with workers, use the shared `/workspace/shared` directory, which all agents in the swarm can access. The same way, workers can share files with you there. Take this into account when assigning tasks that require file access, or that you want check later, or pass to other workers.
|
|
97
|
+
|
|
98
|
+
## Communication Etiquette
|
|
99
|
+
|
|
100
|
+
- ONLY follow-up if there are relevant updates (check history to avoid spamming), or if stated by the user (human). If not, avoid unnecessary messages.
|
|
101
|
+
- When communicating, ALWAYS use the `/swarm-chat` command. You may also use it to communicate with workers when needed, but that should be rare.
|
|
102
|
+
- If you already provided an update to the user and nothing happened in the swarm, you should NOT SPAM the user with repeated updates (e.g. do not send messages like "Ready to lead"). Only provide meaningful updates when something relevant happens.
|
|
103
|
+
|
|
@@ -54,3 +54,8 @@ To do so, use the `agent-swarm` MCP server and call the `join-swarm` with a name
|
|
|
54
54
|
You will have your own persisted directory at `/workspace/personal`. Use it to store any files you need to keep between sessions.
|
|
55
55
|
|
|
56
56
|
If you want to share files with workers and the lead, use the shared `/workspace/shared` directory, which all agents in the swarm can access. Make sure to use it if the task requires sharing files.
|
|
57
|
+
|
|
58
|
+
## Communication Etiquette
|
|
59
|
+
|
|
60
|
+
- ONLY follow-up if clearly stated by the user or the lead. Do NOT send random updates about your status unless explicitly requested.
|
|
61
|
+
- When communicating, ALWAYS use the `/swarm-chat` command.
|
package/src/cli.tsx
CHANGED
|
@@ -33,6 +33,7 @@ interface ParsedArgs {
|
|
|
33
33
|
systemPrompt: string;
|
|
34
34
|
systemPromptFile: string;
|
|
35
35
|
additionalArgs: string[];
|
|
36
|
+
aiLoop: boolean;
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
function parseArgs(args: string[]): ParsedArgs {
|
|
@@ -48,6 +49,7 @@ function parseArgs(args: string[]): ParsedArgs {
|
|
|
48
49
|
let systemPrompt = "";
|
|
49
50
|
let systemPromptFile = "";
|
|
50
51
|
let additionalArgs: string[] = [];
|
|
52
|
+
let aiLoop = false;
|
|
51
53
|
|
|
52
54
|
// Find if there's a "--" separator for additional args
|
|
53
55
|
const separatorIndex = args.indexOf("--");
|
|
@@ -81,6 +83,8 @@ function parseArgs(args: string[]): ParsedArgs {
|
|
|
81
83
|
} else if (arg === "--system-prompt-file") {
|
|
82
84
|
systemPromptFile = mainArgs[i + 1] || systemPromptFile;
|
|
83
85
|
i++;
|
|
86
|
+
} else if (arg === "--ai-loop") {
|
|
87
|
+
aiLoop = true;
|
|
84
88
|
}
|
|
85
89
|
}
|
|
86
90
|
|
|
@@ -97,6 +101,7 @@ function parseArgs(args: string[]): ParsedArgs {
|
|
|
97
101
|
systemPrompt,
|
|
98
102
|
systemPromptFile,
|
|
99
103
|
additionalArgs,
|
|
104
|
+
aiLoop,
|
|
100
105
|
};
|
|
101
106
|
}
|
|
102
107
|
|
|
@@ -266,6 +271,12 @@ function Help() {
|
|
|
266
271
|
</Box>
|
|
267
272
|
<Text>Read system prompt from file</Text>
|
|
268
273
|
</Box>
|
|
274
|
+
<Box>
|
|
275
|
+
<Box width={30}>
|
|
276
|
+
<Text color="yellow">--ai-loop</Text>
|
|
277
|
+
</Box>
|
|
278
|
+
<Text>Use AI-based polling (legacy mode)</Text>
|
|
279
|
+
</Box>
|
|
269
280
|
<Box>
|
|
270
281
|
<Box width={30}>
|
|
271
282
|
<Text color="yellow">-- {"<args...>"}</Text>
|
|
@@ -352,6 +363,12 @@ function Help() {
|
|
|
352
363
|
</Box>
|
|
353
364
|
<Text>Path to system prompt file</Text>
|
|
354
365
|
</Box>
|
|
366
|
+
<Box>
|
|
367
|
+
<Box width={32}>
|
|
368
|
+
<Text color="magenta">AI_LOOP</Text>
|
|
369
|
+
</Box>
|
|
370
|
+
<Text>If "true", use AI-based polling</Text>
|
|
371
|
+
</Box>
|
|
355
372
|
</Box>
|
|
356
373
|
</Box>
|
|
357
374
|
);
|
|
@@ -435,6 +452,7 @@ interface RunnerProps {
|
|
|
435
452
|
systemPrompt: string;
|
|
436
453
|
systemPromptFile: string;
|
|
437
454
|
additionalArgs: string[];
|
|
455
|
+
aiLoop: boolean;
|
|
438
456
|
}
|
|
439
457
|
|
|
440
458
|
function WorkerRunner({
|
|
@@ -443,6 +461,7 @@ function WorkerRunner({
|
|
|
443
461
|
systemPrompt,
|
|
444
462
|
systemPromptFile,
|
|
445
463
|
additionalArgs,
|
|
464
|
+
aiLoop,
|
|
446
465
|
}: RunnerProps) {
|
|
447
466
|
const { exit } = useApp();
|
|
448
467
|
|
|
@@ -453,14 +472,26 @@ function WorkerRunner({
|
|
|
453
472
|
systemPrompt: systemPrompt || undefined,
|
|
454
473
|
systemPromptFile: systemPromptFile || undefined,
|
|
455
474
|
additionalArgs,
|
|
456
|
-
|
|
475
|
+
logsDir: "./logs",
|
|
476
|
+
aiLoop,
|
|
477
|
+
}).catch((err) => {
|
|
478
|
+
console.error("[error] Worker encountered an error:", err);
|
|
479
|
+
exit(err);
|
|
480
|
+
});
|
|
457
481
|
// Note: runWorker runs indefinitely, so we don't call exit() on success
|
|
458
|
-
}, [prompt, yolo, systemPrompt, systemPromptFile, additionalArgs, exit]);
|
|
482
|
+
}, [prompt, yolo, systemPrompt, systemPromptFile, additionalArgs, aiLoop, exit]);
|
|
459
483
|
|
|
460
484
|
return null;
|
|
461
485
|
}
|
|
462
486
|
|
|
463
|
-
function LeadRunner({
|
|
487
|
+
function LeadRunner({
|
|
488
|
+
prompt,
|
|
489
|
+
yolo,
|
|
490
|
+
systemPrompt,
|
|
491
|
+
systemPromptFile,
|
|
492
|
+
additionalArgs,
|
|
493
|
+
aiLoop,
|
|
494
|
+
}: RunnerProps) {
|
|
464
495
|
const { exit } = useApp();
|
|
465
496
|
|
|
466
497
|
useEffect(() => {
|
|
@@ -470,9 +501,14 @@ function LeadRunner({ prompt, yolo, systemPrompt, systemPromptFile, additionalAr
|
|
|
470
501
|
systemPrompt: systemPrompt || undefined,
|
|
471
502
|
systemPromptFile: systemPromptFile || undefined,
|
|
472
503
|
additionalArgs,
|
|
473
|
-
|
|
504
|
+
logsDir: "./logs",
|
|
505
|
+
aiLoop,
|
|
506
|
+
}).catch((err) => {
|
|
507
|
+
console.error("[error] Lead encountered an error:", err);
|
|
508
|
+
exit(err);
|
|
509
|
+
});
|
|
474
510
|
// Note: runLead runs indefinitely, so we don't call exit() on success
|
|
475
|
-
}, [prompt, yolo, systemPrompt, systemPromptFile, additionalArgs, exit]);
|
|
511
|
+
}, [prompt, yolo, systemPrompt, systemPromptFile, additionalArgs, aiLoop, exit]);
|
|
476
512
|
|
|
477
513
|
return null;
|
|
478
514
|
}
|
|
@@ -520,6 +556,7 @@ function App({ args }: { args: ParsedArgs }) {
|
|
|
520
556
|
systemPrompt,
|
|
521
557
|
systemPromptFile,
|
|
522
558
|
additionalArgs,
|
|
559
|
+
aiLoop,
|
|
523
560
|
} = args;
|
|
524
561
|
|
|
525
562
|
switch (command) {
|
|
@@ -537,6 +574,7 @@ function App({ args }: { args: ParsedArgs }) {
|
|
|
537
574
|
systemPrompt={systemPrompt}
|
|
538
575
|
systemPromptFile={systemPromptFile}
|
|
539
576
|
additionalArgs={additionalArgs}
|
|
577
|
+
aiLoop={aiLoop}
|
|
540
578
|
/>
|
|
541
579
|
);
|
|
542
580
|
case "lead":
|
|
@@ -547,6 +585,7 @@ function App({ args }: { args: ParsedArgs }) {
|
|
|
547
585
|
systemPrompt={systemPrompt}
|
|
548
586
|
systemPromptFile={systemPromptFile}
|
|
549
587
|
additionalArgs={additionalArgs}
|
|
588
|
+
aiLoop={aiLoop}
|
|
550
589
|
/>
|
|
551
590
|
);
|
|
552
591
|
case "version":
|
package/src/commands/lead.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getEnabledCapabilities } from "@/server.ts";
|
|
1
2
|
import { type RunnerConfig, type RunnerOptions, runAgent } from "./runner.ts";
|
|
2
3
|
|
|
3
4
|
export type LeadOptions = RunnerOptions;
|
|
@@ -6,6 +7,7 @@ const leadConfig: RunnerConfig = {
|
|
|
6
7
|
role: "lead",
|
|
7
8
|
defaultPrompt: "/start-leader",
|
|
8
9
|
metadataType: "lead_metadata",
|
|
10
|
+
capabilities: getEnabledCapabilities(),
|
|
9
11
|
};
|
|
10
12
|
|
|
11
13
|
export async function runLead(opts: LeadOptions) {
|