@@ -50,6 +50,7 @@ window.pathApp = {
5050 runtimeState : null ,
5151 tutorFeedback : null ,
5252 sessionExecution : null ,
53+ sessionHistory : null ,
5354 } ,
5455
5556 // Animation State
@@ -1876,7 +1877,7 @@ window.pathApp = {
18761877 const includeDivergence = true ;
18771878 const includeRetrain = true ;
18781879 try {
1879- const [ sessionPlan , qualitySnapshot , misconceptions , runtimeState ] = await Promise . all ( [
1880+ const [ sessionPlan , qualitySnapshot , misconceptions , runtimeState , sessionHistory ] = await Promise . all ( [
18801881 this . _requestLearningApi ( '/api/knowledge/session/plan' , {
18811882 userId,
18821883 focusAtomIds,
@@ -1895,13 +1896,18 @@ window.pathApp = {
18951896 fetch ( '/api/knowledge/state' , { method : 'GET' } )
18961897 . then ( ( response ) => response . json ( ) )
18971898 . catch ( ( ) => null ) ,
1899+ this . _requestLearningApi ( '/api/knowledge/session/history' , {
1900+ userId,
1901+ limit : 8 ,
1902+ } ) ,
18981903 ] ) ;
18991904 this . learningWorkbench . sessionPlan = sessionPlan || null ;
19001905 this . learningWorkbench . qualitySnapshot = qualitySnapshot || null ;
19011906 this . learningWorkbench . misconceptions = misconceptions || null ;
19021907 this . learningWorkbench . runtimeState = runtimeState && runtimeState . success === true
19031908 ? runtimeState
19041909 : null ;
1910+ this . learningWorkbench . sessionHistory = sessionHistory || null ;
19051911 this . learningWorkbench . lastUpdatedAt = new Date ( ) . toISOString ( ) ;
19061912
19071913 const actionCount = Number ( sessionPlan ?. summary ?. totalActions || sessionPlan ?. actions ?. length || 0 ) ;
@@ -1979,6 +1985,49 @@ window.pathApp = {
19791985 return answerMap ;
19801986 } ,
19811987
1988+ _appendLearningWorkbenchSessionRecord : function ( record ) {
1989+ if ( ! record || typeof record !== 'object' ) {
1990+ return ;
1991+ }
1992+ const recordId = String ( record . id || '' ) . trim ( ) ;
1993+ if ( ! recordId ) {
1994+ return ;
1995+ }
1996+ const base = this . learningWorkbench . sessionHistory && typeof this . learningWorkbench . sessionHistory === 'object'
1997+ ? this . learningWorkbench . sessionHistory
1998+ : {
1999+ userId : this . learningWorkbench . userId ,
2000+ generatedAt : new Date ( ) . toISOString ( ) ,
2001+ records : [ ] ,
2002+ summary : {
2003+ totalRecords : 0 ,
2004+ totalExecutedActions : 0 ,
2005+ totalUpdatedMasteryCount : 0 ,
2006+ averageMasteryDelta : 0 ,
2007+ averageTutorConfidence : 0 ,
2008+ } ,
2009+ } ;
2010+ const existingRecords = Array . isArray ( base . records ) ? base . records . slice ( ) : [ ] ;
2011+ const deduped = [ record , ...existingRecords . filter ( ( item ) => String ( item ?. id || '' ) . trim ( ) !== recordId ) ] . slice ( 0 , 8 ) ;
2012+ this . learningWorkbench . sessionHistory = {
2013+ ...base ,
2014+ generatedAt : new Date ( ) . toISOString ( ) ,
2015+ records : deduped ,
2016+ summary : {
2017+ ...( base . summary || { } ) ,
2018+ totalRecords : deduped . length ,
2019+ totalExecutedActions : deduped . reduce ( ( sum , item ) => sum + Number ( item ?. executedCount || 0 ) , 0 ) ,
2020+ totalUpdatedMasteryCount : deduped . reduce ( ( sum , item ) => sum + Number ( item ?. updatedMasteryCount || 0 ) , 0 ) ,
2021+ averageMasteryDelta : deduped . length > 0
2022+ ? deduped . reduce ( ( sum , item ) => sum + Number ( item ?. averageMasteryDelta || 0 ) , 0 ) / deduped . length
2023+ : 0 ,
2024+ averageTutorConfidence : deduped . length > 0
2025+ ? deduped . reduce ( ( sum , item ) => sum + Number ( item ?. averageTutorConfidence || 0 ) , 0 ) / deduped . length
2026+ : 0 ,
2027+ } ,
2028+ } ;
2029+ } ,
2030+
19822031 executeLearningWorkbenchAction : async function ( params = { } ) {
19832032 const userId = this . _normalizeLearningWorkbenchUserId ( this . learningWorkbench . userId ) ;
19842033 const atomId = String ( params . atomId || '' ) . trim ( ) ;
@@ -2075,6 +2124,7 @@ window.pathApp = {
20752124 try {
20762125 const result = await this . _requestLearningApi ( '/api/knowledge/session/execute' , {
20772126 userId,
2127+ executionKind : 'session' ,
20782128 sessionPlan,
20792129 actionLimit,
20802130 answersByActionId,
@@ -2087,6 +2137,7 @@ window.pathApp = {
20872137 ...result ,
20882138 receivedAt : new Date ( ) . toISOString ( ) ,
20892139 } ;
2140+ this . _appendLearningWorkbenchSessionRecord ( result ?. record || null ) ;
20902141 const firstExecuted = Array . isArray ( result ?. items )
20912142 ? result . items . find ( ( item ) => item && item . status === 'executed' && item . result )
20922143 : null ;
@@ -2159,6 +2210,7 @@ window.pathApp = {
21592210 try {
21602211 const result = await this . _requestLearningApi ( '/api/knowledge/session/execute' , {
21612212 userId,
2213+ executionKind : 'retest' ,
21622214 sessionPlan : retestSessionPlan ,
21632215 actionLimit : retestActions . length ,
21642216 answersByActionId,
@@ -2172,6 +2224,7 @@ window.pathApp = {
21722224 ...result ,
21732225 receivedAt : new Date ( ) . toISOString ( ) ,
21742226 } ;
2227+ this . _appendLearningWorkbenchSessionRecord ( result ?. record || null ) ;
21752228 const summary = result ?. summary || { } ;
21762229 this . _setLearningWorkbenchStatus (
21772230 `Retest execution finished: executed ${ Number ( summary . executedCount || 0 ) } /${ Number ( summary . attemptedActions || 0 ) } , mastery delta ${ Number ( summary . averageMasteryDelta || 0 ) . toFixed ( 3 ) } .`
@@ -2199,6 +2252,7 @@ window.pathApp = {
21992252 const updatedEl = document . getElementById ( 'learning-workbench-updated-at' ) ;
22002253 const tutorFeedbackEl = document . getElementById ( 'learning-tutor-feedback' ) ;
22012254 const sessionExecutionEl = document . getElementById ( 'learning-session-execution' ) ;
2255+ const sessionHistoryEl = document . getElementById ( 'learning-session-history' ) ;
22022256
22032257 if ( updatedEl ) {
22042258 updatedEl . textContent = this . learningWorkbench . lastUpdatedAt
@@ -2351,15 +2405,33 @@ window.pathApp = {
23512405 }
23522406 }
23532407
2408+ if ( sessionHistoryEl ) {
2409+ const records = this . learningWorkbench . sessionHistory ?. records || [ ] ;
2410+ if ( ! Array . isArray ( records ) || records . length === 0 ) {
2411+ sessionHistoryEl . innerHTML = '<li class="muted">No session history yet.</li>' ;
2412+ } else {
2413+ sessionHistoryEl . innerHTML = records . slice ( 0 , 8 ) . map ( ( record ) => {
2414+ const executedAt = new Date ( record . executedAt || Date . now ( ) ) . toLocaleString ( ) ;
2415+ const kind = this . _escapeHtml ( String ( record . executionKind || 'session' ) ) ;
2416+ const executedCount = Number ( record . executedCount || 0 ) ;
2417+ const attempted = Number ( record . attemptedActions || 0 ) ;
2418+ const delta = Number ( record . averageMasteryDelta || 0 ) ;
2419+ const signedDelta = `${ delta >= 0 ? '+' : '' } ${ delta . toFixed ( 3 ) } ` ;
2420+ return `<li><span class="chip">${ kind } </span> ${ executedAt } · ${ executedCount } /${ attempted } · mastery Δ ${ signedDelta } </li>` ;
2421+ } ) . join ( '' ) ;
2422+ }
2423+ }
2424+
23542425 if ( runtimeEl ) {
23552426 const runtimeState = this . learningWorkbench . runtimeState ?. state || null ;
23562427 if ( ! runtimeState ) {
23572428 runtimeEl . textContent = 'Runtime: unavailable' ;
23582429 } else {
23592430 const sessionTelemetry = runtimeState . sessionActionTelemetry || null ;
2431+ const historyCount = Number ( runtimeState . sessionExecutionHistoryRecords || 0 ) ;
23602432 const sessionSummary = sessionTelemetry
2361- ? `, sessionActions=${ Number ( sessionTelemetry . executionCount || 0 ) } , inferred=${ Number ( sessionTelemetry . inferredMasteryUpdateCount || 0 ) } , explicit=${ Number ( sessionTelemetry . explicitMasteryUpdateCount || 0 ) } `
2362- : '' ;
2433+ ? `, sessionActions=${ Number ( sessionTelemetry . executionCount || 0 ) } , inferred=${ Number ( sessionTelemetry . inferredMasteryUpdateCount || 0 ) } , explicit=${ Number ( sessionTelemetry . explicitMasteryUpdateCount || 0 ) } , history= ${ historyCount } `
2434+ : `, history= ${ historyCount } ` ;
23632435 runtimeEl . textContent = `Runtime: docs=${ runtimeState . documents } , atoms=${ runtimeState . activeAtoms } , relations=${ runtimeState . activeRelationEdges } , ingestP95=${ Number ( runtimeState . ingestTelemetry ?. ingestP95Ms || 0 ) . toFixed ( 2 ) } ms${ sessionSummary } ` ;
23642436 }
23652437 }
0 commit comments