Skip to content

Commit 68b1d61

Browse files
committed
feat(agent-workspace): surface memory operator diagnostics
1 parent a018b2c commit 68b1d61

8 files changed

Lines changed: 563 additions & 0 deletions

docs/diataxis/en/explanation/development-progress-dashboard.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,23 @@ Execution anchor:
306306
- failing references: `24405317254`, `24404975285`,
307307
- recovered run: `24502592419` (`Migration Gates` all green, including runtime/browser/tauri agent-workspace suites).
308308

309+
## Latest Mainline Increment (2026-04-21 M6.15 Memory Operator Diagnostics Visibility Lane)
310+
311+
- Extended agent-workspace diagnostics so product-memory activity is inspectable instead of being buried under generic `apply_memory_policy` events:
312+
- runtime capability events now record `memoryLayer` and `memoryOperation`,
313+
- diagnostics snapshot export now emits `memoryPolicySummary`,
314+
- server-side diagnostics metadata summary now exposes layer/operation counts for persisted reports.
315+
- The new operator summary stays bounded and decision-oriented:
316+
- total memory policy executions,
317+
- readonly vs mutating execution counts,
318+
- success vs failure counts,
319+
- per-layer counts for `session` / `unit` / `long_term`,
320+
- per-operation counts for `read` / `snapshot` / `retrain_plan` / `write` / `evict`.
321+
- This closes the main observability gap introduced by the new long-term read lane:
322+
- long-term visibility is no longer only user-facing,
323+
- operator reports can now distinguish `long_term/read` from `session/write`,
324+
- managed-memory governance remains inspectable without widening mutation scope.
325+
309326
## Latest Mainline Increment (2026-04-21 M6.14 Long-Term Memory Read Visibility Lane)
310327

311328
- Extended the agent-workspace memory capability lane with read-only long-term inspection instead of reopening memory-model scope:

docs/diataxis/en/explanation/local-backend-sufficiency-and-escalation-plan.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ First post-checkpoint product-memory slice now landed on `main`:
2727

2828
- agent workspace exposes read-only `long_term` memory snapshot/read actions,
2929
- managed mutation remains session-scoped by design.
30+
- operator diagnostics now summarize memory-policy execution by layer and operation, so the new product-memory lane is inspectable instead of opaque.
3031

3132
## Current Implementation State
3233

docs/diataxis/zh/explanation/development-progress-dashboard.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,23 @@
306306
- 历史失败参考:`24405317254``24404975285`
307307
- 修复后运行:`24502592419``Migration Gates` 全绿,含 runtime/browser/tauri 三个 agent-workspace 套件)。
308308

309+
## 主线最新增量(2026-04-21 M6.15 记忆操作诊断可见性链路)
310+
311+
- agent-workspace diagnostics 已从“只看到通用 `apply_memory_policy`”提升到“可区分具体 memory 行为”:
312+
- runtime capability event 现在记录 `memoryLayer``memoryOperation`
313+
- diagnostics snapshot 导出新增 `memoryPolicySummary`
314+
- server 侧 persisted report 的 metadata summary 现在暴露 layer / operation 计数。
315+
- 新的 operator summary 保持有界且可决策:
316+
- memory policy 总执行数,
317+
- readonly / mutating 执行计数,
318+
- success / failure 计数,
319+
- `session` / `unit` / `long_term` 分层计数,
320+
- `read` / `snapshot` / `retrain_plan` / `write` / `evict` 分操作计数。
321+
- 这一步补上了 long-term read lane 带来的主要可观测性缺口:
322+
- long-term 记忆能力不再只是用户侧可见,
323+
- operator report 已能区分 `long_term/read``session/write`
324+
- 记忆治理可观测性增强,但没有扩大 mutation scope。
325+
309326
## 主线最新增量(2026-04-21 M6.14 长期记忆只读可见性链路)
310327

311328
- agent-workspace memory capability lane 新增长期记忆只读检查能力,但没有重新打开 memory-model 范围:

docs/diataxis/zh/explanation/local-backend-sufficiency-and-escalation-plan.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
- agent workspace 已暴露只读 `long_term` memory snapshot/read 动作,
2929
- 托管写入/修正/清理仍然按设计限制在 session 层。
30+
- operator diagnostics 现在会按 layer / operation 汇总 memory-policy 执行情况,使这条 product-memory 主线可观测、不可黑箱化。
3031

3132
## 当前实现状态
3233

src/agent_workspace.runtime.behavior.test.ts

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type AgentRuntimeModule = {
2323
lastConversation: Record<string, unknown> | null;
2424
lastFoundationReadiness: Record<string, unknown> | null;
2525
lastFailure: Record<string, unknown> | null;
26+
memoryPolicySummary: Record<string, unknown>;
2627
pathState: {
2728
visible: boolean;
2829
fullscreen: boolean;
@@ -2606,4 +2607,172 @@ describe('agent workspace runtime behavior', () => {
26062607
})
26072608
);
26082609
});
2610+
2611+
test('records memory policy diagnostics summary with layer and operation visibility', async () => {
2612+
const fetchMock = jest
2613+
.fn()
2614+
.mockResolvedValueOnce({
2615+
ok: true,
2616+
status: 200,
2617+
json: async () => ({
2618+
success: true,
2619+
result: {
2620+
userId: 'agent_user_default',
2621+
message: 'Found 1 local knowledge point(s).',
2622+
knowledgePoints: [
2623+
{
2624+
atomId: 'atom-memory-diagnostics-1',
2625+
title: 'Memory Diagnostics Candidate',
2626+
snippet: 'Track readonly and mutating memory actions.',
2627+
score: 0.82,
2628+
capabilities: [
2629+
{
2630+
actionId: 'inspect_long_term_memory_read',
2631+
label: 'Long-Term Memory Read',
2632+
request: {
2633+
userId: 'agent_user_default',
2634+
atomId: 'atom-memory-diagnostics-1',
2635+
memoryLayer: 'long_term',
2636+
memoryOperation: 'read',
2637+
memoryLimit: 8,
2638+
memoryQuery: 'durable retrieval',
2639+
},
2640+
execution: {
2641+
kind: 'knowledge_operation',
2642+
operationId: 'apply_memory_policy',
2643+
resultPresentation: 'memory_policy_card',
2644+
},
2645+
},
2646+
{
2647+
actionId: 'write_memory_note',
2648+
label: 'Store Memory Note',
2649+
request: {
2650+
userId: 'agent_user_default',
2651+
atomId: 'atom-memory-diagnostics-1',
2652+
memoryLayer: 'session',
2653+
memoryOperation: 'write',
2654+
memoryKey: 'conversation_note:atom-memory-diagnostics-1',
2655+
memoryTags: ['agent_workspace', 'conversation_note'],
2656+
memoryReferences: ['atom-memory-diagnostics-1'],
2657+
memoryPromptMessage: 'Store note for atom-memory-diagnostics-1',
2658+
},
2659+
execution: {
2660+
kind: 'knowledge_operation',
2661+
operationId: 'apply_memory_policy',
2662+
resultPresentation: 'memory_policy_card',
2663+
},
2664+
},
2665+
],
2666+
},
2667+
],
2668+
},
2669+
}),
2670+
})
2671+
.mockResolvedValueOnce({
2672+
ok: true,
2673+
status: 200,
2674+
json: async () => ({
2675+
success: true,
2676+
result: {
2677+
layer: 'long_term',
2678+
operation: 'read',
2679+
entries: [
2680+
{ key: 'memory:lt:1', value: 'durable retrieval note' },
2681+
],
2682+
evictedCount: 0,
2683+
stats: {
2684+
session: 2,
2685+
unit: 1,
2686+
longTerm: 6,
2687+
},
2688+
},
2689+
}),
2690+
})
2691+
.mockResolvedValueOnce({
2692+
ok: true,
2693+
status: 200,
2694+
json: async () => ({
2695+
success: true,
2696+
result: {
2697+
layer: 'session',
2698+
operation: 'write',
2699+
entries: [
2700+
{ key: 'conversation_note:atom-memory-diagnostics-1', value: 'Persist this diagnostic note.' },
2701+
],
2702+
evictedCount: 0,
2703+
mutatedCount: 1,
2704+
stats: {
2705+
session: 3,
2706+
unit: 1,
2707+
longTerm: 6,
2708+
},
2709+
},
2710+
}),
2711+
});
2712+
(global as unknown as Record<string, unknown>).fetch = fetchMock;
2713+
const promptMock = jest.fn().mockReturnValue('Persist this diagnostic note.');
2714+
(global as unknown as Record<string, unknown>).prompt = promptMock;
2715+
(dom!.window as unknown as Record<string, unknown>).prompt = promptMock;
2716+
2717+
const runtime = runtimeModule.createAgentWorkspaceRuntime({ defaultUserId: 'agent_user_default' });
2718+
runtime.init();
2719+
2720+
const input = document.getElementById('agent-workspace-input') as HTMLTextAreaElement;
2721+
const form = document.getElementById('agent-workspace-form') as HTMLFormElement;
2722+
input.value = 'run memory diagnostics';
2723+
form.dispatchEvent(new dom!.window.Event('submit', { bubbles: true, cancelable: true }));
2724+
await flushAsync();
2725+
2726+
const actionButtons = Array.from(
2727+
document.querySelectorAll('.agent-workspace-action-button')
2728+
) as HTMLButtonElement[];
2729+
expect(actionButtons).toHaveLength(2);
2730+
2731+
actionButtons[0].click();
2732+
await flushAsync();
2733+
actionButtons[1].click();
2734+
await flushAsync();
2735+
2736+
const snapshot = runtime.getDiagnosticsSnapshot();
2737+
expect(snapshot.memoryPolicySummary).toEqual(
2738+
expect.objectContaining({
2739+
executionCount: 2,
2740+
readonlyExecutions: 1,
2741+
mutatingExecutions: 1,
2742+
successCount: 2,
2743+
failureCount: 0,
2744+
byLayer: {
2745+
session: 1,
2746+
unit: 0,
2747+
long_term: 1,
2748+
},
2749+
byOperation: {
2750+
read: 1,
2751+
snapshot: 0,
2752+
retrain_plan: 0,
2753+
write: 1,
2754+
evict: 0,
2755+
},
2756+
lastEvent: expect.objectContaining({
2757+
memoryLayer: 'session',
2758+
memoryOperation: 'write',
2759+
status: 'success',
2760+
}),
2761+
})
2762+
);
2763+
expect(
2764+
snapshot.capabilityEvents.some(
2765+
(event) => event.memoryLayer === 'long_term' && event.memoryOperation === 'read'
2766+
)
2767+
).toBe(true);
2768+
2769+
const exported = JSON.parse(runtime.exportDiagnosticsReport({ format: 'json' }) as string);
2770+
expect(exported.snapshot.memoryPolicySummary).toEqual(
2771+
expect.objectContaining({
2772+
executionCount: 2,
2773+
readonlyExecutions: 1,
2774+
mutatingExecutions: 1,
2775+
})
2776+
);
2777+
});
26092778
});

0 commit comments

Comments
 (0)