agent sessions: show conversations, not storage ghosts
This commit is contained in:
parent
12da479c23
commit
dd19ab227f
2 changed files with 31 additions and 10 deletions
|
|
@ -152,12 +152,20 @@ souveraine_json() {
|
||||||
local out="[]"
|
local out="[]"
|
||||||
while IFS= read -r f; do
|
while IFS= read -r f; do
|
||||||
[ -n "$f" ] || continue
|
[ -n "$f" ] || continue
|
||||||
local s
|
local s agent_id parent_id agent_name
|
||||||
s=$(jq -c '
|
agent_id=$(jq -r '.agent_id // empty' "$f" 2>/dev/null)
|
||||||
if .archived == true then empty else {
|
parent_id=${agent_id%-sub}
|
||||||
|
agent_name=$(jq -r '.name // empty' "$dir/$parent_id/agent.json" 2>/dev/null)
|
||||||
|
[ -n "$agent_name" ] || agent_name="Souveraine"
|
||||||
|
s=$(jq -c --arg agentName "$agent_name" '
|
||||||
|
# A zero-message record is a newly-minted conversation slot, not
|
||||||
|
# an agent session. Rendering it made every panel restart add a
|
||||||
|
# plausible-looking ghost row.
|
||||||
|
if .archived == true or (.message_count // 0) == 0 then empty else {
|
||||||
provider: "souveraine",
|
provider: "souveraine",
|
||||||
id: (.id // ""),
|
id: (.id // ""),
|
||||||
agentId: (.agent_id // ""),
|
agentId: (.agent_id // ""),
|
||||||
|
agentName: $agentName,
|
||||||
cwd: "",
|
cwd: "",
|
||||||
model: "",
|
model: "",
|
||||||
lastActivity: (.last_message_at // .updated_at // ""),
|
lastActivity: (.last_message_at // .updated_at // ""),
|
||||||
|
|
@ -187,6 +195,7 @@ SOUV=$(souveraine_json); [ -n "$SOUV" ] || SOUV='{"available":false,"er
|
||||||
# timestamps would be a guess wearing the costume of a measurement.
|
# timestamps would be a guess wearing the costume of a measurement.
|
||||||
jq -c -n \
|
jq -c -n \
|
||||||
--argjson now "$NOW" \
|
--argjson now "$NOW" \
|
||||||
|
--argjson window "$((WINDOW_MIN * 60))" \
|
||||||
--argjson claude "$CLAUDE" \
|
--argjson claude "$CLAUDE" \
|
||||||
--argjson codex "$CODEX" \
|
--argjson codex "$CODEX" \
|
||||||
--argjson souv "$SOUV" '
|
--argjson souv "$SOUV" '
|
||||||
|
|
@ -207,6 +216,10 @@ jq -c -n \
|
||||||
else "idle" end;
|
else "idle" end;
|
||||||
( ($claude.sessions // []) + ($codex.sessions // []) + ($souv.sessions // []) )
|
( ($claude.sessions // []) + ($codex.sessions // []) + ($souv.sessions // []) )
|
||||||
| map(. + {state: state($now), age: ($now - (.lastActivity | epoch))})
|
| map(. + {state: state($now), age: ($now - (.lastActivity | epoch))})
|
||||||
|
# `find -mmin` is only the cheap filesystem prefilter. Restores and copies
|
||||||
|
# can touch a May record today; enforce the promised window against the
|
||||||
|
# the record timestamp before anything calls it a current session.
|
||||||
|
| map(select(.age >= 0 and .age <= $window))
|
||||||
| sort_by(.age)
|
| sort_by(.age)
|
||||||
as $all
|
as $all
|
||||||
| {
|
| {
|
||||||
|
|
@ -214,9 +227,9 @@ jq -c -n \
|
||||||
sessions: $all,
|
sessions: $all,
|
||||||
active: ($all | map(select(.state == "active")) | length),
|
active: ($all | map(select(.state == "active")) | length),
|
||||||
providers: {
|
providers: {
|
||||||
claude: ($claude | del(.sessions)) + {sessions: ($claude.sessions // [] | length)},
|
claude: ($claude | del(.sessions)) + {sessions: ($all | map(select(.provider == "claude")) | length)},
|
||||||
codex: ($codex | del(.sessions)) + {sessions: ($codex.sessions // [] | length)},
|
codex: ($codex | del(.sessions)) + {sessions: ($all | map(select(.provider == "codex")) | length)},
|
||||||
souveraine: ($souv | del(.sessions)) + {sessions: ($souv.sessions // [] | length)}
|
souveraine: ($souv | del(.sessions)) + {sessions: ($all | map(select(.provider == "souveraine")) | length)}
|
||||||
}
|
}
|
||||||
}' 2>/dev/null \
|
}' 2>/dev/null \
|
||||||
|| printf '{"ts":%s,"sessions":[],"active":0,"providers":{"claude":{"available":false,"error":"merge failed"},"codex":{"available":false,"error":"merge failed"},"souveraine":{"available":false,"error":"merge failed"}}}\n' "$NOW"
|
|| printf '{"ts":%s,"sessions":[],"active":0,"providers":{"claude":{"available":false,"error":"merge failed"},"codex":{"available":false,"error":"merge failed"},"souveraine":{"available":false,"error":"merge failed"}}}\n' "$NOW"
|
||||||
|
|
|
||||||
|
|
@ -92,15 +92,23 @@ Singleton {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Short human label for a session — the project directory if we have one,
|
// Short human label for a session — the project directory if we have one,
|
||||||
// else the agent, else a truncated id. Never an empty string: a blank chip
|
// else the configured agent name plus a conversation discriminator, else
|
||||||
// is indistinguishable from a broken one.
|
// a truncated id. Never an empty string: a blank chip is indistinguishable
|
||||||
|
// from a broken one, and ten rows all called "agent" are only technically
|
||||||
|
// non-blank.
|
||||||
function sessionLabel(s) {
|
function sessionLabel(s) {
|
||||||
if (!s)
|
if (!s)
|
||||||
return "";
|
return "";
|
||||||
if (s.cwd && s.cwd.length > 0)
|
if (s.cwd && s.cwd.length > 0)
|
||||||
return s.cwd.split("/").filter(x => x.length > 0).pop() ?? s.cwd;
|
return s.cwd.split("/").filter(x => x.length > 0).pop() ?? s.cwd;
|
||||||
if (s.provider === "souveraine")
|
if (s.provider === "souveraine") {
|
||||||
return s.subconscious ? "subconscious" : "agent";
|
const name = s.agentName && s.agentName.length > 0
|
||||||
|
? s.agentName : "Souveraine";
|
||||||
|
const id = (s.id ?? "").slice(0, 4);
|
||||||
|
return s.subconscious
|
||||||
|
? `${name} · subconscious · ${id}`
|
||||||
|
: `${name} · ${id}`;
|
||||||
|
}
|
||||||
return (s.id ?? "").slice(0, 8);
|
return (s.id ?? "").slice(0, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue