agno 2.3.10__py3-none-any.whl → 2.3.12__py3-none-any.whl

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.
Files changed (57) hide show
  1. agno/compression/manager.py +87 -16
  2. agno/db/base.py +5 -5
  3. agno/db/dynamo/dynamo.py +2 -2
  4. agno/db/firestore/firestore.py +2 -2
  5. agno/db/gcs_json/gcs_json_db.py +2 -2
  6. agno/db/in_memory/in_memory_db.py +2 -2
  7. agno/db/json/json_db.py +2 -2
  8. agno/db/mongo/async_mongo.py +170 -68
  9. agno/db/mongo/mongo.py +170 -76
  10. agno/db/mysql/async_mysql.py +93 -69
  11. agno/db/mysql/mysql.py +93 -68
  12. agno/db/postgres/async_postgres.py +104 -78
  13. agno/db/postgres/postgres.py +97 -69
  14. agno/db/redis/redis.py +2 -2
  15. agno/db/singlestore/singlestore.py +91 -66
  16. agno/db/sqlite/async_sqlite.py +101 -78
  17. agno/db/sqlite/sqlite.py +97 -69
  18. agno/db/surrealdb/surrealdb.py +2 -2
  19. agno/exceptions.py +1 -0
  20. agno/knowledge/chunking/fixed.py +4 -1
  21. agno/knowledge/knowledge.py +105 -24
  22. agno/knowledge/reader/csv_reader.py +2 -2
  23. agno/knowledge/reader/text_reader.py +15 -3
  24. agno/knowledge/reader/wikipedia_reader.py +33 -1
  25. agno/knowledge/utils.py +52 -7
  26. agno/memory/strategies/base.py +3 -4
  27. agno/models/anthropic/claude.py +44 -0
  28. agno/models/aws/bedrock.py +60 -0
  29. agno/models/base.py +124 -30
  30. agno/models/google/gemini.py +141 -23
  31. agno/models/litellm/chat.py +25 -0
  32. agno/models/openai/chat.py +21 -0
  33. agno/models/openai/responses.py +44 -0
  34. agno/os/routers/knowledge/knowledge.py +20 -9
  35. agno/run/agent.py +17 -0
  36. agno/run/requirement.py +89 -6
  37. agno/tracing/exporter.py +2 -2
  38. agno/utils/print_response/agent.py +4 -4
  39. agno/utils/print_response/team.py +12 -12
  40. agno/utils/tokens.py +643 -27
  41. agno/vectordb/base.py +15 -2
  42. agno/vectordb/chroma/chromadb.py +6 -2
  43. agno/vectordb/lancedb/lance_db.py +3 -37
  44. agno/vectordb/milvus/milvus.py +6 -32
  45. agno/vectordb/mongodb/mongodb.py +0 -27
  46. agno/vectordb/pgvector/pgvector.py +21 -11
  47. agno/vectordb/pineconedb/pineconedb.py +0 -17
  48. agno/vectordb/qdrant/qdrant.py +6 -29
  49. agno/vectordb/redis/redisdb.py +0 -26
  50. agno/vectordb/singlestore/singlestore.py +16 -8
  51. agno/vectordb/surrealdb/surrealdb.py +0 -36
  52. agno/vectordb/weaviate/weaviate.py +6 -2
  53. {agno-2.3.10.dist-info → agno-2.3.12.dist-info}/METADATA +4 -1
  54. {agno-2.3.10.dist-info → agno-2.3.12.dist-info}/RECORD +57 -57
  55. {agno-2.3.10.dist-info → agno-2.3.12.dist-info}/WHEEL +0 -0
  56. {agno-2.3.10.dist-info → agno-2.3.12.dist-info}/licenses/LICENSE +0 -0
  57. {agno-2.3.10.dist-info → agno-2.3.12.dist-info}/top_level.txt +0 -0
@@ -820,6 +820,16 @@ class OpenAIChat(Model):
820
820
  if response.usage is not None:
821
821
  model_response.response_usage = self._get_metrics(response.usage)
822
822
 
823
+ if model_response.provider_data is None:
824
+ model_response.provider_data = {}
825
+
826
+ if response.id:
827
+ model_response.provider_data["id"] = response.id
828
+ if response.system_fingerprint:
829
+ model_response.provider_data["system_fingerprint"] = response.system_fingerprint
830
+ if response.model_extra:
831
+ model_response.provider_data["model_extra"] = response.model_extra
832
+
823
833
  return model_response
824
834
 
825
835
  def _parse_provider_response_delta(self, response_delta: ChatCompletionChunk) -> ModelResponse:
@@ -842,6 +852,17 @@ class OpenAIChat(Model):
842
852
  if choice_delta.content is not None:
843
853
  model_response.content = choice_delta.content
844
854
 
855
+ # We only want to handle these if content is present
856
+ if model_response.provider_data is None:
857
+ model_response.provider_data = {}
858
+
859
+ if response_delta.id:
860
+ model_response.provider_data["id"] = response_delta.id
861
+ if response_delta.system_fingerprint:
862
+ model_response.provider_data["system_fingerprint"] = response_delta.system_fingerprint
863
+ if response_delta.model_extra:
864
+ model_response.provider_data["model_extra"] = response_delta.model_extra
865
+
845
866
  # Add tool calls
846
867
  if choice_delta.tool_calls is not None:
847
868
  model_response.tool_calls = choice_delta.tool_calls # type: ignore
@@ -17,6 +17,7 @@ from agno.utils.http import get_default_async_client, get_default_sync_client
17
17
  from agno.utils.log import log_debug, log_error, log_warning
18
18
  from agno.utils.models.openai_responses import images_to_message
19
19
  from agno.utils.models.schema_utils import get_response_schema_for_provider
20
+ from agno.utils.tokens import count_schema_tokens
20
21
 
21
22
  try:
22
23
  from openai import APIConnectionError, APIStatusError, AsyncOpenAI, OpenAI, RateLimitError
@@ -520,6 +521,49 @@ class OpenAIResponses(Model):
520
521
  formatted_messages.append(reasoning_output)
521
522
  return formatted_messages
522
523
 
524
+ def count_tokens(
525
+ self,
526
+ messages: List[Message],
527
+ tools: Optional[List[Dict[str, Any]]] = None,
528
+ output_schema: Optional[Union[Dict, Type[BaseModel]]] = None,
529
+ ) -> int:
530
+ try:
531
+ formatted_input = self._format_messages(messages, compress_tool_results=True)
532
+ formatted_tools = self._format_tool_params(messages, tools) if tools else None
533
+
534
+ response = self.get_client().responses.input_tokens.count(
535
+ model=self.id,
536
+ input=formatted_input, # type: ignore
537
+ instructions=self.instructions, # type: ignore
538
+ tools=formatted_tools, # type: ignore
539
+ )
540
+ return response.input_tokens + count_schema_tokens(output_schema, self.id)
541
+ except Exception as e:
542
+ log_warning(f"Failed to count tokens via API: {e}")
543
+ return super().count_tokens(messages, tools, output_schema)
544
+
545
+ async def acount_tokens(
546
+ self,
547
+ messages: List[Message],
548
+ tools: Optional[List[Dict[str, Any]]] = None,
549
+ output_schema: Optional[Union[Dict, Type[BaseModel]]] = None,
550
+ ) -> int:
551
+ """Async version of count_tokens using the async client."""
552
+ try:
553
+ formatted_input = self._format_messages(messages, compress_tool_results=True)
554
+ formatted_tools = self._format_tool_params(messages, tools) if tools else None
555
+
556
+ response = await self.get_async_client().responses.input_tokens.count(
557
+ model=self.id,
558
+ input=formatted_input, # type: ignore
559
+ instructions=self.instructions, # type: ignore
560
+ tools=formatted_tools, # type: ignore
561
+ )
562
+ return response.input_tokens + count_schema_tokens(output_schema, self.id)
563
+ except Exception as e:
564
+ log_warning(f"Failed to count tokens via API: {e}")
565
+ return await super().acount_tokens(messages, tools, output_schema)
566
+
523
567
  def invoke(
524
568
  self,
525
569
  messages: List[Message],
@@ -1,7 +1,7 @@
1
1
  import json
2
2
  import logging
3
3
  import math
4
- from typing import Dict, List, Optional
4
+ from typing import Any, Dict, List, Optional
5
5
 
6
6
  from fastapi import APIRouter, BackgroundTasks, Depends, File, Form, HTTPException, Path, Query, UploadFile
7
7
 
@@ -874,8 +874,8 @@ def attach_routes(router: APIRouter, knowledge_instances: List[Knowledge]) -> AP
874
874
  ) -> ConfigResponseSchema:
875
875
  knowledge = get_knowledge_instance_by_db_id(knowledge_instances, db_id)
876
876
 
877
- # Get factory readers info
878
- readers_info = get_all_readers_info()
877
+ # Get factory readers info (including custom readers from this knowledge instance)
878
+ readers_info = get_all_readers_info(knowledge)
879
879
  reader_schemas = {}
880
880
  # Add factory readers
881
881
  for reader_info in readers_info:
@@ -887,7 +887,12 @@ def attach_routes(router: APIRouter, knowledge_instances: List[Knowledge]) -> AP
887
887
  )
888
888
 
889
889
  # Add custom readers from knowledge.readers
890
- readers_dict: Dict[str, Reader] = knowledge.get_readers() or {}
890
+ readers_result: Any = knowledge.get_readers() or {}
891
+ # Ensure readers_dict is a dictionary (defensive check)
892
+ if not isinstance(readers_result, dict):
893
+ readers_dict: Dict[str, Reader] = {}
894
+ else:
895
+ readers_dict = readers_result
891
896
  if readers_dict:
892
897
  for reader_id, reader in readers_dict.items():
893
898
  # Get chunking strategies from the reader
@@ -907,8 +912,8 @@ def attach_routes(router: APIRouter, knowledge_instances: List[Knowledge]) -> AP
907
912
  chunkers=chunking_strategies,
908
913
  )
909
914
 
910
- # Get content types to readers mapping
911
- types_of_readers = get_content_types_to_readers_mapping()
915
+ # Get content types to readers mapping (including custom readers from this knowledge instance)
916
+ types_of_readers = get_content_types_to_readers_mapping(knowledge)
912
917
  chunkers_list = get_all_chunkers_info()
913
918
 
914
919
  # Convert chunkers list to dictionary format expected by schema
@@ -961,20 +966,26 @@ async def process_content(
961
966
  try:
962
967
  if reader_id:
963
968
  reader = None
964
- if knowledge.readers and reader_id in knowledge.readers:
965
- reader = knowledge.readers[reader_id]
969
+ # Use get_readers() to ensure we get a dict (handles list conversion)
970
+ custom_readers = knowledge.get_readers()
971
+ if custom_readers and reader_id in custom_readers:
972
+ reader = custom_readers[reader_id]
973
+ log_debug(f"Found custom reader: {reader.__class__.__name__}")
966
974
  else:
975
+ # Try to resolve from factory readers
967
976
  key = reader_id.lower().strip().replace("-", "_").replace(" ", "_")
968
977
  candidates = [key] + ([key[:-6]] if key.endswith("reader") else [])
969
978
  for cand in candidates:
970
979
  try:
971
980
  reader = ReaderFactory.create_reader(cand)
972
- log_debug(f"Resolved reader: {reader.__class__.__name__}")
981
+ log_debug(f"Resolved reader from factory: {reader.__class__.__name__}")
973
982
  break
974
983
  except Exception:
975
984
  continue
976
985
  if reader:
977
986
  content.reader = reader
987
+ else:
988
+ log_debug(f"Could not resolve reader with id: {reader_id}")
978
989
  if chunker and content.reader:
979
990
  # Set the chunker name on the reader - let the reader handle it internally
980
991
  content.reader.set_chunking_strategy_from_string(chunker, chunk_size=chunk_size, overlap=chunk_overlap)
agno/run/agent.py CHANGED
@@ -604,6 +604,7 @@ class RunOutput:
604
604
  "reasoning_steps",
605
605
  "reasoning_messages",
606
606
  "references",
607
+ "requirements",
607
608
  ]
608
609
  }
609
610
 
@@ -689,6 +690,9 @@ class RunOutput:
689
690
  else:
690
691
  _dict["tools"].append(tool)
691
692
 
693
+ if self.requirements is not None:
694
+ _dict["requirements"] = [req.to_dict() if hasattr(req, "to_dict") else req for req in self.requirements]
695
+
692
696
  if self.input is not None:
693
697
  _dict["input"] = self.input.to_dict()
694
698
 
@@ -735,6 +739,18 @@ class RunOutput:
735
739
  tools = data.pop("tools", [])
736
740
  tools = [ToolExecution.from_dict(tool) for tool in tools] if tools else None
737
741
 
742
+ # Handle requirements
743
+ requirements_data = data.pop("requirements", None)
744
+ requirements: Optional[List[RunRequirement]] = None
745
+ if requirements_data is not None:
746
+ requirements_list: List[RunRequirement] = []
747
+ for item in requirements_data:
748
+ if isinstance(item, RunRequirement):
749
+ requirements_list.append(item)
750
+ elif isinstance(item, dict):
751
+ requirements_list.append(RunRequirement.from_dict(item))
752
+ requirements = requirements_list if requirements_list else None
753
+
738
754
  images = reconstruct_images(data.pop("images", []))
739
755
  videos = reconstruct_videos(data.pop("videos", []))
740
756
  audio = reconstruct_audio_list(data.pop("audio", []))
@@ -789,6 +805,7 @@ class RunOutput:
789
805
  reasoning_steps=reasoning_steps,
790
806
  reasoning_messages=reasoning_messages,
791
807
  references=references,
808
+ requirements=requirements,
792
809
  **filtered_data,
793
810
  )
794
811
 
agno/run/requirement.py CHANGED
@@ -1,6 +1,6 @@
1
- from dataclasses import dataclass
1
+ from dataclasses import dataclass, field
2
2
  from datetime import datetime, timezone
3
- from typing import TYPE_CHECKING, List, Optional
3
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional
4
4
  from uuid import uuid4
5
5
 
6
6
  from agno.models.response import ToolExecution, UserInputField
@@ -14,7 +14,7 @@ class RunRequirement:
14
14
  """Requirement to complete a paused run (used in HITL flows)"""
15
15
 
16
16
  tool_execution: Optional[ToolExecution] = None
17
- created_at: datetime = datetime.now(timezone.utc)
17
+ created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
18
18
 
19
19
  # User confirmation
20
20
  confirmation: Optional[bool] = None
@@ -26,10 +26,19 @@ class RunRequirement:
26
26
  # External execution
27
27
  external_execution_result: Optional[str] = None
28
28
 
29
- def __init__(self, tool_execution: ToolExecution):
30
- self.id = str(uuid4())
29
+ def __init__(
30
+ self,
31
+ tool_execution: ToolExecution,
32
+ id: Optional[str] = None,
33
+ created_at: Optional[datetime] = None,
34
+ ):
35
+ self.id = id or str(uuid4())
31
36
  self.tool_execution = tool_execution
32
- self.user_input_schema = tool_execution.user_input_schema
37
+ self.user_input_schema = tool_execution.user_input_schema if tool_execution else None
38
+ self.created_at = created_at or datetime.now(timezone.utc)
39
+ self.confirmation = None
40
+ self.confirmation_note = None
41
+ self.external_execution_result = None
33
42
 
34
43
  @property
35
44
  def needs_confirmation(self) -> bool:
@@ -96,3 +105,77 @@ class RunRequirement:
96
105
  def is_resolved(self) -> bool:
97
106
  """Return True if the requirement has been resolved"""
98
107
  return not self.needs_confirmation and not self.needs_user_input and not self.needs_external_execution
108
+
109
+ def to_dict(self) -> Dict[str, Any]:
110
+ """Convert to JSON-serializable dictionary for storage."""
111
+ _dict: Dict[str, Any] = {
112
+ "id": self.id,
113
+ "created_at": self.created_at.isoformat() if isinstance(self.created_at, datetime) else self.created_at,
114
+ "confirmation": self.confirmation,
115
+ "confirmation_note": self.confirmation_note,
116
+ "external_execution_result": self.external_execution_result,
117
+ }
118
+
119
+ if self.tool_execution is not None:
120
+ _dict["tool_execution"] = (
121
+ self.tool_execution.to_dict() if isinstance(self.tool_execution, ToolExecution) else self.tool_execution
122
+ )
123
+
124
+ if self.user_input_schema is not None:
125
+ _dict["user_input_schema"] = [f.to_dict() if hasattr(f, "to_dict") else f for f in self.user_input_schema]
126
+
127
+ return {k: v for k, v in _dict.items() if v is not None}
128
+
129
+ @classmethod
130
+ def from_dict(cls, data: Dict[str, Any]) -> "RunRequirement":
131
+ """Reconstruct from stored dictionary."""
132
+ if data is None:
133
+ raise ValueError("RunRequirement.from_dict() requires a non-None dict")
134
+
135
+ # Handle tool_execution
136
+ tool_data = data.get("tool_execution")
137
+ tool_execution: Optional[ToolExecution] = None
138
+ if isinstance(tool_data, ToolExecution):
139
+ tool_execution = tool_data
140
+ elif isinstance(tool_data, dict):
141
+ tool_execution = ToolExecution.from_dict(tool_data)
142
+
143
+ # Handle created_at (ISO string or datetime)
144
+ created_at_raw = data.get("created_at")
145
+ created_at: Optional[datetime] = None
146
+ if isinstance(created_at_raw, datetime):
147
+ created_at = created_at_raw
148
+ elif isinstance(created_at_raw, str):
149
+ try:
150
+ created_at = datetime.fromisoformat(created_at_raw)
151
+ except ValueError:
152
+ created_at = None
153
+
154
+ # Build requirement - tool_execution is required by __init__
155
+ # For legacy data without tool_execution, create a minimal placeholder
156
+ if tool_execution is None:
157
+ tool_execution = ToolExecution(tool_name="unknown", tool_args={})
158
+
159
+ requirement = cls(
160
+ tool_execution=tool_execution,
161
+ id=data.get("id"),
162
+ created_at=created_at,
163
+ )
164
+
165
+ # Set optional fields
166
+ requirement.confirmation = data.get("confirmation")
167
+ requirement.confirmation_note = data.get("confirmation_note")
168
+ requirement.external_execution_result = data.get("external_execution_result")
169
+
170
+ # Handle user_input_schema
171
+ schema_raw = data.get("user_input_schema")
172
+ if schema_raw is not None:
173
+ rebuilt_schema: List[UserInputField] = []
174
+ for item in schema_raw:
175
+ if isinstance(item, UserInputField):
176
+ rebuilt_schema.append(item)
177
+ elif isinstance(item, dict):
178
+ rebuilt_schema.append(UserInputField.from_dict(item))
179
+ requirement.user_input_schema = rebuilt_schema if rebuilt_schema else None
180
+
181
+ return requirement
agno/tracing/exporter.py CHANGED
@@ -90,7 +90,7 @@ class DatabaseSpanExporter(SpanExporter):
90
90
  # Create trace record (aggregate of all spans)
91
91
  trace = create_trace_from_spans(spans)
92
92
  if trace:
93
- self.db.create_trace(trace)
93
+ self.db.upsert_trace(trace)
94
94
 
95
95
  # Create span records
96
96
  self.db.create_spans(spans)
@@ -124,7 +124,7 @@ class DatabaseSpanExporter(SpanExporter):
124
124
  # Create trace record (aggregate of all spans)
125
125
  trace = create_trace_from_spans(spans)
126
126
  if trace:
127
- create_trace_result = self.db.create_trace(trace)
127
+ create_trace_result = self.db.upsert_trace(trace)
128
128
  if create_trace_result is not None:
129
129
  await create_trace_result
130
130
 
@@ -469,8 +469,8 @@ def build_panels_stream(
469
469
  stats = compression_manager.stats
470
470
  saved = stats.get("original_size", 0) - stats.get("compressed_size", 0)
471
471
  orig = stats.get("original_size", 1)
472
- if stats.get("messages_compressed", 0) > 0:
473
- tool_calls_text += f"\n\nTool results compressed: {stats.get('messages_compressed', 0)} | Saved: {saved:,} chars ({saved / orig * 100:.0f}%)"
472
+ if stats.get("tool_results_compressed", 0) > 0:
473
+ tool_calls_text += f"\n\ncompressed: {stats.get('tool_results_compressed', 0)} | Saved: {saved:,} chars ({saved / orig * 100:.0f}%)"
474
474
 
475
475
  tool_calls_panel = create_panel(
476
476
  content=tool_calls_text,
@@ -847,8 +847,8 @@ def build_panels(
847
847
  stats = compression_manager.stats
848
848
  saved = stats.get("original_size", 0) - stats.get("compressed_size", 0)
849
849
  orig = stats.get("original_size", 1)
850
- if stats.get("messages_compressed", 0) > 0:
851
- tool_calls_text += f"\n\nTool results compressed: {stats.get('messages_compressed', 0)} | Saved: {saved:,} chars ({saved / orig * 100:.0f}%)"
850
+ if stats.get("tool_results_compressed", 0) > 0:
851
+ tool_calls_text += f"\n\ncompressed: {stats.get('tool_results_compressed', 0)} | Saved: {saved:,} chars ({saved / orig * 100:.0f}%)"
852
852
  compression_manager.stats.clear()
853
853
 
854
854
  tool_calls_panel = create_panel(
@@ -267,8 +267,8 @@ def print_response(
267
267
  stats = team.compression_manager.stats
268
268
  saved = stats.get("original_size", 0) - stats.get("compressed_size", 0)
269
269
  orig = stats.get("original_size", 1)
270
- if stats.get("messages_compressed", 0) > 0:
271
- tool_calls_text += f"\n\nTool results compressed: {stats.get('messages_compressed', 0)} | Saved: {saved:,} chars ({saved / orig * 100:.0f}%)"
270
+ if stats.get("tool_results_compressed", 0) > 0:
271
+ tool_calls_text += f"\n\ncompressed: {stats.get('tool_results_compressed', 0)} | Saved: {saved:,} chars ({saved / orig * 100:.0f}%)"
272
272
  team.compression_manager.stats.clear()
273
273
 
274
274
  team_tool_calls_panel = create_panel(
@@ -631,8 +631,8 @@ def print_response_stream(
631
631
  stats = team.compression_manager.stats
632
632
  saved = stats.get("original_size", 0) - stats.get("compressed_size", 0)
633
633
  orig = stats.get("original_size", 1)
634
- if stats.get("messages_compressed", 0) > 0:
635
- tool_calls_text += f"\n\nTool results compressed: {stats.get('messages_compressed', 0)} | Saved: {saved:,} chars ({saved / orig * 100:.0f}%)"
634
+ if stats.get("tool_results_compressed", 0) > 0:
635
+ tool_calls_text += f"\n\ncompressed: {stats.get('tool_results_compressed', 0)} | Saved: {saved:,} chars ({saved / orig * 100:.0f}%)"
636
636
 
637
637
  team_tool_calls_panel = create_panel(
638
638
  content=tool_calls_text,
@@ -841,8 +841,8 @@ def print_response_stream(
841
841
  stats = team.compression_manager.stats
842
842
  saved = stats.get("original_size", 0) - stats.get("compressed_size", 0)
843
843
  orig = stats.get("original_size", 1)
844
- if stats.get("messages_compressed", 0) > 0:
845
- tool_calls_text += f"\n\nTool results compressed: {stats.get('messages_compressed', 0)} | Saved: {saved:,} chars ({saved / orig * 100:.0f}%)"
844
+ if stats.get("tool_results_compressed", 0) > 0:
845
+ tool_calls_text += f"\n\ncompressed: {stats.get('tool_results_compressed', 0)} | Saved: {saved:,} chars ({saved / orig * 100:.0f}%)"
846
846
  team.compression_manager.stats.clear()
847
847
 
848
848
  team_tool_calls_panel = create_panel(
@@ -1132,8 +1132,8 @@ async def aprint_response(
1132
1132
  stats = team.compression_manager.stats
1133
1133
  saved = stats.get("original_size", 0) - stats.get("compressed_size", 0)
1134
1134
  orig = stats.get("original_size", 1)
1135
- if stats.get("messages_compressed", 0) > 0:
1136
- tool_calls_text += f"\n\nTool results compressed: {stats.get('messages_compressed', 0)} | Saved: {saved:,} chars ({saved / orig * 100:.0f}%)"
1135
+ if stats.get("tool_results_compressed", 0) > 0:
1136
+ tool_calls_text += f"\n\ncompressed: {stats.get('tool_results_compressed', 0)} | Saved: {saved:,} chars ({saved / orig * 100:.0f}%)"
1137
1137
  team.compression_manager.stats.clear()
1138
1138
 
1139
1139
  team_tool_calls_panel = create_panel(
@@ -1494,8 +1494,8 @@ async def aprint_response_stream(
1494
1494
  stats = team.compression_manager.stats
1495
1495
  saved = stats.get("original_size", 0) - stats.get("compressed_size", 0)
1496
1496
  orig = stats.get("original_size", 1)
1497
- if stats.get("messages_compressed", 0) > 0:
1498
- tool_calls_text += f"\n\nTool results compressed: {stats.get('messages_compressed', 0)} | Saved: {saved:,} chars ({saved / orig * 100:.0f}%)"
1497
+ if stats.get("tool_results_compressed", 0) > 0:
1498
+ tool_calls_text += f"\n\ncompressed: {stats.get('tool_results_compressed', 0)} | Saved: {saved:,} chars ({saved / orig * 100:.0f}%)"
1499
1499
 
1500
1500
  team_tool_calls_panel = create_panel(
1501
1501
  content=tool_calls_text,
@@ -1722,8 +1722,8 @@ async def aprint_response_stream(
1722
1722
  stats = team.compression_manager.stats
1723
1723
  saved = stats.get("original_size", 0) - stats.get("compressed_size", 0)
1724
1724
  orig = stats.get("original_size", 1)
1725
- if stats.get("messages_compressed", 0) > 0:
1726
- tool_calls_text += f"\n\nTool results compressed: {stats.get('messages_compressed', 0)} | Saved: {saved:,} chars ({saved / orig * 100:.0f}%)"
1725
+ if stats.get("tool_results_compressed", 0) > 0:
1726
+ tool_calls_text += f"\n\ncompressed: {stats.get('tool_results_compressed', 0)} | Saved: {saved:,} chars ({saved / orig * 100:.0f}%)"
1727
1727
  team.compression_manager.stats.clear()
1728
1728
 
1729
1729
  team_tool_calls_panel = create_panel(