agents-relay 2.0.18 → 2.0.19
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 +1 -1
- package/dist/dashboard.js +6 -6
- package/dist/relayd.js +38 -2
- package/package.json +1 -1
package/dist/dashboard-html.js
CHANGED
|
@@ -451,7 +451,7 @@ function routeWorker(record){const id=record?.selected?.worker?.id||record?.work
|
|
|
451
451
|
function renderAudit(records){auditLog.replaceChildren();if(!Array.isArray(records)||!records.length){auditLog.append(element('p','empty',text('No schema v5 routing decisions yet.')));return;}for(const record of records){const card=element('article','audit-entry');const head=element('div','audit-entry-head');head.append(element('strong','',text(routeWorker(record)+' · '+value(record?.selected?.model?.model))),element('span','subtle',text(new Date(record.timestamp).toLocaleString())));card.append(head);const correlation=record.correlation||{};card.append(element('div','subtle',text([correlation.job_id,correlation.task_id].filter(Boolean).join(' / ')||'uncorrelated')));const probabilities=record.decision_evidence?.probabilities||{};const gates=(record.gate_results||[]).filter(item=>!item.eligible).map(item=>item.candidate_id+': '+item.rejection_reasons.join(', '));const nl=String.fromCharCode(10);const details=document.createElement('pre');details.textContent='fallback: '+String(Boolean(record.decision_evidence?.fallback))+(Object.keys(probabilities).length?nl+'probabilities: '+JSON.stringify(probabilities,null,2):'')+(gates.length?nl+'rejected: '+gates.join(nl):'');card.append(details);auditLog.append(card);}}
|
|
452
452
|
async function drawAudit(){auditRefresh.disabled=true;try{renderAudit(await loadJSON('/api/decision-audit'));}catch(error){auditLog.replaceChildren(element('p','error-state',text('Audit unavailable: '+error.message)));}finally{auditRefresh.disabled=false;}}
|
|
453
453
|
async function drawRules(){rulesStatus.textContent='';try{const rules=await loadJSON('/api/execution-router-rules');rulesText.value=typeof rules.text==='string'?rules.text:'';rulesMeta.textContent=rules.hash&&rules.hash!=='none'?'Loaded · '+rules.hash.slice(0,12):'No custom rules saved';}catch(error){rulesMeta.textContent='Unavailable';rulesStatus.textContent='Could not load rules: '+error.message;}void drawAudit();}
|
|
454
|
-
async function testRouter(){rulesTest.disabled=true;routerTestResults.replaceChildren(element('p','subtle',text('
|
|
454
|
+
async function testRouter(){rulesTest.disabled=true;routerTestResults.replaceChildren(element('p','subtle',text('Calling router with current status…')));try{const response=await fetch('/api/router-test',{method:'POST'});if(!response.ok)throw new Error(response.status+' '+await response.text());const result=await response.json();const selected=result.selected||{};const current=result.current||{};routerTestResults.replaceChildren(element('strong','',text((selected.worker||'—')+' · '+(selected.model||'—'))));routerTestResults.append(element('div','subtle',text('route: '+(selected.route||'—'))),element('div','subtle',text('fallback: '+String(Boolean(result.fallback)))),element('pre','',text('probabilities: '+JSON.stringify(result.probabilities||{},null,2)+String.fromCharCode(10)+'browser workspace: '+JSON.stringify(current.browserWorkspace||null,null,2)+String.fromCharCode(10)+'chatgpt running: '+String(current.chatgptRunning??0))));}catch(error){routerTestResults.replaceChildren(element('p','error-state',text('Router test failed: '+error.message)));}finally{rulesTest.disabled=false;}}
|
|
455
455
|
async function saveRules(){rulesSave.disabled=true;rulesStatus.textContent='Saving…';try{const response=await fetch('/api/execution-router-rules',{method:'PUT',headers:{'content-type':'text/plain; charset=utf-8'},body:rulesText.value});if(!response.ok)throw new Error(response.status+' '+await response.text());const rules=await response.json();rulesMeta.textContent='Saved · '+rules.hash.slice(0,12);rulesStatus.textContent='Saved. New routing decisions will load these rules.';}catch(error){rulesStatus.textContent='Save failed: '+error.message;}finally{rulesSave.disabled=false;}}
|
|
456
456
|
async function drawShortcuts(){shortcutsStatus.textContent='';shortcutsText.value=chatShortcutText();}
|
|
457
457
|
function saveShortcuts(){const value=shortcutsText.value.trim();if(value)localStorage.setItem(CHAT_SHORTCUTS_KEY,value);else localStorage.removeItem(CHAT_SHORTCUTS_KEY);shortcutsText.value=chatShortcutText();shortcutsStatus.textContent='Saved.';}
|
package/dist/dashboard.js
CHANGED
|
@@ -57,7 +57,7 @@ async function eventHistory(jobId, taskId, limit) {
|
|
|
57
57
|
}
|
|
58
58
|
export { dashboardHtml, dashboardVersion } from './dashboard-html.js';
|
|
59
59
|
import { dashboardHtml, dashboardVersion } from './dashboard-html.js';
|
|
60
|
-
export function serveDashboard(store, port = 8787, bus, refreshMs = 300000, jobId, usageRegistry, overviewProvider, webhook, statusProvider, githubUsageProvider, exactJobProvider, actions,
|
|
60
|
+
export function serveDashboard(store, port = 8787, bus, refreshMs = 300000, jobId, usageRegistry, overviewProvider, webhook, statusProvider, githubUsageProvider, exactJobProvider, actions, routerTestProvider, decisionAuditProvider) {
|
|
61
61
|
const legacyActions = typeof exactJobProvider === 'object' && exactJobProvider !== null ? exactJobProvider : undefined;
|
|
62
62
|
const legacyExactJobProvider = !exactJobProvider && githubUsageProvider ? githubUsageProvider : undefined;
|
|
63
63
|
const resolvedExactJobProvider = typeof exactJobProvider === 'function' ? exactJobProvider : legacyExactJobProvider;
|
|
@@ -442,21 +442,21 @@ export function serveDashboard(store, port = 8787, bus, refreshMs = 300000, jobI
|
|
|
442
442
|
res.end('Method not allowed');
|
|
443
443
|
return;
|
|
444
444
|
}
|
|
445
|
-
if (req.url === '/api/router-
|
|
445
|
+
if (req.url === '/api/router-test') {
|
|
446
446
|
if (req.method !== 'POST') {
|
|
447
447
|
res.writeHead(405, { allow: 'POST' });
|
|
448
448
|
res.end('Method not allowed');
|
|
449
449
|
return;
|
|
450
450
|
}
|
|
451
|
-
if (!
|
|
451
|
+
if (!routerTestProvider) {
|
|
452
452
|
res.writeHead(503);
|
|
453
|
-
res.end('Router
|
|
453
|
+
res.end('Router test unavailable');
|
|
454
454
|
return;
|
|
455
455
|
}
|
|
456
456
|
try {
|
|
457
|
-
const
|
|
457
|
+
const result = await routerTestProvider();
|
|
458
458
|
res.writeHead(200, { 'content-type': 'application/json' });
|
|
459
|
-
res.end(JSON.stringify(
|
|
459
|
+
res.end(JSON.stringify(result));
|
|
460
460
|
}
|
|
461
461
|
catch (error) {
|
|
462
462
|
res.writeHead(500);
|
package/dist/relayd.js
CHANGED
|
@@ -24,7 +24,8 @@ import { decisionMode, LayaCliDecisionEngine } from './decision.js';
|
|
|
24
24
|
import { JsonlDecisionAuditStore } from './decision-audit.js';
|
|
25
25
|
import { summarizeRuntime } from './runtime-summary.js';
|
|
26
26
|
import { executionRouterRulesPath } from './routing-policy.js';
|
|
27
|
-
import {
|
|
27
|
+
import { workerCandidates } from './worker-routing.js';
|
|
28
|
+
import { routeExecution } from './execution-routing.js';
|
|
28
29
|
export async function overlayOperationalOverviews(overviews, storeFor) {
|
|
29
30
|
return await Promise.all(overviews.map(async (item) => {
|
|
30
31
|
const store = storeFor(item.job.repository, item.job.prNumber);
|
|
@@ -347,7 +348,42 @@ export async function runDaemon(argv) {
|
|
|
347
348
|
taskCancel: workspaceTaskAction('cancel'),
|
|
348
349
|
taskComplete: workspaceTaskComplete,
|
|
349
350
|
taskSetState: workspaceTaskSetState,
|
|
350
|
-
}, async () =>
|
|
351
|
+
}, async () => {
|
|
352
|
+
const usage = await usageRegistry.snapshot();
|
|
353
|
+
const runtime = summarizeRuntime(cachedOverviews.map(item => item.job));
|
|
354
|
+
const workers = workerCandidates([
|
|
355
|
+
{ name: 'codex', id: 'codex', capabilities: ['model', 'codex'] },
|
|
356
|
+
{ name: 'chatgpt', id: 'chatgpt/browser-worker', capabilities: ['model', 'chatgpt', 'browser-harness'] },
|
|
357
|
+
], [], usage);
|
|
358
|
+
const result = await routeExecution(workers, { capabilities: [] }, {
|
|
359
|
+
decisionEngine: new LayaCliDecisionEngine(),
|
|
360
|
+
decisionMode: 'active',
|
|
361
|
+
taskFacts: { storySize: 'M', role: 'router-test' },
|
|
362
|
+
usage,
|
|
363
|
+
chatgptRunning: runtime.workers.chatgpt,
|
|
364
|
+
});
|
|
365
|
+
return {
|
|
366
|
+
selected: {
|
|
367
|
+
route: result.audit?.selected?.id,
|
|
368
|
+
worker: result.selection.workerId,
|
|
369
|
+
adapter: result.selection.adapter,
|
|
370
|
+
provider: result.candidate.routing.provider,
|
|
371
|
+
model: result.candidate.routing.model,
|
|
372
|
+
profile: result.candidate.routing.profile,
|
|
373
|
+
reasoning: result.candidate.routing.reasoning,
|
|
374
|
+
},
|
|
375
|
+
probabilities: result.candidate.routing.decisionEvidence?.probabilities ?? {},
|
|
376
|
+
fallback: result.candidate.routing.decisionEvidence?.fallback ?? false,
|
|
377
|
+
current: {
|
|
378
|
+
chatgptRunning: runtime.workers.chatgpt,
|
|
379
|
+
browserWorkspace: usage.browserWorkspace ?? null,
|
|
380
|
+
providers: usage.providers,
|
|
381
|
+
credits: usage.credits,
|
|
382
|
+
},
|
|
383
|
+
decisionInput: result.audit?.decision_input ?? null,
|
|
384
|
+
gates: result.audit?.gate_results ?? [],
|
|
385
|
+
};
|
|
386
|
+
}, async () => (await decisionAuditStore.read()).filter((record) => record.record_type === 'decision' && record.schema_version === 5));
|
|
351
387
|
await once(server, 'listening');
|
|
352
388
|
const reconcileSafely = async () => {
|
|
353
389
|
try {
|