@desplega.ai/agent-swarm 1.71.2 → 1.72.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 +3 -2
- package/openapi.json +994 -62
- package/package.json +2 -1
- package/src/be/budget-admission.ts +121 -0
- package/src/be/budget-refusal-notify.ts +145 -0
- package/src/be/db.ts +488 -5
- package/src/be/migrations/044_provider_meta.sql +2 -0
- package/src/be/migrations/046_budgets_and_pricing.sql +87 -0
- package/src/be/migrations/047_session_costs_cost_source.sql +16 -0
- package/src/cli.tsx +22 -1
- package/src/commands/claude-managed-setup.ts +687 -0
- package/src/commands/codex-login.ts +1 -1
- package/src/commands/runner.ts +175 -28
- package/src/commands/templates.ts +10 -6
- package/src/http/budgets.ts +219 -0
- package/src/http/index.ts +6 -0
- package/src/http/integrations.ts +134 -0
- package/src/http/poll.ts +161 -3
- package/src/http/pricing.ts +245 -0
- package/src/http/session-data.ts +54 -6
- package/src/http/tasks.ts +23 -2
- package/src/prompts/base-prompt.ts +103 -73
- package/src/prompts/session-templates.ts +43 -0
- package/src/providers/claude-adapter.ts +3 -1
- package/src/providers/claude-managed-adapter.ts +871 -0
- package/src/providers/claude-managed-models.ts +117 -0
- package/src/providers/claude-managed-swarm-events.ts +77 -0
- package/src/providers/codex-adapter.ts +3 -1
- package/src/providers/codex-skill-resolver.ts +10 -0
- package/src/providers/codex-swarm-events.ts +20 -161
- package/src/providers/devin-adapter.ts +894 -0
- package/src/providers/devin-api.ts +207 -0
- package/src/providers/devin-playbooks.ts +91 -0
- package/src/providers/devin-skill-resolver.ts +113 -0
- package/src/providers/index.ts +10 -1
- package/src/providers/pi-mono-adapter.ts +3 -1
- package/src/providers/swarm-events-shared.ts +262 -0
- package/src/providers/types.ts +26 -1
- package/src/tests/base-prompt.test.ts +199 -0
- package/src/tests/budget-admission.test.ts +339 -0
- package/src/tests/budget-claim-gate.test.ts +288 -0
- package/src/tests/budget-refusal-notification.test.ts +324 -0
- package/src/tests/budgets-routes.test.ts +331 -0
- package/src/tests/claude-managed-adapter.test.ts +1301 -0
- package/src/tests/claude-managed-setup.test.ts +325 -0
- package/src/tests/devin-adapter.test.ts +677 -0
- package/src/tests/devin-api.test.ts +339 -0
- package/src/tests/integrations-http.test.ts +211 -0
- package/src/tests/migration-046-budgets.test.ts +327 -0
- package/src/tests/pricing-routes.test.ts +315 -0
- package/src/tests/prompt-template-remaining.test.ts +4 -0
- package/src/tests/prompt-template-session.test.ts +2 -2
- package/src/tests/provider-adapter.test.ts +1 -1
- package/src/tests/runner-budget-refused.test.ts +271 -0
- package/src/tests/session-costs-codex-recompute.test.ts +386 -0
- package/src/tools/poll-task.ts +13 -2
- package/src/tools/task-action.ts +92 -2
- package/src/tools/templates.ts +29 -0
- package/src/types.ts +116 -0
- package/src/utils/budget-backoff.ts +34 -0
- package/src/utils/credentials.ts +4 -0
- package/src/utils/provider-metadata.ts +9 -0
package/src/http/session-data.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { z } from "zod";
|
|
|
3
3
|
import {
|
|
4
4
|
createSessionCost,
|
|
5
5
|
createSessionLogs,
|
|
6
|
+
getActivePricingRow,
|
|
6
7
|
getAllSessionCosts,
|
|
7
8
|
getDashboardCostSummary,
|
|
8
9
|
getSessionCostSummary,
|
|
@@ -12,7 +13,7 @@ import {
|
|
|
12
13
|
getSessionLogsByTaskId,
|
|
13
14
|
getTaskById,
|
|
14
15
|
} from "../be/db";
|
|
15
|
-
import type { SessionCost } from "../types";
|
|
16
|
+
import type { SessionCost, SessionCostSource } from "../types";
|
|
16
17
|
import { route } from "./route-def";
|
|
17
18
|
import { json, jsonError } from "./utils";
|
|
18
19
|
|
|
@@ -69,6 +70,18 @@ const createSessionCostRoute = route({
|
|
|
69
70
|
numTurns: z.number().int().optional(),
|
|
70
71
|
model: z.string().optional(),
|
|
71
72
|
isError: z.boolean().optional(),
|
|
73
|
+
/**
|
|
74
|
+
* Phase 6: when present, drives the codex pricing-table recompute path.
|
|
75
|
+
* Other providers ('claude' / 'pi') always trust harness-reported USD.
|
|
76
|
+
* Optional / undefined keeps back-compat for existing callers.
|
|
77
|
+
*/
|
|
78
|
+
provider: z.enum(["claude", "codex", "pi"]).optional(),
|
|
79
|
+
/**
|
|
80
|
+
* Phase 6: epoch-ms timestamp used as the "active price at time T" lookup
|
|
81
|
+
* basis. Defaults to `Date.now()` when omitted. Including it lets
|
|
82
|
+
* historical recomputes pick the correct `effective_from` row.
|
|
83
|
+
*/
|
|
84
|
+
createdAt: z.number().int().nonnegative().optional(),
|
|
72
85
|
}),
|
|
73
86
|
responses: {
|
|
74
87
|
201: { description: "Cost record stored" },
|
|
@@ -170,19 +183,54 @@ export async function handleSessionData(
|
|
|
170
183
|
if (!parsed) return true;
|
|
171
184
|
|
|
172
185
|
try {
|
|
186
|
+
const inputTokens = parsed.body.inputTokens ?? 0;
|
|
187
|
+
const cachedInputTokens = parsed.body.cacheReadTokens ?? 0;
|
|
188
|
+
const outputTokens = parsed.body.outputTokens ?? 0;
|
|
189
|
+
const model = parsed.body.model || "opus";
|
|
190
|
+
|
|
191
|
+
// Phase 6: Codex USD recompute. When the worker reports `provider='codex'`
|
|
192
|
+
// and DB pricing rows exist for ALL three token classes at the lookup
|
|
193
|
+
// time, recompute `totalCostUsd` from tokens × DB prices and tag the
|
|
194
|
+
// row as 'pricing-table'. If any class has no row, fall back to the
|
|
195
|
+
// worker-reported value with `costSource='harness'` (back-compat for
|
|
196
|
+
// unseeded models). Claude / pi paths always use 'harness'.
|
|
197
|
+
let totalCostUsd = parsed.body.totalCostUsd;
|
|
198
|
+
let costSource: SessionCostSource = "harness";
|
|
199
|
+
|
|
200
|
+
if (parsed.body.provider === "codex") {
|
|
201
|
+
const lookupTime = parsed.body.createdAt ?? Date.now();
|
|
202
|
+
const inputRow = getActivePricingRow("codex", model, "input", lookupTime);
|
|
203
|
+
const cachedRow = getActivePricingRow("codex", model, "cached_input", lookupTime);
|
|
204
|
+
const outputRow = getActivePricingRow("codex", model, "output", lookupTime);
|
|
205
|
+
|
|
206
|
+
if (inputRow && cachedRow && outputRow) {
|
|
207
|
+
// Mirror the existing computeCodexCostUsd logic: subtract cached
|
|
208
|
+
// tokens from input before billing the uncached portion at the full
|
|
209
|
+
// rate (Codex SDK reports input_tokens as TOTAL across the turn).
|
|
210
|
+
const uncachedInputTokens = Math.max(0, inputTokens - cachedInputTokens);
|
|
211
|
+
totalCostUsd =
|
|
212
|
+
(uncachedInputTokens * inputRow.pricePerMillionUsd +
|
|
213
|
+
cachedInputTokens * cachedRow.pricePerMillionUsd +
|
|
214
|
+
outputTokens * outputRow.pricePerMillionUsd) /
|
|
215
|
+
1_000_000;
|
|
216
|
+
costSource = "pricing-table";
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
173
220
|
const cost = createSessionCost({
|
|
174
221
|
sessionId: parsed.body.sessionId,
|
|
175
222
|
taskId: parsed.body.taskId || undefined,
|
|
176
223
|
agentId: parsed.body.agentId,
|
|
177
|
-
totalCostUsd
|
|
178
|
-
inputTokens
|
|
179
|
-
outputTokens
|
|
180
|
-
cacheReadTokens:
|
|
224
|
+
totalCostUsd,
|
|
225
|
+
inputTokens,
|
|
226
|
+
outputTokens,
|
|
227
|
+
cacheReadTokens: cachedInputTokens,
|
|
181
228
|
cacheWriteTokens: parsed.body.cacheWriteTokens ?? 0,
|
|
182
229
|
durationMs: parsed.body.durationMs ?? 0,
|
|
183
230
|
numTurns: parsed.body.numTurns ?? 1,
|
|
184
|
-
model
|
|
231
|
+
model,
|
|
185
232
|
isError: parsed.body.isError ?? false,
|
|
233
|
+
costSource,
|
|
186
234
|
});
|
|
187
235
|
json(res, { success: true, cost }, 201);
|
|
188
236
|
} catch (error) {
|
package/src/http/tasks.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
} from "../be/db";
|
|
21
21
|
import { createTaskWithSiblingAwareness } from "../tasks/sibling-awareness";
|
|
22
22
|
import { telemetry } from "../telemetry";
|
|
23
|
+
import { ProviderNameSchema } from "../types";
|
|
23
24
|
import { route } from "./route-def";
|
|
24
25
|
import { json, jsonError } from "./utils";
|
|
25
26
|
|
|
@@ -78,7 +79,22 @@ const updateClaudeSession = route({
|
|
|
78
79
|
summary: "Update Claude session ID for a task",
|
|
79
80
|
tags: ["Tasks"],
|
|
80
81
|
params: z.object({ id: z.string() }),
|
|
81
|
-
body: z.
|
|
82
|
+
body: z.union([
|
|
83
|
+
z.object({
|
|
84
|
+
claudeSessionId: z.string().min(1),
|
|
85
|
+
provider: z.literal("devin"),
|
|
86
|
+
providerMeta: z.object({
|
|
87
|
+
sessionUrl: z.string(),
|
|
88
|
+
maxAcuLimit: z.number().optional(),
|
|
89
|
+
acuCostUsd: z.number().optional(),
|
|
90
|
+
}),
|
|
91
|
+
}),
|
|
92
|
+
z.object({
|
|
93
|
+
claudeSessionId: z.string().min(1),
|
|
94
|
+
provider: ProviderNameSchema.exclude(["devin"]).optional(),
|
|
95
|
+
providerMeta: z.object({}).optional(),
|
|
96
|
+
}),
|
|
97
|
+
]),
|
|
82
98
|
responses: {
|
|
83
99
|
200: { description: "Session ID updated" },
|
|
84
100
|
404: { description: "Task not found" },
|
|
@@ -291,7 +307,12 @@ export async function handleTasks(
|
|
|
291
307
|
if (updateClaudeSession.match(req.method, pathSegments)) {
|
|
292
308
|
const parsed = await updateClaudeSession.parse(req, res, pathSegments, queryParams);
|
|
293
309
|
if (!parsed) return true;
|
|
294
|
-
const task = updateTaskClaudeSessionId(
|
|
310
|
+
const task = updateTaskClaudeSessionId(
|
|
311
|
+
parsed.params.id,
|
|
312
|
+
parsed.body.claudeSessionId,
|
|
313
|
+
parsed.body.provider,
|
|
314
|
+
parsed.body.providerMeta,
|
|
315
|
+
);
|
|
295
316
|
if (!task) {
|
|
296
317
|
jsonError(res, "Task not found", 404);
|
|
297
318
|
return true;
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* still assembled here based on runtime state.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import type { ProviderTraits } from "../providers/types";
|
|
10
11
|
import { resolveTemplateAsync } from "./resolver";
|
|
11
12
|
|
|
12
13
|
// Side-effect import: register all system + session templates
|
|
@@ -27,6 +28,7 @@ export type BasePromptArgs = {
|
|
|
27
28
|
agentId: string;
|
|
28
29
|
swarmUrl: string;
|
|
29
30
|
capabilities?: string[];
|
|
31
|
+
traits?: ProviderTraits;
|
|
30
32
|
name?: string;
|
|
31
33
|
description?: string;
|
|
32
34
|
soulMd?: string;
|
|
@@ -53,17 +55,25 @@ export type BasePromptArgs = {
|
|
|
53
55
|
};
|
|
54
56
|
|
|
55
57
|
export const getBasePrompt = async (args: BasePromptArgs): Promise<string> => {
|
|
56
|
-
const { role, agentId, swarmUrl } = args;
|
|
58
|
+
const { role, agentId, swarmUrl, traits } = args;
|
|
59
|
+
const { hasMcp = true, hasLocalEnvironment: hasLocalEnv = true } = traits ?? {};
|
|
57
60
|
|
|
58
61
|
const vars: Record<string, string> = { role, agentId, swarmUrl };
|
|
59
62
|
|
|
60
|
-
// Resolve the composite session template (
|
|
61
|
-
|
|
63
|
+
// Resolve the composite session template (trait-aware for remote providers)
|
|
64
|
+
let compositeEventType: string;
|
|
65
|
+
if (!hasMcp) {
|
|
66
|
+
// If no MCP, role cannot be lead
|
|
67
|
+
compositeEventType = "system.session.worker.remote";
|
|
68
|
+
} else {
|
|
69
|
+
compositeEventType = role === "lead" ? "system.session.lead" : "system.session.worker";
|
|
70
|
+
}
|
|
62
71
|
const compositeResult = await resolveTemplateAsync(compositeEventType, vars);
|
|
63
72
|
let prompt = compositeResult.text;
|
|
64
73
|
|
|
65
74
|
// Conditionally inject Slack instructions for workers with Slack-originated tasks
|
|
66
|
-
|
|
75
|
+
// Skip for providers without MCP — they can't call Slack tools (slack-reply, etc.)
|
|
76
|
+
if (role !== "lead" && args.slackContext && hasMcp) {
|
|
67
77
|
const slackResult = await resolveTemplateAsync("system.agent.worker.slack", {
|
|
68
78
|
slackChannelId: args.slackContext.channelId,
|
|
69
79
|
slackThreadTs: args.slackContext.threadTs ?? "",
|
|
@@ -71,8 +81,21 @@ export const getBasePrompt = async (args: BasePromptArgs): Promise<string> => {
|
|
|
71
81
|
prompt += slackResult.text;
|
|
72
82
|
}
|
|
73
83
|
|
|
74
|
-
// Inject agent identity
|
|
75
|
-
if (
|
|
84
|
+
// Inject agent identity
|
|
85
|
+
if (!hasLocalEnv) {
|
|
86
|
+
// Simplified identity for remote providers — no self-evolution, no /workspace files
|
|
87
|
+
prompt += "\n\n## Your Identity\n\n";
|
|
88
|
+
if (args.name) {
|
|
89
|
+
prompt += `**Name:** ${args.name}\n`;
|
|
90
|
+
if (args.description) {
|
|
91
|
+
prompt += `**Description:** ${args.description}\n`;
|
|
92
|
+
}
|
|
93
|
+
prompt += "\n";
|
|
94
|
+
}
|
|
95
|
+
prompt += `You are part of an agent swarm managed by the Desplega platform. `;
|
|
96
|
+
prompt += `You receive tasks from the swarm's lead agent and execute them independently. `;
|
|
97
|
+
prompt += `Focus on quality work and clear communication of results.\n`;
|
|
98
|
+
} else if (args.soulMd || args.identityMd || args.name) {
|
|
76
99
|
prompt += "\n\n## Your Identity\n\n";
|
|
77
100
|
if (args.name) {
|
|
78
101
|
prompt += `**Name:** ${args.name}\n`;
|
|
@@ -90,13 +113,14 @@ export const getBasePrompt = async (args: BasePromptArgs): Promise<string> => {
|
|
|
90
113
|
}
|
|
91
114
|
|
|
92
115
|
// Installed skills section (progressive disclosure — name + description only)
|
|
93
|
-
|
|
116
|
+
// Skip for providers without MCP — skills require the Skill MCP tool
|
|
117
|
+
if (hasMcp && args.skillsSummary && args.skillsSummary.length > 0) {
|
|
94
118
|
const summaries = args.skillsSummary.map((s) => `- /${s.name}: ${s.description}`).join("\n");
|
|
95
119
|
prompt += `\n\n## Installed Skills\n\nThe following skills are available. Use the Skill tool to invoke them by name.\n\n${summaries}\n`;
|
|
96
120
|
}
|
|
97
121
|
|
|
98
|
-
// Installed MCP servers section
|
|
99
|
-
if (args.mcpServersSummary) {
|
|
122
|
+
// Installed MCP servers section — skip for providers without MCP
|
|
123
|
+
if (hasMcp && args.mcpServersSummary) {
|
|
100
124
|
prompt += `\n\n## Installed MCP Servers\n\nThe following MCP servers are configured for your use:\n${args.mcpServersSummary}\n`;
|
|
101
125
|
}
|
|
102
126
|
|
|
@@ -108,13 +132,15 @@ export const getBasePrompt = async (args: BasePromptArgs): Promise<string> => {
|
|
|
108
132
|
prompt += `WARNING: ${args.repoContext.warning}\n\n`;
|
|
109
133
|
}
|
|
110
134
|
|
|
111
|
-
if (
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
135
|
+
if (hasLocalEnv) {
|
|
136
|
+
if (args.repoContext.claudeMd) {
|
|
137
|
+
prompt += `The following CLAUDE.md is from the repository cloned at \`${args.repoContext.clonePath}\`. `;
|
|
138
|
+
prompt += `**IMPORTANT: These instructions apply ONLY when working within the \`${args.repoContext.clonePath}\` directory.** `;
|
|
139
|
+
prompt += `Do NOT apply these rules to files outside that directory.\n\n`;
|
|
140
|
+
prompt += `${args.repoContext.claudeMd}\n`;
|
|
141
|
+
} else if (!args.repoContext.warning) {
|
|
142
|
+
prompt += `Repository is cloned at \`${args.repoContext.clonePath}\` but has no CLAUDE.md file.\n`;
|
|
143
|
+
}
|
|
118
144
|
}
|
|
119
145
|
|
|
120
146
|
// Inject repo guidelines
|
|
@@ -153,73 +179,77 @@ export const getBasePrompt = async (args: BasePromptArgs): Promise<string> => {
|
|
|
153
179
|
}
|
|
154
180
|
}
|
|
155
181
|
|
|
156
|
-
//
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
sharedOrgId
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
182
|
+
// Skip conditional suffix and truncatable sections for remote providers — these
|
|
183
|
+
// reference local Docker environment features (agent-fs, services, artifacts, /workspace files)
|
|
184
|
+
if (hasLocalEnv) {
|
|
185
|
+
// Build conditional suffix (sections that depend on runtime env/capabilities)
|
|
186
|
+
let conditionalSuffix = "";
|
|
187
|
+
|
|
188
|
+
// Conditionally include agent-fs instructions when available
|
|
189
|
+
if (process.env.AGENT_FS_API_URL) {
|
|
190
|
+
const sharedOrgId = process.env.AGENT_FS_SHARED_ORG_ID || "YOUR_SHARED_ORG_ID";
|
|
191
|
+
const agentFsResult = await resolveTemplateAsync("system.agent.agent_fs", {
|
|
192
|
+
agentId,
|
|
193
|
+
sharedOrgId,
|
|
194
|
+
});
|
|
195
|
+
conditionalSuffix += agentFsResult.text;
|
|
196
|
+
}
|
|
168
197
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
198
|
+
if (!args.capabilities || args.capabilities.includes("services")) {
|
|
199
|
+
const servicesResult = await resolveTemplateAsync("system.agent.services", {
|
|
200
|
+
agentId,
|
|
201
|
+
swarmUrl,
|
|
202
|
+
});
|
|
203
|
+
conditionalSuffix += servicesResult.text;
|
|
204
|
+
}
|
|
176
205
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
206
|
+
if (!args.capabilities || args.capabilities.includes("artifacts")) {
|
|
207
|
+
const artifactsResult = await resolveTemplateAsync("system.agent.artifacts", {});
|
|
208
|
+
conditionalSuffix += artifactsResult.text;
|
|
209
|
+
}
|
|
181
210
|
|
|
182
|
-
|
|
183
|
-
|
|
211
|
+
if (args.capabilities) {
|
|
212
|
+
conditionalSuffix += `
|
|
184
213
|
### Capabilities enabled for this agent:
|
|
185
214
|
|
|
186
215
|
- ${args.capabilities.join("\n- ")}
|
|
187
216
|
`;
|
|
188
|
-
|
|
217
|
+
}
|
|
189
218
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
219
|
+
// Inject truncatable sections with per-section and total character caps
|
|
220
|
+
// Priority: agent CLAUDE.md > tools (tools cut first when over total budget)
|
|
221
|
+
const protectedLength = prompt.length + conditionalSuffix.length;
|
|
222
|
+
const totalBudget = Math.max(0, BOOTSTRAP_TOTAL_MAX_CHARS - protectedLength);
|
|
223
|
+
let totalUsed = 0;
|
|
224
|
+
|
|
225
|
+
// Agent CLAUDE.md (higher priority — injected first)
|
|
226
|
+
if (args.claudeMd) {
|
|
227
|
+
const perSectionBudget = Math.min(BOOTSTRAP_MAX_CHARS, totalBudget - totalUsed);
|
|
228
|
+
const section = truncateSection(
|
|
229
|
+
args.claudeMd,
|
|
230
|
+
"## Agent Instructions",
|
|
231
|
+
"CLAUDE.md",
|
|
232
|
+
perSectionBudget,
|
|
233
|
+
);
|
|
234
|
+
prompt += section;
|
|
235
|
+
totalUsed += section.length;
|
|
236
|
+
}
|
|
208
237
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
238
|
+
// Tools (lower priority — gets whatever budget remains)
|
|
239
|
+
if (args.toolsMd) {
|
|
240
|
+
const perSectionBudget = Math.min(BOOTSTRAP_MAX_CHARS, totalBudget - totalUsed);
|
|
241
|
+
const section = truncateSection(
|
|
242
|
+
args.toolsMd,
|
|
243
|
+
"## Your Tools & Capabilities",
|
|
244
|
+
"TOOLS.md",
|
|
245
|
+
perSectionBudget,
|
|
246
|
+
);
|
|
247
|
+
prompt += section;
|
|
248
|
+
totalUsed += section.length;
|
|
249
|
+
}
|
|
221
250
|
|
|
222
|
-
|
|
251
|
+
prompt += conditionalSuffix;
|
|
252
|
+
}
|
|
223
253
|
|
|
224
254
|
return prompt;
|
|
225
255
|
};
|
|
@@ -520,3 +520,46 @@ registerTemplate({
|
|
|
520
520
|
],
|
|
521
521
|
category: "session",
|
|
522
522
|
});
|
|
523
|
+
|
|
524
|
+
// ============================================================================
|
|
525
|
+
// Remote provider templates (no MCP, no Docker container)
|
|
526
|
+
// ============================================================================
|
|
527
|
+
|
|
528
|
+
registerTemplate({
|
|
529
|
+
eventType: "system.agent.worker.remote",
|
|
530
|
+
header: "",
|
|
531
|
+
defaultBody: `
|
|
532
|
+
As a worker agent of the swarm, you are responsible for executing tasks assigned by the lead agent.
|
|
533
|
+
|
|
534
|
+
- Each worker focuses on specific tasks or objectives, contributing to the overall goals of the swarm.
|
|
535
|
+
- Workers MUST report their progress back to the lead and collaborate with other workers as needed.
|
|
536
|
+
|
|
537
|
+
#### How Tasks Work
|
|
538
|
+
|
|
539
|
+
You receive tasks via the session prompt. Each task has a description of what needs to be done.
|
|
540
|
+
|
|
541
|
+
#### Completing Tasks
|
|
542
|
+
|
|
543
|
+
When you finish a task:
|
|
544
|
+
- Provide a clear summary of what you accomplished in your final message
|
|
545
|
+
- If you created a PR, include the PR URL
|
|
546
|
+
- If you encountered blockers, explain what blocked you and what you tried
|
|
547
|
+
|
|
548
|
+
Your output is captured automatically — focus on doing the work and communicating results clearly.
|
|
549
|
+
`,
|
|
550
|
+
variables: [],
|
|
551
|
+
category: "system",
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
registerTemplate({
|
|
555
|
+
eventType: "system.session.worker.remote",
|
|
556
|
+
header: "",
|
|
557
|
+
defaultBody: `{{@template[system.agent.role]}}
|
|
558
|
+
|
|
559
|
+
{{@template[system.agent.worker.remote]}}`,
|
|
560
|
+
variables: [
|
|
561
|
+
{ name: "role", description: "The agent's role" },
|
|
562
|
+
{ name: "agentId", description: "The agent's unique identifier" },
|
|
563
|
+
],
|
|
564
|
+
category: "session",
|
|
565
|
+
});
|
|
@@ -394,7 +394,7 @@ class ClaudeSession implements ProviderSession {
|
|
|
394
394
|
// Session ID from init message
|
|
395
395
|
if (json.type === "system" && json.subtype === "init" && json.session_id) {
|
|
396
396
|
this._sessionId = json.session_id;
|
|
397
|
-
this.emit({ type: "session_init", sessionId: json.session_id });
|
|
397
|
+
this.emit({ type: "session_init", sessionId: json.session_id, provider: "claude" });
|
|
398
398
|
if (json.model) {
|
|
399
399
|
this.contextWindowSize = getContextWindowSize(json.model);
|
|
400
400
|
}
|
|
@@ -434,6 +434,7 @@ class ClaudeSession implements ProviderSession {
|
|
|
434
434
|
numTurns: json.num_turns || 1,
|
|
435
435
|
model: this.model,
|
|
436
436
|
isError: json.is_error || false,
|
|
437
|
+
provider: "claude",
|
|
437
438
|
};
|
|
438
439
|
setCost(cost);
|
|
439
440
|
this.emit({
|
|
@@ -568,6 +569,7 @@ class ClaudeSession implements ProviderSession {
|
|
|
568
569
|
|
|
569
570
|
export class ClaudeAdapter implements ProviderAdapter {
|
|
570
571
|
readonly name = "claude";
|
|
572
|
+
readonly traits = { hasMcp: true, hasLocalEnvironment: true };
|
|
571
573
|
|
|
572
574
|
async createSession(config: ProviderSessionConfig): Promise<ProviderSession> {
|
|
573
575
|
const model = config.model || "opus";
|