agents-relay 1.0.111 → 1.0.112
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 +6 -2
- package/dist/planner.js +1 -1
- package/dist/reconciler.js +1 -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',
|
|
@@ -323,6 +324,7 @@ async function runJobCommand(action, args) {
|
|
|
323
324
|
id,
|
|
324
325
|
title: arg(args, '--title') || undefined,
|
|
325
326
|
objective: objective || undefined,
|
|
327
|
+
projectPath: arg(args, '--project-path') || undefined,
|
|
326
328
|
priority: priority(args),
|
|
327
329
|
executionMode: requestedExecutionMode(args),
|
|
328
330
|
schedule: scheduleFromArgs(args),
|
|
@@ -382,6 +384,8 @@ async function runJobCommand(action, args) {
|
|
|
382
384
|
throw new Error('Job objective cannot be empty');
|
|
383
385
|
job.objective = objective;
|
|
384
386
|
}
|
|
387
|
+
if (hasArg(args, '--project-path'))
|
|
388
|
+
job.projectPath = arg(args, '--project-path') || undefined;
|
|
385
389
|
if (hasArg(args, '--priority'))
|
|
386
390
|
job.priority = priority(args, job.priority ?? 'P2');
|
|
387
391
|
if (hasArg(args, '--mode') || hasArg(args, '--execution-mode'))
|
|
@@ -414,7 +418,7 @@ async function runJobCommand(action, args) {
|
|
|
414
418
|
}
|
|
415
419
|
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
420
|
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()) }); }
|
|
421
|
+
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
422
|
export function dashboardTaskAction(store, reconciler, action) {
|
|
419
423
|
return async (jobId, taskId) => {
|
|
420
424
|
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,7 @@ export class Reconciler extends ReconcilerReviewBase {
|
|
|
444
444
|
let promise;
|
|
445
445
|
try {
|
|
446
446
|
const executionContext = await this.resolvedContext(job, task, 'planner');
|
|
447
|
-
promise = planner.plan({ job, tasks: job.tasks, objective: job.objective ?? job.description ?? job.title, previousPlannerTaskId: task.parentTaskId, executionContext }, controller.signal);
|
|
447
|
+
promise = planner.plan({ job, tasks: job.tasks, objective: job.objective ?? job.description ?? job.title, previousPlannerTaskId: task.parentTaskId, executionContext, retryFeedback: task.error ?? undefined }, controller.signal);
|
|
448
448
|
}
|
|
449
449
|
catch (error) {
|
|
450
450
|
await this.finishPlanner(job.id, task.id, executionId, error instanceof Error ? error : new Error(String(error)));
|
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
|
}
|