@volter/supercode-orchestrator 0.4.142 → 0.4.143
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/board/dispatch.mjs +8 -3
- package/board/workflow.mjs +20 -1
- package/package.json +1 -1
package/board/dispatch.mjs
CHANGED
|
@@ -24,7 +24,7 @@ import { basename, dirname, join } from 'node:path';
|
|
|
24
24
|
import { createHash, randomUUID } from 'node:crypto';
|
|
25
25
|
import { fileURLToPath } from 'node:url';
|
|
26
26
|
import { view, boardPath, claimer, event, json, listBoards, logsDir, now, openBoard, setActor, tx } from './store.mjs';
|
|
27
|
-
import { doors, fire, loadWorkflow, resumeOf, runSpec, requestSessionClose, retireSupersededRuns, refreshRelationAnswers, transitionsFor, scopeOf, statusOf, templateValue, workflowFor } from './workflow.mjs';
|
|
27
|
+
import { doors, fire, loadWorkflow, resumeOf, runSpec, runWorkingSeconds, requestSessionClose, retireSupersededRuns, refreshRelationAnswers, transitionsFor, scopeOf, statusOf, templateValue, workflowFor } from './workflow.mjs';
|
|
28
28
|
import { checkWorkspace, assertWorkspaceOwner, resolveWorkspace } from './workspace.mjs';
|
|
29
29
|
import { evaluate, holds, render } from './expr.mjs';
|
|
30
30
|
import {
|
|
@@ -331,13 +331,13 @@ function supervise(board, fleet, settings, report, entry, effects) {
|
|
|
331
331
|
return;
|
|
332
332
|
}
|
|
333
333
|
// a run past its runtime limit (the status's `run.limits.runtime`), as Hermes times its workers out
|
|
334
|
-
if (limits.runtime && runRow &&
|
|
334
|
+
if (limits.runtime && runRow && session?.wait_started_at == null && runWorkingSeconds(runRow, t) > Number(limits.runtime)) {
|
|
335
335
|
observe('timed_out', { limit_seconds: limits.runtime, error: `ran past max_runtime ${limits.runtime}s` }, 'timed_out');
|
|
336
336
|
return;
|
|
337
337
|
}
|
|
338
338
|
if (session?.surface === 'headless') {
|
|
339
339
|
// Hermes's stale check: a worker running past the limit with no heartbeat in the last hour is stopped
|
|
340
|
-
if (limits.stale && runRow &&
|
|
340
|
+
if (limits.stale && runRow && session?.wait_started_at == null && runWorkingSeconds(runRow, t) >= Number(limits.stale) && !(task.last_heartbeat_at && t - Number(task.last_heartbeat_at) < 3600)) {
|
|
341
341
|
observe('stale', { timeout_seconds: limits.stale, pid: session.pid, error: `no heartbeat after ${t - Number(runRow.started_at)}s running` }, 'reclaimed');
|
|
342
342
|
return;
|
|
343
343
|
}
|
|
@@ -733,6 +733,7 @@ function observeIdle(board, fleet, settings, report, entry, effects) {
|
|
|
733
733
|
if (!(entry.workflow.statuses[status]?.on?.session_idle || entry.workflow.on?.session_idle || entry.workflow.run?.on?.session_idle)) return;
|
|
734
734
|
const runRow = currentRun(db, id);
|
|
735
735
|
const session = runRow?.metadata?.supercode;
|
|
736
|
+
if (session?.wait_started_at != null) return;
|
|
736
737
|
if (!session?.session_id || !['pane', 'native'].includes(session.surface) || session.offline_since != null) return;
|
|
737
738
|
if (session.surface === 'native' && fleet.native?.get(addressOf(session))?.alive !== true) return;
|
|
738
739
|
const live = fleet.sessions.find((x) => x.address === addressOf(session));
|
|
@@ -815,6 +816,10 @@ export async function sessionEffect(board, e) {
|
|
|
815
816
|
if (e.kind === 'send_to_actor') {
|
|
816
817
|
const row = view(board, db => e.runId ? db.prepare('SELECT metadata FROM task_runs WHERE id=?').get(e.runId) : null);
|
|
817
818
|
const session = json(row?.metadata, {})?.supercode;
|
|
819
|
+
if (session?.wait_started_at != null) {
|
|
820
|
+
tx(board, db => event(db, e.id, 'actor_notice_suppressed', { notice: e.durableId, reason: 'run is waiting', run_id: e.runId }, e.runId));
|
|
821
|
+
return true;
|
|
822
|
+
}
|
|
818
823
|
const address = addressOf(session);
|
|
819
824
|
let receipt;
|
|
820
825
|
try {
|
package/board/workflow.mjs
CHANGED
|
@@ -186,13 +186,21 @@ function onlyTicks(was, body) {
|
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
/** Seconds a card's runs spent by role, and the rest of its life as `waiting`. */
|
|
189
|
+
export function runWorkingSeconds(row, at = now()) {
|
|
190
|
+
const metadata = typeof row.metadata === 'string' ? json(row.metadata, {}) : row.metadata;
|
|
191
|
+
const session = metadata?.supercode ?? {};
|
|
192
|
+
const end = Number(row.ended_at ?? at);
|
|
193
|
+
const waiting = Number(session.wait_seconds ?? 0) + (session.wait_started_at != null ? Math.max(0, end - Number(session.wait_started_at)) : 0);
|
|
194
|
+
return Math.max(0, end - Number(row.started_at ?? end) - waiting);
|
|
195
|
+
}
|
|
196
|
+
|
|
189
197
|
function timeOf(db, task) {
|
|
190
198
|
const t = now();
|
|
191
199
|
const out = { coding: 0, reviewing: 0, auditing: 0, triaging: 0 };
|
|
192
200
|
const key = { implementer: 'coding', reviewer: 'reviewing', auditor: 'auditing', triager: 'triaging' };
|
|
193
201
|
for (const r of all(db, 'SELECT started_at, ended_at, metadata FROM task_runs WHERE task_id = ?', task.id)) {
|
|
194
202
|
const role = json(r.metadata, {})?.supercode?.role ?? 'implementer';
|
|
195
|
-
const spent =
|
|
203
|
+
const spent = runWorkingSeconds(r, t);
|
|
196
204
|
const k = key[role] ?? role;
|
|
197
205
|
out[k] = (out[k] ?? 0) + spent;
|
|
198
206
|
}
|
|
@@ -612,6 +620,17 @@ const ACTIONS = {
|
|
|
612
620
|
const result = fire(ctx.db, ctx.board, ctx.entry, ctx.id, name, { roles: [].concat(as), payload, extra: { lanes: lanesIn(ctx.entry) } });
|
|
613
621
|
ctx.effects.push(...result.effects);
|
|
614
622
|
},
|
|
623
|
+
wait_run(ctx, waiting) {
|
|
624
|
+
if (typeof waiting !== 'boolean') throw new Error('wait_run requires a boolean');
|
|
625
|
+
const at = now();
|
|
626
|
+
runSession(ctx, session => {
|
|
627
|
+
if (waiting) return { ...session, wait_started_at: session.wait_started_at ?? at };
|
|
628
|
+
if (session.wait_started_at == null) return session;
|
|
629
|
+
return { ...session, wait_started_at: null,
|
|
630
|
+
wait_seconds: Number(session.wait_seconds ?? 0) + Math.max(0, at - Number(session.wait_started_at)),
|
|
631
|
+
goal_nudged_at: at };
|
|
632
|
+
});
|
|
633
|
+
},
|
|
615
634
|
record(ctx, args, scope) {
|
|
616
635
|
const kind = typeof args === 'string' ? args : args?.kind;
|
|
617
636
|
const given = typeof args === 'object' && args?.payload ? args.payload : null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/supercode-orchestrator",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.143",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The orchestrator runtime over the Volter Harness ontology: one typed operational model whose folder is its serialization, read and written through the harness orchestration doors (docs/ORCHESTRATOR-IR.md)",
|
|
6
6
|
"exports": {
|