agents-relay 1.0.32 → 1.0.34

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 CHANGED
@@ -114,7 +114,7 @@ The minimal agent-network surface is machine-driven registration and discovery.
114
114
 
115
115
  Managed tasks are descriptive work for agents, not shell commands. Use `codex` or `chatgpt` for worker tasks. Commands such as tests, build tools, Markad Vision, ffmpeg, and other CLIs are invoked by the orchestrator or by an executing agent; they are not worker adapters.
116
116
 
117
- Every model-backed task declares a durable output with `--output task-pr` or `--output file --output-path PATH`. Agents Relay enriches the prompt with the PR URL, job/task identity, output contract, and mandatory terminal-event contract.
117
+ Every model-backed task declares a durable output with `--output task-pr` or `--output file --output-path PATH`. Agents Relay bootstraps workers with the managed PR URL, durable task-comment URL, job/task identity, project, output contract, and mandatory terminal-event contract; workers retrieve the task intent from GitHub rather than receiving a duplicate copy of the stored task prompt.
118
118
 
119
119
  For Codex and ChatGPT, **events are authoritative task state**. Event publication uses the canonical Neo `events-bus` surface (`events__publish` for sandboxed/hosted workers, or `NEO_EVENTS_EMIT` for direct local workers); Agents Relay only subscribes and reconciles. Relay publishes `task.process.launched` only after successful adapter launch; `task.started` is worker-owned and must be a new, correlated start acknowledgement. Codex publishes `task.process.exited` when its synchronous runtime exits, while ChatGPT publishes `task.process.async_exited` after its submission runtime exits; neither substitutes for `task.completed`, `task.failed`, `task.blocked`, or `task.cancelled`. The ChatGPT worker-owned tab follows the configured close policy: `after-start` waits for the correlated start acknowledgement, `never` keeps it open for debug, and `after-terminal` waits for a new exact-task terminal event; start-ack failure closes only the owned tab after 60 seconds. The executing agent must publish exactly one correlated terminal event. Relay persists the matching durable state only from that terminal event. Model-backed tasks require an event bus and time out explicitly if no terminal event arrives.
120
120
 
package/dist/cli.js CHANGED
@@ -65,7 +65,7 @@ Example:
65
65
  'job create': `Create or reuse an open PR and persist one durable job marker.
66
66
 
67
67
  Required: --repo OWNER/REPO, --id JOB_ID, and --head BRANCH.
68
- Common: --base BRANCH (default: main), --title TEXT, --body TEXT, --mode fixed|autonomous, --no-auto-merge.
68
+ Common: --base BRANCH (default: main), --title TEXT, --body TEXT, --mode fixed|autonomous, --no-auto-merge, --no-review.
69
69
  With --start, also require --adapter codex|chatgpt, --model MODEL, --output task-pr|file,
70
70
  and --input TEXT. The initial task ID defaults to 'initial'; use --task-id to override it.
71
71
 
@@ -270,7 +270,7 @@ export async function ensureManagedGitHubJob(client, repositoryName, trustedAuth
270
270
  if (!(error instanceof Error) || !error.message.includes('has no durable'))
271
271
  throw error;
272
272
  const now = new Date().toISOString();
273
- job = { id: options.id, title: options.title || pr.title || 'Agents Relay job', objective: options.objective || pr.body || undefined, description: pr.body || undefined, priority: options.priority ?? 'P2', executionMode: options.executionMode ?? 'fixed', autoMerge: options.autoMerge ?? true, prNumber: pr.number, repository: repositoryName, state: 'OPEN', continuation: options.continuation ?? null, initialPlanning: options.initialTasks?.length ? { status: 'pending', decisionId: 'planner-0' } : undefined, createdAt: now, updatedAt: now, tasks: [] };
273
+ job = { id: options.id, title: options.title || pr.title || 'Agents Relay job', objective: options.objective || pr.body || undefined, description: pr.body || undefined, priority: options.priority ?? 'P2', executionMode: options.executionMode ?? 'fixed', autoMerge: options.autoMerge ?? true, reviewEnabled: options.reviewEnabled ?? true, prNumber: pr.number, repository: repositoryName, state: 'OPEN', continuation: options.continuation ?? null, initialPlanning: options.initialTasks?.length ? { status: 'pending', decisionId: 'planner-0' } : undefined, createdAt: now, updatedAt: now, tasks: [] };
274
274
  }
275
275
  if (!job.description && pr.body)
276
276
  job.description = pr.body;
@@ -280,6 +280,8 @@ export async function ensureManagedGitHubJob(client, repositoryName, trustedAuth
280
280
  job.executionMode = options.executionMode;
281
281
  if (options.autoMerge !== undefined)
282
282
  job.autoMerge = options.autoMerge;
283
+ if (options.reviewEnabled !== undefined)
284
+ job.reviewEnabled = options.reviewEnabled;
283
285
  if (options.priority)
284
286
  job.priority = options.priority;
285
287
  else if (!job.priority)
@@ -492,6 +494,7 @@ async function runJobCommand(action, args) {
492
494
  priority: priority(args),
493
495
  executionMode: requestedExecutionMode(args),
494
496
  autoMerge: !hasArg(args, '--no-auto-merge'),
497
+ reviewEnabled: !hasArg(args, '--no-review'),
495
498
  continuation: continuation(args),
496
499
  prNumber,
497
500
  head: arg(args, '--head') || undefined,
@@ -603,7 +606,7 @@ async function main() {
603
606
  }
604
607
  if (command === 'init') {
605
608
  const now = new Date().toISOString();
606
- const job = { id: arg(args, '--id', randomUUID()), title: arg(args, '--title', 'Agents Relay job'), objective: arg(args, '--objective') || undefined, priority: priority(args), executionMode: executionMode(args), autoMerge: !hasArg(args, '--no-auto-merge'), prNumber: Number(arg(args, '--pr', '0')), repository: arg(args, '--repo'), state: 'OPEN', continuation: continuation(args), createdAt: now, updatedAt: now, tasks: [] };
609
+ const job = { id: arg(args, '--id', randomUUID()), title: arg(args, '--title', 'Agents Relay job'), objective: arg(args, '--objective') || undefined, priority: priority(args), executionMode: executionMode(args), autoMerge: !hasArg(args, '--no-auto-merge'), reviewEnabled: !hasArg(args, '--no-review'), prNumber: Number(arg(args, '--pr', '0')), repository: arg(args, '--repo'), state: 'OPEN', continuation: continuation(args), createdAt: now, updatedAt: now, tasks: [] };
607
610
  let store;
608
611
  let file = null;
609
612
  if (arg(args, '--repo') && arg(args, '--pr'))
@@ -13,17 +13,20 @@ export function managedWorkerInput(job, task, context) {
13
13
  if (!task.output)
14
14
  throw new Error(`Task ${task.id} requires an explicit output contract`);
15
15
  const prUrl = `https://github.com/${job.repository}/pull/${job.prNumber}`;
16
+ const taskUrl = task.taskUrl ?? `${prUrl}#issuecomment-${task.id}`;
16
17
  const output = task.output.kind === 'file'
17
18
  ? `file\nPath: ${task.output.path}`
18
19
  : `task/PR\nPR: ${prUrl}\nTask: ${task.id}`;
19
20
  return `[Agents Relay managed task]
20
- PR: ${prUrl}
21
- Job: ${job.id}
22
- Task: ${task.id}
23
- Parent task: ${task.parentTaskId ?? 'none'}
21
+ Job URL: ${prUrl}
22
+ Job ID: ${job.id}
23
+ Task URL: ${taskUrl}
24
+ Task ID: ${task.id}
24
25
  Project: ${task.projectName ?? context?.project.name ?? 'unspecified'}
25
26
 
26
- ${context ? executionContextPrompt(context) + '\n\n' : ''}${task.input}${task.parentTaskId ? '\n\n[Nested delegation contract]\nAny sub-work must be created as a durable Agents Relay child task with parentTaskId=' + task.id + '; do not directly spawn arbitrary child agents.' : ''}
27
+ Retrieve the durable job and task from GitHub before doing the work. Use whatever GitHub access this environment provides: the URLs, a GitHub integration/tool, or GitHub CLI/API. GitHub is the source of truth for task intent and declared output.
28
+
29
+ ${context ? executionContextPrompt(context) + '\n\n' : ''}Follow the resolved project instructions and Agents Relay/events-bus worker contracts.
27
30
 
28
31
  [Output contract]
29
32
  ${output}
@@ -196,7 +199,7 @@ export class Reconciler {
196
199
  await this.store.saveJob(job);
197
200
  }
198
201
  async ensureFinalReview(job, prState, headSha) {
199
- if (prState !== 'OPEN' || job.state !== 'COMPLETED' || !headSha)
202
+ if (job.reviewEnabled === false || prState !== 'OPEN' || job.state !== 'COMPLETED' || !headSha)
200
203
  return;
201
204
  if (!this.preReviewGatesPass(job))
202
205
  return;
package/dist/store.js CHANGED
@@ -434,7 +434,7 @@ export class GitHubStore {
434
434
  const all = [];
435
435
  let cursor = null;
436
436
  do {
437
- const data = await this.graphql('query($owner:String!,$name:String!,$number:Int!,$cursor:String){repository(owner:$owner,name:$name){pullRequest(number:$number){comments(first:100,after:$cursor){nodes{id databaseId body updatedAt author{login}} pageInfo{hasNextPage endCursor}}}}}', { owner, name, number: this.prNumber, cursor });
437
+ const data = await this.graphql('query($owner:String!,$name:String!,$number:Int!,$cursor:String){repository(owner:$owner,name:$name){pullRequest(number:$number){comments(first:100,after:$cursor){nodes{id databaseId url body updatedAt author{login}} pageInfo{hasNextPage endCursor}}}}}', { owner, name, number: this.prNumber, cursor });
438
438
  const repository = data.repository;
439
439
  const pr = repository?.pullRequest;
440
440
  const comments = pr?.comments;
@@ -444,6 +444,7 @@ export class GitHubStore {
444
444
  all.push({
445
445
  id: Number(value.databaseId ?? 0),
446
446
  nodeId: typeof value.id === 'string' ? value.id : undefined,
447
+ url: typeof value.url === 'string' ? value.url : undefined,
447
448
  body: String(value.body ?? ''),
448
449
  updatedAt: String(value.updatedAt ?? ''),
449
450
  authorLogin: typeof author?.login === 'string' ? author.login : null
@@ -486,7 +487,13 @@ export class GitHubStore {
486
487
  if (!job)
487
488
  throw new Error(`Managed GitHub job ${jobId} has no durable ${JOB_MARKER} marker in PR #${this.prNumber}; run agents-relay job adopt --repo ${this.repository} --pr ${this.prNumber} --id ${jobId}`);
488
489
  const soleTrustedJob = jobs.length === 1;
489
- job.tasks = comments.map(x => parseTask(x.body)).filter((x) => x !== null).filter(task => isTaskForJob(task, jobId, soleTrustedJob));
490
+ job.tasks = comments.map(comment => {
491
+ const task = parseTask(comment.body);
492
+ if (!task)
493
+ return null;
494
+ const taskUrl = comment.url ?? (comment.id > 0 ? `https://github.com/${this.repository}/pull/${this.prNumber}#issuecomment-${comment.id}` : undefined);
495
+ return taskUrl ? { ...task, taskUrl } : task;
496
+ }).filter((x) => x !== null).filter(task => isTaskForJob(task, jobId, soleTrustedJob));
490
497
  return job;
491
498
  }
492
499
  async listAgents() { return (await this.list()).filter(comment => this.isTrusted(comment)).map(x => parseAgent(x.body)).filter((x) => x !== null); }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agents-relay",
3
- "version": "1.0.32",
3
+ "version": "1.0.34",
4
4
  "description": "Durable async agent jobs coordinated through GitHub pull requests",
5
5
  "type": "module",
6
6
  "bin": {