agents-relay 1.0.146 → 1.0.148
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
|
@@ -57,10 +57,6 @@ export const dashboardHtml = `<!doctype html>
|
|
|
57
57
|
.job-primary { display:flex; align-items:center; justify-content:space-between; gap:.45rem; min-width:0; }
|
|
58
58
|
.job-status-line { display:flex; align-items:center; gap:.3rem; min-width:0; white-space:nowrap; }
|
|
59
59
|
.job-status-line .badge { flex:0 0 auto; }
|
|
60
|
-
.job-actions { display:flex; align-items:center; gap:.2rem; }
|
|
61
|
-
.job-action { width:1.8rem; height:1.8rem; display:inline-grid; place-items:center; padding:0; border:1px solid var(--border); border-radius:.35rem; background:var(--surface); color:var(--muted); font:inherit; font-size:.95rem; line-height:1; cursor:pointer; }
|
|
62
|
-
.job-action:hover:not(:disabled) { color:var(--accent); border-color:var(--accent); }
|
|
63
|
-
.job-action:disabled { cursor:default; opacity:.4; }
|
|
64
60
|
.status-pill,.badge { display:inline-flex; align-items:center; border-radius:999px; padding:.06rem .42rem; min-height:1.35rem; font-size:.68rem; font-weight:800; }
|
|
65
61
|
.status-pill.ok,.badge.ACTIVE,.badge.RUNNING,.badge.SUCCEEDED,.badge.COMPLETED,.badge.MERGED { background:#e5f3e9; color:var(--ok); }
|
|
66
62
|
.status-pill.warn,.badge.BLOCKED,.badge.DRAFT,.badge.QUEUED,.badge.WAITING,.badge.OPEN { background:#fff1d2; color:var(--warn); }
|
|
@@ -335,12 +331,8 @@ function syncFilters(){
|
|
|
335
331
|
quickDraft.setAttribute('aria-pressed',String(quickMode==='draft'));
|
|
336
332
|
jobSearch.value=searchQuery;
|
|
337
333
|
}
|
|
338
|
-
function actionEnabled(job,action){if(action==='start')return job.state==='DRAFT'&&job.githubState!=='CLOSED'&&job.githubState!=='MERGED';if(action==='reconcile')return job.state==='ACTIVE'&&job.githubState==='OPEN';if(action==='cancel')return job.state!=='COMPLETED'&&job.state!=='CANCELLED'&&job.githubState==='OPEN';return false;}
|
|
339
|
-
function actionButton(job,action,label,icon){const button=document.createElement('button');button.type='button';button.className='job-action';button.textContent=icon;button.title=label;button.setAttribute('aria-label',label);button.disabled=!actionEnabled(job,action);button.addEventListener('click',event=>{event.stopPropagation();void runJobAction(job,action,button);});return button;}
|
|
340
|
-
async function runJobAction(job,action,button){button.disabled=true;try{const response=await fetch('/api/job-action?id='+encodeURIComponent(job.id)+'&action='+encodeURIComponent(action),{method:'POST'});if(!response.ok)throw new Error(response.status+' '+response.statusText);await refresh(true);}catch(error){button.title=labelForAction(action)+': '+error.message;}finally{renderAll();}}
|
|
341
|
-
function labelForAction(action){return action==='start'?'Start':action==='reconcile'?'Reconcile':'Cancel';}
|
|
342
334
|
function repoName(repository){if(typeof repository!=='string'||!repository)return 'unknown-repo';const parts=repository.split('/').filter(Boolean);return parts.at(-1)||repository;}
|
|
343
|
-
function renderJobList(){jobList.replaceChildren();const visible=filteredJobs();if(!jobs.length){jobList.append(element('li','empty',text('No durable jobs discovered.')));return;}if(!visible.length){jobList.append(element('li','empty',text('No jobs match the selected repo.')));return;}for(const job of visible){const row=element('div','job-row'+(isCompleteUnmerged(job)?' complete-unmerged':''));row.setAttribute('aria-current',String(job.id===selectedJob));row.addEventListener('click',()=>selectJob(job.id));const content=element('div','job-content');const select=document.createElement('button');select.type='button';select.className='job-button';select.setAttribute('aria-current',String(job.id===selectedJob));select.title=job.title||job.id;select.addEventListener('click',event=>{event.stopPropagation();selectJob(job.id);});select.append(element('span','job-title',text(repoName(job.repository)+'/PR#'+value(job.prNumber)+': '+value(job.title||job.id))));const states=element('span','job-status-line');states.append(element('span','badge '+value(job.state),text(value(job.state))),element('span','badge '+value(job.runtimeStatus||'IDLE'),text(value(job.runtimeStatus||'IDLE'))));if(job.executionMode==='autonomous')states.append(element('span','badge flag-autonomous',text('AUTONOMOUS')));if(job.reviewEnabled!==false&&job.githubState!=='MERGED')states.append(element('span','badge flag-review',text('REVIEW REQUIRED')));if(job.githubState==='MERGED'&&job.publication?.version)states.append(element('span','badge SUCCEEDED',text('v'+job.publication.version)));if(isCompleteUnmerged(job))states.append(element('span','badge MERGE_PENDING',text('MERGE PENDING')));const
|
|
335
|
+
function renderJobList(){jobList.replaceChildren();const visible=filteredJobs();if(!jobs.length){jobList.append(element('li','empty',text('No durable jobs discovered.')));return;}if(!visible.length){jobList.append(element('li','empty',text('No jobs match the selected repo.')));return;}for(const job of visible){const row=element('div','job-row'+(isCompleteUnmerged(job)?' complete-unmerged':''));row.setAttribute('aria-current',String(job.id===selectedJob));row.addEventListener('click',()=>selectJob(job.id));const content=element('div','job-content');const select=document.createElement('button');select.type='button';select.className='job-button';select.setAttribute('aria-current',String(job.id===selectedJob));select.title=job.title||job.id;select.addEventListener('click',event=>{event.stopPropagation();selectJob(job.id);});select.append(element('span','job-title',text(repoName(job.repository)+'/PR#'+value(job.prNumber)+': '+value(job.title||job.id))));const states=element('span','job-status-line');states.append(element('span','badge '+value(job.state),text(value(job.state))),element('span','badge '+value(job.runtimeStatus||'IDLE'),text(value(job.runtimeStatus||'IDLE'))));if(job.executionMode==='autonomous')states.append(element('span','badge flag-autonomous',text('AUTONOMOUS')));if(job.reviewEnabled!==false&&job.githubState!=='MERGED')states.append(element('span','badge flag-review',text('REVIEW REQUIRED')));if(job.githubState==='MERGED'&&job.publication?.version)states.append(element('span','badge SUCCEEDED',text('v'+job.publication.version)));if(isCompleteUnmerged(job))states.append(element('span','badge MERGE_PENDING',text('MERGE PENDING')));const primary=element('div','job-primary');primary.append(states);const lastLine=element('div','job-last-line');lastLine.append(element('span','subtle',text(compactCounts(counts(job.tasks)))),element('span','subtle',text(relativeTime(job.updatedAt))));content.append(select,primary,lastLine);row.append(content);jobList.append(element('li','',row));}}
|
|
344
336
|
function taskNode(task,children,depth){const li=element('li');const row=document.createElement('button');row.type='button';row.className='task-row';row.setAttribute('aria-current',String(task.id===selectedTaskId));row.title=task.id;row.addEventListener('click',()=>{const deselect=selectedTaskId===task.id;selectedTaskId=deselect?null:task.id;eventTaskId=deselect?null:task.id;rememberSelection();clearEvents();renderAll();void loadEventHistory();});const id=element('span','task-id',text(task.id));id.style.paddingLeft=Math.min(depth,4)*6+'px';row.append(id,element('span','badge '+value(task.state),text(task.state)));li.append(row);const nested=children.get(task.id)||[];if(nested.length){const ul=element('ul','tree');for(const child of nested)ul.append(taskNode(child,children,depth+1));li.append(ul);}return li;}
|
|
345
337
|
function buildTree(tasks){taskTree.replaceChildren();if(!Array.isArray(tasks)||!tasks.length){taskTree.append(element('li','empty',text('No tasks in durable state.')));return;}const known=new Set(tasks.map(task=>task.id));const children=new Map();const roots=[];for(const task of tasks){if(!task.parentTaskId||!known.has(task.parentTaskId))roots.push(task);else{const siblings=children.get(task.parentTaskId)||[];siblings.push(task);children.set(task.parentTaskId,siblings);}}for(const task of roots)taskTree.append(taskNode(task,children,0));}
|
|
346
338
|
function attemptBudget(task){const attempt=Number(task?.attempt)||0;const max=Number(task?.maxAttempts)||0;if(max>=3&&max%3===0){const effectiveMax=Math.max(max,Math.ceil(attempt/3)*3);return attempt+' / 3×'+(effectiveMax/3);}return attempt+' / '+max;}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { storySizeTimeoutMs, taskOverallTimeoutMs } from './types.js';
|
|
2
|
-
import { schedule, transitionTaskEvent, transitionJobEvent, tryTransitionTaskEvent } from './scheduler.js';
|
|
2
|
+
import { completionGateSatisfied, schedule, transitionTaskEvent, transitionJobEvent, tryTransitionTaskEvent } from './scheduler.js';
|
|
3
3
|
import { implementationComplete, implementationTasks } from './runtime-status.js';
|
|
4
4
|
import { eventFor } from './events.js';
|
|
5
5
|
import { routeWorker, workerCandidates } from './worker-routing.js';
|
|
@@ -25,6 +25,8 @@ export class ReconcilerReviewBase extends ReconcilerRuntimeBase {
|
|
|
25
25
|
async ensureFinalReview(job, prState, headSha) {
|
|
26
26
|
if (job.schedule || job.reviewEnabled === false || prState !== 'OPEN' || job.state !== 'ACTIVE' || !implementationComplete(job) || !headSha)
|
|
27
27
|
return;
|
|
28
|
+
if (job.executionMode === 'autonomous' && !completionGateSatisfied(job))
|
|
29
|
+
return;
|
|
28
30
|
const review = job.review;
|
|
29
31
|
if (review?.headSha === headSha && ['started', 'approved', 'changes_required', 'blocked'].includes(review.outcome))
|
|
30
32
|
return;
|
|
@@ -186,12 +188,11 @@ export class ReconcilerReviewBase extends ReconcilerRuntimeBase {
|
|
|
186
188
|
const input = `Address all reviewer findings for PR #${job.prNumber} at ${headSha}:\n\n${issues.map((issue, index) => `${index + 1}. ${issue}`).join('\n')}`;
|
|
187
189
|
const fixTask = {
|
|
188
190
|
jobId: job.id, id, kind: 'work', priority: job.priority, storySize: 'M', projectName: job.title,
|
|
189
|
-
agentName: '
|
|
190
|
-
adapter: 'codex', input, output: { kind: 'task_pr' },
|
|
191
|
-
routing: { provider: 'openai', model: 'gpt-5.6-luna', reasoning: 'medium', decidedBy: 'review-fix', decidedAt: now },
|
|
191
|
+
agentName: 'implementation', parentTaskId: task.id, dependencies: [task.id], capabilities: ['implementation'],
|
|
192
|
+
workerRequirements: { capabilities: [] }, adapter: 'codex', input, output: { kind: 'task_pr' },
|
|
192
193
|
continuation: null, continuationDeliveredAt: null, state: 'DRAFT', attempt: 0, maxAttempts: 3,
|
|
193
194
|
leaseOwner: null, leaseExpiresAt: null, executionId: null, threadId: null, result: null, plannerResult: null,
|
|
194
|
-
error: null, timeoutMs:
|
|
195
|
+
error: null, timeoutMs: 0, createdAt: now, updatedAt: now
|
|
195
196
|
};
|
|
196
197
|
await this.store.appendTask(fixTask);
|
|
197
198
|
await this.emit(eventFor(job.id, id, task.id, 'review.fix_task_created', 'queued', `Created one fix task ${id} for ${issues.length} reviewer finding(s)`, 'orchestrator', { headSha, issues }, { agent: 'relay', component: 'agents-relay' }));
|
package/dist/reconciler.js
CHANGED
|
@@ -281,8 +281,6 @@ export class Reconciler extends ReconcilerReviewBase {
|
|
|
281
281
|
const latest = planners.at(-1);
|
|
282
282
|
if (latest?.plannerResult?.objective_status === 'satisfied')
|
|
283
283
|
return job;
|
|
284
|
-
if (latest && !job.schedule && job.review && job.review.outcome !== 'approved')
|
|
285
|
-
return job;
|
|
286
284
|
const task = createPlannerRoundTask(job, { timeoutMs: this.options.plannerTimeoutMs ?? storySizeTimeoutMs('M') });
|
|
287
285
|
await this.store.appendTask(task);
|
|
288
286
|
await this.emit(eventFor(job.id, task.id, task.parentTaskId, 'planner.created', 'queued', `Planner task ${task.id} created`, 'orchestrator'));
|