agno 2.3.13__py3-none-any.whl → 2.3.14__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/agent/agent.py +1131 -1402
- agno/eval/__init__.py +21 -8
- agno/knowledge/embedder/azure_openai.py +0 -1
- agno/knowledge/embedder/google.py +1 -1
- agno/models/anthropic/claude.py +4 -1
- agno/models/base.py +8 -4
- agno/models/openai/responses.py +2 -2
- agno/os/app.py +39 -0
- agno/os/interfaces/a2a/router.py +619 -9
- agno/os/interfaces/a2a/utils.py +31 -32
- agno/os/middleware/jwt.py +5 -5
- agno/os/routers/agents/schema.py +14 -1
- agno/os/routers/teams/schema.py +14 -1
- agno/os/utils.py +61 -53
- agno/reasoning/anthropic.py +85 -1
- agno/reasoning/azure_ai_foundry.py +93 -1
- agno/reasoning/deepseek.py +91 -1
- agno/reasoning/gemini.py +81 -1
- agno/reasoning/groq.py +103 -1
- agno/reasoning/manager.py +1244 -0
- agno/reasoning/ollama.py +93 -1
- agno/reasoning/openai.py +113 -1
- agno/reasoning/vertexai.py +85 -1
- agno/run/agent.py +11 -0
- agno/run/base.py +1 -1
- agno/run/team.py +11 -0
- agno/session/team.py +0 -3
- agno/team/team.py +1201 -1445
- agno/utils/events.py +69 -2
- agno/utils/hooks.py +4 -10
- agno/utils/print_response/agent.py +26 -0
- agno/utils/print_response/team.py +11 -0
- agno/utils/prompts.py +8 -6
- agno/utils/string.py +46 -0
- agno/utils/team.py +1 -1
- agno/vectordb/milvus/milvus.py +32 -3
- {agno-2.3.13.dist-info → agno-2.3.14.dist-info}/METADATA +3 -2
- {agno-2.3.13.dist-info → agno-2.3.14.dist-info}/RECORD +41 -40
- {agno-2.3.13.dist-info → agno-2.3.14.dist-info}/WHEEL +0 -0
- {agno-2.3.13.dist-info → agno-2.3.14.dist-info}/licenses/LICENSE +0 -0
- {agno-2.3.13.dist-info → agno-2.3.14.dist-info}/top_level.txt +0 -0
agno/utils/events.py
CHANGED
|
@@ -16,6 +16,7 @@ from agno.run.agent import (
|
|
|
16
16
|
PreHookCompletedEvent,
|
|
17
17
|
PreHookStartedEvent,
|
|
18
18
|
ReasoningCompletedEvent,
|
|
19
|
+
ReasoningContentDeltaEvent,
|
|
19
20
|
ReasoningStartedEvent,
|
|
20
21
|
ReasoningStepEvent,
|
|
21
22
|
RunCancelledEvent,
|
|
@@ -47,6 +48,7 @@ from agno.run.team import PostHookStartedEvent as TeamPostHookStartedEvent
|
|
|
47
48
|
from agno.run.team import PreHookCompletedEvent as TeamPreHookCompletedEvent
|
|
48
49
|
from agno.run.team import PreHookStartedEvent as TeamPreHookStartedEvent
|
|
49
50
|
from agno.run.team import ReasoningCompletedEvent as TeamReasoningCompletedEvent
|
|
51
|
+
from agno.run.team import ReasoningContentDeltaEvent as TeamReasoningContentDeltaEvent
|
|
50
52
|
from agno.run.team import ReasoningStartedEvent as TeamReasoningStartedEvent
|
|
51
53
|
from agno.run.team import ReasoningStepEvent as TeamReasoningStepEvent
|
|
52
54
|
from agno.run.team import RunCancelledEvent as TeamRunCancelledEvent
|
|
@@ -161,23 +163,41 @@ def create_run_continued_event(from_run_response: RunOutput) -> RunContinuedEven
|
|
|
161
163
|
)
|
|
162
164
|
|
|
163
165
|
|
|
164
|
-
def create_team_run_error_event(
|
|
166
|
+
def create_team_run_error_event(
|
|
167
|
+
from_run_response: TeamRunOutput,
|
|
168
|
+
error: str,
|
|
169
|
+
error_type: Optional[str] = None,
|
|
170
|
+
error_id: Optional[str] = None,
|
|
171
|
+
additional_data: Optional[Dict[str, Any]] = None,
|
|
172
|
+
) -> TeamRunErrorEvent:
|
|
165
173
|
return TeamRunErrorEvent(
|
|
166
174
|
session_id=from_run_response.session_id,
|
|
167
175
|
team_id=from_run_response.team_id, # type: ignore
|
|
168
176
|
team_name=from_run_response.team_name, # type: ignore
|
|
169
177
|
run_id=from_run_response.run_id,
|
|
170
178
|
content=error,
|
|
179
|
+
error_type=error_type,
|
|
180
|
+
error_id=error_id,
|
|
181
|
+
additional_data=additional_data,
|
|
171
182
|
)
|
|
172
183
|
|
|
173
184
|
|
|
174
|
-
def create_run_error_event(
|
|
185
|
+
def create_run_error_event(
|
|
186
|
+
from_run_response: RunOutput,
|
|
187
|
+
error: str,
|
|
188
|
+
error_type: Optional[str] = None,
|
|
189
|
+
error_id: Optional[str] = None,
|
|
190
|
+
additional_data: Optional[Dict[str, Any]] = None,
|
|
191
|
+
) -> RunErrorEvent:
|
|
175
192
|
return RunErrorEvent(
|
|
176
193
|
session_id=from_run_response.session_id,
|
|
177
194
|
agent_id=from_run_response.agent_id, # type: ignore
|
|
178
195
|
agent_name=from_run_response.agent_name, # type: ignore
|
|
179
196
|
run_id=from_run_response.run_id,
|
|
180
197
|
content=error,
|
|
198
|
+
error_type=error_type,
|
|
199
|
+
error_id=error_id,
|
|
200
|
+
additional_data=additional_data,
|
|
181
201
|
)
|
|
182
202
|
|
|
183
203
|
|
|
@@ -421,6 +441,19 @@ def create_reasoning_step_event(
|
|
|
421
441
|
)
|
|
422
442
|
|
|
423
443
|
|
|
444
|
+
def create_reasoning_content_delta_event(
|
|
445
|
+
from_run_response: RunOutput, reasoning_content: str
|
|
446
|
+
) -> ReasoningContentDeltaEvent:
|
|
447
|
+
"""Create an event for streaming reasoning content chunks."""
|
|
448
|
+
return ReasoningContentDeltaEvent(
|
|
449
|
+
session_id=from_run_response.session_id,
|
|
450
|
+
agent_id=from_run_response.agent_id, # type: ignore
|
|
451
|
+
agent_name=from_run_response.agent_name, # type: ignore
|
|
452
|
+
run_id=from_run_response.run_id,
|
|
453
|
+
reasoning_content=reasoning_content,
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
|
|
424
457
|
def create_team_reasoning_step_event(
|
|
425
458
|
from_run_response: TeamRunOutput, reasoning_step: ReasoningStep, reasoning_content: str
|
|
426
459
|
) -> TeamReasoningStepEvent:
|
|
@@ -435,6 +468,19 @@ def create_team_reasoning_step_event(
|
|
|
435
468
|
)
|
|
436
469
|
|
|
437
470
|
|
|
471
|
+
def create_team_reasoning_content_delta_event(
|
|
472
|
+
from_run_response: TeamRunOutput, reasoning_content: str
|
|
473
|
+
) -> TeamReasoningContentDeltaEvent:
|
|
474
|
+
"""Create an event for streaming reasoning content chunks for Team."""
|
|
475
|
+
return TeamReasoningContentDeltaEvent(
|
|
476
|
+
session_id=from_run_response.session_id,
|
|
477
|
+
team_id=from_run_response.team_id, # type: ignore
|
|
478
|
+
team_name=from_run_response.team_name, # type: ignore
|
|
479
|
+
run_id=from_run_response.run_id,
|
|
480
|
+
reasoning_content=reasoning_content,
|
|
481
|
+
)
|
|
482
|
+
|
|
483
|
+
|
|
438
484
|
def create_reasoning_completed_event(
|
|
439
485
|
from_run_response: RunOutput, content: Optional[Any] = None, content_type: Optional[str] = None
|
|
440
486
|
) -> ReasoningCompletedEvent:
|
|
@@ -698,3 +744,24 @@ def handle_event(
|
|
|
698
744
|
run_response.events = []
|
|
699
745
|
run_response.events.append(event) # type: ignore
|
|
700
746
|
return event
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
def add_error_event(
|
|
750
|
+
error: RunErrorEvent,
|
|
751
|
+
events: Optional[List[RunOutputEvent]],
|
|
752
|
+
):
|
|
753
|
+
if events is None:
|
|
754
|
+
events = []
|
|
755
|
+
events.append(error)
|
|
756
|
+
|
|
757
|
+
return events
|
|
758
|
+
|
|
759
|
+
|
|
760
|
+
def add_team_error_event(
|
|
761
|
+
error: TeamRunErrorEvent,
|
|
762
|
+
events: Optional[List[Union[RunOutputEvent, TeamRunOutputEvent]]],
|
|
763
|
+
):
|
|
764
|
+
if events is None:
|
|
765
|
+
events = []
|
|
766
|
+
events.append(error)
|
|
767
|
+
return events
|
agno/utils/hooks.py
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
from copy import deepcopy
|
|
2
|
-
from typing import
|
|
3
|
-
|
|
4
|
-
if TYPE_CHECKING:
|
|
5
|
-
from agno.eval.base import BaseEval
|
|
2
|
+
from typing import Any, Callable, Dict, List, Optional, Union
|
|
6
3
|
|
|
4
|
+
from agno.eval.base import BaseEval
|
|
7
5
|
from agno.guardrails.base import BaseGuardrail
|
|
8
6
|
from agno.hooks.decorator import HOOK_RUN_IN_BACKGROUND_ATTR
|
|
9
7
|
from agno.utils.log import log_warning
|
|
@@ -57,7 +55,7 @@ def should_run_hook_in_background(hook: Callable[..., Any]) -> bool:
|
|
|
57
55
|
|
|
58
56
|
|
|
59
57
|
def normalize_pre_hooks(
|
|
60
|
-
hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail,
|
|
58
|
+
hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail, BaseEval]]],
|
|
61
59
|
async_mode: bool = False,
|
|
62
60
|
) -> Optional[List[Callable[..., Any]]]:
|
|
63
61
|
"""Normalize pre-hooks to a list format.
|
|
@@ -66,8 +64,6 @@ def normalize_pre_hooks(
|
|
|
66
64
|
hooks: List of hook functions, guardrails, or eval instances
|
|
67
65
|
async_mode: Whether to use async versions of methods
|
|
68
66
|
"""
|
|
69
|
-
from agno.eval.base import BaseEval
|
|
70
|
-
|
|
71
67
|
result_hooks: List[Callable[..., Any]] = []
|
|
72
68
|
|
|
73
69
|
if hooks is not None:
|
|
@@ -102,7 +98,7 @@ def normalize_pre_hooks(
|
|
|
102
98
|
|
|
103
99
|
|
|
104
100
|
def normalize_post_hooks(
|
|
105
|
-
hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail,
|
|
101
|
+
hooks: Optional[List[Union[Callable[..., Any], BaseGuardrail, BaseEval]]],
|
|
106
102
|
async_mode: bool = False,
|
|
107
103
|
) -> Optional[List[Callable[..., Any]]]:
|
|
108
104
|
"""Normalize post-hooks to a list format.
|
|
@@ -111,8 +107,6 @@ def normalize_post_hooks(
|
|
|
111
107
|
hooks: List of hook functions, guardrails, or eval instances
|
|
112
108
|
async_mode: Whether to use async versions of methods
|
|
113
109
|
"""
|
|
114
|
-
from agno.eval.base import BaseEval
|
|
115
|
-
|
|
116
110
|
result_hooks: List[Callable[..., Any]] = []
|
|
117
111
|
|
|
118
112
|
if hooks is not None:
|
|
@@ -134,6 +134,11 @@ def print_response_stream(
|
|
|
134
134
|
)
|
|
135
135
|
except Exception as e:
|
|
136
136
|
log_warning(f"Failed to convert response to JSON: {e}")
|
|
137
|
+
elif agent.output_schema is not None and isinstance(response_event.content, dict):
|
|
138
|
+
try:
|
|
139
|
+
response_content_batch = JSON(json.dumps(response_event.content), indent=2) # type: ignore
|
|
140
|
+
except Exception as e:
|
|
141
|
+
log_warning(f"Failed to convert response to JSON: {e}")
|
|
137
142
|
else:
|
|
138
143
|
try:
|
|
139
144
|
response_content_batch = JSON(json.dumps(response_event.content), indent=4)
|
|
@@ -141,6 +146,12 @@ def print_response_stream(
|
|
|
141
146
|
log_warning(f"Failed to convert response to JSON: {e}")
|
|
142
147
|
if hasattr(response_event, "reasoning_content") and response_event.reasoning_content is not None: # type: ignore
|
|
143
148
|
_response_reasoning_content += response_event.reasoning_content # type: ignore
|
|
149
|
+
|
|
150
|
+
# Handle streaming reasoning content delta events
|
|
151
|
+
if response_event.event == RunEvent.reasoning_content_delta: # type: ignore
|
|
152
|
+
if hasattr(response_event, "reasoning_content") and response_event.reasoning_content is not None: # type: ignore
|
|
153
|
+
_response_reasoning_content += response_event.reasoning_content # type: ignore
|
|
154
|
+
|
|
144
155
|
if hasattr(response_event, "reasoning_steps") and response_event.reasoning_steps is not None: # type: ignore
|
|
145
156
|
reasoning_steps = response_event.reasoning_steps # type: ignore
|
|
146
157
|
|
|
@@ -325,6 +336,11 @@ async def aprint_response_stream(
|
|
|
325
336
|
response_content_batch = JSON(resp.content.model_dump_json(exclude_none=True), indent=2) # type: ignore
|
|
326
337
|
except Exception as e:
|
|
327
338
|
log_warning(f"Failed to convert response to JSON: {e}")
|
|
339
|
+
elif agent.output_schema is not None and isinstance(resp.content, dict):
|
|
340
|
+
try:
|
|
341
|
+
response_content_batch = JSON(json.dumps(resp.content), indent=2) # type: ignore
|
|
342
|
+
except Exception as e:
|
|
343
|
+
log_warning(f"Failed to convert response to JSON: {e}")
|
|
328
344
|
else:
|
|
329
345
|
try:
|
|
330
346
|
response_content_batch = JSON(json.dumps(resp.content), indent=4)
|
|
@@ -333,6 +349,11 @@ async def aprint_response_stream(
|
|
|
333
349
|
if resp.reasoning_content is not None: # type: ignore
|
|
334
350
|
_response_reasoning_content += resp.reasoning_content # type: ignore
|
|
335
351
|
|
|
352
|
+
# Handle streaming reasoning content delta events
|
|
353
|
+
if resp.event == RunEvent.reasoning_content_delta: # type: ignore
|
|
354
|
+
if hasattr(resp, "reasoning_content") and resp.reasoning_content is not None: # type: ignore
|
|
355
|
+
_response_reasoning_content += resp.reasoning_content # type: ignore
|
|
356
|
+
|
|
336
357
|
if hasattr(resp, "reasoning_steps") and resp.reasoning_steps is not None: # type: ignore
|
|
337
358
|
reasoning_steps = resp.reasoning_steps # type: ignore
|
|
338
359
|
|
|
@@ -883,6 +904,11 @@ def build_panels(
|
|
|
883
904
|
response_content_batch = JSON(run_response.content.model_dump_json(exclude_none=True), indent=2)
|
|
884
905
|
except Exception as e:
|
|
885
906
|
log_warning(f"Failed to convert response to JSON: {e}")
|
|
907
|
+
elif output_schema is not None and isinstance(run_response.content, dict):
|
|
908
|
+
try:
|
|
909
|
+
response_content_batch = JSON(json.dumps(run_response.content), indent=2)
|
|
910
|
+
except Exception as e:
|
|
911
|
+
log_warning(f"Failed to convert response to JSON: {e}")
|
|
886
912
|
else:
|
|
887
913
|
try:
|
|
888
914
|
response_content_batch = JSON(json.dumps(run_response.content), indent=4)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import json
|
|
1
2
|
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Set, Union, get_args
|
|
2
3
|
|
|
3
4
|
from pydantic import BaseModel
|
|
@@ -488,6 +489,11 @@ def print_response_stream(
|
|
|
488
489
|
_response_content = JSON(resp.content.model_dump_json(exclude_none=True), indent=2) # type: ignore
|
|
489
490
|
except Exception as e:
|
|
490
491
|
log_warning(f"Failed to convert response to JSON: {e}")
|
|
492
|
+
elif team.output_schema is not None and isinstance(resp.content, dict):
|
|
493
|
+
try:
|
|
494
|
+
_response_content = JSON(json.dumps(resp.content), indent=2) # type: ignore
|
|
495
|
+
except Exception as e:
|
|
496
|
+
log_warning(f"Failed to convert response to JSON: {e}")
|
|
491
497
|
if hasattr(resp, "reasoning_content") and resp.reasoning_content is not None: # type: ignore
|
|
492
498
|
_response_reasoning_content += resp.reasoning_content # type: ignore
|
|
493
499
|
if hasattr(resp, "reasoning_steps") and resp.reasoning_steps is not None: # type: ignore
|
|
@@ -1412,6 +1418,11 @@ async def aprint_response_stream(
|
|
|
1412
1418
|
_response_content = JSON(resp.content.model_dump_json(exclude_none=True), indent=2) # type: ignore
|
|
1413
1419
|
except Exception as e:
|
|
1414
1420
|
log_warning(f"Failed to convert response to JSON: {e}")
|
|
1421
|
+
elif team.output_schema is not None and isinstance(resp.content, dict):
|
|
1422
|
+
try:
|
|
1423
|
+
_response_content = JSON(json.dumps(resp.content), indent=2) # type: ignore
|
|
1424
|
+
except Exception as e:
|
|
1425
|
+
log_warning(f"Failed to convert response to JSON: {e}")
|
|
1415
1426
|
if hasattr(resp, "reasoning_content") and resp.reasoning_content is not None: # type: ignore
|
|
1416
1427
|
_response_reasoning_content += resp.reasoning_content # type: ignore
|
|
1417
1428
|
if hasattr(resp, "reasoning_steps") and resp.reasoning_steps is not None: # type: ignore
|
agno/utils/prompts.py
CHANGED
|
@@ -6,7 +6,7 @@ from pydantic import BaseModel
|
|
|
6
6
|
from agno.utils.log import log_warning
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
def get_json_output_prompt(output_schema: Union[str, list, BaseModel]) -> str:
|
|
9
|
+
def get_json_output_prompt(output_schema: Union[str, list, dict, BaseModel]) -> str:
|
|
10
10
|
"""Return the JSON output prompt for the Agent.
|
|
11
11
|
|
|
12
12
|
This is added to the system prompt when the output_schema is set and structured_outputs is False.
|
|
@@ -22,11 +22,13 @@ def get_json_output_prompt(output_schema: Union[str, list, BaseModel]) -> str:
|
|
|
22
22
|
json_output_prompt += "\n<json_fields>"
|
|
23
23
|
json_output_prompt += f"\n{json.dumps(output_schema)}"
|
|
24
24
|
json_output_prompt += "\n</json_fields>"
|
|
25
|
-
elif (
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
elif isinstance(output_schema, dict):
|
|
26
|
+
json_output_prompt += "\n<json_fields>"
|
|
27
|
+
json_output_prompt += f"\n{json.dumps(output_schema)}"
|
|
28
|
+
json_output_prompt += "\n</json_fields>"
|
|
29
|
+
elif (isinstance(output_schema, type) and issubclass(output_schema, BaseModel)) or isinstance(
|
|
30
|
+
output_schema, BaseModel
|
|
31
|
+
):
|
|
30
32
|
json_schema = output_schema.model_json_schema()
|
|
31
33
|
if json_schema is not None:
|
|
32
34
|
response_model_properties = {}
|
agno/utils/string.py
CHANGED
|
@@ -201,6 +201,52 @@ def parse_response_model_str(content: str, output_schema: Type[BaseModel]) -> Op
|
|
|
201
201
|
return structured_output
|
|
202
202
|
|
|
203
203
|
|
|
204
|
+
def parse_response_dict_str(content: str) -> Optional[dict]:
|
|
205
|
+
"""Parse dict from string content, extracting JSON if needed"""
|
|
206
|
+
from agno.utils.reasoning import extract_thinking_content
|
|
207
|
+
|
|
208
|
+
# Handle thinking content b/w <think> tags
|
|
209
|
+
if "</think>" in content:
|
|
210
|
+
reasoning_content, output_content = extract_thinking_content(content)
|
|
211
|
+
if reasoning_content:
|
|
212
|
+
content = output_content
|
|
213
|
+
|
|
214
|
+
# Clean content first to simplify all parsing attempts
|
|
215
|
+
cleaned_content = _clean_json_content(content)
|
|
216
|
+
|
|
217
|
+
try:
|
|
218
|
+
# First attempt: direct JSON parsing on cleaned content
|
|
219
|
+
return json.loads(cleaned_content)
|
|
220
|
+
except json.JSONDecodeError as e:
|
|
221
|
+
logger.warning(f"Failed to parse cleaned JSON: {e}")
|
|
222
|
+
|
|
223
|
+
# Second attempt: Extract individual JSON objects
|
|
224
|
+
candidate_jsons = _extract_json_objects(cleaned_content)
|
|
225
|
+
|
|
226
|
+
if len(candidate_jsons) == 1:
|
|
227
|
+
# Single JSON object - try to parse it directly
|
|
228
|
+
try:
|
|
229
|
+
return json.loads(candidate_jsons[0])
|
|
230
|
+
except json.JSONDecodeError:
|
|
231
|
+
pass
|
|
232
|
+
|
|
233
|
+
if len(candidate_jsons) > 1:
|
|
234
|
+
# Final attempt: Merge multiple JSON objects
|
|
235
|
+
merged_data: dict = {}
|
|
236
|
+
for candidate in candidate_jsons:
|
|
237
|
+
try:
|
|
238
|
+
obj = json.loads(candidate)
|
|
239
|
+
if isinstance(obj, dict):
|
|
240
|
+
merged_data.update(obj)
|
|
241
|
+
except json.JSONDecodeError:
|
|
242
|
+
continue
|
|
243
|
+
if merged_data:
|
|
244
|
+
return merged_data
|
|
245
|
+
|
|
246
|
+
logger.warning("All parsing attempts failed.")
|
|
247
|
+
return None
|
|
248
|
+
|
|
249
|
+
|
|
204
250
|
def generate_id(seed: Optional[str] = None) -> str:
|
|
205
251
|
"""
|
|
206
252
|
Generate a deterministic UUID5 based on a seed string.
|
agno/utils/team.py
CHANGED
|
@@ -59,7 +59,7 @@ def add_interaction_to_team_run_context(
|
|
|
59
59
|
team_run_context: Dict[str, Any],
|
|
60
60
|
member_name: str,
|
|
61
61
|
task: str,
|
|
62
|
-
run_response: Union[RunOutput, TeamRunOutput],
|
|
62
|
+
run_response: Optional[Union[RunOutput, TeamRunOutput]],
|
|
63
63
|
) -> None:
|
|
64
64
|
if "member_responses" not in team_run_context:
|
|
65
65
|
team_run_context["member_responses"] = []
|
agno/vectordb/milvus/milvus.py
CHANGED
|
@@ -651,7 +651,11 @@ class Milvus(VectorDb):
|
|
|
651
651
|
return MILVUS_DISTANCE_MAP.get(self.distance, "COSINE")
|
|
652
652
|
|
|
653
653
|
def search(
|
|
654
|
-
self,
|
|
654
|
+
self,
|
|
655
|
+
query: str,
|
|
656
|
+
limit: int = 5,
|
|
657
|
+
filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
658
|
+
search_params: Optional[Dict[str, Any]] = None,
|
|
655
659
|
) -> List[Document]:
|
|
656
660
|
"""
|
|
657
661
|
Search for documents matching the query.
|
|
@@ -660,6 +664,10 @@ class Milvus(VectorDb):
|
|
|
660
664
|
query (str): Query string to search for
|
|
661
665
|
limit (int): Maximum number of results to return
|
|
662
666
|
filters (Optional[Dict[str, Any]]): Filters to apply to the search
|
|
667
|
+
search_params (Optional[Dict[str, Any]]): Milvus search parameters including:
|
|
668
|
+
- radius (float): Minimum similarity threshold for range search
|
|
669
|
+
- range_filter (float): Maximum similarity threshold for range search
|
|
670
|
+
- params (dict): Index-specific search params (e.g., nprobe, ef)
|
|
663
671
|
|
|
664
672
|
Returns:
|
|
665
673
|
List[Document]: List of matching documents
|
|
@@ -681,6 +689,7 @@ class Milvus(VectorDb):
|
|
|
681
689
|
filter=self._build_expr(filters),
|
|
682
690
|
output_fields=["*"],
|
|
683
691
|
limit=limit,
|
|
692
|
+
search_params=search_params,
|
|
684
693
|
)
|
|
685
694
|
|
|
686
695
|
# Build search results
|
|
@@ -708,8 +717,27 @@ class Milvus(VectorDb):
|
|
|
708
717
|
return search_results
|
|
709
718
|
|
|
710
719
|
async def async_search(
|
|
711
|
-
self,
|
|
720
|
+
self,
|
|
721
|
+
query: str,
|
|
722
|
+
limit: int = 5,
|
|
723
|
+
filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None,
|
|
724
|
+
search_params: Optional[Dict[str, Any]] = None,
|
|
712
725
|
) -> List[Document]:
|
|
726
|
+
"""
|
|
727
|
+
Asynchronously search for documents matching the query.
|
|
728
|
+
|
|
729
|
+
Args:
|
|
730
|
+
query (str): Query string to search for
|
|
731
|
+
limit (int): Maximum number of results to return
|
|
732
|
+
filters (Optional[Dict[str, Any]]): Filters to apply to the search
|
|
733
|
+
search_params (Optional[Dict[str, Any]]): Milvus search parameters including:
|
|
734
|
+
- radius (float): Minimum similarity threshold for range search
|
|
735
|
+
- range_filter (float): Maximum similarity threshold for range search
|
|
736
|
+
- params (dict): Index-specific search params (e.g., nprobe, ef)
|
|
737
|
+
|
|
738
|
+
Returns:
|
|
739
|
+
List[Document]: List of matching documents
|
|
740
|
+
"""
|
|
713
741
|
if isinstance(filters, List):
|
|
714
742
|
log_warning("Filters Expressions are not supported in Milvus. No filters will be applied.")
|
|
715
743
|
filters = None
|
|
@@ -727,6 +755,7 @@ class Milvus(VectorDb):
|
|
|
727
755
|
filter=self._build_expr(filters),
|
|
728
756
|
output_fields=["*"],
|
|
729
757
|
limit=limit,
|
|
758
|
+
search_params=search_params,
|
|
730
759
|
)
|
|
731
760
|
|
|
732
761
|
# Build search results
|
|
@@ -1073,7 +1102,7 @@ class Milvus(VectorDb):
|
|
|
1073
1102
|
if isinstance(v, (list, tuple)):
|
|
1074
1103
|
# For array values, use json_contains_any
|
|
1075
1104
|
values_str = json.dumps(v)
|
|
1076
|
-
expr = f'json_contains_any(meta_data
|
|
1105
|
+
expr = f'json_contains_any(meta_data["{k}"], {values_str})'
|
|
1077
1106
|
elif isinstance(v, str):
|
|
1078
1107
|
# For string values
|
|
1079
1108
|
expr = f'meta_data["{k}"] == "{v}"'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agno
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.14
|
|
4
4
|
Summary: Agno: a lightweight library for building Multi-Agent Systems
|
|
5
5
|
Author-email: Ashpreet Bedi <ashpreet@agno.com>
|
|
6
6
|
Project-URL: homepage, https://agno.com
|
|
@@ -212,7 +212,7 @@ Provides-Extra: firestore
|
|
|
212
212
|
Requires-Dist: google-cloud-firestore; extra == "firestore"
|
|
213
213
|
Provides-Extra: redis
|
|
214
214
|
Requires-Dist: redis; extra == "redis"
|
|
215
|
-
Requires-Dist: redisvl; extra == "redis"
|
|
215
|
+
Requires-Dist: redisvl>=0.12.1; extra == "redis"
|
|
216
216
|
Provides-Extra: mysql
|
|
217
217
|
Requires-Dist: pymysql; extra == "mysql"
|
|
218
218
|
Requires-Dist: asyncmy; extra == "mysql"
|
|
@@ -364,6 +364,7 @@ Requires-Dist: agno[pinecone]; extra == "vectordbs"
|
|
|
364
364
|
Requires-Dist: agno[surrealdb]; extra == "vectordbs"
|
|
365
365
|
Requires-Dist: agno[upstash]; extra == "vectordbs"
|
|
366
366
|
Requires-Dist: agno[pylance]; extra == "vectordbs"
|
|
367
|
+
Requires-Dist: agno[redis]; extra == "vectordbs"
|
|
367
368
|
Provides-Extra: knowledge
|
|
368
369
|
Requires-Dist: agno[pdf]; extra == "knowledge"
|
|
369
370
|
Requires-Dist: agno[docx]; extra == "knowledge"
|