agents-relay 1.0.111 → 1.0.113
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/cli-help.js +2 -2
- package/dist/cli.js +10 -3
- package/dist/planner.js +1 -1
- package/dist/reconciler.js +7 -1
- package/dist/relayd.js +2 -2
- package/dist/workspace.js +16 -3
- package/package.json +1 -1
package/dist/cli-help.js
CHANGED
|
@@ -44,7 +44,7 @@ Example:
|
|
|
44
44
|
|
|
45
45
|
Required: --repo OWNER/REPO, --id JOB_ID, and either --head BRANCH or --pr NUMBER.
|
|
46
46
|
With --head, reuse/create the PR for that head. With --pr, bind an existing unmanaged PR.
|
|
47
|
-
Common: --base BRANCH (default: main), --title TEXT, --objective-file PATH|- (preferred), --objective MARKDOWN (short/simple only), --priority P0|P1|P2|P3, --mode fixed|autonomous, --no-auto-merge, --no-review. --objective and --objective-file are mutually exclusive. For a new --head Job, one is required and must contain enough standalone context to complete the Job without the originating chat/thread. Objective Markdown is also the default PR body; --body is an explicit override.
|
|
47
|
+
Common: --base BRANCH (default: main), --title TEXT, --objective-file PATH|- (preferred), --objective MARKDOWN (short/simple only), --project-path RELATIVE_PATH, --priority P0|P1|P2|P3, --mode fixed|autonomous, --no-auto-merge, --no-review. --objective and --objective-file are mutually exclusive. For a new --head Job, one is required and must contain enough standalone context to complete the Job without the originating chat/thread. Objective Markdown is also the default PR body; --body is an explicit override.
|
|
48
48
|
Job creation never creates executable tasks. The orchestrator decides the initial task batch separately. Re-running create against an already healthy Job is idempotent and does not mutate its metadata.
|
|
49
49
|
|
|
50
50
|
Example:
|
|
@@ -52,7 +52,7 @@ Example:
|
|
|
52
52
|
'job update': `Partially update mutable metadata on a healthy existing Job.
|
|
53
53
|
|
|
54
54
|
Required: --repo OWNER/REPO, --pr NUMBER, and --id JOB_ID.
|
|
55
|
-
Mutable: --title, --objective-file PATH|- (preferred) or --objective MARKDOWN, --priority, --mode fixed|autonomous, --schedule, --auto-merge|--no-auto-merge, --review|--no-review, and continuation options. Updating the objective also updates the PR body.
|
|
55
|
+
Mutable: --title, --objective-file PATH|- (preferred) or --objective MARKDOWN, --project-path RELATIVE_PATH, --priority, --mode fixed|autonomous, --schedule, --auto-merge|--no-auto-merge, --review|--no-review, and continuation options. Updating the objective also updates the PR body.
|
|
56
56
|
Unspecified fields are preserved. Marker/binding corruption is never repaired implicitly; update fails with a precise diagnostic instead.
|
|
57
57
|
|
|
58
58
|
Example:
|
package/dist/cli.js
CHANGED
|
@@ -18,7 +18,7 @@ import { AgentObjectivePlanner, CommandObjectivePlanner } from './planner.js';
|
|
|
18
18
|
import { extendRetryBudget, transitionJobEvent, transitionTaskEvent } from './scheduler.js';
|
|
19
19
|
import { dueBuckets, processDueScheduledJobs, syncScheduleLabels } from './scheduled-jobs.js';
|
|
20
20
|
import { resolveExecutionContext } from './execution-context.js';
|
|
21
|
-
import { defaultWorkspaceRoot, resolveManagedProjectPath } from './workspace.js';
|
|
21
|
+
import { defaultWorkspaceRoot, resolveManagedProjectPath, resolveRepositoryProjectPath } from './workspace.js';
|
|
22
22
|
import { runBlockerCommand } from './cli-blocker.js';
|
|
23
23
|
import { helpText, usage } from './cli-help.js';
|
|
24
24
|
export { helpText } from './cli-help.js';
|
|
@@ -44,6 +44,7 @@ export async function ensureManagedGitHubJob(client, repositoryName, trustedAuth
|
|
|
44
44
|
id: options.id,
|
|
45
45
|
title: options.title || pr.title || 'Agents Relay job',
|
|
46
46
|
objective: options.objective || pr.body || undefined,
|
|
47
|
+
projectPath: options.projectPath,
|
|
47
48
|
description: pr.body || undefined,
|
|
48
49
|
priority: options.priority ?? 'P2',
|
|
49
50
|
executionMode: options.executionMode ?? 'fixed',
|
|
@@ -179,8 +180,11 @@ async function runTaskCommand(action, args) {
|
|
|
179
180
|
return;
|
|
180
181
|
}
|
|
181
182
|
if (action === 'retry' || action === 'cancel') {
|
|
182
|
-
if (action === 'retry')
|
|
183
|
+
if (action === 'retry') {
|
|
183
184
|
task.maxAttempts = extendRetryBudget(task);
|
|
185
|
+
if (task.kind === 'planner' && task.error)
|
|
186
|
+
task.plannerRetryFeedback = task.error;
|
|
187
|
+
}
|
|
184
188
|
await transitionTaskEvent(task, action === 'retry' ? 'retry' : task.state === 'RUNNING' ? 'task.cancelled' : 'cancel');
|
|
185
189
|
task.error = action === 'retry' ? null : 'Cancelled by user';
|
|
186
190
|
task.leaseOwner = null;
|
|
@@ -323,6 +327,7 @@ async function runJobCommand(action, args) {
|
|
|
323
327
|
id,
|
|
324
328
|
title: arg(args, '--title') || undefined,
|
|
325
329
|
objective: objective || undefined,
|
|
330
|
+
projectPath: arg(args, '--project-path') || undefined,
|
|
326
331
|
priority: priority(args),
|
|
327
332
|
executionMode: requestedExecutionMode(args),
|
|
328
333
|
schedule: scheduleFromArgs(args),
|
|
@@ -382,6 +387,8 @@ async function runJobCommand(action, args) {
|
|
|
382
387
|
throw new Error('Job objective cannot be empty');
|
|
383
388
|
job.objective = objective;
|
|
384
389
|
}
|
|
390
|
+
if (hasArg(args, '--project-path'))
|
|
391
|
+
job.projectPath = arg(args, '--project-path') || undefined;
|
|
385
392
|
if (hasArg(args, '--priority'))
|
|
386
393
|
job.priority = priority(args, job.priority ?? 'P2');
|
|
387
394
|
if (hasArg(args, '--mode') || hasArg(args, '--execution-mode'))
|
|
@@ -414,7 +421,7 @@ async function runJobCommand(action, args) {
|
|
|
414
421
|
}
|
|
415
422
|
export function runtimePlanner(args) { const plannerCommand = arg([...args], '--planner-command'); const modelRuntime = arg([...args], '--codex', 'codex'); return plannerCommand ? new CommandObjectivePlanner(plannerCommand) : new AgentObjectivePlanner(modelRuntime); }
|
|
416
423
|
export function runtimeReviewer() { return { requirements: { capabilities: ['model'] } }; }
|
|
417
|
-
export function runtime(store, args, bus, usageRegistry = codexAndZaiUsageRegistry()) { const emit = (event) => { process.stderr.write(`${JSON.stringify(event)}\n`); }; const modelRuntime = arg(args, '--codex', 'codex'); const policy = chatGptTabClosePolicy(args); const planner = runtimePlanner(args); return new Reconciler(store, { owner: arg(args, '--owner', `cli-${process.pid}`), maxConcurrent: Number(arg(args, '--concurrency', '4')), leaseMs: Number(arg(args, '--lease-ms', '300000')), adapters: [new CodexAdapter(modelRuntime), new ChatGptAdapter({ tabClosePolicy: policy })], continuations: [new CodexThreadContinuation(modelRuntime), new CommandContinuation(), new WebhookContinuation()], planner, usageSnapshotProvider: () => usageRegistry.snapshot(), decisionEngine: new LayaCliDecisionEngine(), decisionMode: decisionMode(), reviewer: runtimeReviewer(), eventBus: bus, emit, chatgptTabClosePolicy: policy, projectPathForJob: job => resolveManagedProjectPath(job.repository, arg(args, '--project-path'), arg(args, '--workspace-root') || defaultWorkspaceRoot()) }); }
|
|
424
|
+
export function runtime(store, args, bus, usageRegistry = codexAndZaiUsageRegistry()) { const emit = (event) => { process.stderr.write(`${JSON.stringify(event)}\n`); }; const modelRuntime = arg(args, '--codex', 'codex'); const policy = chatGptTabClosePolicy(args); const planner = runtimePlanner(args); return new Reconciler(store, { owner: arg(args, '--owner', `cli-${process.pid}`), maxConcurrent: Number(arg(args, '--concurrency', '4')), leaseMs: Number(arg(args, '--lease-ms', '300000')), adapters: [new CodexAdapter(modelRuntime), new ChatGptAdapter({ tabClosePolicy: policy })], continuations: [new CodexThreadContinuation(modelRuntime), new CommandContinuation(), new WebhookContinuation()], planner, usageSnapshotProvider: () => usageRegistry.snapshot(), decisionEngine: new LayaCliDecisionEngine(), decisionMode: decisionMode(), reviewer: runtimeReviewer(), eventBus: bus, emit, chatgptTabClosePolicy: policy, projectPathForJob: async (job) => resolveRepositoryProjectPath(await resolveManagedProjectPath(job.repository, arg(args, '--project-path'), arg(args, '--workspace-root') || defaultWorkspaceRoot()), job.projectPath) }); }
|
|
418
425
|
export function dashboardTaskAction(store, reconciler, action) {
|
|
419
426
|
return async (jobId, taskId) => {
|
|
420
427
|
const job = await store.load(jobId);
|
package/dist/planner.js
CHANGED
|
@@ -147,7 +147,7 @@ export function plannerInput(context) {
|
|
|
147
147
|
boundaries: agent.restrictions,
|
|
148
148
|
runtime: agent.runtime,
|
|
149
149
|
}));
|
|
150
|
-
return JSON.stringify({ objective: context.objective, previous_planner_task_id: context.previousPlannerTaskId, visible_agents: visibleAgents ?? [], execution_context: context.executionContext, tasks: context.tasks.map(task => ({ id: task.id, kind: task.kind ?? 'work', parent_task_id: task.parentTaskId, state: task.state, input: task.input, result: task.result, planner_result: task.plannerResult, error: task.error })) });
|
|
150
|
+
return JSON.stringify({ objective: context.objective, retry_feedback: context.retryFeedback, previous_planner_task_id: context.previousPlannerTaskId, visible_agents: visibleAgents ?? [], execution_context: context.executionContext, tasks: context.tasks.map(task => ({ id: task.id, kind: task.kind ?? 'work', parent_task_id: task.parentTaskId, state: task.state, input: task.input, result: task.result, planner_result: task.plannerResult, error: task.error })) });
|
|
151
151
|
}
|
|
152
152
|
export class CommandObjectivePlanner {
|
|
153
153
|
command;
|
package/dist/reconciler.js
CHANGED
|
@@ -444,7 +444,10 @@ export class Reconciler extends ReconcilerReviewBase {
|
|
|
444
444
|
let promise;
|
|
445
445
|
try {
|
|
446
446
|
const executionContext = await this.resolvedContext(job, task, 'planner');
|
|
447
|
-
|
|
447
|
+
const context = { job, tasks: job.tasks, objective: job.objective ?? job.description ?? job.title, previousPlannerTaskId: task.parentTaskId, executionContext, retryFeedback: task.plannerRetryFeedback };
|
|
448
|
+
task.input = plannerInput(context);
|
|
449
|
+
await this.store.saveTask(task);
|
|
450
|
+
promise = planner.plan(context, controller.signal);
|
|
448
451
|
}
|
|
449
452
|
catch (error) {
|
|
450
453
|
await this.finishPlanner(job.id, task.id, executionId, error instanceof Error ? error : new Error(String(error)));
|
|
@@ -465,6 +468,7 @@ export class Reconciler extends ReconcilerReviewBase {
|
|
|
465
468
|
if (task.state === 'CANCELLED')
|
|
466
469
|
return;
|
|
467
470
|
if (error) {
|
|
471
|
+
task.plannerRetryFeedback = error.message;
|
|
468
472
|
task.error = error.message;
|
|
469
473
|
task.leaseOwner = null;
|
|
470
474
|
task.leaseExpiresAt = null;
|
|
@@ -490,6 +494,7 @@ export class Reconciler extends ReconcilerReviewBase {
|
|
|
490
494
|
task.plannerResult = result;
|
|
491
495
|
task.result = { summary: result.assessment, data: { objective_status: result.objective_status, next_tasks: result.next_tasks } };
|
|
492
496
|
task.error = null;
|
|
497
|
+
task.plannerRetryFeedback = undefined;
|
|
493
498
|
task.leaseOwner = null;
|
|
494
499
|
task.leaseExpiresAt = null;
|
|
495
500
|
task.executionId = null;
|
|
@@ -508,6 +513,7 @@ export class Reconciler extends ReconcilerReviewBase {
|
|
|
508
513
|
await this.emit(eventFor(job.id, task.id, task.parentTaskId, 'planner.children_failed', 'failed', `Planner ${task.id} child materialization failed: ${message}`, 'user'));
|
|
509
514
|
}
|
|
510
515
|
else {
|
|
516
|
+
task.plannerRetryFeedback = message;
|
|
511
517
|
task.error = message;
|
|
512
518
|
task.leaseOwner = null;
|
|
513
519
|
task.leaseExpiresAt = null;
|
package/dist/relayd.js
CHANGED
|
@@ -13,7 +13,7 @@ import { dashboardManagedJobs, GitHubStore, InMemoryStore, loadManagedGitHubPull
|
|
|
13
13
|
import { githubAuthContext } from './github-auth.js';
|
|
14
14
|
import { dashboardJobAction, dashboardTaskAction, isEntrypoint, runtimePlanner, runtimeReviewer, startService, SERVICE_DEFAULTS } from './cli.js';
|
|
15
15
|
import { codexAndZaiUsageRegistry } from './usage.js';
|
|
16
|
-
import { defaultWorkspaceRoot, discoverWorkspaceRepositories, resolveManagedProjectPath } from './workspace.js';
|
|
16
|
+
import { defaultWorkspaceRoot, discoverWorkspaceRepositories, resolveManagedProjectPath, resolveRepositoryProjectPath } from './workspace.js';
|
|
17
17
|
import { deriveJobRuntimeStatus } from './runtime-status.js';
|
|
18
18
|
import { decisionMode, LayaCliDecisionEngine } from './decision.js';
|
|
19
19
|
import { JsonlDecisionAuditStore } from './decision-audit.js';
|
|
@@ -76,7 +76,7 @@ export async function runDaemon(argv) {
|
|
|
76
76
|
const usageRegistry = codexAndZaiUsageRegistry();
|
|
77
77
|
const decisionAuditStore = new JsonlDecisionAuditStore(process.env.AGENTS_RELAY_DECISION_AUDIT_PATH ?? join(homedir(), '.agents-relay', 'decision-audit.jsonl'));
|
|
78
78
|
let cachedOverviews = [];
|
|
79
|
-
const makeReconciler = (store, maxConcurrent) => new Reconciler(store, { owner: `relayd-${process.pid}`, maxConcurrent, leaseMs: Number(value(argv, '--lease-ms', '300000')), adapters: [new CodexAdapter(value(argv, '--codex', 'codex')), new ChatGptAdapter()], continuations: [new CodexThreadContinuation(value(argv, '--codex', 'codex')), new CommandContinuation(), new WebhookContinuation()], planner: runtimePlanner(argv), usageSnapshotProvider: () => usageRegistry.snapshot(), runtimeSummaryProvider: () => ({ chatgptRunning: summarizeRuntime(cachedOverviews.map(item => item.job)).workers.chatgpt }), decisionEngine: new LayaCliDecisionEngine(), decisionMode: decisionMode(), decisionAuditStore, eventBus: bus, reviewer: runtimeReviewer(), projectPathForJob: job => repositoryPaths.get(job.repository) ?? resolveManagedProjectPath(job.repository, explicitProjectPath, workspaceRoot) });
|
|
79
|
+
const makeReconciler = (store, maxConcurrent) => new Reconciler(store, { owner: `relayd-${process.pid}`, maxConcurrent, leaseMs: Number(value(argv, '--lease-ms', '300000')), adapters: [new CodexAdapter(value(argv, '--codex', 'codex')), new ChatGptAdapter()], continuations: [new CodexThreadContinuation(value(argv, '--codex', 'codex')), new CommandContinuation(), new WebhookContinuation()], planner: runtimePlanner(argv), usageSnapshotProvider: () => usageRegistry.snapshot(), runtimeSummaryProvider: () => ({ chatgptRunning: summarizeRuntime(cachedOverviews.map(item => item.job)).workers.chatgpt }), decisionEngine: new LayaCliDecisionEngine(), decisionMode: decisionMode(), decisionAuditStore, eventBus: bus, reviewer: runtimeReviewer(), projectPathForJob: async (job) => resolveRepositoryProjectPath(repositoryPaths.get(job.repository) ?? await resolveManagedProjectPath(job.repository, explicitProjectPath, workspaceRoot), job.projectPath) });
|
|
80
80
|
if (repositories.length === 0)
|
|
81
81
|
throw new Error(`No Git repositories with GitHub origins found under ${normalized.workspaceRoot ?? defaultWorkspaceRoot()}`);
|
|
82
82
|
const pool = new RepositoryWorkerPool(client, repositories, trusted, concurrency, makeReconciler);
|
package/dist/workspace.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { mkdir, readdir, stat } from 'node:fs/promises';
|
|
2
|
-
import { dirname, join, relative, resolve } from 'node:path';
|
|
2
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import { execFile } from 'node:child_process';
|
|
5
5
|
import { promisify } from 'node:util';
|
|
@@ -75,11 +75,24 @@ export async function resolveManagedProjectPath(repository, explicitProjectPath
|
|
|
75
75
|
return resolve(explicitProjectPath);
|
|
76
76
|
return repository ? resolveWorkspaceRepositoryPath(repository, root) : resolve(cwd);
|
|
77
77
|
}
|
|
78
|
+
export function resolveRepositoryProjectPath(repositoryRoot, projectPath) {
|
|
79
|
+
const root = resolve(repositoryRoot);
|
|
80
|
+
if (!projectPath)
|
|
81
|
+
return root;
|
|
82
|
+
if (isAbsolute(projectPath))
|
|
83
|
+
throw new Error('Job projectPath must be repository-relative');
|
|
84
|
+
const target = resolve(root, projectPath);
|
|
85
|
+
const rel = relative(root, target);
|
|
86
|
+
if (rel === '..' || rel.startsWith('..' + sep) || isAbsolute(rel))
|
|
87
|
+
throw new Error('Job projectPath escapes repository root');
|
|
88
|
+
return target;
|
|
89
|
+
}
|
|
78
90
|
async function git(path, args) {
|
|
79
91
|
return (await execFileAsync('git', ['-C', path, ...args])).stdout.trim();
|
|
80
92
|
}
|
|
81
93
|
export async function prepareManagedExecutionWorktree(projectPath, repository, prNumber, head, executionId) {
|
|
82
94
|
const primary = await git(projectPath, ['rev-parse', '--show-toplevel']);
|
|
95
|
+
const projectRelative = (await git(projectPath, ['rev-parse', '--show-prefix'])).replace(/\/$/, '');
|
|
83
96
|
const remote = await git(primary, ['config', '--get', 'remote.origin.url']);
|
|
84
97
|
if (githubRepositoryFromRemote(remote) !== repository)
|
|
85
98
|
throw new Error(`Primary checkout ${primary} does not match ${repository}`);
|
|
@@ -96,7 +109,7 @@ export async function prepareManagedExecutionWorktree(projectPath, repository, p
|
|
|
96
109
|
const existingHead = await git(worktree, ['rev-parse', 'HEAD']);
|
|
97
110
|
if (resolve(existingRoot) !== resolve(worktree) || existingHead !== head.sha)
|
|
98
111
|
throw new Error(`Existing execution worktree ${worktree} is not the expected PR head`);
|
|
99
|
-
return worktree;
|
|
112
|
+
return projectRelative ? join(worktree, projectRelative) : worktree;
|
|
100
113
|
}
|
|
101
114
|
catch (error) {
|
|
102
115
|
try {
|
|
@@ -104,7 +117,7 @@ export async function prepareManagedExecutionWorktree(projectPath, repository, p
|
|
|
104
117
|
}
|
|
105
118
|
catch {
|
|
106
119
|
await git(primary, ['worktree', 'add', '--detach', worktree, head.sha]);
|
|
107
|
-
return worktree;
|
|
120
|
+
return projectRelative ? join(worktree, projectRelative) : worktree;
|
|
108
121
|
}
|
|
109
122
|
throw error;
|
|
110
123
|
}
|