@@ -2,7 +2,10 @@ import { ExecutionPrompt } from '@bitcode/execution-generics/prompts/ExecutionPr
22import { hierarchicalFormatter } from '@bitcode/prompts/formatters' ;
33import type { PromptPart } from '@bitcode/prompts/parts/PromptPart' ;
44
5- import { buildSynthesisPromptLayers } from '../asset-packs-synthesis-pipeline' ;
5+ import {
6+ buildSynthesisPromptLayers ,
7+ sumLlmTokensFromExecutionTree ,
8+ } from '../asset-packs-synthesis-pipeline' ;
69import { measurementCatalogForLens , type AssetPacksSynthesisLens } from '../asset-packs-synthesis' ;
710
811// Satisfy the ExecutionPrompt root requirements exactly as AgentExecution does
@@ -78,3 +81,30 @@ describe('AssetPacksSynthesis formal prompt build-up (Gate 3 chunk F)', () => {
7881 expect ( deposit ) . toContain ( 'demand-alignment' ) ;
7982 } ) ;
8083} ) ;
84+
85+ describe ( 'sumLlmTokensFromExecutionTree' , ( ) => {
86+ function node ( usage : Record < string , number > | null , children : any [ ] = [ ] ) {
87+ const map = new Map < string , any > ( ) ;
88+ for ( let i = 0 ; i < children . length ; i += 1 ) map . set ( `c${ i } ` , children [ i ] ) ;
89+ return {
90+ get : ( namespace : string , key : string ) =>
91+ namespace === 'llm' && key === 'usage' ? usage : undefined ,
92+ children : map ,
93+ } ;
94+ }
95+
96+ it ( 'sums nested Map children (SDIVF PTRR trees), not only array children' , ( ) => {
97+ const root = node ( { promptTokens : 10 , completionTokens : 5 } , [
98+ node ( { promptTokens : 20 , completionTokens : 8 } , [
99+ node ( { totalTokens : 100 } ) ,
100+ ] ) ,
101+ node ( { prompt_tokens : 3 , completion_tokens : 2 } ) ,
102+ ] ) ;
103+ // 15 + 28 + 100 + 5 = 148
104+ expect ( sumLlmTokensFromExecutionTree ( root ) ) . toBe ( 148 ) ;
105+ } ) ;
106+
107+ it ( 'returns null when no usage is present anywhere' , ( ) => {
108+ expect ( sumLlmTokensFromExecutionTree ( node ( null , [ node ( null ) ] ) ) ) . toBeNull ( ) ;
109+ } ) ;
110+ } ) ;
0 commit comments