bus: agent state per role, and the Console shows it (#1548)
Row 59 round 2, owner Filbert, candidate manifest 9acfac19 on 3d298920.
Approved by Darkwing (27591) and Dewey (27595); Sage's gate green.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -849,11 +849,14 @@ export class Broker {
|
||||
s.human || s.reader ? 'human' : s.role,
|
||||
)
|
||||
.map((d) => this.#decisionView(d));
|
||||
if (verb === 'agents')
|
||||
return this.#store.all(
|
||||
if (verb === 'agents') {
|
||||
const claims = this.#store.all(
|
||||
"SELECT * FROM role_claims c WHERE business=? AND op='claim' AND seq=(SELECT max(seq) FROM role_claims WHERE business=c.business AND role=c.role) ORDER BY role",
|
||||
s.business,
|
||||
);
|
||||
// A role session gets the claims only: another role's decisions aren't its to read.
|
||||
return s.human || s.reader ? claims.map((c) => this.#agentState(c)) : claims;
|
||||
}
|
||||
if (verb === 'tasks') return this.#taskRows(s.business);
|
||||
return this.#trail(s, identifier(a.subject));
|
||||
}
|
||||
@@ -904,6 +907,28 @@ export class Broker {
|
||||
fail('unknown-verb');
|
||||
}
|
||||
}
|
||||
// Row 59 (#1548): a held role's state for the Agents view, derived from what the bus
|
||||
// already records. Working: messages the current holder received and hasn't marked read;
|
||||
// the runner marks each one read after its turn. Input needed: the role's open decisions
|
||||
// routed to the human, in Inbox order. Working wins over waiting, as on the control board.
|
||||
#agentState(c) {
|
||||
const busy = this.#store.get(
|
||||
"SELECT count(*) AS messages, min(d.at) AS since FROM messages m JOIN deliveries d ON d.message=m.id AND d.op='delivered' WHERE m.business=? AND m.to_role=? AND d.holder_run=? AND NOT EXISTS(SELECT 1 FROM deliveries r WHERE r.message=m.id AND r.op='read')",
|
||||
c.business,
|
||||
c.role,
|
||||
c.holder_run,
|
||||
);
|
||||
const inputNeeded = this.#store
|
||||
.all(
|
||||
`SELECT d.* FROM decisions d WHERE business=? AND raised_by_role=? AND route_to='human' AND NOT EXISTS(SELECT 1 FROM decision_events x WHERE x.decision=d.id AND x.op IN ${CLOSED}) ORDER BY CASE class WHEN 'gated' THEN 0 ELSE 1 END,seq`,
|
||||
c.business,
|
||||
c.role,
|
||||
)
|
||||
.map((d) => ({ id: d.id, question: d.question, class: d.class, blocking: !!d.blocking, task_ref: d.task_ref, at: d.at }));
|
||||
const working = busy.messages ? { messages: busy.messages, since: busy.since } : null;
|
||||
const state = working ? 'working' : inputNeeded.length ? 'waiting' : 'idle';
|
||||
return { ...c, state, working, inputNeeded };
|
||||
}
|
||||
#claimEnd(s, h, op, decision) {
|
||||
this.#store.run(
|
||||
'INSERT INTO role_claims(at,business,role,op,holder_run,harness,address,by,decision) VALUES(?,?,?,?,?,?,?,?,?)',
|
||||
|
||||
Reference in New Issue
Block a user