agents-relay 2.0.86 → 2.0.87
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/dashboard-html.js
CHANGED
|
@@ -332,7 +332,7 @@ function element(name,className,child){const node=document.createElement(name);i
|
|
|
332
332
|
function yamlScalar(input){if(input===null)return 'null';if(typeof input==='boolean'||typeof input==='number')return String(input);return JSON.stringify(String(input));}
|
|
333
333
|
function yamlDump(input,indent=0){const pad=' '.repeat(indent);if(Array.isArray(input)){if(!input.length)return pad+'[]';return input.map(item=>{if(item&&typeof item==='object'){return pad+'-\\n'+yamlDump(item,indent+2);}return pad+'- '+yamlScalar(item);}).join('\\n');}if(input&&typeof input==='object'){const entries=Object.entries(input);if(!entries.length)return pad+'{}';const lines=[];for(const [key,item] of entries){if(typeof item==='string'&&item.includes('\\n')){lines.push(pad+key+': |');for(const line of item.replace(/\\n$/,'').split('\\n'))lines.push(' '.repeat(indent+2)+line);continue;}if(item&&typeof item==='object'){lines.push(pad+key+':');lines.push(yamlDump(item,indent+2));}else{lines.push(pad+key+': '+yamlScalar(item));}}return lines.join('\\n');}return pad+yamlScalar(input);}
|
|
334
334
|
function field(label,input){const box=element('div','detail-group');box.append(element('p','detail-label',text(label)),element('p','detail-value',text(input)));return box;}
|
|
335
|
-
function markdownField(label,input){const box=element('div','detail-group');box.append(element('p','detail-label',text(label)),markdownValue(input));return box;}
|
|
335
|
+
function threadField(label,threadId){const box=element('div','detail-group');box.append(element('p','detail-label',text(label)));const id=String(threadId||'').trim();if(!/^[0-9a-f]{8}-[0-9a-f-]{27,}$/i.test(id)){box.append(element('p','detail-value',text(id||'—')));return box;}const link=document.createElement('a');link.className='detail-value';link.href='https://chatgpt.com/c/'+encodeURIComponent(id);link.target='implementation';link.rel='noopener noreferrer';link.textContent=id.slice(0,8);link.title=id;box.append(link);return box;}function markdownField(label,input){const box=element('div','detail-group');box.append(element('p','detail-label',text(label)),markdownValue(input));return box;}
|
|
336
336
|
function rememberSelection(){if(selectedJob)sessionStorage.setItem('agents-relay:selected-job',selectedJob);else sessionStorage.removeItem('agents-relay:selected-job');if(selectedTaskId)sessionStorage.setItem('agents-relay:selected-task',selectedTaskId);else sessionStorage.removeItem('agents-relay:selected-task');}
|
|
337
337
|
function syncMobileJobsView(){const detail=mobileJobs.matches&&Boolean(selectedJob)&&location.hash.startsWith('#/jobs/');document.body.dataset.mobileJobsView=detail?'detail':'list';}
|
|
338
338
|
function shortManagedId(id,repository,kind){const parts=String(repository||'').split('/');if(parts.length!==2)return String(id||'');const prefix=kind+'-'+parts[0].length+'-'+parts[0]+'-'+parts[1]+'-';const value=String(id||'');const suffix=value.startsWith(prefix)?value.slice(prefix.length):'';return /^[0-9]+$/.test(suffix)?'#'+suffix:value;}function jobSelectionKey(job){return job?String(job.repository||'')+'|'+String(job.prNumber||'')+'|'+String(job.id||''):'';}
|
|
@@ -403,7 +403,7 @@ function taskStateField(task){const box=element('div','detail-group');box.append
|
|
|
403
403
|
function manualOverrideField(task){const rows=Array.isArray(task.manualStateOverrides)?task.manualStateOverrides:[];const last=rows.at(-1);return field('Manual override',last?last.from+' → '+last.to+' · '+relativeTime(last.at):'—');}
|
|
404
404
|
function renderTaskDetail(task){taskDetailRoot.replaceChildren();if(!task){taskDetailRoot.append(element('p','empty',text('Select a task to inspect execution details.')));return;}const routing=task.routing||{};const groups=element('div','detail-groups');groups.append(field('Title',task.title||'—'),field('Task ID',task.id),field('Kind',task.kind||'work'),taskStateField(task),manualOverrideField(task),field('Planning decision',task.planningDecisionId||'—'),field('Planning source',task.planningSource||'—'),field('Planning round',task.planningRound===undefined?'—':String(task.planningRound)),field('Project / agent',value(task.projectName)+' / '+value(task.agentName)),field('Parent task',task.parentTaskId||'root'),field('Adapter',task.adapter),field('Provider / model',value(routing.provider)+' / '+value(routing.model)),field('Reasoning / profile',value(routing.reasoning||routing.profile)),field('Attempt',attemptBudget(task)),field('Dependencies',Array.isArray(task.dependencies)&&task.dependencies.length?task.dependencies.join(', '):'none'),taskCommentField(task),chatField(task));const job=selected();if(task.reviewHeadSha&&job)groups.append(commitField('HEAD commit',job,task.reviewHeadSha));const graph=agentGraphField(task);if(graph)groups.append(graph);if(task.plannerResult)groups.append(field('Objective status',task.plannerResult.objective_status),markdownField('Assessment',task.plannerResult.assessment));if(task.error)groups.append(field('Error',task.error));taskDetailRoot.append(groups);}
|
|
405
405
|
function reviewStatus(job){const review=job?.review;if(!review)return 'Not started';if(review.outcome==='approved'&&review.headSha===job.headSha)return 'MERGE READY · approved';const stale=Array.isArray(job?.tasks)&&job.tasks.some(task=>task.agentName==='reviewer'&&task.reviewHeadSha&&job.headSha&&task.reviewHeadSha!==job.headSha);if(stale)return 'STALE · awaiting review';return String(review.outcome||'pending').replace('_',' ').toUpperCase();}
|
|
406
|
-
function renderSelectedJob(){jobDetail.replaceChildren();const job=selected();if(!job){selectedJobTitle.textContent='';jobDetail.append(element('div','empty',text('No durable jobs discovered.')));buildTree([]);renderTaskDetail(null);return;}selectedJobTitle.textContent=value(job.title||job.id);if(jobSelectionKey(job)!==selectedJob){selectedJob=jobSelectionKey(job);selectedTaskId=null;eventTaskId=null;clearEvents();rememberSelection();}const summary=element('div','job-summary');summary.append(field('PR state',job.githubState||'UNKNOWN'),jobStateField(job),field('Runtime status',job.runtimeStatus||'IDLE'),field('Execution mode',job.executionMode||'fixed'),field('Cadence',cadence(job)),field('Review',reviewStatus(job)),field('Creator thread',job.creatorThreadId||'—'),
|
|
406
|
+
function renderSelectedJob(){jobDetail.replaceChildren();const job=selected();if(!job){selectedJobTitle.textContent='';jobDetail.append(element('div','empty',text('No durable jobs discovered.')));buildTree([]);renderTaskDetail(null);return;}selectedJobTitle.textContent=value(job.title||job.id);if(jobSelectionKey(job)!==selectedJob){selectedJob=jobSelectionKey(job);selectedTaskId=null;eventTaskId=null;clearEvents();rememberSelection();}const summary=element('div','job-summary');summary.append(field('PR state',job.githubState||'UNKNOWN'),jobStateField(job),field('Runtime status',job.runtimeStatus||'IDLE'),field('Execution mode',job.executionMode||'fixed'),field('Cadence',cadence(job)),field('Review',reviewStatus(job)),field('Creator thread',job.creatorThreadId||'—'),threadField('Implementation thread',job.implementationThreadId),threadField('Reviewer thread',job.reviewerThreadId),commitField('Review head SHA',job,job.review?.headSha||job.headSha||''),prField(job),field('Repository',job.repository||'—'),field('Last activity',relativeTime(job.updatedAt)),field('Task states',compactCounts(job.tasks)),chatShortcutField(job));jobDetail.append(summary);const selectedTask=(job.tasks||[]).find(task=>task.id===selectedTaskId)||null;if(selectedTaskId&&!selectedTask){selectedTaskId=null;eventTaskId=null;clearEvents();rememberSelection();}buildTree(job.tasks||[]);renderTaskDetail(selectedTask);renderEventScope();}
|
|
407
407
|
function renderAll(){jobs.sort(compareJobs);syncFilters();renderJobList();renderSelectedJob();syncMobileJobsView();}
|
|
408
408
|
function isCompleteUnmerged(job){return job.runtimeStatus==='MERGE_PENDING';}
|
|
409
409
|
function isTerminalJob(job){return ['COMPLETED','CANCELLED'].includes(job.state)||['MERGED','CLOSED'].includes(job.githubState);}
|
package/dist/reconciler.js
CHANGED
|
@@ -8,7 +8,7 @@ import { dependencyReady, schedule, transitionTaskEvent } from './scheduler.js';
|
|
|
8
8
|
import { applyTaskRetryAction } from './task-actions.js';
|
|
9
9
|
import { LaunchFailure, StartAckTimeout } from './adapters.js';
|
|
10
10
|
import { eventFor } from './events.js';
|
|
11
|
-
import { createPlanRound, materializePlannerChild, pendingPlan
|
|
11
|
+
import { createPlanRound, materializePlannerChild, pendingPlan } from './planner.js';
|
|
12
12
|
import { retryPendingPlannerUnblocks } from './planner-runtime.js';
|
|
13
13
|
import { dispatchPlannerOrchestration, plannerOrchestrationFacts } from './workflow/planner-orchestration-v2.js';
|
|
14
14
|
import { resolveExecutionContext } from './execution-context.js';
|
|
@@ -269,7 +269,8 @@ export class Reconciler extends ReconcilerReviewBase {
|
|
|
269
269
|
async recoverPlannerChildren(job) {
|
|
270
270
|
for (const plan of (job.plans ?? []).filter(item => item.status === 'SUCCEEDED' && item.plannerResult)) {
|
|
271
271
|
const executionContext = await this.plannerContext(job, plan);
|
|
272
|
-
|
|
272
|
+
// Historical plans were validated on commit. Rechecking against later Task failures
|
|
273
|
+
// blocks recovery before the Troubleshooter graph can run.
|
|
273
274
|
const children = plan.plannerResult.next_tasks.map(spec => materializePlannerChild(job, plan, spec, executionContext));
|
|
274
275
|
for (const child of children) {
|
|
275
276
|
const existing = job.tasks.find(item => item.id === child.id);
|
package/package.json
CHANGED
|
@@ -114,6 +114,8 @@ For `objective_status: "in_progress"`, `assessment` must be Markdown containing:
|
|
|
114
114
|
|
|
115
115
|
For `objective_status: "satisfied"`, `assessment` may be a concise evidence-based completion assessment without a graph.
|
|
116
116
|
|
|
117
|
+
Each item in `next_tasks` MUST include a concise, meaningful `title` of **5–8 words** (separate from the detailed `input`). Do not use the input text as a title.
|
|
118
|
+
|
|
117
119
|
Each item in next_tasks contains id, input, output, and storySize. `unblocks`, when present, is an array of `{repository, prNumber, jobId, taskId, resolutionMode?}` records identifying Tasks that must remain waiting until the current Job resolves their blocker. It may also contain parentTaskId, priority, projectName, agentName, dependencies, capabilities, workerRequirements, maxAttempts, and timeoutMs. Adapter/routing fields are selected by Relay after planning; do not invent them.
|
|
118
120
|
|
|
119
121
|
### Exact `next_tasks` serialization
|
|
@@ -138,6 +140,7 @@ A valid non-satisfied response:
|
|
|
138
140
|
"next_tasks": [
|
|
139
141
|
{
|
|
140
142
|
"id": "episode-2026-09-26",
|
|
143
|
+
"title": "Produce and verify daily content package",
|
|
141
144
|
"input": "Produce and verify the dated content package.",
|
|
142
145
|
"output": {"kind": "file", "path": "runs/2026-09-26/package.md"},
|
|
143
146
|
"storySize": "L",
|