agents-relay 1.0.9 → 1.0.11
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/dist/pool.js
CHANGED
|
@@ -21,6 +21,7 @@ export class RepositoryWorkerPool {
|
|
|
21
21
|
makeReconciler;
|
|
22
22
|
running = false;
|
|
23
23
|
pending = false;
|
|
24
|
+
jobTargets = new Map();
|
|
24
25
|
constructor(client, repository, trustedAuthors, concurrency, makeReconciler) {
|
|
25
26
|
this.client = client;
|
|
26
27
|
this.trustedAuthors = trustedAuthors;
|
|
@@ -30,6 +31,8 @@ export class RepositoryWorkerPool {
|
|
|
30
31
|
}
|
|
31
32
|
repositories;
|
|
32
33
|
async reconcileDiscovered(discovered) {
|
|
34
|
+
for (const item of discovered)
|
|
35
|
+
this.jobTargets.set(item.job.id, { repository: item.job.repository, prNumber: item.job.prNumber });
|
|
33
36
|
// Terminal PRs must be reconciled before OPEN-job scheduling. Otherwise the
|
|
34
37
|
// OPEN-only runnable filter can strand durable jobs after GitHub merges/closes them.
|
|
35
38
|
for (const job of terminalManagedJobs(discovered)) {
|
|
@@ -71,11 +74,25 @@ export class RepositoryWorkerPool {
|
|
|
71
74
|
async reconcileTarget(repository, prNumber, jobId) {
|
|
72
75
|
if (!this.repositories.includes(repository))
|
|
73
76
|
return;
|
|
77
|
+
this.jobTargets.set(jobId, { repository, prNumber });
|
|
74
78
|
const store = new GitHubStore(this.client, repository, prNumber, this.trustedAuthors);
|
|
75
79
|
await this.makeReconciler(store, Math.max(1, this.concurrency)).reconcile(jobId);
|
|
76
80
|
}
|
|
81
|
+
async handleTerminalEvent(event) {
|
|
82
|
+
const target = this.jobTargets.get(event.job_id);
|
|
83
|
+
if (!target || !this.repositories.includes(target.repository)) {
|
|
84
|
+
process.stderr.write(`warning: terminal event target unknown for job ${event.job_id}\n`);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const store = new GitHubStore(this.client, target.repository, target.prNumber, this.trustedAuthors);
|
|
88
|
+
await this.makeReconciler(store, Math.max(1, this.concurrency)).handleEvent(event);
|
|
89
|
+
}
|
|
77
90
|
async watch(bus) {
|
|
78
91
|
return bus.subscribeAll(async (event) => {
|
|
92
|
+
if (['task.completed', 'task.failed', 'task.blocked'].includes(event.type)) {
|
|
93
|
+
await this.handleTerminalEvent(event);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
79
96
|
if (event.type === 'job.wake' || event.type === 'github.webhook') {
|
|
80
97
|
const repository = typeof event.data?.repository === 'string' ? event.data.repository : '';
|
|
81
98
|
const prNumber = Number(event.data?.prNumber);
|
package/dist/reconciler.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { schedule, transitionTask } from './scheduler.js';
|
|
3
|
+
import { LaunchFailure } from './adapters.js';
|
|
3
4
|
import { eventFor } from './events.js';
|
|
4
5
|
import { parsePlannerResult, plannerInput } from './planner.js';
|
|
5
6
|
const PRIORITY_RANK = { P0: 0, P1: 1, P2: 2, P3: 3 };
|
|
@@ -50,18 +51,19 @@ export class Reconciler {
|
|
|
50
51
|
this.store = store;
|
|
51
52
|
this.options = options;
|
|
52
53
|
}
|
|
54
|
+
async handleEvent(event) {
|
|
55
|
+
if (['task.completed', 'task.failed', 'task.blocked'].includes(event.type)) {
|
|
56
|
+
await this.applyTerminalEvent(event);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (event.type === 'job.wake' || event.type === 'github.webhook')
|
|
60
|
+
await this.reconcile(event.job_id);
|
|
61
|
+
}
|
|
53
62
|
async watch(jobId) {
|
|
54
63
|
if (!this.options.eventBus)
|
|
55
64
|
return async () => { };
|
|
56
65
|
try {
|
|
57
|
-
return await this.options.eventBus.subscribe(jobId,
|
|
58
|
-
if (['task.completed', 'task.failed', 'task.blocked'].includes(event.type)) {
|
|
59
|
-
await this.applyTerminalEvent(event);
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
if (event.type === 'job.wake' || event.type === 'github.webhook')
|
|
63
|
-
await this.reconcile(jobId);
|
|
64
|
-
});
|
|
66
|
+
return await this.options.eventBus.subscribe(jobId, event => this.handleEvent(event));
|
|
65
67
|
}
|
|
66
68
|
catch (error) {
|
|
67
69
|
await this.reportTransportFailure(error);
|
|
@@ -244,7 +246,9 @@ export class Reconciler {
|
|
|
244
246
|
this.detach(this.timeoutTask(job.id, task.id, durableExecutionId), job.id, task.id, 'worker terminal-event timeout');
|
|
245
247
|
}, Math.max(1, task.timeoutMs));
|
|
246
248
|
this.terminalTimers.set(task.id, terminalTimer);
|
|
247
|
-
this.detach(execution.promise.then(result => this.runtimeSettled(job.id, task.id, durableExecutionId, result, null), error =>
|
|
249
|
+
this.detach(execution.promise.then(result => this.runtimeSettled(job.id, task.id, durableExecutionId, result, null), error => error instanceof LaunchFailure
|
|
250
|
+
? this.failLaunch(job.id, task.id, durableExecutionId, error.message, 'delivery')
|
|
251
|
+
: this.runtimeSettled(job.id, task.id, durableExecutionId, null, error instanceof Error ? error.message : String(error))), job.id, task.id, 'worker runtime completion');
|
|
248
252
|
}
|
|
249
253
|
async launchPlanner(job, task) {
|
|
250
254
|
const planner = this.options.planner;
|
|
@@ -343,12 +347,12 @@ export class Reconciler {
|
|
|
343
347
|
clearTimeout(timer);
|
|
344
348
|
this.terminalTimers.delete(taskId);
|
|
345
349
|
}
|
|
346
|
-
async failLaunch(jobId, taskId, executionId, message) {
|
|
350
|
+
async failLaunch(jobId, taskId, executionId, message, phase = 'launch') {
|
|
347
351
|
const job = await this.store.load(jobId);
|
|
348
352
|
const task = job.tasks.find(item => item.id === taskId);
|
|
349
353
|
if (!task || task.executionId !== executionId || task.state !== 'RUNNING')
|
|
350
354
|
return;
|
|
351
|
-
const event = eventFor(jobId, taskId, task.parentTaskId, 'task.failed', 'failed', `Worker
|
|
355
|
+
const event = eventFor(jobId, taskId, task.parentTaskId, 'task.failed', 'failed', `Worker ${phase} failed: ${message}`, 'user', { phase });
|
|
352
356
|
await this.applyTerminalEvent(event);
|
|
353
357
|
await this.emit(event);
|
|
354
358
|
}
|
package/package.json
CHANGED
|
@@ -144,16 +144,13 @@ else:
|
|
|
144
144
|
attachments = _upload_files(CFG.get("file", []))
|
|
145
145
|
selector = _composer()
|
|
146
146
|
before_count = len(_user_turns())
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
click_at_xy(info["x"], info["y"])
|
|
155
|
-
press_key("CTRL+A")
|
|
156
|
-
type_text(CFG["prompt"])
|
|
147
|
+
info = js(f"""(() => {{
|
|
148
|
+
const e=document.querySelector({json.dumps(selector)});
|
|
149
|
+
const r=e.getBoundingClientRect();
|
|
150
|
+
return {{x:r.x+r.width/2,y:r.y+r.height/2}};
|
|
151
|
+
}})()""")
|
|
152
|
+
click_at_xy(info["x"], info["y"])
|
|
153
|
+
type_text(CFG["prompt"])
|
|
157
154
|
if CFG["prompt"].strip() not in _composer_text(selector):
|
|
158
155
|
raise RuntimeError("Temporary Chat prompt was not observed in the composer")
|
|
159
156
|
|