Skip to content

Commit 451de65

Browse files
committed
feat(agent-workspace): add mastery misconceptions capability lane
1 parent e630dfe commit 451de65

14 files changed

Lines changed: 292 additions & 1 deletion

docs/brainstorms/2026-04-14-mainline-reality-reconciliation-and-next-direction-requirements.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,18 @@ npm run verify:agent-workspace:tauri
219219
- frontend payload-builder read query passthrough assertion,
220220
- runtime endpoint/payload/message assertions for memory read execution.
221221

222+
#### M6.8 Progress Note (2026-04-14)
223+
224+
- [Done] typed conversation capability surface expanded with `inspect_mastery_misconceptions` action, `query_mastery_misconceptions` operation, and `mastery_misconceptions_card` presentation.
225+
- [Done] conversation capability emission now includes scoped mastery misconception inspection execution through `/api/knowledge/mastery/misconceptions` with bounded `topK`.
226+
- [Done] contract/runtime planners preserve scoped misconception payload shaping:
227+
- bounded `topK`,
228+
- optional atom-scoped `atomIds` passthrough.
229+
- [Done] regression coverage expanded for:
230+
- misconception capability wiring in conversation output,
231+
- frontend payload-builder misconception endpoint/body assertions,
232+
- runtime endpoint/payload/message assertions for misconception inspection execution.
233+
222234
### M7 (Future): Foundation Lane Re-entry (Evidence-First)
223235

224236
Entry criteria:

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,21 @@ Execution anchor:
188188
- frontend payload-builder read query passthrough,
189189
- runtime endpoint/payload/message assertions for memory read execution.
190190

191+
## Latest Mainline Increment (2026-04-14 M6.8 Mastery Misconceptions Capability Lane)
192+
193+
- Added `inspect_mastery_misconceptions` to the typed conversation action union on mainline.
194+
- Extended capability operation/result unions with:
195+
- `query_mastery_misconceptions`,
196+
- `mastery_misconceptions_card`.
197+
- Extended `runAgentConversation(...)` capability emission to include scoped misconception inspection through `/api/knowledge/mastery/misconceptions`.
198+
- Kept contract/runtime planner behavior aligned for misconception payload shaping:
199+
- bounded `topK`,
200+
- optional atom-scoped `atomIds`.
201+
- Expanded regression coverage for:
202+
- misconception capability wiring in conversation output,
203+
- frontend misconception payload-builder endpoint/body assertions,
204+
- runtime endpoint/payload/message assertions for misconception execution and rendering.
205+
191206
## Mainline vs Working-Branch Snapshot (2026-04-14)
192207

193208
| Capability Slice | Working Branch (`feat/learning-multi-tutor-adapter`) | Mainline (`origin/main`) | Integration Status |

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,21 @@
188188
- 前端 payload-builder 的 read query 透传断言,
189189
- runtime read 路径 endpoint/payload/消息断言。
190190

191+
## 主线最新增量(2026-04-14 M6.8 误解洞察能力链路)
192+
193+
- 主线 typed conversation action union 新增 `inspect_mastery_misconceptions`
194+
- capability operation/result union 同步扩展:
195+
- `query_mastery_misconceptions`
196+
- `mastery_misconceptions_card`
197+
- `runAgentConversation(...)` capability 输出新增误解洞察动作,执行路径对接 `/api/knowledge/mastery/misconceptions`
198+
- contract/runtime payload 规划保持对齐:
199+
- `topK` 有界收敛,
200+
- 可选 `atomIds` 范围透传。
201+
- 回归覆盖同步扩展:
202+
- conversation 输出中的 misconception capability 连线断言,
203+
- 前端 misconception payload-builder 的 endpoint/body 断言,
204+
- runtime misconception 路径 endpoint/payload/消息断言。
205+
191206
## 主线 vs 工作分支快照(2026-04-14)
192207

193208
| 能力切片 | 工作分支(`feat/learning-multi-tutor-adapter`| 主线(`origin/main`| 集成状态 |

src/agent_workspace.contract.parity.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ describe('agent_workspace contract parity', () => {
1414
'execute_tutor_action',
1515
'build_study_session',
1616
'query_session_history',
17+
'query_mastery_misconceptions',
1718
'capture_learning_quality_snapshot',
1819
'apply_memory_policy',
1920
];
@@ -29,6 +30,7 @@ describe('agent_workspace contract parity', () => {
2930
'tutor_action_card',
3031
'study_session_card',
3132
'session_history_card',
33+
'mastery_misconceptions_card',
3234
'learning_quality_snapshot_card',
3335
'memory_policy_card',
3436
];

src/agent_workspace.frontend.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,31 @@ describe('agent_workspace frontend operation contract', () => {
210210
});
211211
});
212212

213+
test('query_mastery_misconceptions builds scoped misconceptions payload', () => {
214+
const requestPlan = buildKnowledgeOperationRequestPayload({
215+
request: {
216+
userId: 'learner-a',
217+
atomId: 'atom-2',
218+
topK: 6,
219+
},
220+
execution: {
221+
operationId: 'query_mastery_misconceptions',
222+
},
223+
});
224+
225+
expect(requestPlan).toEqual({
226+
operationId: 'query_mastery_misconceptions',
227+
endpoint: '/api/knowledge/mastery/misconceptions',
228+
method: 'POST',
229+
resultPresentation: 'mastery_misconceptions_card',
230+
body: {
231+
userId: 'learner-a',
232+
topK: 6,
233+
atomIds: ['atom-2'],
234+
},
235+
});
236+
});
237+
213238
test('capture_learning_quality_snapshot builds snapshot payload', () => {
214239
const requestPlan = buildKnowledgeOperationRequestPayload({
215240
request: {
@@ -345,6 +370,7 @@ describe('agent_workspace frontend operation contract', () => {
345370
execute_tutor_action: 'assistant_message',
346371
build_study_session: 'study_session_card',
347372
query_session_history: 'session_history_card',
373+
query_mastery_misconceptions: 'mastery_misconceptions_card',
348374
capture_learning_quality_snapshot: 'learning_quality_snapshot_card',
349375
apply_memory_policy: 'memory_policy_card',
350376
});
@@ -357,6 +383,9 @@ describe('agent_workspace frontend operation contract', () => {
357383
expect(diagnostics.operationAllowedResultPresentations.query_session_history).toEqual(
358384
expect.arrayContaining(['session_history_card'])
359385
);
386+
expect(diagnostics.operationAllowedResultPresentations.query_mastery_misconceptions).toEqual(
387+
expect.arrayContaining(['mastery_misconceptions_card'])
388+
);
360389
expect(diagnostics.operationAllowedResultPresentations.capture_learning_quality_snapshot).toEqual(
361390
expect.arrayContaining(['learning_quality_snapshot_card'])
362391
);

src/agent_workspace.runtime.behavior.test.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ describe('agent workspace runtime behavior', () => {
8484
? '/api/knowledge/session/plan'
8585
: operationId === 'query_session_history'
8686
? '/api/knowledge/session/history'
87+
: operationId === 'query_mastery_misconceptions'
88+
? '/api/knowledge/mastery/misconceptions'
8789
: operationId === 'capture_learning_quality_snapshot'
8890
? '/api/knowledge/quality/snapshot'
8991
: operationId === 'apply_memory_policy'
@@ -109,6 +111,21 @@ describe('agent workspace runtime behavior', () => {
109111
},
110112
};
111113
}
114+
if (operationId === 'query_mastery_misconceptions') {
115+
return {
116+
operationId,
117+
endpoint,
118+
method: 'POST',
119+
resultPresentation: capability.execution.resultPresentation,
120+
body: {
121+
userId: request.userId,
122+
topK: Number.isFinite(Number(request.topK)) ? Number(request.topK) : 5,
123+
...(typeof request.atomId === 'string' && request.atomId.trim().length > 0
124+
? { atomIds: [request.atomId.trim()] }
125+
: {}),
126+
},
127+
};
128+
}
112129
return {
113130
operationId,
114131
endpoint,
@@ -356,6 +373,94 @@ describe('agent workspace runtime behavior', () => {
356373
expect(messages.textContent || '').toContain('Study session built');
357374
});
358375

376+
test('executes mastery misconceptions capability and renders summary message', async () => {
377+
const fetchMock = jest
378+
.fn()
379+
.mockResolvedValueOnce({
380+
ok: true,
381+
status: 200,
382+
json: async () => ({
383+
success: true,
384+
result: {
385+
userId: 'agent_user_default',
386+
message: 'Found 1 local knowledge point(s).',
387+
knowledgePoints: [
388+
{
389+
atomId: 'atom-misconception-1',
390+
title: 'Misconception Candidate',
391+
snippet: 'Inspect misconception concentration.',
392+
score: 0.72,
393+
capabilities: [
394+
{
395+
actionId: 'inspect_mastery_misconceptions',
396+
label: 'Mastery Misconceptions',
397+
request: {
398+
userId: 'agent_user_default',
399+
atomId: 'atom-misconception-1',
400+
topK: 6,
401+
},
402+
execution: {
403+
kind: 'knowledge_operation',
404+
operationId: 'query_mastery_misconceptions',
405+
resultPresentation: 'mastery_misconceptions_card',
406+
},
407+
},
408+
],
409+
},
410+
],
411+
},
412+
}),
413+
})
414+
.mockResolvedValueOnce({
415+
ok: true,
416+
status: 200,
417+
json: async () => ({
418+
success: true,
419+
result: {
420+
summary: {
421+
trackedTags: 2,
422+
totalObservations: 7,
423+
},
424+
items: [
425+
{
426+
errorTag: 'overgeneralization',
427+
},
428+
],
429+
},
430+
}),
431+
});
432+
(global as unknown as Record<string, unknown>).fetch = fetchMock;
433+
434+
const runtime = runtimeModule.createAgentWorkspaceRuntime({ defaultUserId: 'agent_user_default' });
435+
runtime.init();
436+
437+
const input = document.getElementById('agent-workspace-input') as HTMLTextAreaElement;
438+
const form = document.getElementById('agent-workspace-form') as HTMLFormElement;
439+
input.value = 'inspect misconceptions';
440+
form.dispatchEvent(new dom!.window.Event('submit', { bubbles: true, cancelable: true }));
441+
await flushAsync();
442+
443+
const actionButton = document.querySelector('.agent-workspace-action-button') as HTMLButtonElement;
444+
expect(actionButton).not.toBeNull();
445+
actionButton.click();
446+
await flushAsync();
447+
448+
expect(fetchMock).toHaveBeenNthCalledWith(
449+
2,
450+
'/api/knowledge/mastery/misconceptions',
451+
expect.objectContaining({ method: 'POST' })
452+
);
453+
const payload = JSON.parse(String(fetchMock.mock.calls[1]?.[1]?.body || '{}')) as {
454+
topK?: number;
455+
atomIds?: string[];
456+
};
457+
expect(payload.topK).toBe(6);
458+
expect(payload.atomIds).toEqual(['atom-misconception-1']);
459+
460+
const messages = document.getElementById('agent-workspace-messages') as HTMLElement;
461+
expect(messages.textContent || '').toContain('Mastery misconceptions loaded');
462+
});
463+
359464
test('executes follow-up tutor capability and renders assistant message', async () => {
360465
const fetchMock = jest
361466
.fn()

src/agent_workspace.runtime.integration.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ describe('agent workspace runtime integration baseline', () => {
2626
expect(runtimeSource).toContain('/api/knowledge/conversation');
2727
expect(runtimeSource).toContain('/api/knowledge/session/plan');
2828
expect(runtimeSource).toContain('/api/knowledge/session/history');
29+
expect(runtimeSource).toContain('/api/knowledge/mastery/misconceptions');
2930
expect(runtimeSource).toContain('/api/knowledge/quality/snapshot');
3031
expect(runtimeSource).toContain('/api/knowledge/memory/policy');
3132
expect(runtimeSource).toContain('focusOnNode');

src/frontend/agent_workspace.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@
3838
defaultResultPresentation: 'session_history_card',
3939
allowedResultPresentations: Object.freeze(['session_history_card']),
4040
}),
41+
query_mastery_misconceptions: Object.freeze({
42+
endpoint: '/api/knowledge/mastery/misconceptions',
43+
method: 'POST',
44+
defaultResultPresentation: 'mastery_misconceptions_card',
45+
allowedResultPresentations: Object.freeze(['mastery_misconceptions_card']),
46+
}),
4147
capture_learning_quality_snapshot: Object.freeze({
4248
endpoint: '/api/knowledge/quality/snapshot',
4349
method: 'POST',
@@ -122,6 +128,13 @@
122128
return Math.max(1, Math.min(100, Math.floor(base)));
123129
}
124130

131+
function resolveMisconceptionTopK(rawTopK, fallback) {
132+
const numericTopK = Number(rawTopK);
133+
const numericFallback = Number(fallback);
134+
const base = Number.isFinite(numericTopK) ? numericTopK : (Number.isFinite(numericFallback) ? numericFallback : 5);
135+
return Math.max(1, Math.min(20, Math.floor(base)));
136+
}
137+
125138
function createAgentConversationPayload(options) {
126139
const source = options || {};
127140
const userId = typeof source.userId === 'string' ? source.userId.trim() : '';
@@ -263,6 +276,25 @@
263276
};
264277
}
265278

279+
if (operationId === 'query_mastery_misconceptions') {
280+
const userId = String(request.userId || '').trim();
281+
if (!userId) {
282+
throw new Error('query_mastery_misconceptions requires request.userId.');
283+
}
284+
const atomId = String(request.atomId || '').trim();
285+
return {
286+
operationId,
287+
endpoint: config.endpoint,
288+
method: config.method,
289+
resultPresentation,
290+
body: {
291+
userId,
292+
topK: resolveMisconceptionTopK(request.topK, 5),
293+
...(atomId ? { atomIds: [atomId] } : {}),
294+
},
295+
};
296+
}
297+
266298
if (operationId === 'capture_learning_quality_snapshot') {
267299
const userId = String(request.userId || '').trim();
268300
if (!userId) {

src/frontend/agent_workspace_runtime.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@
8080
return Math.max(1, Math.min(100, Math.floor(base)));
8181
}
8282

83+
function resolveMisconceptionTopK(rawTopK, fallback) {
84+
const numericTopK = Number(rawTopK);
85+
const numericFallback = Number(fallback);
86+
const base = Number.isFinite(numericTopK) ? numericTopK : (Number.isFinite(numericFallback) ? numericFallback : 5);
87+
return Math.max(1, Math.min(20, Math.floor(base)));
88+
}
89+
8390
function getI18nText(key, fallback, params) {
8491
if (
8592
globalScope
@@ -217,6 +224,20 @@
217224
},
218225
};
219226
}
227+
if (operationId === 'query_mastery_misconceptions') {
228+
const atomId = trimString(request.atomId);
229+
return {
230+
operationId,
231+
endpoint: '/api/knowledge/mastery/misconceptions',
232+
method: 'POST',
233+
resultPresentation: trimString(execution.resultPresentation) || 'mastery_misconceptions_card',
234+
body: {
235+
userId: trimString(request.userId),
236+
topK: resolveMisconceptionTopK(request.topK, 5),
237+
...(atomId ? { atomIds: [atomId] } : {}),
238+
},
239+
};
240+
}
220241
if (operationId === 'capture_learning_quality_snapshot') {
221242
return {
222243
operationId,
@@ -586,6 +607,31 @@
586607
return;
587608
}
588609

610+
if (presentation === 'mastery_misconceptions_card') {
611+
const summary = result && result.summary && typeof result.summary === 'object'
612+
? result.summary
613+
: {};
614+
const trackedTags = Number(summary.trackedTags);
615+
const totalObservations = Number(summary.totalObservations);
616+
const topItem = Array.isArray(result && result.items) && result.items.length > 0
617+
? result.items[0]
618+
: null;
619+
const topErrorTag = trimString(topItem && topItem.errorTag);
620+
appendMessage(
621+
'assistant',
622+
getI18nText(
623+
'agentWorkspace.messages.masteryMisconceptionsLoaded',
624+
`Mastery misconceptions loaded (${Number.isFinite(trackedTags) ? trackedTags : 0} tags, ${Number.isFinite(totalObservations) ? totalObservations : 0} observations, top "${topErrorTag || 'n/a'}").`,
625+
{
626+
trackedTags: Number.isFinite(trackedTags) ? trackedTags : 0,
627+
totalObservations: Number.isFinite(totalObservations) ? totalObservations : 0,
628+
topErrorTag: topErrorTag || 'n/a',
629+
}
630+
)
631+
);
632+
return;
633+
}
634+
589635
if (presentation === 'learning_quality_snapshot_card') {
590636
const snapshot = result && result.snapshot && typeof result.snapshot === 'object'
591637
? result.snapshot

src/frontend/locales/en.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@
241241
"generateCounterexample": "Generate Counterexample",
242242
"buildStudySession": "Build Session",
243243
"inspectSessionHistory": "Session History",
244+
"inspectMasteryMisconceptions": "Mastery Misconceptions",
244245
"inspectLearningQualitySnapshot": "Learning Quality",
245246
"inspectMemorySnapshot": "Memory Snapshot",
246247
"inspectMemoryRetrainPlan": "Memory Retrain Plan",
@@ -268,6 +269,8 @@
268269
"studySessionBuilt": "Study session built ({totalActions} actions, {totalEstimatedMinutes} min).",
269270
"sessionHistoryFailed": "Session history request failed.",
270271
"sessionHistoryLoaded": "Session history loaded ({totalRecords} sessions, {totalExecutedActions} actions).",
272+
"masteryMisconceptionsFailed": "Mastery misconceptions request failed.",
273+
"masteryMisconceptionsLoaded": "Mastery misconceptions loaded ({trackedTags} tags, {totalObservations} observations, top \"{topErrorTag}\").",
271274
"learningQualitySnapshotFailed": "Learning quality snapshot request failed.",
272275
"learningQualitySnapshotLoaded": "Learning quality snapshot loaded (retest {retestPassRatePct}%, recurrence {misconceptionRecurrenceRatePct}%).",
273276
"memoryPolicyFailed": "Memory snapshot request failed.",

0 commit comments

Comments
 (0)