Improve agent status dashboard: fix memory file detection, show status text and session count
- Fix departments route: use readdirSync instead of broken glob pattern to find memory files - Show global memory file info (last modified, size) when no per-agent files exist - Add status text label (Running/Idle) and session count display to AgentStatus component - Improve visual layout with fixed-width info column - Closes #2.
This commit is contained in:
parent
1cd5c252b3
commit
bbef0ebeed
2 changed files with 45 additions and 24 deletions
|
|
@ -1,22 +1,38 @@
|
||||||
// GET /api/agent/departments — list departments with status
|
// GET /api/agent/departments — list departments with status
|
||||||
import { execSync } from "child_process";
|
import { execSync } from "child_process";
|
||||||
|
import { readdirSync, statSync } from "fs";
|
||||||
|
import { join } from "path";
|
||||||
import { DEPARTMENTS } from "@/lib/constants";
|
import { DEPARTMENTS } from "@/lib/constants";
|
||||||
|
|
||||||
|
const MEMORY_DIR = "/home/sscoble/.openclaw/workspace/memory";
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
try {
|
try {
|
||||||
|
// Get info about the most recent daily memory file
|
||||||
|
let globalLastSession = null;
|
||||||
|
let globalMemorySize = null;
|
||||||
|
try {
|
||||||
|
const files = readdirSync(MEMORY_DIR)
|
||||||
|
.filter((f) => f.endsWith(".md"))
|
||||||
|
.sort()
|
||||||
|
.reverse();
|
||||||
|
if (files.length > 0) {
|
||||||
|
const latest = join(MEMORY_DIR, files[0]);
|
||||||
|
const st = statSync(latest);
|
||||||
|
globalLastSession = new Date(st.mtime).toISOString();
|
||||||
|
globalMemorySize = formatBytes(st.size);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// memory dir not found
|
||||||
|
}
|
||||||
|
|
||||||
const departments = DEPARTMENTS.map((d) => {
|
const departments = DEPARTMENTS.map((d) => {
|
||||||
|
const name = d.name.replace("@", "");
|
||||||
let status = "idle";
|
let status = "idle";
|
||||||
let lastSession = null;
|
let lastSession = globalLastSession;
|
||||||
let memorySize = null;
|
let memorySize = globalMemorySize;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Check for memory files per department
|
|
||||||
const name = d.name.replace("@", "");
|
|
||||||
const memPath = `/home/sscoble/.openclaw/workspace/memory/${name}-YYYY-MM-DD.md`;
|
|
||||||
// Simple check: does a recent memory file exist?
|
|
||||||
const today = new Date().toISOString().split("T")[0];
|
|
||||||
const yesterday = new Date(Date.now() - 86400000).toISOString().split("T")[0];
|
|
||||||
|
|
||||||
// Check if the agent's process is running
|
// Check if the agent's process is running
|
||||||
const procCheck = execSync(
|
const procCheck = execSync(
|
||||||
`pgrep -f 'openclaw.*${name}' || true`,
|
`pgrep -f 'openclaw.*${name}' || true`,
|
||||||
|
|
@ -26,24 +42,21 @@ export async function GET() {
|
||||||
status = "running";
|
status = "running";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check memory file size
|
// Check for per-agent memory file
|
||||||
try {
|
try {
|
||||||
const stat = execSync(
|
const agentFiles = readdirSync(MEMORY_DIR)
|
||||||
`stat --format='%Y %s' /home/sscoble/.openclaw/workspace/memory/${name}-*.md 2>/dev/null || true`,
|
.filter((f) => f.startsWith(name) && f.endsWith(".md"));
|
||||||
{ encoding: "utf-8", timeout: 2000 }
|
if (agentFiles.length > 0) {
|
||||||
);
|
const latest = join(MEMORY_DIR, agentFiles.sort().reverse()[0]);
|
||||||
if (stat.trim()) {
|
const st = statSync(latest);
|
||||||
const parts = stat.trim().split(" ");
|
lastSession = new Date(st.mtime).toISOString();
|
||||||
const timestamp = parseInt(parts[0]) * 1000;
|
memorySize = formatBytes(st.size);
|
||||||
const sizeBytes = parseInt(parts[1]);
|
|
||||||
lastSession = new Date(timestamp).toISOString();
|
|
||||||
memorySize = formatBytes(sizeBytes);
|
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// no memory file
|
// no per-agent memory file, use global
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// process check failed
|
// process check failed, leave status as idle
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,14 @@ export default function AgentStatus({ agent }) {
|
||||||
<p className="text-sm font-medium text-gray-200">{agent.name}</p>
|
<p className="text-sm font-medium text-gray-200">{agent.name}</p>
|
||||||
<p className="text-xs text-gray-500 truncate">{agent.role}</p>
|
<p className="text-xs text-gray-500 truncate">{agent.role}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-right text-xs text-gray-500 flex-shrink-0">
|
<div className="text-right text-xs text-gray-500 flex-shrink-0 min-w-[100px]">
|
||||||
|
{agent.status && (
|
||||||
|
<p className={`font-medium ${agent.status === "running" ? "text-green-400" : "text-yellow-400"}`}>
|
||||||
|
{agent.status.charAt(0).toUpperCase() + agent.status.slice(1)}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
{agent.lastSession && (
|
{agent.lastSession && (
|
||||||
<p>
|
<p className="mt-0.5">
|
||||||
{new Date(agent.lastSession).toLocaleDateString("en-US", {
|
{new Date(agent.lastSession).toLocaleDateString("en-US", {
|
||||||
month: "short",
|
month: "short",
|
||||||
day: "numeric",
|
day: "numeric",
|
||||||
|
|
@ -27,6 +32,9 @@ export default function AgentStatus({ agent }) {
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{agent.memorySize && <p className="mt-0.5">{agent.memorySize}</p>}
|
{agent.memorySize && <p className="mt-0.5">{agent.memorySize}</p>}
|
||||||
|
{agent.sessionCount !== undefined && (
|
||||||
|
<p className="mt-0.5 text-gray-600">{agent.sessionCount} sessions</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue