@@ -252,6 +252,12 @@ def export_chats():
252252 ctx_token_limit = ctx_window .get ("tokenLimit" , 0 )
253253 ctx_pct_remaining = ctx_window .get ("percentageRemainingFloat" ) or ctx_window .get ("percentageRemaining" )
254254
255+ # Token counts (AI bubbles only)
256+ tc_dict = (b .get ("tokenCount" ) or {}) if btype == "assistant" else {}
257+ in_tok = tc_dict .get ("inputTokens" ) or 0
258+ out_tok = tc_dict .get ("outputTokens" ) or 0
259+ cached_tok = tc_dict .get ("cachedTokens" ) or 0
260+
255261 bubbles .append ({
256262 "type" : btype ,
257263 "text" : text ,
@@ -263,6 +269,9 @@ def export_chats():
263269 "contextTokensUsed" : ctx_tokens_used if ctx_tokens_used > 0 else None ,
264270 "contextTokenLimit" : ctx_token_limit if ctx_token_limit > 0 else None ,
265271 "contextPctRemaining" : round (ctx_pct_remaining , 1 ) if ctx_pct_remaining else None ,
272+ "inputTokens" : in_tok if in_tok > 0 else None ,
273+ "outputTokens" : out_tok if out_tok > 0 else None ,
274+ "cachedTokens" : cached_tok if cached_tok > 0 else None ,
266275 })
267276
268277 bubbles .sort (key = lambda x : x ["timestamp" ] or 0 )
@@ -287,6 +296,12 @@ def export_chats():
287296 files_removed = cd .get ("removedFiles" , 0 )
288297 max_ctx_used = max ((b_item .get ("contextTokensUsed" , 0 ) or 0 ) for b_item in bubbles ) if bubbles else 0
289298 ctx_limit = max ((b_item .get ("contextTokenLimit" , 0 ) or 0 ) for b_item in bubbles ) if bubbles else 0
299+ total_input_tokens = sum (b_item .get ("inputTokens" ) or 0 for b_item in bubbles )
300+ total_output_tokens = sum (b_item .get ("outputTokens" ) or 0 for b_item in bubbles )
301+ total_cached_tokens = sum (b_item .get ("cachedTokens" ) or 0 for b_item in bubbles )
302+ usage_data = cd .get ("usageData" ) or {}
303+ total_cost_raw = usage_data .get ("cost" ) or usage_data .get ("estimatedCost" )
304+ total_cost = total_cost_raw if isinstance (total_cost_raw , (int , float )) and total_cost_raw > 0 else None
290305
291306 # Build frontmatter
292307 created_ms = to_epoch_ms (cd .get ("createdAt" )) or ts_ms
@@ -296,9 +311,18 @@ def export_chats():
296311 md += f"created_at: { datetime .fromtimestamp (created_ms / 1000 ).isoformat ()} \n "
297312 md += f"updated_at: { datetime .fromtimestamp (updated_at_ms / 1000 ).isoformat () if updated_at_ms else datetime .now ().isoformat ()} \n "
298313 md += f"workspace: { ws_slug } \n "
314+ md += f"workspace_name: { ws_display_name } \n "
299315 md += f"message_count: { len (bubbles )} \n "
300316 if model_name :
301317 md += f"model: { model_name } \n "
318+ if total_input_tokens :
319+ md += f"total_input_tokens: { total_input_tokens } \n "
320+ if total_output_tokens :
321+ md += f"total_output_tokens: { total_output_tokens } \n "
322+ if total_cached_tokens :
323+ md += f"total_cached_tokens: { total_cached_tokens } \n "
324+ if total_cost :
325+ md += f"total_cost_usd: { total_cost :.6f} \n "
302326 if total_response_ms :
303327 md += f"total_response_time_sec: { total_response_ms / 1000 :.1f} \n "
304328 if total_thinking_ms :
@@ -326,6 +350,15 @@ def export_chats():
326350 meta_parts = []
327351 if bubble .get ("model" ):
328352 meta_parts .append (f"Model: { bubble ['model' ]} " )
353+ if bubble .get ("inputTokens" ) or bubble .get ("outputTokens" ):
354+ tok_parts = []
355+ if bubble .get ("inputTokens" ):
356+ tok_parts .append (f"In: { bubble ['inputTokens' ]:,} " )
357+ if bubble .get ("outputTokens" ):
358+ tok_parts .append (f"Out: { bubble ['outputTokens' ]:,} " )
359+ if bubble .get ("cachedTokens" ):
360+ tok_parts .append (f"Cached: { bubble ['cachedTokens' ]:,} " )
361+ meta_parts .append (" / " .join (tok_parts ))
329362 if bubble .get ("responseTimeMs" ):
330363 meta_parts .append (f"Response: { bubble ['responseTimeMs' ] / 1000 :.1f} s" )
331364 if bubble .get ("thinkingDurationMs" ):
0 commit comments