amfs-http-server 0.3.7__tar.gz → 0.3.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: amfs-http-server
3
- Version: 0.3.7
3
+ Version: 0.3.8
4
4
  Summary: AMFS HTTP/REST API server with SSE support
5
5
  License-Expression: Apache-2.0
6
6
  Requires-Python: >=3.11
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "amfs-http-server"
3
- version = "0.3.7"
3
+ version = "0.3.8"
4
4
  description = "AMFS HTTP/REST API server with SSE support"
5
5
  requires-python = ">=3.11"
6
6
  license = "Apache-2.0"
@@ -989,28 +989,48 @@ async def get_stats(
989
989
 
990
990
  vis = _get_visibility_filter(request)
991
991
  if vis is not None and vis.should_filter():
992
+ # Visibility-scoped stats. This branch must return the SAME shape as
993
+ # MemoryStats (which mem.stats() below produces), because the client
994
+ # parses /stats via MemoryStats.model_validate — any missing field
995
+ # silently defaults (confidence→0.0, outcome→0) and any mis-named key
996
+ # (e.g. "oldest_entry" vs "oldest_entry_at") is dropped to None. The
997
+ # earlier partial dict caused exactly that: correct counts but zeroed
998
+ # confidence/outcome and null timestamps.
999
+ from amfs_core.models import MemoryStats
1000
+
992
1001
  entries = mem.list()
993
1002
  entries = vis.filter_entries(entries)
994
1003
 
995
- entity_set: set[str] = set()
996
- agent_set: set[str] = set()
1004
+ agents: dict[str, int] = {}
1005
+ entities: dict[str, int] = {}
1006
+ confidences: list[float] = []
1007
+ written_ats: list[Any] = []
1008
+ outcome_linked = 0
997
1009
  for e in entries:
998
- entity_set.add(e.entity_path)
999
- agent_set.add(e.provenance.agent_id)
1000
-
1001
- return {
1002
- "total_entries": len(entries),
1003
- "total_entities": len(entity_set),
1004
- "total_agents": len(agent_set),
1005
- "oldest_entry": min(
1006
- (e.provenance.written_at for e in entries if e.provenance.written_at),
1007
- default=None,
1008
- ),
1009
- "newest_entry": max(
1010
- (e.provenance.written_at for e in entries if e.provenance.written_at),
1011
- default=None,
1012
- ),
1013
- }
1010
+ entities[e.entity_path] = entities.get(e.entity_path, 0) + 1
1011
+ aid = e.provenance.agent_id
1012
+ agents[aid] = agents.get(aid, 0) + 1
1013
+ confidences.append(float(e.confidence))
1014
+ if getattr(e, "outcome_count", 0):
1015
+ outcome_linked += 1
1016
+ wa = getattr(e.provenance, "written_at", None)
1017
+ if wa is not None:
1018
+ written_ats.append(wa)
1019
+
1020
+ scoped = MemoryStats(
1021
+ total_entries=len(entries),
1022
+ total_entities=len(entities),
1023
+ total_agents=len(agents),
1024
+ agents=agents,
1025
+ entities=entities,
1026
+ confidence_avg=(sum(confidences) / len(confidences)) if confidences else 0.0,
1027
+ confidence_min=min(confidences) if confidences else 0.0,
1028
+ confidence_max=max(confidences) if confidences else 0.0,
1029
+ outcome_linked_count=outcome_linked,
1030
+ oldest_entry_at=min(written_ats) if written_ats else None,
1031
+ newest_entry_at=max(written_ats) if written_ats else None,
1032
+ )
1033
+ return json.loads(json.dumps(scoped.model_dump(mode="json"), default=str))
1014
1034
 
1015
1035
  stats = mem.stats()
1016
1036
  return json.loads(json.dumps(stats.model_dump(mode="json"), default=str))