agents-relay 2.0.154 → 2.0.156

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
@@ -168,7 +168,7 @@ Review destinations are durable Job facts. `job create` and `job update` accept
168
168
  `--reviewer-thread-id` and `--creator-thread-id`; a reviewer ID takes precedence
169
169
  over the creator/origin ID. A local runtime invocation may pass
170
170
  `--thread-id` as an explicit one-run review override. When a destination exists,
171
- final-review routing requires a ChatGPT/browser-workspace worker and submits the
171
+ final-review routing requires a ChatGPT/webhelm worker and submits the
172
172
  review request as a verified `new-turn` to that existing thread with the Job ID,
173
173
  PR number, and immutable review head SHA. Failure still follows the ordinary
174
174
  review task retry/recovery path; a transport failure is never treated as
@@ -255,7 +255,7 @@ Every model-backed task declares a durable output with `--output task-pr` or `--
255
255
 
256
256
  For Codex and ChatGPT, **correlated worker events are authoritative lifecycle inputs**, not a separate durable store. 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 subscribes, validates correlation, applies graph transitions, persists results in RelayStore, and projects them to GitHub. 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 one-shot submission runtime exits; neither substitutes for `task.completed`, `task.failed`, `task.blocked`, or `task.cancelled`. 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.
257
257
 
258
- The ChatGPT adapter uses Relay's `agents/chatgpt-worker.agent.md` lifecycle contract and invokes Browser Workspace exactly as a one-shot platform action: `browser-workspace platform run chatgpt temporary-submit --auto-session --config <file>`. Browser Workspace owns creation/release of the fresh Temporary Chat session, selectors, attachments, and submit verification; Relay does not self-heal browser failures and instead lets delivery failures enter its normal retry/recovery lifecycle. Legacy `--chatgpt-tab-close-policy` values remain accepted for compatibility around Relay's event barriers, but they do not control the Browser Workspace auto-session lifetime. The adapter never uses a pre-existing user tab, polls for the assistant response, resumes/reopens a thread, or treats conversation text as the result channel. Any observed ChatGPT thread ID is diagnostic only.
258
+ The ChatGPT adapter uses Relay's `agents/chatgpt-worker.agent.md` lifecycle contract and invokes Browser Workspace exactly as a one-shot platform action: `webhelm platform run chatgpt temporary-submit --auto-session --config <file>`. Browser Workspace owns creation/release of the fresh Temporary Chat session, selectors, attachments, and submit verification; Relay does not self-heal browser failures and instead lets delivery failures enter its normal retry/recovery lifecycle. Legacy `--chatgpt-tab-close-policy` values remain accepted for compatibility around Relay's event barriers, but they do not control the Browser Workspace auto-session lifetime. The adapter never uses a pre-existing user tab, polls for the assistant response, resumes/reopens a thread, or treats conversation text as the result channel. Any observed ChatGPT thread ID is diagnostic only.
259
259
 
260
260
  ~~~sh
261
261
  npx agents-relay task create --repo OWNER/REPO --pr 5 --id job-1 \
@@ -306,7 +306,7 @@ For autonomous Jobs, `UNBLOCKED` is historical: Relay does not retry that old Ta
306
306
 
307
307
  ### Browser Workspace product boundary
308
308
 
309
- Agents Relay owns the persistent `Relay` browser workspace as product infrastructure. At daemon startup it runs `browser-workspace status`, dynamically imports the returned absolute `admin_helper`, and calls `ensureWorkspace("Relay", 6)`. This bootstrap is best-effort: Browser Workspace discovery/helper failures are logged and skipped so they do not prevent `agents-relayd` from starting; ChatGPT browser work may remain unavailable until Browser Workspace recovers. Ordinary ChatGPT worker activity uses the public Browser Workspace one-shot `platform run ... --auto-session` command; orchestrator-owned self-healing flows may still use explicit session commands. Relay does not create or delete workspaces through CLI lifecycle commands.
309
+ Agents Relay owns the persistent `Relay` browser workspace as product infrastructure. At daemon startup it runs `webhelm status`, dynamically imports the returned absolute `admin_helper`, and calls `ensureWorkspace("Relay", 6)`. This bootstrap is best-effort: Browser Workspace discovery/helper failures are logged and skipped so they do not prevent `agents-relayd` from starting; ChatGPT browser work may remain unavailable until Browser Workspace recovers. Ordinary ChatGPT worker activity uses the public Browser Workspace one-shot `platform run ... --auto-session` command; orchestrator-owned self-healing flows may still use explicit session commands. Relay does not create or delete workspaces through CLI lifecycle commands.
310
310
 
311
311
  ## Shared publication reporting
312
312
 
package/dist/adapters.js CHANGED
@@ -171,8 +171,8 @@ export function parseDriverJson(output) {
171
171
  }
172
172
  throw new Error('browser-worker driver returned no submitted receipt');
173
173
  }
174
- function browserWorkspaceCli(override = process.env.AGENTS_RELAY_BROWSER_WORKSPACE_COMMAND) {
175
- return override ? { command: override, prefix: [] } : { command: 'uvx', prefix: ['browser-workspace'] };
174
+ function browserWorkspaceCli(override = process.env.AGENTS_RELAY_WEBHELM_COMMAND) {
175
+ return override ? { command: override, prefix: [] } : { command: 'uvx', prefix: ['--from', 'browser-workspace', 'webhelm'] };
176
176
  }
177
177
  const browserWorkspaceInjection = new AsyncLocalStorage();
178
178
  function browserWorkspaceCommand(cli, args, stdin, signal) {
@@ -181,7 +181,7 @@ function browserWorkspaceCommand(cli, args, stdin, signal) {
181
181
  function rawBrowserWorkspaceCommand(cli, args, stdin, signal) {
182
182
  return new Promise((resolve, reject) => {
183
183
  const child = spawnOwnedProcess(cli.command, [...cli.prefix, ...args], {
184
- invocation: 'browser-workspace.command',
184
+ invocation: 'webhelm.command',
185
185
  signal,
186
186
  spawn: { shell: false, stdio: [stdin === undefined ? 'ignore' : 'pipe', 'pipe', 'pipe'] },
187
187
  });
@@ -200,7 +200,7 @@ function rawBrowserWorkspaceCommand(cli, args, stdin, signal) {
200
200
  else {
201
201
  // Browser Workspace reports a compact code/message JSON on nonzero exit.
202
202
  // Preserve existing Relay failure behavior; only simplify the error text.
203
- let reason = stderr.trim() || stdout.trim() || `browser-workspace exited ${code}`;
203
+ let reason = stderr.trim() || stdout.trim() || `webhelm exited ${code}`;
204
204
  try {
205
205
  const envelope = parseWorkspaceJson(stdout);
206
206
  const result = envelope.result;
@@ -234,7 +234,7 @@ function parseWorkspaceJson(output) {
234
234
  }
235
235
  catch { /* diagnostics may precede JSON */ }
236
236
  }
237
- throw new Error('browser-workspace returned no JSON result');
237
+ throw new Error('webhelm returned no JSON result');
238
238
  }
239
239
  /** Parse only the trusted manifest emitted before the explicit task-data boundary. */
240
240
  function declaredPromptReferences(prompt) {
@@ -274,14 +274,14 @@ async function accessiblePromptReferences(prompt) {
274
274
  }
275
275
  return readable;
276
276
  }
277
- export async function ensureChatGptBrowserWorkspace(command = process.env.AGENTS_RELAY_BROWSER_WORKSPACE_COMMAND) {
277
+ export async function ensureChatGptBrowserWorkspace(command = process.env.AGENTS_RELAY_WEBHELM_COMMAND) {
278
278
  const status = parseWorkspaceJson(await browserWorkspaceCommand(browserWorkspaceCli(command), ['status']));
279
279
  if (typeof status.admin_helper !== 'string' || !status.admin_helper.startsWith('/')) {
280
- throw new Error('browser-workspace status returned no absolute admin_helper path');
280
+ throw new Error('webhelm status returned no absolute admin_helper path');
281
281
  }
282
282
  const admin = await import(pathToFileURL(status.admin_helper).href);
283
283
  if (typeof admin.ensureWorkspace !== 'function') {
284
- throw new Error('browser-workspace admin helper does not export ensureWorkspace');
284
+ throw new Error('webhelm admin helper does not export ensureWorkspace');
285
285
  }
286
286
  await admin.ensureWorkspace(CHATGPT_BROWSER_WORKSPACE, CHATGPT_BROWSER_WORKSPACE_POOL_SIZE);
287
287
  }
@@ -289,7 +289,7 @@ async function runBrowserWorker(cli, configFile, signal, action = 'temporary-sub
289
289
  const session = parseWorkspaceJson(await browserWorkspaceCommand(cli, ['session', 'start', '--workspace', CHATGPT_BROWSER_WORKSPACE], undefined, signal));
290
290
  const sessionId = session.session_id;
291
291
  if (typeof sessionId !== 'string' || !sessionId)
292
- throw new Error('browser-workspace session start returned no session_id');
292
+ throw new Error('webhelm session start returned no session_id');
293
293
  try {
294
294
  return await browserWorkspaceCommand(cli, ['platform', 'run', 'chatgpt', action, '--session-id', sessionId, '--config', configFile], undefined, signal);
295
295
  }
@@ -347,7 +347,7 @@ function parseBrowserWorkerResponse(output) {
347
347
  export class ChatGptAdapter {
348
348
  name = 'chatgpt';
349
349
  id = 'chatgpt/browser-worker';
350
- capabilities = ['model', 'chatgpt', 'browser-workspace'];
350
+ capabilities = ['model', 'chatgpt', 'webhelm'];
351
351
  runner;
352
352
  tabClosePolicy;
353
353
  constructor(options = {}) {
@@ -259,7 +259,7 @@ export class ReconcilerRuntimeBase {
259
259
  const currentTask = currentJob.tasks.find(task => task.id === taskId);
260
260
  const platformFailure = currentTask?.adapter === 'chatgpt' ? classifyChatGptPlatformFailure(failure, phase) : undefined;
261
261
  const failureReason = phase === 'start-ack' ? 'worker_start_timeout'
262
- : /BROWSER_WORKSPACE_UNAVAILABLE|browser-workspace runtime dependency unavailable|browser-workspace session start returned no session_id|no close frame received or sent/i.test(message)
262
+ : /WEBHELM_UNAVAILABLE|webhelm runtime dependency unavailable|webhelm session start returned no session_id|no close frame received or sent/i.test(message)
263
263
  ? 'browser_workspace_unavailable'
264
264
  : undefined;
265
265
  const claim = executionId ?? `${jobId}:${taskId}`;
@@ -305,7 +305,7 @@ export class ReconcilerRuntimeBase {
305
305
  this.detach(this.emit(event), jobId, taskId, 'worker failure event');
306
306
  if (runtimeRetry) {
307
307
  this.detach(this.emit(eventFor(jobId, taskId, runtimeRetry.parentTaskId, 'task.rerouting', 'queued', 'ChatGPT platform rejection recorded; routing the same Task through Execution Router', 'orchestrator', { previousFailure: transition.task.platformFailure?.classification, executionId, attempt: runtimeRetry.attempt, maxAttempts: runtimeRetry.maxAttempts })), jobId, taskId, 'runtime retry event');
308
- this.detach(this.eventCoordinator.accept({ jobId, reason: 'browser-workspace-runtime-retry' }), jobId, taskId, 'runtime retry reconcile wake');
308
+ this.detach(this.eventCoordinator.accept({ jobId, reason: 'webhelm-runtime-retry' }), jobId, taskId, 'runtime retry reconcile wake');
309
309
  return;
310
310
  }
311
311
  this.detach(this.eventCoordinator.accept({ jobId, reason: `worker-${phase}-failure` }), jobId, taskId, 'worker failure reconcile wake');
package/dist/relayd.js CHANGED
@@ -465,7 +465,7 @@ export async function runDaemon(argv) {
465
465
  const runtime = summarizeRuntime(cachedOverviews.map(item => item.job));
466
466
  const workers = workerCandidates([
467
467
  { name: 'codex', id: 'codex', capabilities: ['model', 'codex'] },
468
- { name: 'chatgpt', id: 'chatgpt/browser-worker', capabilities: ['model', 'chatgpt', 'browser-workspace'] },
468
+ { name: 'chatgpt', id: 'chatgpt/browser-worker', capabilities: ['model', 'chatgpt', 'webhelm'] },
469
469
  ], [], usage);
470
470
  const result = await routeExecution(workers, task.workerRequirements ?? { capabilities: task.capabilities ?? [] }, {
471
471
  decisionEngine: executionDecisionEngine(),
@@ -50,7 +50,7 @@ export function prepareReviewerThreadDelivery(job, task, override) {
50
50
  }
51
51
  export function chatgptThreadRequirements(configured) {
52
52
  const base = configured ?? { capabilities: ['model'] };
53
- const capabilities = new Set([...base.capabilities, 'model', 'chatgpt', 'browser-workspace']);
53
+ const capabilities = new Set([...base.capabilities, 'model', 'chatgpt', 'webhelm']);
54
54
  return { ...base, capabilities: [...capabilities], runtime: 'chatgpt' };
55
55
  }
56
56
  export function runtimeReviewer(args = []) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agents-relay",
3
- "version": "2.0.154",
3
+ "version": "2.0.156",
4
4
  "description": "Durable async agent jobs coordinated through GitHub pull requests",
5
5
  "repository": {
6
6
  "type": "git",
@@ -27,7 +27,7 @@ Read `skills/agents-relay/troubleshooter-qa.md` for user-editable best practices
27
27
  - shared worker/runtime/tool/Agents Relay defect;
28
28
  - genuine external/human blocker.
29
29
  4. Diagnose the smallest root cause from the combined durable Task + event sequence + logs. The final `task.error` is only one piece of evidence. Never retry first and investigate later.
30
- 5. For ChatGPT browser failures, run `browser-workspace platform run chatgpt validate --session-id SESSION_ID` in a caller-owned `Relay` session and close the session afterward. Parse the action JSON from the platform-run `result.stdout` (the outer `result.ok` only reports command execution). The action returns exactly JSON `true` on validation success or one failure ID: `PAGE_NOT_READY`, `COMPOSER_NOT_READY`, or `DELIVERY_ERROR`. Treat any unexpected output or runner error as validation unavailable. These are UI-readiness results, NOT authentication results. None permits a human login escalation. Never independently interpret DOM snapshots, sign-in buttons, or disabled Send; only confirmed authentication failure from the actual Worker authentication protocol can justify login escalation. Inspect original task delivery/start-ack evidence separately.
30
+ 5. For ChatGPT browser failures, run `webhelm platform run chatgpt validate --session-id SESSION_ID` in a caller-owned `Relay` session and close the session afterward. Parse the action JSON from the platform-run `result.stdout` (the outer `result.ok` only reports command execution). The action returns exactly JSON `true` on validation success or one failure ID: `PAGE_NOT_READY`, `COMPOSER_NOT_READY`, or `DELIVERY_ERROR`. Treat any unexpected output or runner error as validation unavailable. These are UI-readiness results, NOT authentication results. None permits a human login escalation. Never independently interpret DOM snapshots, sign-in buttons, or disabled Send; only confirmed authentication failure from the actual Worker authentication protocol can justify login escalation. Inspect original task delivery/start-ack evidence separately.
31
31
 
32
32
  6. Repair:
33
33
  - For a transient failure, verify the transient condition is gone.