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.
- agno/compression/manager.py +87 -16
- agno/db/base.py +5 -5
- agno/db/dynamo/dynamo.py +2 -2
- agno/db/firestore/firestore.py +2 -2
- agno/db/gcs_json/gcs_json_db.py +2 -2
- agno/db/in_memory/in_memory_db.py +2 -2
- agno/db/json/json_db.py +2 -2
- agno/db/mongo/async_mongo.py +170 -68
- agno/db/mongo/mongo.py +170 -76
- agno/db/mysql/async_mysql.py +93 -69
- agno/db/mysql/mysql.py +93 -68
- agno/db/postgres/async_postgres.py +104 -78
- agno/db/postgres/postgres.py +97 -69
- agno/db/redis/redis.py +2 -2
- agno/db/singlestore/singlestore.py +91 -66
- agno/db/sqlite/async_sqlite.py +101 -78
- agno/db/sqlite/sqlite.py +97 -69
- agno/db/surrealdb/surrealdb.py +2 -2
- agno/exceptions.py +1 -0
- agno/knowledge/chunking/fixed.py +4 -1
- agno/knowledge/knowledge.py +105 -24
- agno/knowledge/reader/csv_reader.py +2 -2
- agno/knowledge/reader/text_reader.py +15 -3
- agno/knowledge/reader/wikipedia_reader.py +33 -1
- agno/knowledge/utils.py +52 -7
- agno/memory/strategies/base.py +3 -4
- agno/models/anthropic/claude.py +44 -0
- agno/models/aws/bedrock.py +60 -0
- agno/models/base.py +124 -30
- agno/models/google/gemini.py +141 -23
- agno/models/litellm/chat.py +25 -0
- agno/models/openai/chat.py +21 -0
- agno/models/openai/responses.py +44 -0
- agno/os/routers/knowledge/knowledge.py +20 -9
- agno/run/agent.py +17 -0
- agno/run/requirement.py +89 -6
- agno/tracing/exporter.py +2 -2
- agno/utils/print_response/agent.py +4 -4
- agno/utils/print_response/team.py +12 -12
- agno/utils/tokens.py +643 -27
- agno/vectordb/base.py +15 -2
- agno/vectordb/chroma/chromadb.py +6 -2
- agno/vectordb/lancedb/lance_db.py +3 -37
- agno/vectordb/milvus/milvus.py +6 -32
- agno/vectordb/mongodb/mongodb.py +0 -27
- agno/vectordb/pgvector/pgvector.py +21 -11
- agno/vectordb/pineconedb/pineconedb.py +0 -17
- agno/vectordb/qdrant/qdrant.py +6 -29
- agno/vectordb/redis/redisdb.py +0 -26
- agno/vectordb/singlestore/singlestore.py +16 -8
- agno/vectordb/surrealdb/surrealdb.py +0 -36
- agno/vectordb/weaviate/weaviate.py +6 -2
- {agno-2.3.10.dist-info → agno-2.3.12.dist-info}/METADATA +4 -1
- {agno-2.3.10.dist-info → agno-2.3.12.dist-info}/RECORD +57 -57
- {agno-2.3.10.dist-info → agno-2.3.12.dist-info}/WHEEL +0 -0
- {agno-2.3.10.dist-info → agno-2.3.12.dist-info}/licenses/LICENSE +0 -0
- {agno-2.3.10.dist-info → agno-2.3.12.dist-info}/top_level.txt +0 -0
agno/models/openai/chat.py
CHANGED
|
@@ -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
|
agno/models/openai/responses.py
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
965
|
-
|
|
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__(
|
|
30
|
-
self
|
|
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.
|
|
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.
|
|
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("
|
|
473
|
-
tool_calls_text += f"\n\
|
|
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("
|
|
851
|
-
tool_calls_text += f"\n\
|
|
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("
|
|
271
|
-
tool_calls_text += f"\n\
|
|
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("
|
|
635
|
-
tool_calls_text += f"\n\
|
|
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("
|
|
845
|
-
tool_calls_text += f"\n\
|
|
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("
|
|
1136
|
-
tool_calls_text += f"\n\
|
|
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("
|
|
1498
|
-
tool_calls_text += f"\n\
|
|
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("
|
|
1726
|
-
tool_calls_text += f"\n\
|
|
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(
|