@desplega.ai/agent-swarm 1.84.1 → 1.86.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 +1 -0
- package/openapi.json +1 -1
- package/package.json +8 -6
- package/src/be/db-queries/oauth.ts +33 -0
- package/src/be/db.ts +51 -1
- package/src/be/migrations/077_oauth_refresh_locks.sql +8 -0
- package/src/be/migrations/078_backfill_gpt_5_5_pricing.sql +15 -0
- package/src/be/modelsdev-cache.json +152028 -0
- package/src/be/modelsdev-cache.ts +46 -0
- package/src/be/seed-pricing.ts +7 -44
- package/src/cli.tsx +12 -2
- package/src/commands/codex-session-runner.ts +132 -0
- package/src/commands/credential-wait.ts +2 -2
- package/src/commands/provider-credentials.ts +10 -5
- package/src/commands/runner.ts +62 -9
- package/src/http/index.ts +11 -3
- package/src/http/tasks.ts +17 -0
- package/src/http/utils.ts +17 -0
- package/src/oauth/ensure-token.ts +97 -11
- package/src/prompts/base-prompt.ts +49 -3
- package/src/providers/claude-adapter.ts +83 -2
- package/src/providers/claude-managed-models.ts +18 -2
- package/src/providers/codex-adapter.ts +417 -97
- package/src/providers/codex-models.ts +9 -2
- package/src/providers/index.ts +28 -19
- package/src/providers/pi-mono-adapter.ts +44 -25
- package/src/providers/pricing-sources.md +7 -4
- package/src/providers/swarm-events-shared.ts +14 -0
- package/src/server.ts +2 -0
- package/src/slack/HEURISTICS.md +5 -1
- package/src/slack/handlers.test.ts +35 -0
- package/src/slack/handlers.ts +79 -2
- package/src/tasks/worker-follow-up.ts +82 -0
- package/src/tests/agents-list-model-display.test.ts +13 -1
- package/src/tests/base-prompt.test.ts +46 -8
- package/src/tests/claude-managed-adapter.test.ts +4 -4
- package/src/tests/codex-adapter-otel.test.ts +4 -4
- package/src/tests/codex-adapter.test.ts +20 -7
- package/src/tests/codex-swarm-events.test.ts +35 -0
- package/src/tests/context-window.test.ts +1 -0
- package/src/tests/credential-check.test.ts +48 -29
- package/src/tests/db-queries-oauth.test.ts +27 -0
- package/src/tests/ensure-token.test.ts +71 -0
- package/src/tests/entrypoint-config-env-export.test.ts +81 -0
- package/src/tests/follow-up-redelivery-guard.test.ts +165 -0
- package/src/tests/http-log-scrubbing.test.ts +24 -0
- package/src/tests/list-endpoint-slimming.test.ts +22 -1
- package/src/tests/migration-046-budgets.test.ts +6 -5
- package/src/tests/oauth-access-token-tool.test.ts +138 -0
- package/src/tests/pi-mono-adapter.test.ts +37 -1
- package/src/tests/pricing-routes.test.ts +6 -5
- package/src/tests/provider-adapter.test.ts +10 -10
- package/src/tests/provider-command-format.test.ts +4 -4
- package/src/tests/runner-fallback-output.test.ts +118 -39
- package/src/tests/session-costs-codex-recompute.test.ts +25 -0
- package/src/tests/task-completion-idempotency.test.ts +89 -0
- package/src/tools/oauth-access-token.ts +118 -0
- package/src/tools/send-task.ts +30 -9
- package/src/tools/store-progress.ts +12 -77
- package/src/tools/tool-config.ts +2 -1
- package/src/types.ts +5 -0
- package/src/utils/context-window.ts +1 -0
- package/src/utils/secret-scrubber.ts +23 -0
- package/templates/schedules/daily-blocker-digest/config.json +13 -0
- package/templates/schedules/daily-blocker-digest/content.md +150 -0
- package/templates/schedules/daily-compounding-reflection/config.json +21 -0
- package/templates/schedules/daily-compounding-reflection/content.md +210 -0
- package/templates/schedules/daily-hn-briefing/config.json +13 -0
- package/templates/schedules/daily-hn-briefing/content.md +97 -0
- package/templates/schedules/daily-workflow-health-audit/config.json +13 -0
- package/templates/schedules/daily-workflow-health-audit/content.md +189 -0
- package/templates/schedules/gtm-weekly-review/config.json +13 -0
- package/templates/schedules/gtm-weekly-review/content.md +58 -0
- package/templates/schedules/weekly-dependabot-triage/config.json +13 -0
- package/templates/schedules/weekly-dependabot-triage/content.md +45 -0
- package/templates/schema.ts +26 -0
- package/templates/skills/agentmail-sending/config.json +13 -0
- package/templates/skills/agentmail-sending/content.md +48 -0
- package/templates/skills/artifacts/config.json +13 -0
- package/templates/skills/artifacts/content.md +87 -0
- package/templates/skills/browser-use-cloud/config.json +13 -0
- package/templates/skills/browser-use-cloud/content.md +155 -0
- package/templates/skills/desloppify/config.json +13 -0
- package/templates/skills/desloppify/content.md +201 -0
- package/templates/skills/exa-search/config.json +13 -0
- package/templates/skills/exa-search/content.md +106 -0
- package/templates/skills/jira-interaction/config.json +13 -0
- package/templates/skills/jira-interaction/content.md +252 -0
- package/templates/skills/kapso-whatsapp/config.json +13 -0
- package/templates/skills/kapso-whatsapp/content.md +369 -0
- package/templates/skills/kv-storage/config.json +13 -0
- package/templates/skills/kv-storage/content.md +111 -0
- package/templates/skills/linear-interaction/config.json +20 -0
- package/templates/skills/linear-interaction/content.md +230 -0
- package/templates/skills/pages/config.json +18 -0
- package/templates/skills/pages/content.md +85 -0
- package/templates/skills/profile-corruption-escalation/config.json +13 -0
- package/templates/skills/profile-corruption-escalation/content.md +105 -0
- package/templates/skills/scheduled-task-resilience/config.json +13 -0
- package/templates/skills/scheduled-task-resilience/content.md +95 -0
- package/templates/skills/sprite-cli/config.json +13 -0
- package/templates/skills/sprite-cli/content.md +133 -0
- package/templates/skills/turso-interaction/config.json +13 -0
- package/templates/skills/turso-interaction/content.md +192 -0
- package/templates/skills/workflow-iterate/config.json +18 -0
- package/templates/skills/workflow-iterate/content.md +399 -0
- package/templates/skills/workflow-structured-output/config.json +13 -0
- package/templates/skills/workflow-structured-output/content.md +101 -0
- package/templates/skills/x-api-interactions/config.json +13 -0
- package/templates/skills/x-api-interactions/content.md +109 -0
- package/templates/workflows/autopilot/config.json +13 -0
- package/templates/workflows/autopilot/content.md +58 -0
- package/templates/workflows/linear-drain-loop/config.json +21 -0
- package/templates/workflows/linear-drain-loop/content.md +72 -0
- package/templates/workflows/ralph-loop/config.json +13 -0
- package/templates/workflows/ralph-loop/content.md +75 -0
package/README.md
CHANGED
|
@@ -124,6 +124,7 @@ Check [our templates](https://templates.agent-swarm.dev) for a quick start.
|
|
|
124
124
|
- **Workflow engine with Human-in-the-Loop** — DAG-based automation with approval gates, retries, and structured I/O. [Workflows →](https://docs.agent-swarm.dev/docs/concepts/workflows)
|
|
125
125
|
- **Scheduled & recurring tasks** — cron-based automation for standing work. [Scheduling →](https://docs.agent-swarm.dev/docs/concepts/scheduling)
|
|
126
126
|
- **Harness & LLM agnostic** — run with Claude Code, OpenAI Codex, pi-mono, Devin, Claude Managed Agents, raw LLMs, or opencode. [Harness config →](https://docs.agent-swarm.dev/docs/guides/harness-configuration) · [Add a new provider →](https://docs.agent-swarm.dev/docs/guides/harness-providers)
|
|
127
|
+
- **Follow-up continuity across all harnesses** — child tasks inherit bounded prior-task context even on providers without native session resume, while resumable providers still reuse prior sessions when possible. [Task lifecycle →](https://docs.agent-swarm.dev/docs/concepts/task-lifecycle)
|
|
127
128
|
- **Skills & MCP servers** — reusable procedural knowledge and per-agent MCP servers with scope cascade. [MCP tools →](https://docs.agent-swarm.dev/docs/reference/mcp-tools)
|
|
128
129
|
- **DB-backed pages** — agents publish HTML or JSON pages (reports, dashboards, action specs) via the `create_page` MCP tool with public / authed / password modes, version history, view counters, diff helpers, and PDF export. [MCP tools → Pages](https://docs.agent-swarm.dev/docs/reference/mcp-tools#pages-tools)
|
|
129
130
|
- **KV store** — Redis-like namespaced key/value store with auto-scoped context (Slack thread / PR / Linear issue / page). [MCP tools → KV](https://docs.agent-swarm.dev/docs/reference/mcp-tools#kv-tools)
|
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.86.0",
|
|
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": [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@desplega.ai/agent-swarm",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.86.0",
|
|
4
4
|
"description": "Multi-agent orchestration for Claude Code, Codex, Gemini CLI, and other AI coding assistants",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "desplega.sh <contact@desplega.sh>",
|
|
@@ -45,6 +45,8 @@
|
|
|
45
45
|
"tsc:check": "bun tsc --noEmit",
|
|
46
46
|
"check:db-boundary": "bash scripts/check-db-boundary.sh",
|
|
47
47
|
"check:api-key-boundary": "bash scripts/check-api-key-boundary.sh",
|
|
48
|
+
"sync-chart-version": "bun scripts/sync-chart-version.ts",
|
|
49
|
+
"check-chart-version": "bun scripts/sync-chart-version.ts --check-if-package-version-changed",
|
|
48
50
|
"cli": "bun src/cli.tsx",
|
|
49
51
|
"hook": "bun src/hooks/hook.ts",
|
|
50
52
|
"claude": "bun src/cli.tsx claude",
|
|
@@ -108,12 +110,12 @@
|
|
|
108
110
|
"@desplega.ai/localtunnel": "^2.2.0",
|
|
109
111
|
"@inkjs/ui": "^2.0.0",
|
|
110
112
|
"@linear/sdk": "^77.0.0",
|
|
111
|
-
"@earendil-works/pi-agent-core": "^0.
|
|
112
|
-
"@earendil-works/pi-ai": "^0.
|
|
113
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
113
|
+
"@earendil-works/pi-agent-core": "^0.76.0",
|
|
114
|
+
"@earendil-works/pi-ai": "^0.76.0",
|
|
115
|
+
"@earendil-works/pi-coding-agent": "^0.76.0",
|
|
114
116
|
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
115
|
-
"@openai/codex-sdk": "^0.
|
|
116
|
-
"@opencode-ai/sdk": "^1.15.
|
|
117
|
+
"@openai/codex-sdk": "^0.135.0",
|
|
118
|
+
"@opencode-ai/sdk": "^1.15.12",
|
|
117
119
|
"@openfort/openfort-node": "^0.9.1",
|
|
118
120
|
"@opentelemetry/api": "^1.9.1",
|
|
119
121
|
"@opentelemetry/exporter-trace-otlp-http": "^0.218.0",
|
|
@@ -180,3 +180,36 @@ export function isTokenExpiringSoon(provider: string, bufferMs = 5 * 60 * 1000):
|
|
|
180
180
|
const expiresAt = new Date(tokens.expiresAt).getTime();
|
|
181
181
|
return expiresAt - Date.now() < bufferMs;
|
|
182
182
|
}
|
|
183
|
+
|
|
184
|
+
// ── OAuth Refresh Locks ──
|
|
185
|
+
|
|
186
|
+
export function acquireOAuthRefreshLock(provider: string, ttlMs: number): string | null {
|
|
187
|
+
const owner = crypto.randomUUID();
|
|
188
|
+
const now = Date.now();
|
|
189
|
+
const expiresAt = new Date(now + ttlMs).toISOString();
|
|
190
|
+
const nowIso = new Date(now).toISOString();
|
|
191
|
+
|
|
192
|
+
getDb()
|
|
193
|
+
.query(
|
|
194
|
+
`INSERT INTO oauth_refresh_locks (provider, owner, expiresAt, createdAt, updatedAt)
|
|
195
|
+
VALUES (?, ?, ?, ?, ?)
|
|
196
|
+
ON CONFLICT(provider) DO UPDATE SET
|
|
197
|
+
owner = excluded.owner,
|
|
198
|
+
expiresAt = excluded.expiresAt,
|
|
199
|
+
updatedAt = excluded.updatedAt
|
|
200
|
+
WHERE oauth_refresh_locks.expiresAt <= ?`,
|
|
201
|
+
)
|
|
202
|
+
.run(provider, owner, expiresAt, nowIso, nowIso, nowIso);
|
|
203
|
+
|
|
204
|
+
const row = getDb()
|
|
205
|
+
.query("SELECT owner FROM oauth_refresh_locks WHERE provider = ?")
|
|
206
|
+
.get(provider) as { owner: string } | null;
|
|
207
|
+
|
|
208
|
+
return row?.owner === owner ? owner : null;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function releaseOAuthRefreshLock(provider: string, owner: string): void {
|
|
212
|
+
getDb()
|
|
213
|
+
.query("DELETE FROM oauth_refresh_locks WHERE provider = ? AND owner = ?")
|
|
214
|
+
.run(provider, owner);
|
|
215
|
+
}
|
package/src/be/db.ts
CHANGED
|
@@ -1012,6 +1012,7 @@ type AgentTaskRow = {
|
|
|
1012
1012
|
swarmVersion: string | null;
|
|
1013
1013
|
provider: string | null;
|
|
1014
1014
|
providerMeta: string | null;
|
|
1015
|
+
totalCostUsd?: number | null;
|
|
1015
1016
|
};
|
|
1016
1017
|
|
|
1017
1018
|
function rowToAgentTask(row: AgentTaskRow): AgentTask {
|
|
@@ -1075,6 +1076,7 @@ function rowToAgentTask(row: AgentTaskRow): AgentTask {
|
|
|
1075
1076
|
swarmVersion: row.swarmVersion ?? undefined,
|
|
1076
1077
|
provider: (row.provider as ProviderName | null) ?? undefined,
|
|
1077
1078
|
providerMeta: parseProviderMeta(row.provider as ProviderName | null, row.providerMeta),
|
|
1079
|
+
totalCostUsd: row.totalCostUsd ?? undefined,
|
|
1078
1080
|
};
|
|
1079
1081
|
}
|
|
1080
1082
|
|
|
@@ -1110,6 +1112,7 @@ function rowToAgentTaskSummary(row: AgentTaskRow): AgentTaskSummary {
|
|
|
1110
1112
|
lastUpdatedAt: t.lastUpdatedAt,
|
|
1111
1113
|
finishedAt: t.finishedAt,
|
|
1112
1114
|
peakContextPercent: t.peakContextPercent,
|
|
1115
|
+
totalCostUsd: t.totalCostUsd,
|
|
1113
1116
|
};
|
|
1114
1117
|
}
|
|
1115
1118
|
|
|
@@ -1504,7 +1507,10 @@ export function getAllTasks(
|
|
|
1504
1507
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1505
1508
|
const limit = filters?.limit ?? 25;
|
|
1506
1509
|
const offset = filters?.offset ?? 0;
|
|
1507
|
-
const query = `SELECT
|
|
1510
|
+
const query = `SELECT agent_tasks.*,
|
|
1511
|
+
(SELECT SUM(totalCostUsd) FROM session_costs WHERE session_costs.taskId = agent_tasks.id) AS totalCostUsd
|
|
1512
|
+
FROM agent_tasks ${whereClause}
|
|
1513
|
+
ORDER BY lastUpdatedAt DESC, priority DESC LIMIT ${limit} OFFSET ${offset}`;
|
|
1508
1514
|
|
|
1509
1515
|
const rows = getDb()
|
|
1510
1516
|
.prepare<AgentTaskRow, (string | AgentTaskStatus)[]>(query)
|
|
@@ -1869,6 +1875,50 @@ export function findCompletedTaskInThread(
|
|
|
1869
1875
|
return row ? rowToAgentTask(row) : null;
|
|
1870
1876
|
}
|
|
1871
1877
|
|
|
1878
|
+
/**
|
|
1879
|
+
* Find the most recent CANCELLED task in a Slack thread. Used by the
|
|
1880
|
+
* follow-up re-delegation guard so a cancellation (worker SIGTERM,
|
|
1881
|
+
* runner-side abort, swarm-events tool-loop abort) doesn't permanently
|
|
1882
|
+
* jam re-dispatch when an earlier sibling task in the same thread also
|
|
1883
|
+
* completed.
|
|
1884
|
+
*
|
|
1885
|
+
* Matches both:
|
|
1886
|
+
* - `status = 'cancelled'` (the canonical terminal state from cancelTask)
|
|
1887
|
+
* - `status = 'failed'` with a failureReason that starts with "cancelled"
|
|
1888
|
+
* or "exit 130" or contains "cancelled" (the codex-adapter abort path
|
|
1889
|
+
* emits `failureReason: "cancelled"` and exits 130).
|
|
1890
|
+
*/
|
|
1891
|
+
export function findRecentCancelledTaskInThread(
|
|
1892
|
+
channelId: string,
|
|
1893
|
+
threadTs: string,
|
|
1894
|
+
windowMinutes: number,
|
|
1895
|
+
): AgentTask | null {
|
|
1896
|
+
const since = new Date(Date.now() - windowMinutes * 60 * 1000).toISOString();
|
|
1897
|
+
const row = getDb()
|
|
1898
|
+
.prepare<AgentTaskRow, [string, string, string]>(
|
|
1899
|
+
`SELECT * FROM agent_tasks
|
|
1900
|
+
WHERE slackChannelId = ?
|
|
1901
|
+
AND slackThreadTs = ?
|
|
1902
|
+
AND lastUpdatedAt > ?
|
|
1903
|
+
AND (
|
|
1904
|
+
status = 'cancelled'
|
|
1905
|
+
OR (
|
|
1906
|
+
status = 'failed'
|
|
1907
|
+
AND failureReason IS NOT NULL
|
|
1908
|
+
AND (
|
|
1909
|
+
failureReason LIKE 'cancelled%'
|
|
1910
|
+
OR failureReason LIKE 'exit 130%'
|
|
1911
|
+
OR failureReason LIKE '%cancelled%'
|
|
1912
|
+
)
|
|
1913
|
+
)
|
|
1914
|
+
)
|
|
1915
|
+
ORDER BY lastUpdatedAt DESC
|
|
1916
|
+
LIMIT 1`,
|
|
1917
|
+
)
|
|
1918
|
+
.get(channelId, threadTs, since);
|
|
1919
|
+
return row ? rowToAgentTask(row) : null;
|
|
1920
|
+
}
|
|
1921
|
+
|
|
1872
1922
|
export function completeTask(id: string, output?: string): AgentTask | null {
|
|
1873
1923
|
const oldTask = getTaskById(id);
|
|
1874
1924
|
if (!oldTask) return null;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
-- Cross-process mutex for OAuth refresh-token rotation.
|
|
2
|
+
CREATE TABLE IF NOT EXISTS oauth_refresh_locks (
|
|
3
|
+
provider TEXT PRIMARY KEY,
|
|
4
|
+
owner TEXT NOT NULL,
|
|
5
|
+
expiresAt TEXT NOT NULL,
|
|
6
|
+
createdAt TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
7
|
+
updatedAt TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
8
|
+
);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
-- 078_backfill_gpt_5_5_pricing.sql
|
|
2
|
+
-- Backfill Codex GPT-5.5 pricing into existing databases.
|
|
3
|
+
--
|
|
4
|
+
-- The vendored models.dev cache already contains gpt-5.5, and fresh server
|
|
5
|
+
-- boots seed it from src/be/seed-pricing.ts. Existing long-lived DBs can still
|
|
6
|
+
-- be missing those rows, which makes real gpt-5.5 Codex runs land as
|
|
7
|
+
-- costSource='unpriced'. Keep this migration idempotent so every environment
|
|
8
|
+
-- gets the baseline Standard-tier rates.
|
|
9
|
+
|
|
10
|
+
INSERT OR IGNORE INTO pricing
|
|
11
|
+
(provider, model, token_class, effective_from, price_per_million_usd, createdAt, lastUpdatedAt)
|
|
12
|
+
VALUES
|
|
13
|
+
('codex', 'gpt-5.5', 'input', 0, 5.0, 0, 0),
|
|
14
|
+
('codex', 'gpt-5.5', 'cached_input', 0, 0.5, 0, 0),
|
|
15
|
+
('codex', 'gpt-5.5', 'output', 0, 30.0, 0, 0);
|