@@ -2385,148 +2385,32 @@ async def api_stats(
23852385 ):
23862386 """Get statistics about memory nodes and links for a memory bank."""
23872387 try :
2388- # Authenticate and set tenant schema
2389- await app .state .memory ._authenticate_tenant (request_context )
2390- if app .state .memory ._operation_validator :
2391- from hindsight_api .extensions import BankReadContext
2392-
2393- ctx = BankReadContext (bank_id = bank_id , operation = "get_bank_stats" , request_context = request_context )
2394- await app .state .memory ._validate_operation (
2395- app .state .memory ._operation_validator .validate_bank_read (ctx )
2396- )
2397- pool = await app .state .memory ._get_pool ()
2398- async with acquire_with_retry (pool ) as conn :
2399- # Get node counts by fact_type
2400- node_stats = await conn .fetch (
2401- f"""
2402- SELECT fact_type, COUNT(*) as count
2403- FROM { fq_table ("memory_units" )}
2404- WHERE bank_id = $1
2405- GROUP BY fact_type
2406- """ ,
2407- bank_id ,
2408- )
2409-
2410- # Get link counts by link_type
2411- link_stats = await conn .fetch (
2412- f"""
2413- SELECT ml.link_type, COUNT(*) as count
2414- FROM { fq_table ("memory_links" )} ml
2415- JOIN { fq_table ("memory_units" )} mu ON ml.from_unit_id = mu.id
2416- WHERE mu.bank_id = $1
2417- GROUP BY ml.link_type
2418- """ ,
2419- bank_id ,
2420- )
2421-
2422- # Get link counts by fact_type (from nodes)
2423- link_fact_type_stats = await conn .fetch (
2424- f"""
2425- SELECT mu.fact_type, COUNT(*) as count
2426- FROM { fq_table ("memory_links" )} ml
2427- JOIN { fq_table ("memory_units" )} mu ON ml.from_unit_id = mu.id
2428- WHERE mu.bank_id = $1
2429- GROUP BY mu.fact_type
2430- """ ,
2431- bank_id ,
2432- )
2433-
2434- # Get link counts by fact_type AND link_type
2435- link_breakdown_stats = await conn .fetch (
2436- f"""
2437- SELECT mu.fact_type, ml.link_type, COUNT(*) as count
2438- FROM { fq_table ("memory_links" )} ml
2439- JOIN { fq_table ("memory_units" )} mu ON ml.from_unit_id = mu.id
2440- WHERE mu.bank_id = $1
2441- GROUP BY mu.fact_type, ml.link_type
2442- """ ,
2443- bank_id ,
2444- )
2445-
2446- # Get pending and failed operations counts
2447- ops_stats = await conn .fetch (
2448- f"""
2449- SELECT status, COUNT(*) as count
2450- FROM { fq_table ("async_operations" )}
2451- WHERE bank_id = $1
2452- GROUP BY status
2453- """ ,
2454- bank_id ,
2455- )
2456- ops_by_status = {row ["status" ]: row ["count" ] for row in ops_stats }
2457- pending_operations = ops_by_status .get ("pending" , 0 )
2458- failed_operations = ops_by_status .get ("failed" , 0 )
2459-
2460- # Get document count
2461- doc_count_result = await conn .fetchrow (
2462- f"""
2463- SELECT COUNT(*) as count
2464- FROM { fq_table ("documents" )}
2465- WHERE bank_id = $1
2466- """ ,
2467- bank_id ,
2468- )
2469- total_documents = doc_count_result ["count" ] if doc_count_result else 0
2470-
2471- # Get consolidation stats from memory-level tracking
2472- consolidation_stats = await conn .fetchrow (
2473- f"""
2474- SELECT
2475- MAX(consolidated_at) as last_consolidated_at,
2476- COUNT(*) FILTER (WHERE consolidated_at IS NULL AND fact_type IN ('experience', 'world')) as pending
2477- FROM { fq_table ("memory_units" )}
2478- WHERE bank_id = $1
2479- """ ,
2480- bank_id ,
2481- )
2482- last_consolidated_at = consolidation_stats ["last_consolidated_at" ] if consolidation_stats else None
2483- pending_consolidation = consolidation_stats ["pending" ] if consolidation_stats else 0
2484-
2485- # Count total observations (consolidated knowledge)
2486- observation_count_result = await conn .fetchrow (
2487- f"""
2488- SELECT COUNT(*) as count
2489- FROM { fq_table ("memory_units" )}
2490- WHERE bank_id = $1 AND fact_type = 'observation'
2491- """ ,
2492- bank_id ,
2493- )
2494- total_observations = observation_count_result ["count" ] if observation_count_result else 0
2495-
2496- # Format results
2497- nodes_by_type = {row ["fact_type" ]: row ["count" ] for row in node_stats }
2498- links_by_type = {row ["link_type" ]: row ["count" ] for row in link_stats }
2499- links_by_fact_type = {row ["fact_type" ]: row ["count" ] for row in link_fact_type_stats }
2500-
2501- # Build detailed breakdown: {fact_type: {link_type: count}}
2502- links_breakdown = {}
2503- for row in link_breakdown_stats :
2504- fact_type = row ["fact_type" ]
2505- link_type = row ["link_type" ]
2506- count = row ["count" ]
2507- if fact_type not in links_breakdown :
2508- links_breakdown [fact_type ] = {}
2509- links_breakdown [fact_type ][link_type ] = count
2510-
2511- total_nodes = sum (nodes_by_type .values ())
2512- total_links = sum (links_by_type .values ())
2513-
2514- return BankStatsResponse (
2515- bank_id = bank_id ,
2516- total_nodes = total_nodes ,
2517- total_links = total_links ,
2518- total_documents = total_documents ,
2519- nodes_by_fact_type = nodes_by_type ,
2520- links_by_link_type = links_by_type ,
2521- links_by_fact_type = links_by_fact_type ,
2522- links_breakdown = links_breakdown ,
2523- pending_operations = pending_operations ,
2524- failed_operations = failed_operations ,
2525- last_consolidated_at = (last_consolidated_at .isoformat () if last_consolidated_at else None ),
2526- pending_consolidation = pending_consolidation ,
2527- total_observations = total_observations ,
2528- )
2529-
2388+ stats = await app .state .memory .get_bank_stats (bank_id , request_context = request_context )
2389+ nodes_by_type = stats ["node_counts" ]
2390+ links_by_type = stats ["link_counts" ]
2391+ links_by_fact_type = stats ["link_counts_by_fact_type" ]
2392+ links_breakdown : dict [str , dict [str , int ]] = {}
2393+ for row in stats ["link_breakdown" ]:
2394+ ft = row ["fact_type" ]
2395+ if ft not in links_breakdown :
2396+ links_breakdown [ft ] = {}
2397+ links_breakdown [ft ][row ["link_type" ]] = row ["count" ]
2398+ ops = stats ["operations" ]
2399+ return BankStatsResponse (
2400+ bank_id = bank_id ,
2401+ total_nodes = sum (nodes_by_type .values ()),
2402+ total_links = sum (links_by_type .values ()),
2403+ total_documents = stats ["total_documents" ],
2404+ nodes_by_fact_type = nodes_by_type ,
2405+ links_by_link_type = links_by_type ,
2406+ links_by_fact_type = links_by_fact_type ,
2407+ links_breakdown = links_breakdown ,
2408+ pending_operations = ops .get ("pending" , 0 ),
2409+ failed_operations = ops .get ("failed" , 0 ),
2410+ last_consolidated_at = stats ["last_consolidated_at" ],
2411+ pending_consolidation = stats ["pending_consolidation" ],
2412+ total_observations = stats ["total_observations" ],
2413+ )
25302414 except OperationValidationError as e :
25312415 raise HTTPException (status_code = e .status_code , detail = e .reason )
25322416 except (AuthenticationError , HTTPException ):
0 commit comments