dao-ai 0.0.36__py3-none-any.whl → 0.1.1__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.
- dao_ai/__init__.py +29 -0
- dao_ai/cli.py +195 -30
- dao_ai/config.py +770 -244
- dao_ai/genie/__init__.py +1 -22
- dao_ai/genie/cache/__init__.py +1 -2
- dao_ai/genie/cache/base.py +20 -70
- dao_ai/genie/cache/core.py +75 -0
- dao_ai/genie/cache/lru.py +44 -21
- dao_ai/genie/cache/semantic.py +390 -109
- dao_ai/genie/core.py +35 -0
- dao_ai/graph.py +27 -253
- dao_ai/hooks/__init__.py +9 -6
- dao_ai/hooks/core.py +22 -190
- dao_ai/memory/__init__.py +10 -0
- dao_ai/memory/core.py +23 -5
- dao_ai/memory/databricks.py +389 -0
- dao_ai/memory/postgres.py +2 -2
- dao_ai/messages.py +6 -4
- dao_ai/middleware/__init__.py +125 -0
- dao_ai/middleware/assertions.py +778 -0
- dao_ai/middleware/base.py +50 -0
- dao_ai/middleware/core.py +61 -0
- dao_ai/middleware/guardrails.py +415 -0
- dao_ai/middleware/human_in_the_loop.py +228 -0
- dao_ai/middleware/message_validation.py +554 -0
- dao_ai/middleware/summarization.py +192 -0
- dao_ai/models.py +1177 -108
- dao_ai/nodes.py +118 -161
- dao_ai/optimization.py +664 -0
- dao_ai/orchestration/__init__.py +52 -0
- dao_ai/orchestration/core.py +287 -0
- dao_ai/orchestration/supervisor.py +264 -0
- dao_ai/orchestration/swarm.py +226 -0
- dao_ai/prompts.py +126 -29
- dao_ai/providers/databricks.py +126 -381
- dao_ai/state.py +139 -21
- dao_ai/tools/__init__.py +8 -5
- dao_ai/tools/core.py +57 -4
- dao_ai/tools/email.py +280 -0
- dao_ai/tools/genie.py +47 -24
- dao_ai/tools/mcp.py +4 -3
- dao_ai/tools/memory.py +50 -0
- dao_ai/tools/python.py +4 -12
- dao_ai/tools/search.py +14 -0
- dao_ai/tools/slack.py +1 -1
- dao_ai/tools/unity_catalog.py +8 -6
- dao_ai/tools/vector_search.py +16 -9
- dao_ai/utils.py +72 -8
- dao_ai-0.1.1.dist-info/METADATA +1878 -0
- dao_ai-0.1.1.dist-info/RECORD +62 -0
- dao_ai/chat_models.py +0 -204
- dao_ai/guardrails.py +0 -112
- dao_ai/tools/genie/__init__.py +0 -236
- dao_ai/tools/human_in_the_loop.py +0 -100
- dao_ai-0.0.36.dist-info/METADATA +0 -951
- dao_ai-0.0.36.dist-info/RECORD +0 -47
- {dao_ai-0.0.36.dist-info → dao_ai-0.1.1.dist-info}/WHEEL +0 -0
- {dao_ai-0.0.36.dist-info → dao_ai-0.1.1.dist-info}/entry_points.txt +0 -0
- {dao_ai-0.0.36.dist-info → dao_ai-0.1.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
from typing import Any, Optional
|
|
2
|
-
|
|
3
|
-
from langchain_core.runnables import RunnableConfig
|
|
4
|
-
from langchain_core.runnables.base import RunnableLike
|
|
5
|
-
from langchain_core.tools import BaseTool
|
|
6
|
-
from langchain_core.tools import tool as create_tool
|
|
7
|
-
from langgraph.prebuilt.interrupt import HumanInterrupt, HumanInterruptConfig
|
|
8
|
-
from langgraph.types import interrupt
|
|
9
|
-
from loguru import logger
|
|
10
|
-
|
|
11
|
-
from dao_ai.config import (
|
|
12
|
-
BaseFunctionModel,
|
|
13
|
-
HumanInTheLoopModel,
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def add_human_in_the_loop(
|
|
18
|
-
tool: RunnableLike,
|
|
19
|
-
*,
|
|
20
|
-
interrupt_config: HumanInterruptConfig | None = None,
|
|
21
|
-
review_prompt: Optional[str] = "Please review the tool call",
|
|
22
|
-
) -> BaseTool:
|
|
23
|
-
"""
|
|
24
|
-
Wrap a tool with human-in-the-loop functionality.
|
|
25
|
-
This function takes a tool (either a callable or a BaseTool instance) and wraps it
|
|
26
|
-
with a human-in-the-loop mechanism. When the tool is invoked, it will first
|
|
27
|
-
request human review before executing the tool's logic. The human can choose to
|
|
28
|
-
accept, edit the input, or provide a custom response.
|
|
29
|
-
|
|
30
|
-
Args:
|
|
31
|
-
tool (Callable[..., Any] | BaseTool): _description_
|
|
32
|
-
interrupt_config (HumanInterruptConfig | None, optional): _description_. Defaults to None.
|
|
33
|
-
|
|
34
|
-
Raises:
|
|
35
|
-
ValueError: _description_
|
|
36
|
-
|
|
37
|
-
Returns:
|
|
38
|
-
BaseTool: _description_
|
|
39
|
-
"""
|
|
40
|
-
if not isinstance(tool, BaseTool):
|
|
41
|
-
tool = create_tool(tool)
|
|
42
|
-
|
|
43
|
-
if interrupt_config is None:
|
|
44
|
-
interrupt_config = {
|
|
45
|
-
"allow_accept": True,
|
|
46
|
-
"allow_edit": True,
|
|
47
|
-
"allow_respond": True,
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
logger.debug(f"Wrapping tool {tool} with human-in-the-loop functionality")
|
|
51
|
-
|
|
52
|
-
@create_tool(tool.name, description=tool.description, args_schema=tool.args_schema)
|
|
53
|
-
async def call_tool_with_interrupt(config: RunnableConfig, **tool_input) -> Any:
|
|
54
|
-
logger.debug(f"call_tool_with_interrupt: {tool.name} with input: {tool_input}")
|
|
55
|
-
request: HumanInterrupt = {
|
|
56
|
-
"action_request": {
|
|
57
|
-
"action": tool.name,
|
|
58
|
-
"args": tool_input,
|
|
59
|
-
},
|
|
60
|
-
"config": interrupt_config,
|
|
61
|
-
"description": review_prompt,
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
logger.debug(f"Human interrupt request: {request}")
|
|
65
|
-
response: dict[str, Any] = interrupt([request])[0]
|
|
66
|
-
logger.debug(f"Human interrupt response: {response}")
|
|
67
|
-
|
|
68
|
-
if response["type"] == "accept":
|
|
69
|
-
tool_response = await tool.ainvoke(tool_input, config=config)
|
|
70
|
-
elif response["type"] == "edit":
|
|
71
|
-
tool_input = response["args"]["args"]
|
|
72
|
-
tool_response = await tool.ainvoke(tool_input, config=config)
|
|
73
|
-
elif response["type"] == "response":
|
|
74
|
-
user_feedback = response["args"]
|
|
75
|
-
tool_response = user_feedback
|
|
76
|
-
else:
|
|
77
|
-
raise ValueError(f"Unknown interrupt response type: {response['type']}")
|
|
78
|
-
|
|
79
|
-
return tool_response
|
|
80
|
-
|
|
81
|
-
return call_tool_with_interrupt
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def as_human_in_the_loop(
|
|
85
|
-
tool: RunnableLike, function: BaseFunctionModel | str
|
|
86
|
-
) -> RunnableLike:
|
|
87
|
-
if isinstance(function, BaseFunctionModel):
|
|
88
|
-
human_in_the_loop: HumanInTheLoopModel | None = function.human_in_the_loop
|
|
89
|
-
if human_in_the_loop:
|
|
90
|
-
# Get tool name safely - handle RunnableBinding objects
|
|
91
|
-
tool_name = getattr(tool, "name", None) or getattr(
|
|
92
|
-
getattr(tool, "bound", None), "name", "unknown_tool"
|
|
93
|
-
)
|
|
94
|
-
logger.debug(f"Adding human-in-the-loop to tool: {tool_name}")
|
|
95
|
-
tool = add_human_in_the_loop(
|
|
96
|
-
tool=tool,
|
|
97
|
-
interrupt_config=human_in_the_loop.interupt_config,
|
|
98
|
-
review_prompt=human_in_the_loop.review_prompt,
|
|
99
|
-
)
|
|
100
|
-
return tool
|