Fix repo face ready state after operator naps
This commit is contained in:
parent
8c06c59ab7
commit
a46ee828a6
3 changed files with 52 additions and 5 deletions
|
|
@ -108,11 +108,13 @@ async function buildSnapshot() {
|
|||
error: participant.faceStatePath ? "State file was not readable." : "No Face state path registered.",
|
||||
tree: [],
|
||||
};
|
||||
participant.restState = participant.faceState.restState ?? null;
|
||||
}
|
||||
const activeTurns = participantSnapshots.filter((participant) => participant.activeJobId);
|
||||
const readyNow = participantSnapshots.filter((participant) =>
|
||||
participant.status === "active" &&
|
||||
!participant.activeJobId &&
|
||||
participant.restState?.isNapping !== true &&
|
||||
typeof participant.nextTurnInMinutes === "number" &&
|
||||
participant.nextTurnInMinutes <= 0,
|
||||
);
|
||||
|
|
@ -218,8 +220,15 @@ function buildUpcomingTurns(participants) {
|
|||
avatarUrl: participant.avatarUrl,
|
||||
participantKind: participant.participantKind,
|
||||
activeJobId: participant.activeJobId,
|
||||
restState: participant.restState,
|
||||
pendingMentionCount: participant.pendingMentionCount,
|
||||
shuffleReason: participant.pendingMentionCount > 0 ? "mention" : participant.activeJobId ? "active" : null,
|
||||
shuffleReason: participant.pendingMentionCount > 0
|
||||
? "mention"
|
||||
: participant.activeJobId
|
||||
? "active"
|
||||
: participant.restState?.isNapping === true
|
||||
? "nap"
|
||||
: null,
|
||||
nextTurnInMinutes: participant.nextTurnInMinutes,
|
||||
effectiveSpeed: participant.effectiveSpeed,
|
||||
heat: participant.heat,
|
||||
|
|
@ -411,6 +420,7 @@ async function readFaceStates(identityMetadata) {
|
|||
path: identity.faceStatePath,
|
||||
summary: truncate(rendered?.summary ?? "", 1200),
|
||||
counts: countFaceState(typedState),
|
||||
restState: projectRestState(typedState),
|
||||
tree: buildFaceStateTree(typedState),
|
||||
});
|
||||
} catch (error) {
|
||||
|
|
@ -425,6 +435,21 @@ async function readFaceStates(identityMetadata) {
|
|||
return states;
|
||||
}
|
||||
|
||||
function projectRestState(typedState) {
|
||||
const sleepCycle = typedState?.scheduledRuntime?.sleepCycle;
|
||||
if (!sleepCycle || typeof sleepCycle !== "object") {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
isNapping: sleepCycle.isNapping === true,
|
||||
napEndsAt: stringOrNull(sleepCycle.currentNapEndsAt),
|
||||
nextNapStartsAt: stringOrNull(sleepCycle.nextNapStartsAt),
|
||||
activeDreamThemes: Array.isArray(sleepCycle.activeDreamThemes)
|
||||
? sleepCycle.activeDreamThemes.slice(0, 8).map(String)
|
||||
: [],
|
||||
};
|
||||
}
|
||||
|
||||
function countFaceState(typedState) {
|
||||
return {
|
||||
shortTerm: typedState?.thoughtMemory?.shortTerm?.length ?? 0,
|
||||
|
|
@ -1242,7 +1267,11 @@ function renderHtml(snapshot) {
|
|||
const text = (value) => value === null || value === undefined || value === "" ? "missing" : String(value);
|
||||
const esc = (value) => text(value).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
||||
const number = (value) => typeof value === "number" ? value.toLocaleString(undefined, { maximumFractionDigits: 2 }) : "missing";
|
||||
const minutes = (value) => typeof value === "number" ? (value <= 0 ? "ready" : value.toLocaleString(undefined, { maximumFractionDigits: 1 }) + "m") : "missing";
|
||||
const minutes = (value, restState = null) => restState?.isNapping === true
|
||||
? "napping"
|
||||
: typeof value === "number"
|
||||
? (value <= 0 ? "ready" : value.toLocaleString(undefined, { maximumFractionDigits: 1 }) + "m")
|
||||
: "missing";
|
||||
const relative = (timestamp) => {
|
||||
if (!timestamp) return "missing";
|
||||
const time = Date.parse(timestamp);
|
||||
|
|
@ -1303,7 +1332,7 @@ function renderHtml(snapshot) {
|
|||
function renderCtb(turns) {
|
||||
return "<nav class=\\"ctb-rail\\" aria-label=\\"Upcoming CTB turns\\">" + turns.map((turn) => {
|
||||
const klass = ["turn-card", turn.identityId === selectedIdentity ? "selected" : "", turn.activeJobId ? "active-turn" : "", turn.pendingMentionCount > 0 ? "mention-turn" : ""].filter(Boolean).join(" ");
|
||||
return "<button class=\\"" + klass + "\\" type=\\"button\\" data-select=\\"" + esc(turn.identityId) + "\\" title=\\"" + esc(turn.displayName + " / " + minutes(turn.nextTurnInMinutes)) + "\\">" + avatarHtml(turn) + "<strong>" + esc(turn.displayName) + "</strong><span>" + esc(minutes(turn.nextTurnInMinutes)) + "</span>" + (turn.shuffleReason ? "<span class=\\"turn-reason\\">" + esc(turn.shuffleReason) + "</span>" : "") + "</button>";
|
||||
return "<button class=\\"" + klass + "\\" type=\\"button\\" data-select=\\"" + esc(turn.identityId) + "\\" title=\\"" + esc(turn.displayName + " / " + minutes(turn.nextTurnInMinutes, turn.restState)) + "\\">" + avatarHtml(turn) + "<strong>" + esc(turn.displayName) + "</strong><span>" + esc(minutes(turn.nextTurnInMinutes, turn.restState)) + "</span>" + (turn.shuffleReason ? "<span class=\\"turn-reason\\">" + esc(turn.shuffleReason) + "</span>" : "") + "</button>";
|
||||
}).join("") + "</nav>";
|
||||
}
|
||||
|
||||
|
|
@ -1312,7 +1341,7 @@ function renderHtml(snapshot) {
|
|||
const counts = agent.faceState?.counts || {};
|
||||
const memoryCount = (counts.shortTerm || 0) + (counts.memories || 0);
|
||||
return "<section class=\\"pane inspector-pane\\">" + renderControls(snapshot, participants) + "<div class=\\"inspector-hero\\">" + avatarHtml(agent) + "<div><p class=\\"kicker\\">Selected Face</p><h1>" + esc(agent.displayName) + "</h1><p class=\\"muted mono\\">" + esc(agent.identityId) + " / " + esc(agent.repoName) + "</p></div></div><div class=\\"agent-stats\\">" +
|
||||
statBar("Turn", minutes(agent.nextTurnInMinutes), turnPercent(agent.nextTurnInMinutes), "cool") +
|
||||
statBar("Turn", minutes(agent.nextTurnInMinutes, agent.restState), turnPercent(agent.nextTurnInMinutes), agent.restState?.isNapping === true ? "warm" : "cool") +
|
||||
statBar("Memory", number(memoryCount), Math.min(100, memoryCount * 7), "cool") +
|
||||
statBar("Pressure", number(counts.pressures || 0), Math.min(100, (counts.pressures || 0) * 14), (counts.pressures || 0) > 4 ? "hot" : "") +
|
||||
statBar("Heat", number(agent.heat), Math.min(100, (agent.heat || 0) * 34), (agent.heat || 0) > 1.5 ? "hot" : "") +
|
||||
|
|
|
|||
|
|
@ -758,7 +758,24 @@ function projectSleepCycleForOperatorAbsence(
|
|||
now: Date,
|
||||
): VoidScheduledRuntime["sleepCycle"] {
|
||||
if (idleCooling?.napModeActive !== true) {
|
||||
return sleepCycle;
|
||||
const activeDreamThemes = sleepCycle.activeDreamThemes.filter((theme) => theme !== "operator-absence-dreaming");
|
||||
if (sleepCycle.isNapping !== true || !sleepCycle.activeDreamThemes.includes("operator-absence-dreaming")) {
|
||||
return activeDreamThemes.length === sleepCycle.activeDreamThemes.length
|
||||
? sleepCycle
|
||||
: {
|
||||
...sleepCycle,
|
||||
activeDreamThemes,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...sleepCycle,
|
||||
isNapping: false,
|
||||
currentNapStartedAt: undefined,
|
||||
currentNapEndsAt: undefined,
|
||||
nextNapStartsAt: new Date(now.getTime() + 180 * 60_000).toISOString(),
|
||||
activeDreamThemes,
|
||||
};
|
||||
}
|
||||
|
||||
const nowMs = now.getTime();
|
||||
|
|
|
|||
|
|
@ -344,3 +344,4 @@
|
|||
{"ts":"2026-05-25T12:49:01Z","type":"implementation","status":"ok","note":"Renamed the local EpiphanyGraph repo to Norn and updated the Norn Face registry/state to use E:/Projects/Norn and repo:Norn. The Norn repo builds with dotnet and the Norn viewer typecheck/build passes."}
|
||||
{"ts":"2026-05-25T17:36:36Z","type":"implementation","status":"ok","note":"Revived the local VoidBot stack and repo Face swarm: npm run stack:start restored runtime-stack.json to ready with bot PID 24512 and worker PID 30640, npm run state:check passed live-service gates with only a backup warning, state/agent-swarm-paused.json is now paused=false, repo Face heartbeats and mood drift ran ok, first unpaused Void moderation turn completed ok, and Norn reconciled into the active CTB participant roster."}
|
||||
{"ts":"2026-05-25T18:53:32Z","type":"implementation","status":"ok","note":"Slowed repo Face CTB cadence by 10x in the live control surface: cadenceMultiplier is now 0.04, scheduler/dashboard/API minimum is 0.01, and effective-speed/recovery floors now preserve sub-0.1 cadence instead of silently flattening it. Typecheck and a real heartbeat pass succeeded without queuing an unprompted Face turn."}
|
||||
{"ts":"2026-05-25T21:28:29Z","type":"implementation","status":"ok","note":"Fixed repo Face CTB wake/ready split: operator-absence naps now end when operator absence ends, and the swarm dashboard includes Face rest state so napping Faces are not shown as ready. Verified build and a forced repo-face heartbeat queued Fensalir, Norn, and Nibu."}
|
||||
|
|
|
|||
Loading…
Reference in a new issue