mirror of
https://github.com/JohnRiceML/clawport-ui.git
synced 2026-08-14 00:47:50 +00:00
fix: memory page shows indexed status correctly (#24)
Add --json flag to `openclaw memory status --deep` call and handle the new array-of-agents response format. Previously the missing --json flag caused JSON.parse to fail, always falling back to indexed: false. Now correctly derives indexed state from status.files > 0 && !dirty across all agents, sums chunks for totalEntries, and reads provider/vector from the primary agent. Bumps to v0.8.9. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
a51ac3cbe0
commit
40db84d69b
@@ -331,6 +331,53 @@ describe('getMemoryStatus', () => {
|
||||
expect(status.lastIndexed).toBeNull()
|
||||
expect(status.totalEntries).toBeNull()
|
||||
})
|
||||
|
||||
it('parses new array-of-agents format from openclaw memory status --deep --json', () => {
|
||||
mockExecSync.mockReturnValue(JSON.stringify([
|
||||
{
|
||||
agentId: 'main',
|
||||
status: { files: 9, chunks: 13, dirty: false, provider: 'gemini', vector: { available: true } },
|
||||
},
|
||||
{
|
||||
agentId: 'helper',
|
||||
status: { files: 3, chunks: 5, dirty: false, provider: 'gemini', vector: { available: true } },
|
||||
},
|
||||
]))
|
||||
|
||||
const status = getMemoryStatus()
|
||||
expect(status.indexed).toBe(true)
|
||||
expect(status.totalEntries).toBe(18) // 13 + 5 chunks
|
||||
expect(status.vectorAvailable).toBe(true)
|
||||
expect(status.embeddingProvider).toBe('gemini')
|
||||
})
|
||||
|
||||
it('reports not indexed when any agent has dirty files', () => {
|
||||
mockExecSync.mockReturnValue(JSON.stringify([
|
||||
{
|
||||
agentId: 'main',
|
||||
status: { files: 9, chunks: 13, dirty: false, provider: 'gemini', vector: { available: true } },
|
||||
},
|
||||
{
|
||||
agentId: 'helper',
|
||||
status: { files: 3, chunks: 5, dirty: true, provider: 'gemini', vector: { available: true } },
|
||||
},
|
||||
]))
|
||||
|
||||
const status = getMemoryStatus()
|
||||
expect(status.indexed).toBe(false)
|
||||
})
|
||||
|
||||
it('reports not indexed when an agent has zero files', () => {
|
||||
mockExecSync.mockReturnValue(JSON.stringify([
|
||||
{
|
||||
agentId: 'main',
|
||||
status: { files: 0, chunks: 0, dirty: false, provider: 'gemini', vector: { available: true } },
|
||||
},
|
||||
]))
|
||||
|
||||
const status = getMemoryStatus()
|
||||
expect(status.indexed).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
// ── computeMemoryStats ──────────────────────────────────────────
|
||||
|
||||
+33
-8
@@ -3,6 +3,7 @@ import { readFileSync, existsSync, statSync, readdirSync } from 'fs'
|
||||
import { join, basename, dirname } from 'path'
|
||||
import { execSync } from 'child_process'
|
||||
import { requireEnv } from '@/lib/env'
|
||||
import { extractJson } from '@/lib/cli-utils'
|
||||
|
||||
// ── Date pattern for daily logs ─────────────────────────────────
|
||||
|
||||
@@ -213,21 +214,45 @@ export function getMemoryStatus(): MemoryStatus {
|
||||
}
|
||||
|
||||
try {
|
||||
const output = execSync(`${bin} memory status --deep`, {
|
||||
const output = execSync(`${bin} memory status --deep --json`, {
|
||||
timeout: 15000,
|
||||
encoding: 'utf-8',
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
}).trim()
|
||||
|
||||
// Try JSON parse first
|
||||
try {
|
||||
const data = JSON.parse(output)
|
||||
const data = extractJson(output)
|
||||
|
||||
// New format: array of per-agent status objects
|
||||
// [{ agentId, status: { files, chunks, dirty, provider, vector } }, ...]
|
||||
if (Array.isArray(data) && data.length > 0) {
|
||||
const agents = data as { agentId?: string; status?: Record<string, unknown> }[]
|
||||
const primary = agents[0].status ?? {}
|
||||
const totalEntries = agents.reduce(
|
||||
(sum, a) => sum + (typeof a.status?.chunks === 'number' ? a.status.chunks : 0), 0,
|
||||
)
|
||||
const allIndexed = agents.every(
|
||||
a => (typeof a.status?.files === 'number' && a.status.files > 0) && !a.status?.dirty,
|
||||
)
|
||||
const vec = primary.vector as Record<string, unknown> | undefined
|
||||
return {
|
||||
indexed: allIndexed,
|
||||
lastIndexed: null,
|
||||
totalEntries,
|
||||
vectorAvailable: typeof vec?.available === 'boolean' ? vec.available : null,
|
||||
embeddingProvider: typeof primary.provider === 'string' ? primary.provider : null,
|
||||
raw: output,
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy flat object format
|
||||
const flat = data as Record<string, unknown>
|
||||
return {
|
||||
indexed: data.indexed ?? false,
|
||||
lastIndexed: data.lastIndexed ?? null,
|
||||
totalEntries: data.totalEntries ?? null,
|
||||
vectorAvailable: data.vectorAvailable ?? null,
|
||||
embeddingProvider: data.embeddingProvider ?? null,
|
||||
indexed: flat.indexed === true,
|
||||
lastIndexed: typeof flat.lastIndexed === 'string' ? flat.lastIndexed : null,
|
||||
totalEntries: typeof flat.totalEntries === 'number' ? flat.totalEntries : null,
|
||||
vectorAvailable: typeof flat.vectorAvailable === 'boolean' ? flat.vectorAvailable : null,
|
||||
embeddingProvider: typeof flat.embeddingProvider === 'string' ? flat.embeddingProvider : null,
|
||||
raw: output,
|
||||
}
|
||||
} catch {
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "clawport-ui",
|
||||
"version": "0.8.8",
|
||||
"version": "0.8.9",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "clawport-ui",
|
||||
"version": "0.8.8",
|
||||
"version": "0.8.9",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@dagrejs/dagre": "^2.0.4",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "clawport-ui",
|
||||
"version": "0.8.8",
|
||||
"version": "0.8.9",
|
||||
"description": "Open-source dashboard for managing, monitoring, and chatting with your OpenClaw AI agents.",
|
||||
"homepage": "https://clawport.dev",
|
||||
"repository": {
|
||||
|
||||
Reference in New Issue
Block a user