dao-ai 0.1.5__py3-none-any.whl → 0.1.20__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. dao_ai/apps/__init__.py +24 -0
  2. dao_ai/apps/handlers.py +105 -0
  3. dao_ai/apps/model_serving.py +29 -0
  4. dao_ai/apps/resources.py +1122 -0
  5. dao_ai/apps/server.py +39 -0
  6. dao_ai/cli.py +446 -16
  7. dao_ai/config.py +1034 -103
  8. dao_ai/evaluation.py +543 -0
  9. dao_ai/genie/__init__.py +55 -7
  10. dao_ai/genie/cache/__init__.py +34 -7
  11. dao_ai/genie/cache/base.py +143 -2
  12. dao_ai/genie/cache/context_aware/__init__.py +31 -0
  13. dao_ai/genie/cache/context_aware/base.py +1151 -0
  14. dao_ai/genie/cache/context_aware/in_memory.py +609 -0
  15. dao_ai/genie/cache/context_aware/persistent.py +802 -0
  16. dao_ai/genie/cache/context_aware/postgres.py +1166 -0
  17. dao_ai/genie/cache/core.py +1 -1
  18. dao_ai/genie/cache/lru.py +257 -75
  19. dao_ai/genie/cache/optimization.py +890 -0
  20. dao_ai/genie/core.py +235 -11
  21. dao_ai/memory/postgres.py +175 -39
  22. dao_ai/middleware/__init__.py +5 -0
  23. dao_ai/middleware/tool_selector.py +129 -0
  24. dao_ai/models.py +327 -370
  25. dao_ai/nodes.py +4 -4
  26. dao_ai/orchestration/core.py +33 -9
  27. dao_ai/orchestration/supervisor.py +23 -8
  28. dao_ai/orchestration/swarm.py +6 -1
  29. dao_ai/{prompts.py → prompts/__init__.py} +12 -61
  30. dao_ai/prompts/instructed_retriever_decomposition.yaml +58 -0
  31. dao_ai/prompts/instruction_reranker.yaml +14 -0
  32. dao_ai/prompts/router.yaml +37 -0
  33. dao_ai/prompts/verifier.yaml +46 -0
  34. dao_ai/providers/base.py +28 -2
  35. dao_ai/providers/databricks.py +352 -33
  36. dao_ai/state.py +1 -0
  37. dao_ai/tools/__init__.py +5 -3
  38. dao_ai/tools/genie.py +103 -26
  39. dao_ai/tools/instructed_retriever.py +366 -0
  40. dao_ai/tools/instruction_reranker.py +202 -0
  41. dao_ai/tools/mcp.py +539 -97
  42. dao_ai/tools/router.py +89 -0
  43. dao_ai/tools/slack.py +13 -2
  44. dao_ai/tools/sql.py +7 -3
  45. dao_ai/tools/unity_catalog.py +32 -10
  46. dao_ai/tools/vector_search.py +493 -160
  47. dao_ai/tools/verifier.py +159 -0
  48. dao_ai/utils.py +182 -2
  49. dao_ai/vector_search.py +9 -1
  50. {dao_ai-0.1.5.dist-info → dao_ai-0.1.20.dist-info}/METADATA +10 -8
  51. dao_ai-0.1.20.dist-info/RECORD +89 -0
  52. dao_ai/agent_as_code.py +0 -22
  53. dao_ai/genie/cache/semantic.py +0 -970
  54. dao_ai-0.1.5.dist-info/RECORD +0 -70
  55. {dao_ai-0.1.5.dist-info → dao_ai-0.1.20.dist-info}/WHEEL +0 -0
  56. {dao_ai-0.1.5.dist-info → dao_ai-0.1.20.dist-info}/entry_points.txt +0 -0
  57. {dao_ai-0.1.5.dist-info → dao_ai-0.1.20.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,129 @@
1
+ """
2
+ Tool selector middleware for intelligently filtering tools before LLM calls.
3
+
4
+ This middleware uses an LLM to select relevant tools from a large set, improving
5
+ performance and accuracy by reducing context size and improving focus.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from typing import Any
11
+
12
+ from langchain.agents.middleware import LLMToolSelectorMiddleware
13
+ from langchain_core.language_models import LanguageModelLike
14
+ from loguru import logger
15
+
16
+ from dao_ai.config import ToolModel
17
+
18
+
19
+ def create_llm_tool_selector_middleware(
20
+ model: LanguageModelLike,
21
+ max_tools: int = 3,
22
+ always_include: list[str | ToolModel | dict[str, Any]] | None = None,
23
+ ) -> LLMToolSelectorMiddleware:
24
+ """
25
+ Create an LLMToolSelectorMiddleware for intelligent tool selection.
26
+
27
+ Uses an LLM to analyze the current query and select the most relevant tools
28
+ before calling the main model. This is particularly useful for agents with
29
+ many tools (10+) where most aren't relevant for any given query.
30
+
31
+ Benefits:
32
+ - Reduces token usage by filtering irrelevant tools
33
+ - Improves model focus and accuracy
34
+ - Optimizes cost for agents with large tool sets
35
+ - Maintains context window efficiency
36
+
37
+ Args:
38
+ model: The LLM to use for tool selection. Typically a smaller, faster
39
+ model like "gpt-4o-mini" or similar.
40
+ max_tools: Maximum number of tools to select for each query.
41
+ Default 3. Adjust based on your use case - higher values
42
+ increase context but improve tool coverage.
43
+ always_include: List of tools that should always be included regardless
44
+ of the LLM's selection. Can be:
45
+ - str: Tool name
46
+ - ToolModel: Full tool configuration
47
+ - dict: Tool configuration dictionary
48
+ Use this for critical tools that should always be available.
49
+
50
+ Returns:
51
+ LLMToolSelectorMiddleware configured with the specified parameters
52
+
53
+ Example:
54
+ from dao_ai.middleware import create_llm_tool_selector_middleware
55
+ from dao_ai.llms import create_llm
56
+
57
+ # Use a fast, cheap model for tool selection
58
+ selector_llm = create_llm("databricks-gpt-4o-mini")
59
+
60
+ middleware = create_llm_tool_selector_middleware(
61
+ model=selector_llm,
62
+ max_tools=3,
63
+ always_include=["search_web"], # Always include search
64
+ )
65
+
66
+ Use Cases:
67
+ - Large tool sets (10+ tools) where most are specialized
68
+ - Cost optimization by reducing tokens in main model calls
69
+ - Improved accuracy by reducing tool confusion
70
+ - Dynamic tool filtering based on query relevance
71
+
72
+ Note:
73
+ The selector model makes an additional LLM call for each agent turn.
74
+ Choose a fast, inexpensive model to minimize latency and cost overhead.
75
+ """
76
+ # Extract tool names from always_include
77
+ always_include_names: list[str] = []
78
+ if always_include:
79
+ always_include_names = _resolve_tool_names(always_include)
80
+
81
+ logger.debug(
82
+ "Creating LLM tool selector middleware",
83
+ max_tools=max_tools,
84
+ always_include_count=len(always_include_names),
85
+ always_include=always_include_names,
86
+ )
87
+
88
+ return LLMToolSelectorMiddleware(
89
+ model=model,
90
+ max_tools=max_tools,
91
+ always_include=always_include_names if always_include_names else None,
92
+ )
93
+
94
+
95
+ def _resolve_tool_names(tools: list[str | ToolModel | dict[str, Any]]) -> list[str]:
96
+ """
97
+ Extract tool names from a list of tool specifications.
98
+
99
+ Args:
100
+ tools: List of tool specifications (strings, ToolModels, or dicts)
101
+
102
+ Returns:
103
+ List of tool names as strings
104
+ """
105
+ names: list[str] = []
106
+
107
+ for tool_spec in tools:
108
+ if isinstance(tool_spec, str):
109
+ # Simple string tool name
110
+ names.append(tool_spec)
111
+ elif isinstance(tool_spec, ToolModel):
112
+ # ToolModel - use its name
113
+ names.append(tool_spec.name)
114
+ elif isinstance(tool_spec, dict):
115
+ # Dictionary - try to extract name
116
+ if "name" in tool_spec:
117
+ names.append(tool_spec["name"])
118
+ else:
119
+ logger.warning(
120
+ "Tool dict missing 'name' field, skipping",
121
+ tool_spec=tool_spec,
122
+ )
123
+ else:
124
+ logger.warning(
125
+ "Unknown tool specification type, skipping",
126
+ tool_spec_type=type(tool_spec).__name__,
127
+ )
128
+
129
+ return names