swarmlord 0.1.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/LICENSE +21 -0
- package/README.md +198 -0
- package/dist/index.cjs +670 -0
- package/dist/index.d.cts +615 -0
- package/dist/index.d.mts +615 -0
- package/dist/index.d.ts +615 -0
- package/dist/index.mjs +668 -0
- package/package.json +44 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,670 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function parseSSEStream(stream) {
|
|
4
|
+
const reader = stream.getReader();
|
|
5
|
+
const decoder = new TextDecoder();
|
|
6
|
+
let buffer = "";
|
|
7
|
+
return {
|
|
8
|
+
[Symbol.asyncIterator]() {
|
|
9
|
+
return {
|
|
10
|
+
async next() {
|
|
11
|
+
while (true) {
|
|
12
|
+
const eventEnd = buffer.indexOf("\n\n");
|
|
13
|
+
if (eventEnd !== -1) {
|
|
14
|
+
const raw = buffer.slice(0, eventEnd);
|
|
15
|
+
buffer = buffer.slice(eventEnd + 2);
|
|
16
|
+
let type = "";
|
|
17
|
+
let data = "";
|
|
18
|
+
for (const line of raw.split("\n")) {
|
|
19
|
+
if (line.startsWith("event: ")) type = line.slice(7);
|
|
20
|
+
else if (line.startsWith("data: ")) data = line.slice(6);
|
|
21
|
+
}
|
|
22
|
+
if (type) return { value: { type, data }, done: false };
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const { done, value } = await reader.read();
|
|
26
|
+
if (done) return { value: void 0, done: true };
|
|
27
|
+
buffer += decoder.decode(value, { stream: true });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function toAgentEvent(raw) {
|
|
35
|
+
let parsed;
|
|
36
|
+
try {
|
|
37
|
+
parsed = JSON.parse(raw.data);
|
|
38
|
+
} catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
switch (raw.type) {
|
|
42
|
+
case "message.part.delta": {
|
|
43
|
+
const delta = parsed.delta;
|
|
44
|
+
const field = parsed.field;
|
|
45
|
+
if (field === "text" && delta) return { type: "text-delta", delta };
|
|
46
|
+
if (field === "reasoning" && delta) return { type: "reasoning-delta", delta };
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
case "message.part.updated": {
|
|
50
|
+
const part = parsed.part;
|
|
51
|
+
if (!part) return null;
|
|
52
|
+
if (part.type === "tool") {
|
|
53
|
+
const toolPart = part;
|
|
54
|
+
if (toolPart.state.status === "running") return { type: "tool-start", part: toolPart };
|
|
55
|
+
if (toolPart.state.status === "completed") {
|
|
56
|
+
if (toolPart.state.attachments) {
|
|
57
|
+
for (const file of toolPart.state.attachments) {
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return { type: "tool-complete", part: toolPart };
|
|
61
|
+
}
|
|
62
|
+
if (toolPart.state.status === "error") {
|
|
63
|
+
return { type: "tool-error", part: toolPart, error: toolPart.state.error };
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
if (part.type === "step-finish") {
|
|
68
|
+
const sfp = part;
|
|
69
|
+
return { type: "step-finish", tokens: sfp.tokens, cost: sfp.cost, reason: sfp.reason };
|
|
70
|
+
}
|
|
71
|
+
if (part.type === "file") {
|
|
72
|
+
return { type: "attachment", file: part };
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
case "message.updated": {
|
|
77
|
+
const info = parsed.info ?? parsed;
|
|
78
|
+
return { type: "message-updated", info };
|
|
79
|
+
}
|
|
80
|
+
case "session.status": {
|
|
81
|
+
const status = parsed.status;
|
|
82
|
+
return status ? { type: "status-change", status } : null;
|
|
83
|
+
}
|
|
84
|
+
case "session.idle":
|
|
85
|
+
return { type: "session-idle", sessionId: parsed.sessionID ?? "" };
|
|
86
|
+
case "session.error":
|
|
87
|
+
return { type: "error", error: parsed.error ?? "Unknown error" };
|
|
88
|
+
case "permission.asked":
|
|
89
|
+
return { type: "permission-asked", request: parsed };
|
|
90
|
+
default:
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function createSessionHandle(id, opts, agentConfig) {
|
|
96
|
+
const { apiKey, baseUrl } = opts;
|
|
97
|
+
function headers() {
|
|
98
|
+
return { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" };
|
|
99
|
+
}
|
|
100
|
+
function buildMessageBody(input) {
|
|
101
|
+
if (typeof input === "string") {
|
|
102
|
+
return {
|
|
103
|
+
content: input,
|
|
104
|
+
agent: agentConfig?.name,
|
|
105
|
+
model: agentConfig?.model,
|
|
106
|
+
config: agentConfig?.config
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
parts: input.parts,
|
|
111
|
+
agent: input.agent ?? agentConfig?.name,
|
|
112
|
+
model: input.model ?? agentConfig?.model,
|
|
113
|
+
config: input.config ?? agentConfig?.config
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
id,
|
|
118
|
+
async send(input, callbacks) {
|
|
119
|
+
const res = await fetch(`${baseUrl}/session/${id}/message`, {
|
|
120
|
+
method: "POST",
|
|
121
|
+
headers: headers(),
|
|
122
|
+
body: JSON.stringify(buildMessageBody(input))
|
|
123
|
+
});
|
|
124
|
+
if (!res.ok) {
|
|
125
|
+
const text = await res.text();
|
|
126
|
+
const err = new Error(`Agent error (${res.status}): ${text}`);
|
|
127
|
+
callbacks?.onError?.(err);
|
|
128
|
+
throw err;
|
|
129
|
+
}
|
|
130
|
+
if (!res.body) throw new Error("No response body");
|
|
131
|
+
callbacks?.onConnect?.();
|
|
132
|
+
const parts = [];
|
|
133
|
+
let messageId = "";
|
|
134
|
+
let fullText = "";
|
|
135
|
+
let finalTokens;
|
|
136
|
+
let finalCost;
|
|
137
|
+
let finalError;
|
|
138
|
+
for await (const raw of parseSSEStream(res.body)) {
|
|
139
|
+
const event = toAgentEvent(raw);
|
|
140
|
+
if (!event) continue;
|
|
141
|
+
switch (event.type) {
|
|
142
|
+
case "text-delta":
|
|
143
|
+
fullText += event.delta;
|
|
144
|
+
callbacks?.onText?.(event.delta);
|
|
145
|
+
break;
|
|
146
|
+
case "reasoning-delta":
|
|
147
|
+
callbacks?.onReasoning?.(event.delta);
|
|
148
|
+
break;
|
|
149
|
+
case "tool-start":
|
|
150
|
+
parts.push(event.part);
|
|
151
|
+
callbacks?.onToolStart?.(event.part);
|
|
152
|
+
break;
|
|
153
|
+
case "tool-complete": {
|
|
154
|
+
replacePart(parts, event.part);
|
|
155
|
+
callbacks?.onToolComplete?.(event.part);
|
|
156
|
+
if (event.part.state.status === "completed" && event.part.state.attachments) {
|
|
157
|
+
for (const file of event.part.state.attachments) {
|
|
158
|
+
callbacks?.onAttachment?.(file);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
case "tool-error": {
|
|
164
|
+
replacePart(parts, event.part);
|
|
165
|
+
callbacks?.onToolError?.(event.part, event.error);
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
case "step-finish":
|
|
169
|
+
callbacks?.onStepFinish?.(event.tokens, event.cost);
|
|
170
|
+
break;
|
|
171
|
+
case "attachment":
|
|
172
|
+
callbacks?.onAttachment?.(event.file);
|
|
173
|
+
break;
|
|
174
|
+
case "permission-asked":
|
|
175
|
+
if (callbacks?.onPermission) {
|
|
176
|
+
const reply = await callbacks.onPermission(event.request);
|
|
177
|
+
await fetch(`${baseUrl}/session/${id}/permission/${event.request.id}`, {
|
|
178
|
+
method: "POST",
|
|
179
|
+
headers: headers(),
|
|
180
|
+
body: JSON.stringify({ reply })
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
break;
|
|
184
|
+
case "status-change":
|
|
185
|
+
callbacks?.onStatus?.(event.status);
|
|
186
|
+
break;
|
|
187
|
+
case "message-updated": {
|
|
188
|
+
const info = event.info;
|
|
189
|
+
if (info.id) messageId = info.id;
|
|
190
|
+
if (info.role === "assistant") {
|
|
191
|
+
finalTokens = info.tokens;
|
|
192
|
+
finalCost = info.cost;
|
|
193
|
+
if (info.error) finalError = info.error;
|
|
194
|
+
}
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
case "error":
|
|
198
|
+
callbacks?.onError?.(new Error(event.error));
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return { messageId, text: fullText, parts, tokens: finalTokens, cost: finalCost, error: finalError };
|
|
203
|
+
},
|
|
204
|
+
async *stream(input) {
|
|
205
|
+
const res = await fetch(`${baseUrl}/session/${id}/message`, {
|
|
206
|
+
method: "POST",
|
|
207
|
+
headers: headers(),
|
|
208
|
+
body: JSON.stringify(buildMessageBody(input))
|
|
209
|
+
});
|
|
210
|
+
if (!res.ok) throw new Error(`Agent error (${res.status}): ${await res.text()}`);
|
|
211
|
+
if (!res.body) throw new Error("No response body");
|
|
212
|
+
yield { type: "connect" };
|
|
213
|
+
for await (const raw of parseSSEStream(res.body)) {
|
|
214
|
+
const event = toAgentEvent(raw);
|
|
215
|
+
if (event) yield event;
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
async abort() {
|
|
219
|
+
const res = await fetch(`${baseUrl}/session/${id}/abort`, { method: "POST", headers: headers() });
|
|
220
|
+
if (!res.ok) throw new Error(`Failed to abort: ${res.status}`);
|
|
221
|
+
},
|
|
222
|
+
async summarize() {
|
|
223
|
+
const res = await fetch(`${baseUrl}/session/${id}/summarize`, { method: "POST", headers: headers() });
|
|
224
|
+
if (!res.ok) throw new Error(`Failed to summarize: ${res.status}`);
|
|
225
|
+
},
|
|
226
|
+
async revert(messageId) {
|
|
227
|
+
const res = await fetch(`${baseUrl}/session/${id}/revert`, {
|
|
228
|
+
method: "POST",
|
|
229
|
+
headers: headers(),
|
|
230
|
+
body: JSON.stringify({ messageId })
|
|
231
|
+
});
|
|
232
|
+
if (!res.ok) throw new Error(`Failed to revert: ${res.status}`);
|
|
233
|
+
},
|
|
234
|
+
async shell(command, shellOpts) {
|
|
235
|
+
const res = await fetch(`${baseUrl}/session/${id}/shell`, {
|
|
236
|
+
method: "POST",
|
|
237
|
+
headers: headers(),
|
|
238
|
+
body: JSON.stringify({ command, ...shellOpts })
|
|
239
|
+
});
|
|
240
|
+
if (!res.ok) throw new Error(`Shell error: ${res.status}`);
|
|
241
|
+
return res.json();
|
|
242
|
+
},
|
|
243
|
+
async getInfo() {
|
|
244
|
+
const res = await fetch(`${baseUrl}/session/${id}`, { headers: headers() });
|
|
245
|
+
if (!res.ok) throw new Error(`Failed to get session: ${res.status}`);
|
|
246
|
+
return res.json();
|
|
247
|
+
},
|
|
248
|
+
async getMessages() {
|
|
249
|
+
const res = await fetch(`${baseUrl}/session/${id}/message`, { headers: headers() });
|
|
250
|
+
if (!res.ok) throw new Error(`Failed to get messages: ${res.status}`);
|
|
251
|
+
return res.json();
|
|
252
|
+
},
|
|
253
|
+
async getMetrics() {
|
|
254
|
+
const res = await fetch(`${baseUrl}/session/${id}/metrics`, { headers: headers() });
|
|
255
|
+
if (!res.ok) throw new Error(`Failed to get metrics: ${res.status}`);
|
|
256
|
+
return res.json();
|
|
257
|
+
},
|
|
258
|
+
async getTodos() {
|
|
259
|
+
const res = await fetch(`${baseUrl}/session/${id}/todo`, { headers: headers() });
|
|
260
|
+
if (!res.ok) throw new Error(`Failed to get todos: ${res.status}`);
|
|
261
|
+
return res.json();
|
|
262
|
+
},
|
|
263
|
+
async getFile(path) {
|
|
264
|
+
const res = await fetch(`${baseUrl}/session/${id}/file?path=${encodeURIComponent(path)}`, {
|
|
265
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
266
|
+
});
|
|
267
|
+
if (!res.ok) throw new Error(`Failed to get file: ${res.status}`);
|
|
268
|
+
return res.text();
|
|
269
|
+
},
|
|
270
|
+
async getFileBuffer(path) {
|
|
271
|
+
const res = await fetch(`${baseUrl}/session/${id}/file?path=${encodeURIComponent(path)}&encoding=base64`, {
|
|
272
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
273
|
+
});
|
|
274
|
+
if (!res.ok) throw new Error(`Failed to get file: ${res.status}`);
|
|
275
|
+
const b64 = await res.text();
|
|
276
|
+
const bin = atob(b64);
|
|
277
|
+
const bytes = new Uint8Array(bin.length);
|
|
278
|
+
for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
|
|
279
|
+
return bytes.buffer;
|
|
280
|
+
},
|
|
281
|
+
async getArtifact(key) {
|
|
282
|
+
const res = await fetch(`${baseUrl}/session/${id}/artifact/${encodeURIComponent(key)}`, {
|
|
283
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
284
|
+
});
|
|
285
|
+
if (!res.ok) throw new Error(`Failed to get artifact: ${res.status}`);
|
|
286
|
+
return res.text();
|
|
287
|
+
},
|
|
288
|
+
async getArtifactBuffer(key) {
|
|
289
|
+
const res = await fetch(`${baseUrl}/session/${id}/artifact/${encodeURIComponent(key)}`, {
|
|
290
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
291
|
+
});
|
|
292
|
+
if (!res.ok) throw new Error(`Failed to get artifact: ${res.status}`);
|
|
293
|
+
return res.arrayBuffer();
|
|
294
|
+
},
|
|
295
|
+
async update(updateOpts) {
|
|
296
|
+
const res = await fetch(`${baseUrl}/session/${id}`, {
|
|
297
|
+
method: "PATCH",
|
|
298
|
+
headers: headers(),
|
|
299
|
+
body: JSON.stringify(updateOpts)
|
|
300
|
+
});
|
|
301
|
+
if (!res.ok) throw new Error(`Failed to update session: ${res.status}`);
|
|
302
|
+
},
|
|
303
|
+
async delete() {
|
|
304
|
+
const res = await fetch(`${baseUrl}/session/${id}`, { method: "DELETE", headers: headers() });
|
|
305
|
+
if (!res.ok) throw new Error(`Failed to delete session: ${res.status}`);
|
|
306
|
+
},
|
|
307
|
+
async runCommand(name, args) {
|
|
308
|
+
const res = await fetch(`${baseUrl}/session/${id}/command`, {
|
|
309
|
+
method: "POST",
|
|
310
|
+
headers: headers(),
|
|
311
|
+
body: JSON.stringify({ name, args })
|
|
312
|
+
});
|
|
313
|
+
if (!res.ok) throw new Error(`Failed to run command: ${res.status}`);
|
|
314
|
+
const data = await res.json();
|
|
315
|
+
return data.result ?? "";
|
|
316
|
+
},
|
|
317
|
+
async replyToPermission(requestId, reply, message) {
|
|
318
|
+
const res = await fetch(`${baseUrl}/session/${id}/permission/${requestId}`, {
|
|
319
|
+
method: "POST",
|
|
320
|
+
headers: headers(),
|
|
321
|
+
body: JSON.stringify({ reply, message })
|
|
322
|
+
});
|
|
323
|
+
if (!res.ok) throw new Error(`Failed to reply to permission: ${res.status}`);
|
|
324
|
+
},
|
|
325
|
+
async events(lastEventId) {
|
|
326
|
+
const reqHeaders = { Authorization: `Bearer ${apiKey}` };
|
|
327
|
+
if (lastEventId !== void 0) reqHeaders["Last-Event-ID"] = String(lastEventId);
|
|
328
|
+
const res = await fetch(`${baseUrl}/session/${id}/events`, { headers: reqHeaders });
|
|
329
|
+
if (!res.ok) throw new Error(`Failed to connect to events: ${res.status}`);
|
|
330
|
+
if (!res.body) throw new Error("No response body");
|
|
331
|
+
return res.body;
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
function replacePart(parts, updated) {
|
|
336
|
+
const idx = parts.findIndex((p) => p.id === updated.id);
|
|
337
|
+
if (idx !== -1) parts[idx] = updated;
|
|
338
|
+
else parts.push(updated);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const POLL_INITIAL_MS = 1e3;
|
|
342
|
+
const POLL_MAX_MS = 15e3;
|
|
343
|
+
const POLL_BACKOFF = 1.5;
|
|
344
|
+
function createTaskHandle(sessionId, opts) {
|
|
345
|
+
const { apiKey, baseUrl } = opts;
|
|
346
|
+
function headers() {
|
|
347
|
+
return { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" };
|
|
348
|
+
}
|
|
349
|
+
return {
|
|
350
|
+
id: sessionId,
|
|
351
|
+
async poll() {
|
|
352
|
+
const res = await fetch(`${baseUrl}/session/${sessionId}/status`, { headers: headers() });
|
|
353
|
+
if (!res.ok) throw new Error(`Failed to poll task: ${res.status}`);
|
|
354
|
+
const data = await res.json();
|
|
355
|
+
return data.status;
|
|
356
|
+
},
|
|
357
|
+
async result(resultOpts) {
|
|
358
|
+
const timeout = resultOpts?.timeoutMs ?? 6e5;
|
|
359
|
+
const deadline = Date.now() + timeout;
|
|
360
|
+
let interval = POLL_INITIAL_MS;
|
|
361
|
+
while (Date.now() < deadline) {
|
|
362
|
+
const status = await this.poll();
|
|
363
|
+
if (status === "idle" || status === "error") {
|
|
364
|
+
const msgRes = await fetch(`${baseUrl}/session/${sessionId}/message`, { headers: headers() });
|
|
365
|
+
if (!msgRes.ok) throw new Error(`Failed to get task result: ${msgRes.status}`);
|
|
366
|
+
const messages = await msgRes.json();
|
|
367
|
+
const lastAssistant = messages.findLast((m) => m.info.role === "assistant");
|
|
368
|
+
const textParts = lastAssistant?.parts.filter((p) => p.type === "text") ?? [];
|
|
369
|
+
const text = textParts.map((p) => p.text).join("\n");
|
|
370
|
+
let tokens;
|
|
371
|
+
let cost;
|
|
372
|
+
if (lastAssistant?.info.role === "assistant") {
|
|
373
|
+
const aInfo = lastAssistant.info;
|
|
374
|
+
tokens = aInfo.tokens;
|
|
375
|
+
cost = aInfo.cost;
|
|
376
|
+
}
|
|
377
|
+
return {
|
|
378
|
+
sessionId,
|
|
379
|
+
status: status === "error" ? "error" : "completed",
|
|
380
|
+
text,
|
|
381
|
+
messages,
|
|
382
|
+
tokens,
|
|
383
|
+
cost
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
387
|
+
interval = Math.min(interval * POLL_BACKOFF, POLL_MAX_MS);
|
|
388
|
+
}
|
|
389
|
+
throw new Error(`Task timed out after ${timeout}ms`);
|
|
390
|
+
},
|
|
391
|
+
async cancel() {
|
|
392
|
+
const res = await fetch(`${baseUrl}/session/${sessionId}/abort`, {
|
|
393
|
+
method: "POST",
|
|
394
|
+
headers: headers()
|
|
395
|
+
});
|
|
396
|
+
if (!res.ok) throw new Error(`Failed to cancel task: ${res.status}`);
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
async function launchTask(opts, prompt, agentConfig, taskOpts) {
|
|
401
|
+
const { apiKey, baseUrl } = opts;
|
|
402
|
+
function headers() {
|
|
403
|
+
return { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" };
|
|
404
|
+
}
|
|
405
|
+
const createRes = await fetch(`${baseUrl}/session`, {
|
|
406
|
+
method: "POST",
|
|
407
|
+
headers: headers(),
|
|
408
|
+
body: JSON.stringify({
|
|
409
|
+
title: taskOpts?.title ?? `Task: ${prompt.slice(0, 50)}`,
|
|
410
|
+
config: agentConfig?.config,
|
|
411
|
+
webhook: taskOpts?.webhook
|
|
412
|
+
})
|
|
413
|
+
});
|
|
414
|
+
if (!createRes.ok) throw new Error(`Failed to create task session: ${createRes.status}`);
|
|
415
|
+
const session = await createRes.json();
|
|
416
|
+
const promptRes = await fetch(`${baseUrl}/session/${session.id}/prompt_async`, {
|
|
417
|
+
method: "POST",
|
|
418
|
+
headers: headers(),
|
|
419
|
+
body: JSON.stringify({
|
|
420
|
+
content: prompt,
|
|
421
|
+
agent: agentConfig?.name,
|
|
422
|
+
model: agentConfig?.model
|
|
423
|
+
})
|
|
424
|
+
});
|
|
425
|
+
if (!promptRes.ok) throw new Error(`Failed to start task: ${promptRes.status}`);
|
|
426
|
+
return createTaskHandle(session.id, opts);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function createScheduleHandle(id, opts) {
|
|
430
|
+
const { apiKey, baseUrl } = opts;
|
|
431
|
+
function headers() {
|
|
432
|
+
return { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" };
|
|
433
|
+
}
|
|
434
|
+
return {
|
|
435
|
+
id,
|
|
436
|
+
async trigger() {
|
|
437
|
+
const res = await fetch(`${baseUrl}/background/${id}/trigger`, {
|
|
438
|
+
method: "POST",
|
|
439
|
+
headers: headers()
|
|
440
|
+
});
|
|
441
|
+
if (!res.ok) throw new Error(`Failed to trigger schedule: ${res.status}`);
|
|
442
|
+
const data = await res.json();
|
|
443
|
+
return createTaskHandle(data.sessionId, opts);
|
|
444
|
+
},
|
|
445
|
+
async pause() {
|
|
446
|
+
const res = await fetch(`${baseUrl}/background/${id}`, {
|
|
447
|
+
method: "PATCH",
|
|
448
|
+
headers: headers(),
|
|
449
|
+
body: JSON.stringify({ enabled: false })
|
|
450
|
+
});
|
|
451
|
+
if (!res.ok) throw new Error(`Failed to pause schedule: ${res.status}`);
|
|
452
|
+
},
|
|
453
|
+
async resume() {
|
|
454
|
+
const res = await fetch(`${baseUrl}/background/${id}`, {
|
|
455
|
+
method: "PATCH",
|
|
456
|
+
headers: headers(),
|
|
457
|
+
body: JSON.stringify({ enabled: true })
|
|
458
|
+
});
|
|
459
|
+
if (!res.ok) throw new Error(`Failed to resume schedule: ${res.status}`);
|
|
460
|
+
},
|
|
461
|
+
async update(updateOpts) {
|
|
462
|
+
const res = await fetch(`${baseUrl}/background/${id}`, {
|
|
463
|
+
method: "PATCH",
|
|
464
|
+
headers: headers(),
|
|
465
|
+
body: JSON.stringify(updateOpts)
|
|
466
|
+
});
|
|
467
|
+
if (!res.ok) throw new Error(`Failed to update schedule: ${res.status}`);
|
|
468
|
+
},
|
|
469
|
+
async delete() {
|
|
470
|
+
const res = await fetch(`${baseUrl}/background/${id}`, {
|
|
471
|
+
method: "DELETE",
|
|
472
|
+
headers: headers()
|
|
473
|
+
});
|
|
474
|
+
if (!res.ok) throw new Error(`Failed to delete schedule: ${res.status}`);
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
async function createSchedule(opts, agentConfig, scheduleOpts) {
|
|
479
|
+
const { apiKey, baseUrl } = opts;
|
|
480
|
+
const res = await fetch(`${baseUrl}/background`, {
|
|
481
|
+
method: "POST",
|
|
482
|
+
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
|
|
483
|
+
body: JSON.stringify({
|
|
484
|
+
cron: scheduleOpts.cron,
|
|
485
|
+
prompt: scheduleOpts.prompt,
|
|
486
|
+
model: scheduleOpts.model ?? agentConfig?.model ?? "anthropic/claude-sonnet-4-20250514",
|
|
487
|
+
agent: agentConfig?.name,
|
|
488
|
+
config: agentConfig?.config
|
|
489
|
+
})
|
|
490
|
+
});
|
|
491
|
+
if (!res.ok) throw new Error(`Failed to create schedule: ${res.status}`);
|
|
492
|
+
const data = await res.json();
|
|
493
|
+
return createScheduleHandle(data.id, opts);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
function createTriggerHandle(id, webhookUrl, webhookSecret, opts) {
|
|
497
|
+
const { apiKey, baseUrl } = opts;
|
|
498
|
+
function headers() {
|
|
499
|
+
return { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" };
|
|
500
|
+
}
|
|
501
|
+
return {
|
|
502
|
+
id,
|
|
503
|
+
webhookUrl,
|
|
504
|
+
webhookSecret,
|
|
505
|
+
async pause() {
|
|
506
|
+
const res = await fetch(`${baseUrl}/trigger/${id}`, {
|
|
507
|
+
method: "PATCH",
|
|
508
|
+
headers: headers(),
|
|
509
|
+
body: JSON.stringify({ enabled: false })
|
|
510
|
+
});
|
|
511
|
+
if (!res.ok) throw new Error(`Failed to pause trigger: ${res.status}`);
|
|
512
|
+
},
|
|
513
|
+
async resume() {
|
|
514
|
+
const res = await fetch(`${baseUrl}/trigger/${id}`, {
|
|
515
|
+
method: "PATCH",
|
|
516
|
+
headers: headers(),
|
|
517
|
+
body: JSON.stringify({ enabled: true })
|
|
518
|
+
});
|
|
519
|
+
if (!res.ok) throw new Error(`Failed to resume trigger: ${res.status}`);
|
|
520
|
+
},
|
|
521
|
+
async update(updateOpts) {
|
|
522
|
+
const res = await fetch(`${baseUrl}/trigger/${id}`, {
|
|
523
|
+
method: "PATCH",
|
|
524
|
+
headers: headers(),
|
|
525
|
+
body: JSON.stringify(updateOpts)
|
|
526
|
+
});
|
|
527
|
+
if (!res.ok) throw new Error(`Failed to update trigger: ${res.status}`);
|
|
528
|
+
},
|
|
529
|
+
async delete() {
|
|
530
|
+
const res = await fetch(`${baseUrl}/trigger/${id}`, {
|
|
531
|
+
method: "DELETE",
|
|
532
|
+
headers: headers()
|
|
533
|
+
});
|
|
534
|
+
if (!res.ok) throw new Error(`Failed to delete trigger: ${res.status}`);
|
|
535
|
+
},
|
|
536
|
+
async getInfo() {
|
|
537
|
+
const res = await fetch(`${baseUrl}/trigger/${id}`, { headers: headers() });
|
|
538
|
+
if (!res.ok) throw new Error(`Failed to get trigger: ${res.status}`);
|
|
539
|
+
return res.json();
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
async function launchTrigger(opts, agentConfig, triggerOpts) {
|
|
544
|
+
const { apiKey, baseUrl } = opts;
|
|
545
|
+
const res = await fetch(`${baseUrl}/trigger`, {
|
|
546
|
+
method: "POST",
|
|
547
|
+
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
|
|
548
|
+
body: JSON.stringify({
|
|
549
|
+
provider: triggerOpts.provider,
|
|
550
|
+
events: triggerOpts.events,
|
|
551
|
+
promptTemplate: triggerOpts.promptTemplate,
|
|
552
|
+
agent: agentConfig?.name,
|
|
553
|
+
model: agentConfig?.model ?? triggerOpts.model,
|
|
554
|
+
providerConfig: triggerOpts.providerConfig,
|
|
555
|
+
agentConfig: agentConfig?.config,
|
|
556
|
+
outputs: triggerOpts.outputs
|
|
557
|
+
})
|
|
558
|
+
});
|
|
559
|
+
if (!res.ok) throw new Error(`Failed to create trigger: ${res.status}`);
|
|
560
|
+
const data = await res.json();
|
|
561
|
+
return createTriggerHandle(data.id, data.webhookUrl, data.webhookSecret, opts);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
function createAgentHandle(clientOpts, config) {
|
|
565
|
+
const { apiKey, baseUrl } = clientOpts;
|
|
566
|
+
return {
|
|
567
|
+
config,
|
|
568
|
+
async createSession(sessionOpts) {
|
|
569
|
+
const res = await fetch(`${baseUrl}/session`, {
|
|
570
|
+
method: "POST",
|
|
571
|
+
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
|
|
572
|
+
body: JSON.stringify({
|
|
573
|
+
title: sessionOpts?.title,
|
|
574
|
+
config: config.config,
|
|
575
|
+
webhook: sessionOpts?.webhook
|
|
576
|
+
})
|
|
577
|
+
});
|
|
578
|
+
if (!res.ok) throw new Error(`Failed to create session: ${res.status}`);
|
|
579
|
+
const data = await res.json();
|
|
580
|
+
return createSessionHandle(data.id, clientOpts, config);
|
|
581
|
+
},
|
|
582
|
+
session(id) {
|
|
583
|
+
return createSessionHandle(id, clientOpts, config);
|
|
584
|
+
},
|
|
585
|
+
async forkSession(id) {
|
|
586
|
+
const res = await fetch(`${baseUrl}/session/${id}/fork`, {
|
|
587
|
+
method: "POST",
|
|
588
|
+
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" }
|
|
589
|
+
});
|
|
590
|
+
if (!res.ok) throw new Error(`Failed to fork session: ${res.status}`);
|
|
591
|
+
const data = await res.json();
|
|
592
|
+
return createSessionHandle(data.id, clientOpts, config);
|
|
593
|
+
},
|
|
594
|
+
async run(prompt, runOpts) {
|
|
595
|
+
return launchTask(clientOpts, prompt, config, runOpts);
|
|
596
|
+
},
|
|
597
|
+
async schedule(scheduleOpts) {
|
|
598
|
+
return createSchedule(clientOpts, config, scheduleOpts);
|
|
599
|
+
},
|
|
600
|
+
async trigger(triggerOpts) {
|
|
601
|
+
return launchTrigger(clientOpts, config, triggerOpts);
|
|
602
|
+
}
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
const DEFAULT_BASE_URL = "https://api.swarmlord.ai";
|
|
607
|
+
function createClient(opts) {
|
|
608
|
+
const baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
609
|
+
const normalizedOpts = { ...opts, baseUrl };
|
|
610
|
+
function headers() {
|
|
611
|
+
return { Authorization: `Bearer ${opts.apiKey}`, "Content-Type": "application/json" };
|
|
612
|
+
}
|
|
613
|
+
return {
|
|
614
|
+
agent(nameOrConfig) {
|
|
615
|
+
const config = typeof nameOrConfig === "string" ? { name: nameOrConfig } : nameOrConfig;
|
|
616
|
+
return createAgentHandle(normalizedOpts, config);
|
|
617
|
+
},
|
|
618
|
+
session(id) {
|
|
619
|
+
return createSessionHandle(id, normalizedOpts);
|
|
620
|
+
},
|
|
621
|
+
task(sessionId) {
|
|
622
|
+
return createTaskHandle(sessionId, normalizedOpts);
|
|
623
|
+
},
|
|
624
|
+
schedule(id) {
|
|
625
|
+
return createScheduleHandle(id, normalizedOpts);
|
|
626
|
+
},
|
|
627
|
+
trigger(id) {
|
|
628
|
+
return createTriggerHandle(id, "", "", normalizedOpts);
|
|
629
|
+
},
|
|
630
|
+
async listSessions(listOpts) {
|
|
631
|
+
const params = new URLSearchParams();
|
|
632
|
+
if (listOpts?.limit) params.set("limit", String(listOpts.limit));
|
|
633
|
+
if (listOpts?.archived !== void 0) params.set("archived", String(listOpts.archived));
|
|
634
|
+
const qs = params.toString();
|
|
635
|
+
const res = await fetch(`${baseUrl}/session${qs ? `?${qs}` : ""}`, { headers: headers() });
|
|
636
|
+
if (!res.ok) throw new Error(`Failed to list sessions: ${res.status}`);
|
|
637
|
+
return res.json();
|
|
638
|
+
},
|
|
639
|
+
async listSchedules() {
|
|
640
|
+
const res = await fetch(`${baseUrl}/background`, { headers: headers() });
|
|
641
|
+
if (!res.ok) throw new Error(`Failed to list schedules: ${res.status}`);
|
|
642
|
+
return res.json();
|
|
643
|
+
},
|
|
644
|
+
async listTriggers() {
|
|
645
|
+
const res = await fetch(`${baseUrl}/trigger`, { headers: headers() });
|
|
646
|
+
if (!res.ok) throw new Error(`Failed to list triggers: ${res.status}`);
|
|
647
|
+
return res.json();
|
|
648
|
+
},
|
|
649
|
+
async getConfig() {
|
|
650
|
+
const res = await fetch(`${baseUrl}/config`, { headers: headers() });
|
|
651
|
+
if (!res.ok) throw new Error(`Failed to get config: ${res.status}`);
|
|
652
|
+
return res.json();
|
|
653
|
+
},
|
|
654
|
+
async updateConfig(config) {
|
|
655
|
+
const res = await fetch(`${baseUrl}/config`, {
|
|
656
|
+
method: "PATCH",
|
|
657
|
+
headers: headers(),
|
|
658
|
+
body: JSON.stringify(config)
|
|
659
|
+
});
|
|
660
|
+
if (!res.ok) throw new Error(`Failed to update config: ${res.status}`);
|
|
661
|
+
},
|
|
662
|
+
async listModels() {
|
|
663
|
+
const res = await fetch(`${baseUrl}/provider`, { headers: headers() });
|
|
664
|
+
if (!res.ok) throw new Error(`Failed to list models: ${res.status}`);
|
|
665
|
+
return res.json();
|
|
666
|
+
}
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
exports.createClient = createClient;
|