@workermill/agent 0.8.8 → 0.8.10
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 +6 -5
- package/dist/cli.js +23 -64
- package/dist/index.js +15 -123
- package/package.json +3 -2
- package/dist/ai-sdk-generate.d.ts +0 -33
- package/dist/ai-sdk-generate.js +0 -160
- package/dist/api.d.ts +0 -13
- package/dist/api.js +0 -29
- package/dist/cli.d.ts +0 -8
- package/dist/commands/logs.d.ts +0 -9
- package/dist/commands/logs.js +0 -52
- package/dist/commands/pull.d.ts +0 -4
- package/dist/commands/pull.js +0 -35
- package/dist/commands/setup.d.ts +0 -11
- package/dist/commands/setup.js +0 -412
- package/dist/commands/start.d.ts +0 -11
- package/dist/commands/start.js +0 -152
- package/dist/commands/status.d.ts +0 -6
- package/dist/commands/status.js +0 -86
- package/dist/commands/stop.d.ts +0 -6
- package/dist/commands/stop.js +0 -61
- package/dist/commands/update.d.ts +0 -1
- package/dist/commands/update.js +0 -20
- package/dist/config.d.ts +0 -77
- package/dist/config.js +0 -286
- package/dist/index.d.ts +0 -14
- package/dist/plan-validator.d.ts +0 -104
- package/dist/plan-validator.js +0 -436
- package/dist/planner.d.ts +0 -40
- package/dist/planner.js +0 -792
- package/dist/poller.d.ts +0 -20
- package/dist/poller.js +0 -346
- package/dist/providers.d.ts +0 -18
- package/dist/providers.js +0 -118
- package/dist/spawner.d.ts +0 -116
- package/dist/spawner.js +0 -603
- package/dist/updater.d.ts +0 -8
- package/dist/updater.js +0 -40
- package/dist/version.d.ts +0 -1
- package/dist/version.js +0 -4
package/dist/poller.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Remote Agent Poller
|
|
3
|
-
*
|
|
4
|
-
* Main poll loop: every N seconds, query the cloud API for tasks,
|
|
5
|
-
* dispatch to planner or spawner based on task status.
|
|
6
|
-
*/
|
|
7
|
-
import type { AgentConfig } from "./config.js";
|
|
8
|
-
/**
|
|
9
|
-
* Stop all polling and heartbeat loops.
|
|
10
|
-
* Called during graceful shutdown to prevent the event loop from staying alive.
|
|
11
|
-
*/
|
|
12
|
-
export declare function stopPolling(): void;
|
|
13
|
-
/**
|
|
14
|
-
* Start the poll loop.
|
|
15
|
-
*/
|
|
16
|
-
export declare function startPolling(config: AgentConfig): void;
|
|
17
|
-
/**
|
|
18
|
-
* Start the heartbeat loop.
|
|
19
|
-
*/
|
|
20
|
-
export declare function startHeartbeat(config: AgentConfig): void;
|
package/dist/poller.js
DELETED
|
@@ -1,346 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Remote Agent Poller
|
|
3
|
-
*
|
|
4
|
-
* Main poll loop: every N seconds, query the cloud API for tasks,
|
|
5
|
-
* dispatch to planner or spawner based on task status.
|
|
6
|
-
*/
|
|
7
|
-
import chalk from "chalk";
|
|
8
|
-
import { api } from "./api.js";
|
|
9
|
-
import { planTask } from "./planner.js";
|
|
10
|
-
import { spawnWorker, spawnManagerWorker, getActiveCount, getActiveTaskIds, stopTask, } from "./spawner.js";
|
|
11
|
-
import { AGENT_VERSION } from "./version.js";
|
|
12
|
-
import { selfUpdate, restartAgent } from "./updater.js";
|
|
13
|
-
// Track tasks currently being planned (to avoid double-dispatching)
|
|
14
|
-
const planningInProgress = new Set();
|
|
15
|
-
// Track manager tasks in progress (to avoid double-dispatching)
|
|
16
|
-
const managerInProgress = new Set();
|
|
17
|
-
// Cached org config
|
|
18
|
-
let orgConfig = null;
|
|
19
|
-
// Flags to avoid spamming update notices every heartbeat
|
|
20
|
-
let updateNoticePrinted = false;
|
|
21
|
-
let updateInProgress = false;
|
|
22
|
-
/** Timestamp prefix for log lines */
|
|
23
|
-
function ts() {
|
|
24
|
-
return chalk.dim(new Date().toLocaleTimeString());
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Fetch org config from the cloud API (cached).
|
|
28
|
-
*/
|
|
29
|
-
async function getOrgConfig() {
|
|
30
|
-
if (orgConfig)
|
|
31
|
-
return orgConfig;
|
|
32
|
-
try {
|
|
33
|
-
const response = await api.get("/api/agent/config");
|
|
34
|
-
orgConfig = response.data;
|
|
35
|
-
return orgConfig;
|
|
36
|
-
}
|
|
37
|
-
catch (error) {
|
|
38
|
-
console.error(`${ts()} ${chalk.red("✗")} Failed to fetch org config`);
|
|
39
|
-
return {};
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Run a single poll iteration.
|
|
44
|
-
*/
|
|
45
|
-
async function pollOnce(config) {
|
|
46
|
-
// Skip polling when a required update is in progress
|
|
47
|
-
if (updateInProgress)
|
|
48
|
-
return;
|
|
49
|
-
try {
|
|
50
|
-
const response = await api.get("/api/agent/poll", {
|
|
51
|
-
params: { agentId: config.agentId },
|
|
52
|
-
});
|
|
53
|
-
const tasks = response.data.tasks;
|
|
54
|
-
if (tasks.length === 0)
|
|
55
|
-
return;
|
|
56
|
-
for (const task of tasks) {
|
|
57
|
-
if (task.status === "planning" && !planningInProgress.has(task.id)) {
|
|
58
|
-
// Claim and plan
|
|
59
|
-
await handlePlanningTask(task, config);
|
|
60
|
-
}
|
|
61
|
-
else if (task.status === "queued") {
|
|
62
|
-
// Claim and spawn
|
|
63
|
-
await handleQueuedTask(task, config);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
// Handle manager tasks (log analysis, PR review)
|
|
67
|
-
const managerTasks = response.data.managerTasks;
|
|
68
|
-
if (managerTasks && managerTasks.length > 0) {
|
|
69
|
-
for (const mt of managerTasks) {
|
|
70
|
-
if (!managerInProgress.has(mt.id)) {
|
|
71
|
-
await handleManagerTask(mt, config);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
catch (error) {
|
|
77
|
-
const err = error;
|
|
78
|
-
const busy = planningInProgress.size > 0 || getActiveCount() > 0 || managerInProgress.size > 0;
|
|
79
|
-
if (err.response?.status === 401) {
|
|
80
|
-
if (!busy) {
|
|
81
|
-
console.error(`${ts()} ${chalk.red("✗")} Authentication failed. Check your API key.`);
|
|
82
|
-
}
|
|
83
|
-
// Silent when busy — transient DB pool exhaustion on server
|
|
84
|
-
}
|
|
85
|
-
else if (!busy) {
|
|
86
|
-
console.warn(`${ts()} ${chalk.yellow("⚠")} Poll error: ${err.message || String(error)}`);
|
|
87
|
-
}
|
|
88
|
-
// Silent when busy — expected during heavy planning/execution
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Handle a task in "planning" status.
|
|
93
|
-
*/
|
|
94
|
-
async function handlePlanningTask(task, config) {
|
|
95
|
-
// Claim the task (also returns org credentials for provider API keys)
|
|
96
|
-
let credentials;
|
|
97
|
-
let claimedTask;
|
|
98
|
-
try {
|
|
99
|
-
const claimResponse = await api.post("/api/agent/claim", {
|
|
100
|
-
taskId: task.id,
|
|
101
|
-
agentId: config.agentId,
|
|
102
|
-
});
|
|
103
|
-
if (!claimResponse.data.claimed) {
|
|
104
|
-
return; // Another agent or cloud orchestrator claimed it
|
|
105
|
-
}
|
|
106
|
-
credentials = claimResponse.data.credentials;
|
|
107
|
-
claimedTask = claimResponse.data.task;
|
|
108
|
-
}
|
|
109
|
-
catch {
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
const taskLabel = chalk.cyan(task.id.slice(0, 8));
|
|
113
|
-
// Check if this is a retry with an existing plan (resume scenario).
|
|
114
|
-
// The API preserves planJson/executionPlanV2 on retry when stories exist,
|
|
115
|
-
// so we can skip planning entirely and transition straight to queued.
|
|
116
|
-
const isRetryWithPlan = claimedTask &&
|
|
117
|
-
(claimedTask.retryCount ?? 0) > 0 &&
|
|
118
|
-
claimedTask.executionPlanV2 != null;
|
|
119
|
-
if (isRetryWithPlan) {
|
|
120
|
-
console.log();
|
|
121
|
-
console.log(`${ts()} ${chalk.magenta("◆ RESUME")} ${taskLabel} ${task.summary.substring(0, 60)}`);
|
|
122
|
-
console.log(`${ts()} ${taskLabel} Retry #${claimedTask.retryCount} with existing plan — skipping planning`);
|
|
123
|
-
planningInProgress.add(task.id);
|
|
124
|
-
// Tell the API to resume with the existing plan (planning → queued)
|
|
125
|
-
try {
|
|
126
|
-
await api.post("/api/agent/resume-plan", {
|
|
127
|
-
taskId: task.id,
|
|
128
|
-
agentId: config.agentId,
|
|
129
|
-
});
|
|
130
|
-
console.log(`${ts()} ${taskLabel} ${chalk.green("✓")} Resumed with existing plan → ${chalk.green("queued")}`);
|
|
131
|
-
}
|
|
132
|
-
catch (err) {
|
|
133
|
-
const error = err;
|
|
134
|
-
const detail = error.response?.data?.error || error.message || String(err);
|
|
135
|
-
console.error(`${ts()} ${taskLabel} ${chalk.red("✗")} Resume failed: ${detail}`);
|
|
136
|
-
}
|
|
137
|
-
planningInProgress.delete(task.id);
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
console.log();
|
|
141
|
-
console.log(`${ts()} ${chalk.magenta("◆ PLANNING")} ${taskLabel} ${task.summary.substring(0, 60)}`);
|
|
142
|
-
planningInProgress.add(task.id);
|
|
143
|
-
// Run planning asynchronously (don't block the poll loop)
|
|
144
|
-
planTask(task, config, credentials)
|
|
145
|
-
.then((success) => {
|
|
146
|
-
if (success) {
|
|
147
|
-
console.log(`${ts()} ${chalk.green("✓")} Planning complete for ${taskLabel}`);
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
console.log(`${ts()} ${chalk.red("✗")} Planning failed for ${taskLabel}`);
|
|
151
|
-
}
|
|
152
|
-
})
|
|
153
|
-
.catch((err) => console.error(`${ts()} ${chalk.red("✗")} Planning error for ${taskLabel}:`, err.message || err))
|
|
154
|
-
.finally(() => planningInProgress.delete(task.id));
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* Handle a task in "queued" status.
|
|
158
|
-
*/
|
|
159
|
-
async function handleQueuedTask(task, config) {
|
|
160
|
-
// Check concurrency limit
|
|
161
|
-
const activeCount = getActiveCount();
|
|
162
|
-
if (activeCount >= config.maxWorkers) {
|
|
163
|
-
return; // At capacity
|
|
164
|
-
}
|
|
165
|
-
// Claim the task
|
|
166
|
-
let claimData;
|
|
167
|
-
try {
|
|
168
|
-
const claimResponse = await api.post("/api/agent/claim", {
|
|
169
|
-
taskId: task.id,
|
|
170
|
-
agentId: config.agentId,
|
|
171
|
-
});
|
|
172
|
-
claimData = claimResponse.data;
|
|
173
|
-
if (!claimData.claimed) {
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
catch {
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
// Report started
|
|
181
|
-
try {
|
|
182
|
-
await api.post("/api/agent/started", {
|
|
183
|
-
taskId: task.id,
|
|
184
|
-
agentId: config.agentId,
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
catch (err) {
|
|
188
|
-
const taskLabel = chalk.cyan(task.id.slice(0, 8));
|
|
189
|
-
console.warn(`${ts()} ${chalk.yellow("⚠")} Failed to report started for ${taskLabel}`);
|
|
190
|
-
}
|
|
191
|
-
const taskLabel = chalk.cyan(task.id.slice(0, 8));
|
|
192
|
-
console.log();
|
|
193
|
-
console.log(`${ts()} ${chalk.blue("▶ EXECUTING")} ${taskLabel} ${task.summary.substring(0, 60)}`);
|
|
194
|
-
const oc = await getOrgConfig();
|
|
195
|
-
const spawnableTask = claimData.task || {
|
|
196
|
-
id: task.id,
|
|
197
|
-
summary: task.summary,
|
|
198
|
-
description: task.description,
|
|
199
|
-
jiraIssueKey: task.jiraIssueKey,
|
|
200
|
-
workerModel: task.workerModel,
|
|
201
|
-
workerProvider: task.workerProvider,
|
|
202
|
-
githubRepo: task.githubRepo,
|
|
203
|
-
scmProvider: task.scmProvider,
|
|
204
|
-
skipManagerReview: task.skipManagerReview,
|
|
205
|
-
deploymentEnabled: task.deploymentEnabled,
|
|
206
|
-
improvementEnabled: task.improvementEnabled,
|
|
207
|
-
qualityGateBypass: task.qualityGateBypass,
|
|
208
|
-
standardSdkMode: task.standardSdkMode,
|
|
209
|
-
parentTaskId: task.parentTaskId,
|
|
210
|
-
taskNotes: task.taskNotes,
|
|
211
|
-
githubPrUrl: task.githubPrUrl,
|
|
212
|
-
githubPrNumber: task.githubPrNumber,
|
|
213
|
-
executionPlanV2: task.executionPlanV2,
|
|
214
|
-
jiraFields: task.jiraFields || {},
|
|
215
|
-
};
|
|
216
|
-
// Pass org credentials from the claim response to the container
|
|
217
|
-
const credentials = claimData.credentials;
|
|
218
|
-
// Spawn asynchronously (don't block the poll loop)
|
|
219
|
-
spawnWorker(spawnableTask, config, oc, credentials).catch((err) => console.error(`${ts()} ${chalk.red("✗")} Spawn failed for ${taskLabel}:`, err.message || err));
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* Handle a manager task (log analysis or PR review).
|
|
223
|
-
*/
|
|
224
|
-
async function handleManagerTask(task, config) {
|
|
225
|
-
const taskLabel = chalk.cyan(task.id.slice(0, 8));
|
|
226
|
-
managerInProgress.add(task.id);
|
|
227
|
-
// Claim the manager task
|
|
228
|
-
try {
|
|
229
|
-
const claimResponse = await api.post("/api/agent/claim-manager", {
|
|
230
|
-
taskId: task.id,
|
|
231
|
-
agentId: config.agentId,
|
|
232
|
-
action: task.managerAction,
|
|
233
|
-
});
|
|
234
|
-
if (!claimResponse.data.claimed) {
|
|
235
|
-
managerInProgress.delete(task.id);
|
|
236
|
-
return; // Another agent or cloud ECS claimed it
|
|
237
|
-
}
|
|
238
|
-
const claimedTask = claimResponse.data.task;
|
|
239
|
-
const credentials = claimResponse.data.credentials || {};
|
|
240
|
-
const actionLabel = task.managerAction === "analyze_logs"
|
|
241
|
-
? chalk.yellow("LOG ANALYSIS")
|
|
242
|
-
: chalk.yellow("PR REVIEW");
|
|
243
|
-
console.log();
|
|
244
|
-
console.log(`${ts()} ${chalk.magenta("◆ MANAGER")} ${actionLabel} ${taskLabel} ${task.summary.substring(0, 60)}`);
|
|
245
|
-
const managerTask = {
|
|
246
|
-
id: task.id,
|
|
247
|
-
summary: claimedTask?.summary || task.summary,
|
|
248
|
-
description: claimedTask?.description || task.description,
|
|
249
|
-
jiraIssueKey: claimedTask?.jiraIssueKey || task.jiraIssueKey,
|
|
250
|
-
githubRepo: claimedTask?.githubRepo || task.githubRepo,
|
|
251
|
-
scmProvider: claimedTask?.scmProvider || task.scmProvider,
|
|
252
|
-
githubPrUrl: claimedTask?.githubPrUrl || task.githubPrUrl,
|
|
253
|
-
githubPrNumber: claimedTask?.githubPrNumber || task.githubPrNumber,
|
|
254
|
-
managerAction: task.managerAction,
|
|
255
|
-
};
|
|
256
|
-
// Spawn asynchronously (don't block the poll loop)
|
|
257
|
-
spawnManagerWorker(managerTask, config, credentials)
|
|
258
|
-
.then(() => {
|
|
259
|
-
console.log(`${ts()} ${taskLabel} ${chalk.magenta("MGR")} ${chalk.green("✓")} Manager ${task.managerAction} dispatched`);
|
|
260
|
-
})
|
|
261
|
-
.catch((err) => {
|
|
262
|
-
console.error(`${ts()} ${taskLabel} ${chalk.magenta("MGR")} ${chalk.red("✗")} Manager spawn failed:`, err.message || err);
|
|
263
|
-
})
|
|
264
|
-
.finally(() => managerInProgress.delete(task.id));
|
|
265
|
-
}
|
|
266
|
-
catch (err) {
|
|
267
|
-
managerInProgress.delete(task.id);
|
|
268
|
-
const error = err;
|
|
269
|
-
console.error(`${ts()} ${taskLabel} ${chalk.red("✗")} Failed to claim manager task:`, error.message || String(err));
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
// Store interval IDs so they can be cleared on shutdown
|
|
273
|
-
let pollIntervalId = null;
|
|
274
|
-
let heartbeatIntervalId = null;
|
|
275
|
-
/**
|
|
276
|
-
* Stop all polling and heartbeat loops.
|
|
277
|
-
* Called during graceful shutdown to prevent the event loop from staying alive.
|
|
278
|
-
*/
|
|
279
|
-
export function stopPolling() {
|
|
280
|
-
if (pollIntervalId) {
|
|
281
|
-
clearInterval(pollIntervalId);
|
|
282
|
-
pollIntervalId = null;
|
|
283
|
-
}
|
|
284
|
-
if (heartbeatIntervalId) {
|
|
285
|
-
clearInterval(heartbeatIntervalId);
|
|
286
|
-
heartbeatIntervalId = null;
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
/**
|
|
290
|
-
* Start the poll loop.
|
|
291
|
-
*/
|
|
292
|
-
export function startPolling(config) {
|
|
293
|
-
console.log(` ${chalk.dim("Polling every")} ${config.pollIntervalMs / 1000}s ${chalk.dim("· waiting for tasks...")}`);
|
|
294
|
-
// Initial poll
|
|
295
|
-
pollOnce(config);
|
|
296
|
-
// Recurring poll
|
|
297
|
-
pollIntervalId = setInterval(() => pollOnce(config), config.pollIntervalMs);
|
|
298
|
-
}
|
|
299
|
-
/**
|
|
300
|
-
* Start the heartbeat loop.
|
|
301
|
-
*/
|
|
302
|
-
export function startHeartbeat(config) {
|
|
303
|
-
heartbeatIntervalId = setInterval(async () => {
|
|
304
|
-
// Include BOTH running containers AND tasks being planned/managed
|
|
305
|
-
const containerTaskIds = getActiveTaskIds();
|
|
306
|
-
const planningTaskIds = Array.from(planningInProgress);
|
|
307
|
-
const managerTaskIds = Array.from(managerInProgress);
|
|
308
|
-
const activeTaskIds = [...containerTaskIds, ...planningTaskIds, ...managerTaskIds];
|
|
309
|
-
try {
|
|
310
|
-
const response = await api.post("/api/agent/heartbeat", {
|
|
311
|
-
agentId: config.agentId,
|
|
312
|
-
activeTasks: activeTaskIds,
|
|
313
|
-
agentVersion: AGENT_VERSION,
|
|
314
|
-
});
|
|
315
|
-
// Stop containers for tasks cancelled via the cloud dashboard
|
|
316
|
-
const cancelledTasks = response.data?.cancelledTasks;
|
|
317
|
-
if (cancelledTasks && cancelledTasks.length > 0) {
|
|
318
|
-
for (const taskId of cancelledTasks) {
|
|
319
|
-
stopTask(taskId);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
// Handle update signals from server
|
|
323
|
-
const { updateAvailable, updateRequired, latestVersion } = response.data ?? {};
|
|
324
|
-
if (updateRequired && !updateInProgress) {
|
|
325
|
-
updateInProgress = true;
|
|
326
|
-
console.log(`${ts()} ${chalk.red("⚠ Agent update required")} (current: ${AGENT_VERSION}, required: ${latestVersion})`);
|
|
327
|
-
console.log(`${ts()} ${chalk.yellow("Refusing new tasks until updated.")}`);
|
|
328
|
-
const success = await selfUpdate();
|
|
329
|
-
if (success) {
|
|
330
|
-
restartAgent();
|
|
331
|
-
}
|
|
332
|
-
else {
|
|
333
|
-
console.log(`${ts()} ${chalk.red("Auto-update failed.")} Run: npm install -g @workermill/agent@latest`);
|
|
334
|
-
updateInProgress = false;
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
else if (updateAvailable && !updateNoticePrinted && !updateRequired) {
|
|
338
|
-
updateNoticePrinted = true;
|
|
339
|
-
console.log(`${ts()} ${chalk.yellow(`Update available: ${latestVersion}`)} (current: ${AGENT_VERSION}). Run: workermill-agent update`);
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
catch {
|
|
343
|
-
// Heartbeat failures are non-critical
|
|
344
|
-
}
|
|
345
|
-
}, config.heartbeatIntervalMs);
|
|
346
|
-
}
|
package/dist/providers.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Lightweight HTTP wrappers for text generation across AI providers.
|
|
3
|
-
*
|
|
4
|
-
* Used for planning and critic stages when the org's provider is not Anthropic.
|
|
5
|
-
* No heavy SDK dependencies — uses the existing axios dependency for HTTP calls.
|
|
6
|
-
* Streaming is not needed (planning/critic are text-only, result matters).
|
|
7
|
-
*/
|
|
8
|
-
export type AIProvider = "anthropic" | "openai" | "google" | "ollama";
|
|
9
|
-
export interface GenerateTextOptions {
|
|
10
|
-
maxTokens?: number;
|
|
11
|
-
temperature?: number;
|
|
12
|
-
timeoutMs?: number;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Generate text from any supported AI provider via direct HTTP API calls.
|
|
16
|
-
* Returns the raw text response.
|
|
17
|
-
*/
|
|
18
|
-
export declare function generateText(provider: AIProvider, model: string, prompt: string, apiKey: string, options?: GenerateTextOptions): Promise<string>;
|
package/dist/providers.js
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Lightweight HTTP wrappers for text generation across AI providers.
|
|
3
|
-
*
|
|
4
|
-
* Used for planning and critic stages when the org's provider is not Anthropic.
|
|
5
|
-
* No heavy SDK dependencies — uses the existing axios dependency for HTTP calls.
|
|
6
|
-
* Streaming is not needed (planning/critic are text-only, result matters).
|
|
7
|
-
*/
|
|
8
|
-
import axios from "axios";
|
|
9
|
-
const DEFAULT_MAX_TOKENS = 16384;
|
|
10
|
-
const DEFAULT_TIMEOUT_MS = 600_000; // 10 minutes (matches Claude CLI timeout)
|
|
11
|
-
/**
|
|
12
|
-
* Generate text from any supported AI provider via direct HTTP API calls.
|
|
13
|
-
* Returns the raw text response.
|
|
14
|
-
*/
|
|
15
|
-
export async function generateText(provider, model, prompt, apiKey, options) {
|
|
16
|
-
const maxTokens = options?.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
17
|
-
const temperature = options?.temperature ?? 0.7;
|
|
18
|
-
const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
19
|
-
switch (provider) {
|
|
20
|
-
case "anthropic":
|
|
21
|
-
return generateAnthropic(model, prompt, apiKey, maxTokens, temperature, timeoutMs);
|
|
22
|
-
case "openai":
|
|
23
|
-
return generateOpenAI(model, prompt, apiKey, maxTokens, temperature, timeoutMs);
|
|
24
|
-
case "google":
|
|
25
|
-
return generateGoogle(model, prompt, apiKey, maxTokens, temperature, timeoutMs);
|
|
26
|
-
case "ollama":
|
|
27
|
-
return generateOllama(model, prompt, apiKey, maxTokens, temperature, timeoutMs);
|
|
28
|
-
default:
|
|
29
|
-
throw new Error(`Unsupported AI provider: ${provider}`);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Anthropic Messages API (for orgs with API key, not CLI).
|
|
34
|
-
*/
|
|
35
|
-
async function generateAnthropic(model, prompt, apiKey, maxTokens, temperature, timeoutMs) {
|
|
36
|
-
const response = await axios.post("https://api.anthropic.com/v1/messages", {
|
|
37
|
-
model,
|
|
38
|
-
max_tokens: maxTokens,
|
|
39
|
-
temperature,
|
|
40
|
-
messages: [{ role: "user", content: prompt }],
|
|
41
|
-
}, {
|
|
42
|
-
headers: {
|
|
43
|
-
"x-api-key": apiKey,
|
|
44
|
-
"anthropic-version": "2023-06-01",
|
|
45
|
-
"Content-Type": "application/json",
|
|
46
|
-
},
|
|
47
|
-
timeout: timeoutMs,
|
|
48
|
-
});
|
|
49
|
-
const content = response.data?.content;
|
|
50
|
-
if (Array.isArray(content)) {
|
|
51
|
-
return content
|
|
52
|
-
.filter((block) => block.type === "text")
|
|
53
|
-
.map((block) => block.text)
|
|
54
|
-
.join("");
|
|
55
|
-
}
|
|
56
|
-
throw new Error("Unexpected Anthropic API response format");
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* OpenAI Chat Completions API.
|
|
60
|
-
*/
|
|
61
|
-
async function generateOpenAI(model, prompt, apiKey, maxTokens, temperature, timeoutMs) {
|
|
62
|
-
const response = await axios.post("https://api.openai.com/v1/chat/completions", {
|
|
63
|
-
model,
|
|
64
|
-
max_tokens: maxTokens,
|
|
65
|
-
temperature,
|
|
66
|
-
messages: [{ role: "user", content: prompt }],
|
|
67
|
-
}, {
|
|
68
|
-
headers: {
|
|
69
|
-
Authorization: `Bearer ${apiKey}`,
|
|
70
|
-
"Content-Type": "application/json",
|
|
71
|
-
},
|
|
72
|
-
timeout: timeoutMs,
|
|
73
|
-
});
|
|
74
|
-
const message = response.data?.choices?.[0]?.message;
|
|
75
|
-
if (message?.content)
|
|
76
|
-
return message.content;
|
|
77
|
-
throw new Error("Unexpected OpenAI API response format");
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Google Generative AI (Gemini) API.
|
|
81
|
-
*/
|
|
82
|
-
async function generateGoogle(model, prompt, apiKey, maxTokens, temperature, timeoutMs) {
|
|
83
|
-
const response = await axios.post(`https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`, {
|
|
84
|
-
contents: [{ parts: [{ text: prompt }] }],
|
|
85
|
-
generationConfig: {
|
|
86
|
-
maxOutputTokens: maxTokens,
|
|
87
|
-
temperature,
|
|
88
|
-
},
|
|
89
|
-
}, {
|
|
90
|
-
headers: { "Content-Type": "application/json" },
|
|
91
|
-
timeout: timeoutMs,
|
|
92
|
-
});
|
|
93
|
-
const candidate = response.data?.candidates?.[0];
|
|
94
|
-
const text = candidate?.content?.parts?.[0]?.text;
|
|
95
|
-
if (text)
|
|
96
|
-
return text;
|
|
97
|
-
throw new Error("Unexpected Google AI API response format");
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Ollama Generate API (self-hosted).
|
|
101
|
-
* `apiKey` is used as the Ollama base URL (e.g. "http://localhost:11434").
|
|
102
|
-
*/
|
|
103
|
-
async function generateOllama(model, prompt, ollamaHost, _maxTokens, temperature, timeoutMs) {
|
|
104
|
-
const baseUrl = ollamaHost || "http://localhost:11434";
|
|
105
|
-
const response = await axios.post(`${baseUrl}/api/generate`, {
|
|
106
|
-
model,
|
|
107
|
-
prompt,
|
|
108
|
-
stream: false,
|
|
109
|
-
options: { temperature },
|
|
110
|
-
}, {
|
|
111
|
-
headers: { "Content-Type": "application/json" },
|
|
112
|
-
timeout: timeoutMs,
|
|
113
|
-
});
|
|
114
|
-
const text = response.data?.response;
|
|
115
|
-
if (text)
|
|
116
|
-
return text;
|
|
117
|
-
throw new Error("Unexpected Ollama API response format");
|
|
118
|
-
}
|
package/dist/spawner.d.ts
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Remote Agent Spawner
|
|
3
|
-
*
|
|
4
|
-
* Spawns Docker worker containers that talk directly to the cloud WorkerMill API.
|
|
5
|
-
* Extracted from api/src/services/local-epic-spawner.ts with key differences:
|
|
6
|
-
* - API_BASE_URL points to cloud (https://workermill.com)
|
|
7
|
-
* - ORG_API_KEY is the real org API key
|
|
8
|
-
* - Container logs stream to cloud dashboard via SSE
|
|
9
|
-
*/
|
|
10
|
-
import type { AgentConfig } from "./config.js";
|
|
11
|
-
export interface SpawnableTask {
|
|
12
|
-
id: string;
|
|
13
|
-
orgId?: string;
|
|
14
|
-
summary: string;
|
|
15
|
-
description: string | null;
|
|
16
|
-
jiraIssueKey: string | null;
|
|
17
|
-
workerModel: string;
|
|
18
|
-
workerProvider?: string;
|
|
19
|
-
workerPersona?: string;
|
|
20
|
-
githubRepo: string;
|
|
21
|
-
scmProvider: string;
|
|
22
|
-
skipManagerReview?: boolean;
|
|
23
|
-
executionPlanV2: unknown;
|
|
24
|
-
jiraFields: Record<string, unknown>;
|
|
25
|
-
taskNotes?: string;
|
|
26
|
-
deploymentEnabled?: boolean;
|
|
27
|
-
improvementEnabled?: boolean;
|
|
28
|
-
qualityGateBypass?: boolean;
|
|
29
|
-
standardSdkMode?: boolean;
|
|
30
|
-
parentTaskId?: string;
|
|
31
|
-
githubPrUrl?: string;
|
|
32
|
-
githubPrNumber?: number;
|
|
33
|
-
retryCount?: number;
|
|
34
|
-
pipelineVersion?: string;
|
|
35
|
-
}
|
|
36
|
-
/** Org credentials returned by /api/agent/claim */
|
|
37
|
-
export interface ClaimCredentials {
|
|
38
|
-
jiraBaseUrl?: string;
|
|
39
|
-
jiraEmail?: string;
|
|
40
|
-
jiraApiToken?: string;
|
|
41
|
-
linearApiKey?: string;
|
|
42
|
-
managerProvider?: string;
|
|
43
|
-
managerModelId?: string;
|
|
44
|
-
customerAwsAccessKeyId?: string;
|
|
45
|
-
customerAwsSecretAccessKey?: string;
|
|
46
|
-
customerAwsRegion?: string;
|
|
47
|
-
customerAwsRoleArn?: string;
|
|
48
|
-
customerAwsExternalId?: string;
|
|
49
|
-
issueTrackerProvider?: string;
|
|
50
|
-
bitbucketEmail?: string;
|
|
51
|
-
githubReviewerToken?: string;
|
|
52
|
-
scmBaseUrl?: string;
|
|
53
|
-
ollamaContextWindow?: number;
|
|
54
|
-
scmToken?: string;
|
|
55
|
-
githubToken?: string;
|
|
56
|
-
bitbucketUsername?: string;
|
|
57
|
-
anthropicApiKey?: string;
|
|
58
|
-
openaiApiKey?: string;
|
|
59
|
-
googleApiKey?: string;
|
|
60
|
-
ollamaBaseUrl?: string;
|
|
61
|
-
vllmBaseUrl?: string;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Spawn a Docker worker container for a task.
|
|
65
|
-
*/
|
|
66
|
-
export declare function spawnWorker(task: SpawnableTask, config: AgentConfig, orgConfig: Record<string, unknown>, credentials?: ClaimCredentials): Promise<void>;
|
|
67
|
-
/**
|
|
68
|
-
* Get count of actively running containers.
|
|
69
|
-
*/
|
|
70
|
-
export declare function getActiveCount(): number;
|
|
71
|
-
/**
|
|
72
|
-
* Get IDs of all active tasks.
|
|
73
|
-
*/
|
|
74
|
-
export declare function getActiveTaskIds(): string[];
|
|
75
|
-
/**
|
|
76
|
-
* Stop a specific task's container by task ID.
|
|
77
|
-
*/
|
|
78
|
-
export declare function stopTask(taskId: string): void;
|
|
79
|
-
/**
|
|
80
|
-
* Stop all running containers.
|
|
81
|
-
*/
|
|
82
|
-
export declare function stopAll(): Promise<void>;
|
|
83
|
-
/** Manager task returned by the poll endpoint */
|
|
84
|
-
export interface ManagerTask {
|
|
85
|
-
id: string;
|
|
86
|
-
summary: string;
|
|
87
|
-
description: string | null;
|
|
88
|
-
jiraIssueKey: string | null;
|
|
89
|
-
githubRepo: string;
|
|
90
|
-
scmProvider: string;
|
|
91
|
-
githubPrUrl?: string;
|
|
92
|
-
githubPrNumber?: number;
|
|
93
|
-
managerAction: "analyze_logs" | "review_pr";
|
|
94
|
-
}
|
|
95
|
-
/** Credentials for manager tasks (subset of ClaimCredentials) */
|
|
96
|
-
export interface ManagerCredentials {
|
|
97
|
-
managerProvider?: string;
|
|
98
|
-
managerModelId?: string;
|
|
99
|
-
anthropicApiKey?: string;
|
|
100
|
-
openaiApiKey?: string;
|
|
101
|
-
googleApiKey?: string;
|
|
102
|
-
ollamaBaseUrl?: string;
|
|
103
|
-
jiraBaseUrl?: string;
|
|
104
|
-
jiraEmail?: string;
|
|
105
|
-
jiraApiToken?: string;
|
|
106
|
-
linearApiKey?: string;
|
|
107
|
-
issueTrackerProvider?: string;
|
|
108
|
-
scmToken?: string;
|
|
109
|
-
githubToken?: string;
|
|
110
|
-
bitbucketUsername?: string;
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Spawn a manager Docker container for PR review or log analysis.
|
|
114
|
-
* Uses the same worker image but overrides the entrypoint to manager-entrypoint.sh.
|
|
115
|
-
*/
|
|
116
|
-
export declare function spawnManagerWorker(task: ManagerTask, config: AgentConfig, credentials?: ManagerCredentials): Promise<void>;
|