rootdriver 0.1.0__tar.gz → 0.3.0__tar.gz

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.
@@ -0,0 +1,135 @@
1
+ Metadata-Version: 2.4
2
+ Name: rootdriver
3
+ Version: 0.3.0
4
+ Summary: Rooted in Origin, Driving All Things
5
+ Author-email: zimvir <zimvir@qq.com>
6
+ License: MIT
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: openai>=1.0.0
10
+ Requires-Dist: pydantic>=2.0.0
11
+ Provides-Extra: dev
12
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
13
+
14
+ # RootDriver
15
+
16
+ 根源出发,驱动万物
17
+
18
+ 一个轻量级的 Python AI Agent 开发框架,支持单智能体和多智能体应用。
19
+
20
+ ## 特性
21
+
22
+ - **简洁易用**:装饰器方式定义工具,快速构建 Agent
23
+ - **模块化设计**:LLM 适配器、工具系统、会话管理解耦
24
+ - **工具调用**:支持 function calling,自动执行工具并返回结果
25
+ - **状态管理**:支持内存和数据库持久化检查点
26
+ - **异常体系**:完整的异常类层次结构
27
+ - **异步支持**:全面异步支持,并发多 Agent / 工具调用
28
+
29
+ ## 安装
30
+
31
+ ```bash
32
+ pip install rootdriver
33
+ ```
34
+
35
+ ## 快速开始
36
+
37
+ ### 定义工具
38
+
39
+ ```python
40
+ from rootdriver import tool
41
+
42
+ @tool
43
+ def get_weather(city: str) -> str:
44
+ """获取城市天气"""
45
+ return f"{city} 晴天"
46
+ ```
47
+
48
+ ### 创建 Agent
49
+
50
+ ```python
51
+ from rootdriver import Agent, AgentLLM, OpenAIAdapter
52
+
53
+ agent = Agent(
54
+ agent_llm=AgentLLM(
55
+ adapter=OpenAIAdapter(
56
+ api_key="YOUR_API_KEY",
57
+ base_url="BASE_URL"
58
+ ),
59
+ model="gpt-4",
60
+ ),
61
+ tools=[get_weather],
62
+ system_prompt="你是一个有用的助手",
63
+ )
64
+
65
+ # 单次对话
66
+ response = agent.talk("北京天气怎么样?")
67
+ print(response)
68
+ ```
69
+
70
+ ### 使用工具
71
+
72
+ ```python
73
+ # 完整对话循环(包含工具调用)
74
+ response = agent.react("帮我查下上海天气")
75
+ print(response)
76
+ ```
77
+
78
+ ### 异步用法
79
+
80
+ ```python
81
+ import asyncio
82
+ from rootdriver import Agent, AgentLLM, OpenAIAdapter
83
+
84
+ async def main():
85
+ agent = Agent(agent_llm=AgentLLM(...))
86
+
87
+ # 单次异步对话
88
+ response = await agent.atalk("你好")
89
+ print(response)
90
+
91
+ # 并发多个 Agent
92
+ results = await asyncio.gather(
93
+ agent.areact("问题1"),
94
+ agent.areact("问题2"),
95
+ agent.areact("问题3"),
96
+ )
97
+
98
+ asyncio.run(main())
99
+ ```
100
+
101
+ ## 核心组件
102
+
103
+ | 组件 | 说明 |
104
+ |------|------|
105
+ | `Agent` | 智能体入口,整合 LLM、工具、会话 |
106
+ | `Engine` | 核心引擎,处理对话循环和工具调用 |
107
+ | `Conversation` | 会话管理,维护消息历史 |
108
+ | `LLM` | LLM 调用封装 |
109
+ | `Tool` | 工具集合,管理所有可调用工具 |
110
+ | `State` | 状态管理,支持检查点和持久化 |
111
+
112
+ ## 项目结构
113
+
114
+ ```
115
+ rootdriver/
116
+ ├── agent.py # Agent 智能体
117
+ ├── engine.py # 引擎核心
118
+ ├── conversation.py # 对话管理
119
+ ├── state.py # 状态管理
120
+ ├── exception.py # 异常定义
121
+ ├── llm/
122
+ │ ├── llm.py # LLM 封装
123
+ │ ├── base_adapter.py # 适配器基类
124
+ │ └── adapter/
125
+ │ └── openai_adapter.py # OpenAI 适配器
126
+ ├── tool/
127
+ │ ├── base_tool.py # 工具基类
128
+ │ └── tools.py # 工具集
129
+ ├── types/ # 类型定义
130
+ └── utils/ # 工具函数
131
+ ```
132
+
133
+ ## License
134
+
135
+ MIT
@@ -0,0 +1,122 @@
1
+ # RootDriver
2
+
3
+ 根源出发,驱动万物
4
+
5
+ 一个轻量级的 Python AI Agent 开发框架,支持单智能体和多智能体应用。
6
+
7
+ ## 特性
8
+
9
+ - **简洁易用**:装饰器方式定义工具,快速构建 Agent
10
+ - **模块化设计**:LLM 适配器、工具系统、会话管理解耦
11
+ - **工具调用**:支持 function calling,自动执行工具并返回结果
12
+ - **状态管理**:支持内存和数据库持久化检查点
13
+ - **异常体系**:完整的异常类层次结构
14
+ - **异步支持**:全面异步支持,并发多 Agent / 工具调用
15
+
16
+ ## 安装
17
+
18
+ ```bash
19
+ pip install rootdriver
20
+ ```
21
+
22
+ ## 快速开始
23
+
24
+ ### 定义工具
25
+
26
+ ```python
27
+ from rootdriver import tool
28
+
29
+ @tool
30
+ def get_weather(city: str) -> str:
31
+ """获取城市天气"""
32
+ return f"{city} 晴天"
33
+ ```
34
+
35
+ ### 创建 Agent
36
+
37
+ ```python
38
+ from rootdriver import Agent, AgentLLM, OpenAIAdapter
39
+
40
+ agent = Agent(
41
+ agent_llm=AgentLLM(
42
+ adapter=OpenAIAdapter(
43
+ api_key="YOUR_API_KEY",
44
+ base_url="BASE_URL"
45
+ ),
46
+ model="gpt-4",
47
+ ),
48
+ tools=[get_weather],
49
+ system_prompt="你是一个有用的助手",
50
+ )
51
+
52
+ # 单次对话
53
+ response = agent.talk("北京天气怎么样?")
54
+ print(response)
55
+ ```
56
+
57
+ ### 使用工具
58
+
59
+ ```python
60
+ # 完整对话循环(包含工具调用)
61
+ response = agent.react("帮我查下上海天气")
62
+ print(response)
63
+ ```
64
+
65
+ ### 异步用法
66
+
67
+ ```python
68
+ import asyncio
69
+ from rootdriver import Agent, AgentLLM, OpenAIAdapter
70
+
71
+ async def main():
72
+ agent = Agent(agent_llm=AgentLLM(...))
73
+
74
+ # 单次异步对话
75
+ response = await agent.atalk("你好")
76
+ print(response)
77
+
78
+ # 并发多个 Agent
79
+ results = await asyncio.gather(
80
+ agent.areact("问题1"),
81
+ agent.areact("问题2"),
82
+ agent.areact("问题3"),
83
+ )
84
+
85
+ asyncio.run(main())
86
+ ```
87
+
88
+ ## 核心组件
89
+
90
+ | 组件 | 说明 |
91
+ |------|------|
92
+ | `Agent` | 智能体入口,整合 LLM、工具、会话 |
93
+ | `Engine` | 核心引擎,处理对话循环和工具调用 |
94
+ | `Conversation` | 会话管理,维护消息历史 |
95
+ | `LLM` | LLM 调用封装 |
96
+ | `Tool` | 工具集合,管理所有可调用工具 |
97
+ | `State` | 状态管理,支持检查点和持久化 |
98
+
99
+ ## 项目结构
100
+
101
+ ```
102
+ rootdriver/
103
+ ├── agent.py # Agent 智能体
104
+ ├── engine.py # 引擎核心
105
+ ├── conversation.py # 对话管理
106
+ ├── state.py # 状态管理
107
+ ├── exception.py # 异常定义
108
+ ├── llm/
109
+ │ ├── llm.py # LLM 封装
110
+ │ ├── base_adapter.py # 适配器基类
111
+ │ └── adapter/
112
+ │ └── openai_adapter.py # OpenAI 适配器
113
+ ├── tool/
114
+ │ ├── base_tool.py # 工具基类
115
+ │ └── tools.py # 工具集
116
+ ├── types/ # 类型定义
117
+ └── utils/ # 工具函数
118
+ ```
119
+
120
+ ## License
121
+
122
+ MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "rootdriver"
7
- version = "0.1.0"
7
+ version = "0.3.0"
8
8
  description = "Rooted in Origin, Driving All Things"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -22,5 +22,8 @@ dev = [
22
22
  "pytest>=7.0.0",
23
23
  ]
24
24
 
25
+ [tool.pytest.ini_options]
26
+ asyncio_mode = "auto"
27
+
25
28
  [tool.setuptools]
26
29
  packages = ["rootdriver"]
@@ -0,0 +1,58 @@
1
+ __version__ = "0.3.0"
2
+ __author__ = "zimvir"
3
+ __email__ = "zimvir@qq.com"
4
+
5
+ from .agent import Agent
6
+ from .engine import Engine
7
+ from .conversation import Conversation
8
+ from .state import State
9
+ from .llm import LLM
10
+ from .llm.base_adapter import BaseAdapter
11
+ from .llm.adapter import OpenAIAdapter
12
+ from .tool import tool, Tool
13
+ from .types.agent import AgentLLM
14
+ from .types import Message, ToolDefinition, ToolCall
15
+ from .exception import (
16
+ LLMError,
17
+ LLMInvokeError,
18
+ LLMResponseError,
19
+ ToolError,
20
+ ToolNotFoundError,
21
+ ToolInvokeError,
22
+ ToolArgumentError,
23
+ AgentError,
24
+ ConversationError,
25
+ StateError,
26
+ CheckpointNotFoundError,
27
+ StateSaveError,
28
+ StateLoadError,
29
+ )
30
+
31
+ __all__ = [
32
+ "Agent",
33
+ "Engine",
34
+ "Conversation",
35
+ "State",
36
+ "LLM",
37
+ "BaseAdapter",
38
+ "OpenAIAdapter",
39
+ "tool",
40
+ "Tool",
41
+ "AgentLLM",
42
+ "Message",
43
+ "ToolDefinition",
44
+ "ToolCall",
45
+ "LLMError",
46
+ "LLMInvokeError",
47
+ "LLMResponseError",
48
+ "ToolError",
49
+ "ToolNotFoundError",
50
+ "ToolInvokeError",
51
+ "ToolArgumentError",
52
+ "AgentError",
53
+ "ConversationError",
54
+ "StateError",
55
+ "CheckpointNotFoundError",
56
+ "StateSaveError",
57
+ "StateLoadError",
58
+ ]
@@ -1,12 +1,12 @@
1
1
  from pathlib import Path
2
2
  from uuid import uuid4
3
-
3
+ import asyncio
4
4
  from .engine import Engine
5
5
  from .llm import LLM
6
6
  from .conversation import Conversation
7
7
  from .tool import Tool, BaseTool
8
8
  from .types.agent import AgentLLM
9
- from .types import ToolDefinition
9
+ from .state import State
10
10
  from .utils import build_system_message, build_message, build_tool_message, build_user_message, build_assistant_message
11
11
 
12
12
  class Agent:
@@ -14,18 +14,20 @@ class Agent:
14
14
  def __init__(
15
15
  self,
16
16
  agent_llm: AgentLLM,
17
- *,
17
+ id: str | None = None,
18
18
  tools: list[BaseTool] | None = None,
19
19
  system_prompt: str | None = None,
20
- id: str | None = None,
21
- # save_path: str | Path | None = None,
22
- # max_retries: int = 3,
23
- timeout: float | None = None,
20
+
21
+ db_path: str| None = None,
22
+ # llm_retry: int = 3,
23
+ # timeout: float | None = None,
24
24
  ):
25
+ self.id = id if id else uuid4().hex
26
+ self.db_path = db_path
27
+
25
28
  self.conversation = Conversation(system_prompt)
26
29
  self.tool = Tool(tools if tools else [])
27
- self.id = id if id else uuid4().hex
28
- # self.save_path = save_path
30
+ self.state = State(self, self.db_path)
29
31
 
30
32
  self.engine = Engine(
31
33
  model=agent_llm.model,
@@ -45,4 +47,15 @@ class Agent:
45
47
  return self.engine.invoke(build_user_message(input_prompt)).content
46
48
 
47
49
 
50
+ """==========异步部分=========="""
51
+ async def areact(self, input_prompt:str) -> "str":
52
+ """一次 react 异步循环"""
53
+ response = await self.engine.arun(build_user_message(input_prompt))
54
+ return response.content
55
+
56
+ async def atalk(self, input_prompt:str) -> "str":
57
+ """一次 agent 异步调用"""
58
+ return await self.engine.ainvoke(build_user_message(input_prompt)).content
59
+
60
+
48
61
 
@@ -40,6 +40,9 @@ class Conversation:
40
40
  def append_system(self, content: str) -> "Conversation":
41
41
  self.messages.append(Message(role="system", content=content, created_at=get_iso_timestamp()))
42
42
  return self
43
+ def update_message(self, messages: list[Message]) -> "Conversation":
44
+ self.messages = messages.copy()
45
+ return self
43
46
 
44
47
  def delete(self, index: int=-1) -> "Conversation":
45
48
  self.messages.pop(index)
@@ -53,18 +56,18 @@ class Conversation:
53
56
  '''返回 字典加列表组成的message(可转成json用于网络、跨语言传输) 组成的列表'''
54
57
  return [m.model_dump(exclude_none=True) for m in self.messages]
55
58
 
56
-
57
59
  @classmethod
58
60
  def from_dict_list(cls, messages: list[dict]) -> "Conversation":
59
61
  conv = cls()
60
62
  conv.messages = [Message.model_validate(m) for m in messages]
61
63
  return conv
62
-
64
+ from_messages_to_conversation = from_dict_list
63
65
  @classmethod
64
66
  def from_list(cls, messages: list[Message]) -> "Conversation":
65
67
  conv = cls()
66
68
  conv.messages = list(messages)
67
69
  return conv
70
+ from_messages_list_to_conversation = from_dict_list
68
71
 
69
72
  def clear(self) -> "Conversation":
70
73
  self.messages = []
@@ -1,4 +1,4 @@
1
-
1
+ import asyncio
2
2
 
3
3
  from .llm import LLM
4
4
  from .conversation import Conversation
@@ -14,18 +14,16 @@ class Engine:
14
14
  self.model = model
15
15
 
16
16
  def invoke(self, input_message:Message) -> Message:
17
+ """但系调用llm,并存入记忆,无tool调用"""
17
18
  self.conversation.append(input_message)
18
19
  message = self.chat()
19
20
  return message
20
21
 
21
22
  def chat(self) -> Message:
22
23
  """
23
-
24
24
  1. 读会话消息
25
25
  2. 大模型交流
26
26
  3. 追加会话消息
27
- 4. 判断 是否调用工具
28
- 5. 是: tool 返回结果并追加,否: 追加并返回
29
27
  """
30
28
  # 1. 读会话消息
31
29
  message = self.conversation.get_messages()
@@ -41,17 +39,9 @@ class Engine:
41
39
 
42
40
  def deal_tool_or_output(self, response_message:Message) -> Message|None:
43
41
  """
44
- 1. 追加输入
45
- 2. 读会话消息
46
- 3. 大模型交流
47
- 4. 追加会话消息
48
- 5. 判断 是否调用工具
49
- 6. 是: tool 返回结果并追加,否: 追加并返回
50
-
51
-
52
- Returns:
53
-
54
- """
42
+ 5. 判断 是否调用工具
43
+ 6. 是: tool 返回结果并追加,否: 追加并返回
44
+ """
55
45
 
56
46
  # 5. 判断 是否调用工具
57
47
  if response_message.tool_calls:
@@ -106,3 +96,68 @@ class Engine:
106
96
  """把 LLM 响应转成 Message 。"""
107
97
  return response.message
108
98
 
99
+ """==========异步部分=========="""
100
+ async def ainvoke(self, input_message:Message) -> Message:
101
+ """但系调用llm,并存入记忆,无tool调用"""
102
+ self.conversation.append(input_message)
103
+ message = await self.achat()
104
+ return message
105
+
106
+
107
+ async def achat(self) -> Message:
108
+ """
109
+ 1. 读会话消息
110
+ 2. 大模型交流
111
+ 3. 追加会话消息
112
+ """
113
+ # 1. 读会话消息
114
+ message = self.conversation.get_messages()
115
+
116
+ # 2. llm交互
117
+ response = await self.llm.ainvoke(self.messages_to_llm_request(message))
118
+
119
+ # 3. 追加会话消息
120
+ response_message = self.llm_response_to_message(response)
121
+ self.conversation.append(response_message)
122
+
123
+ return response_message
124
+
125
+ async def adeal_tool_or_output(self, response_message:Message) -> Message|None:
126
+ """
127
+ 5. 判断 是否调用工具
128
+ 6. 是: tool 返回结果并追加,否: 追加并返回
129
+ """
130
+
131
+ # 5. 判断 是否调用工具
132
+ if response_message.tool_calls:
133
+ # 6. 是: tool 返回结果追加
134
+ tool_results = await self.tool.ainvoke_many(response_message.tool_calls)
135
+ self.conversation.append_many([build_tool_message(tool_result.tool_call_id, tool_result.content) for tool_result in tool_results])
136
+ return None
137
+ else:
138
+ # 6. 否: 追加并返回
139
+ return response_message
140
+
141
+
142
+ async def arun(self, input_message:Message) ->Message:
143
+ """
144
+ 1. 追加输入
145
+ 2. 读会话消息
146
+ 3. 大模型交流
147
+ 4. 追加会话消息
148
+ 5. 判断 是否调用工具
149
+ 6. 是: tool 返回结果并追加,否: 追加并返回
150
+
151
+
152
+ Returns:
153
+
154
+ """
155
+ self.conversation.append(input_message)
156
+ while True:
157
+
158
+ response_message = await self.achat()
159
+ result = await self.adeal_tool_or_output(response_message)
160
+ if result is None:
161
+ continue
162
+ elif isinstance(result, Message):
163
+ return result
@@ -0,0 +1,119 @@
1
+ """RootDriver 异常体系。"""
2
+
3
+
4
+ # ============== LLM 相关 ==============
5
+
6
+ class LLMError(Exception):
7
+ """LLM 调用基类。"""
8
+
9
+ def __init__(self, message: str, model: str = None, **kwargs):
10
+ self.model = model
11
+ super().__init__(message)
12
+
13
+
14
+ class LLMInvokeError(LLMError):
15
+ """LLM 调用失败(网络错误、API 错误、超时等)。"""
16
+
17
+ def __init__(self, message: str, model: str = None, status_code: int = None, **kwargs):
18
+ self.status_code = status_code
19
+ super().__init__(message, model)
20
+
21
+
22
+ class LLMResponseError(LLMError):
23
+ """LLM 返回格式异常(解析失败、缺少字段等)。"""
24
+
25
+ pass
26
+
27
+
28
+ class AdapterError(Exception):
29
+ """适配器基类。"""
30
+
31
+ pass
32
+
33
+
34
+ # ============== 工具相关 ==============
35
+
36
+ class ToolError(Exception):
37
+ """工具基类。"""
38
+
39
+ pass
40
+
41
+
42
+ class ToolNotFoundError(ToolError):
43
+ """工具不存在。"""
44
+
45
+ def __init__(self, name: str, available: list = None):
46
+ self.name = name
47
+ self.available = available or []
48
+ msg = f"Tool '{name}' not found"
49
+ if available:
50
+ msg += f", available: {available}"
51
+ super().__init__(msg)
52
+
53
+
54
+ class ToolInvokeError(ToolError):
55
+ """工具执行失败。"""
56
+
57
+ def __init__(self, name: str, reason: str = None):
58
+ self.name = name
59
+ self.reason = reason
60
+ msg = f"Tool '{name}' invoke failed"
61
+ if reason:
62
+ msg += f": {reason}"
63
+ super().__init__(msg)
64
+
65
+
66
+ class ToolArgumentError(ToolError):
67
+ """工具参数错误。"""
68
+
69
+ def __init__(self, name: str, missing: list = None, invalid: dict = None):
70
+ self.name = name
71
+ self.missing = missing or []
72
+ self.invalid = invalid or {}
73
+ msg = f"Tool '{name}' argument error"
74
+ if missing:
75
+ msg += f", missing: {missing}"
76
+ super().__init__(msg)
77
+
78
+
79
+ # ============== Agent / 会话相关 ==============
80
+
81
+ class AgentError(Exception):
82
+ """Agent 基类。"""
83
+
84
+ pass
85
+
86
+
87
+ class ConversationError(Exception):
88
+ """会话操作错误。"""
89
+
90
+ pass
91
+
92
+
93
+ # ============== State 相关 ==============
94
+
95
+ class StateError(Exception):
96
+ """State 基类。"""
97
+
98
+ pass
99
+
100
+
101
+ class CheckpointNotFoundError(StateError):
102
+ """检查点不存在。"""
103
+
104
+ def __init__(self, name: str, source: str = "memory"):
105
+ self.name = name
106
+ self.source = source
107
+ super().__init__(f"Checkpoint '{name}' not found in {source}")
108
+
109
+
110
+ class StateSaveError(StateError):
111
+ """状态保存失败。"""
112
+
113
+ pass
114
+
115
+
116
+ class StateLoadError(StateError):
117
+ """状态加载失败。"""
118
+
119
+ pass
@@ -0,0 +1,103 @@
1
+
2
+
3
+ from __future__ import annotations
4
+
5
+ from .conversation import Conversation
6
+ from .exception import CheckpointNotFoundError
7
+ import json
8
+
9
+ class State:
10
+ def __init__(self, agent_obj:Agent, db_path):
11
+ self.agent = agent_obj
12
+ self.db_path = db_path
13
+ self.checkpoints:dict[str,Conversation] = {}
14
+
15
+ def checkpoint(self, name) -> "State":
16
+ self.checkpoints[name] = self.agent.conversation.copy()
17
+ return self
18
+ def save_messages(self, name:str, agent_id, messages:list[dict]) -> Agent:
19
+ """
20
+ Args:
21
+ name: 检查点 的名称
22
+ agent_id: agent的id, 默认当前agent的id
23
+ """
24
+ # 打开数据库
25
+ data = json.load(self.db_path)
26
+ # 确保有此agent
27
+ if data.get(agent_id) is None:
28
+ data[agent_id] = {}
29
+ data[agent_id][name] = messages
30
+ json.dump(data, self.db_path)
31
+ return self.agent
32
+ def save_from_now(self, name:str, agent_id:str|None=None) -> Agent:
33
+ """
34
+ Args:
35
+ name: 检查点 的名称
36
+ agent_id: agent的id, 默认当前agent的id
37
+ """
38
+ self.save_messages(name, agent_id, self.agent.conversation.get_messages_in_list())
39
+ return self.agent
40
+ def save_from_checkpoints(self, name:str,checkpoint_name:str, agent_id:str|None=None) -> Agent:
41
+ """
42
+ Args:
43
+ name: 检查点 的名称
44
+ checkpoint_name : 再checkpoints中的name
45
+ agent_id: agent的id, 默认当前agent的id
46
+ """
47
+ checkpoint = self.checkpoints.get(checkpoint_name)
48
+ if checkpoint is None:
49
+ raise CheckpointNotFoundError(checkpoint_name, "memory")
50
+ messages = checkpoint.get_messages_in_list()
51
+ self.save_messages(name, agent_id, messages)
52
+ return self.agent
53
+
54
+ def get_from_checkpoints(self, name) -> Conversation:
55
+ """
56
+ Args:
57
+ name: 检查点 的名称
58
+ agent_id: agent的id, 默认当前agent的id
59
+ Return:
60
+ Conversation
61
+ """
62
+
63
+ checkpoint:Conversation = self.checkpoints.get(name, None)
64
+ if checkpoint is None:
65
+ raise CheckpointNotFoundError(name, "memory")
66
+ return checkpoint
67
+ def get_from_db(self, name, agent_id:str|None=None) -> Conversation:
68
+ """
69
+ Args:
70
+ name: 检查点 的名称
71
+ agent_id: agent的id, 默认当前agent的id
72
+ Return:
73
+ Conversation
74
+ """
75
+ if agent_id is None:
76
+ agent_id = self.agent.id
77
+
78
+ data = json.load(self.db_path)
79
+
80
+ if data.get(agent_id) is None:
81
+ raise CheckpointNotFoundError(name, f"db (unknown agent_id: {agent_id})")
82
+
83
+ messages = data[agent_id].get(name, None)
84
+ if messages is None:
85
+ raise CheckpointNotFoundError(name, f"db ({self.db_path})")
86
+
87
+ return Conversation.from_messages_list_to_conversation(messages)
88
+
89
+ def load_from_checkpoint(self, name:str|None=None) -> Agent:
90
+ messages = self.get_from_checkpoints(name).messages
91
+ self.agent.conversation.update_message(messages)
92
+ return self.agent
93
+
94
+ def load_from_db(self, name:str|None=None, agent_id:str|None =None ) -> Agent:
95
+ """
96
+ Args:
97
+ name: 检查点 的名称
98
+ agent_id: agent的id, 默认当前agent的id
99
+ """
100
+ agent_id = agent_id if agent_id is not None else self.agent.id
101
+ messages = self.get_from_db(name, agent_id).messages
102
+ self.agent.conversation.update_message(messages)
103
+ return self.agent
@@ -0,0 +1,135 @@
1
+ Metadata-Version: 2.4
2
+ Name: rootdriver
3
+ Version: 0.3.0
4
+ Summary: Rooted in Origin, Driving All Things
5
+ Author-email: zimvir <zimvir@qq.com>
6
+ License: MIT
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: openai>=1.0.0
10
+ Requires-Dist: pydantic>=2.0.0
11
+ Provides-Extra: dev
12
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
13
+
14
+ # RootDriver
15
+
16
+ 根源出发,驱动万物
17
+
18
+ 一个轻量级的 Python AI Agent 开发框架,支持单智能体和多智能体应用。
19
+
20
+ ## 特性
21
+
22
+ - **简洁易用**:装饰器方式定义工具,快速构建 Agent
23
+ - **模块化设计**:LLM 适配器、工具系统、会话管理解耦
24
+ - **工具调用**:支持 function calling,自动执行工具并返回结果
25
+ - **状态管理**:支持内存和数据库持久化检查点
26
+ - **异常体系**:完整的异常类层次结构
27
+ - **异步支持**:全面异步支持,并发多 Agent / 工具调用
28
+
29
+ ## 安装
30
+
31
+ ```bash
32
+ pip install rootdriver
33
+ ```
34
+
35
+ ## 快速开始
36
+
37
+ ### 定义工具
38
+
39
+ ```python
40
+ from rootdriver import tool
41
+
42
+ @tool
43
+ def get_weather(city: str) -> str:
44
+ """获取城市天气"""
45
+ return f"{city} 晴天"
46
+ ```
47
+
48
+ ### 创建 Agent
49
+
50
+ ```python
51
+ from rootdriver import Agent, AgentLLM, OpenAIAdapter
52
+
53
+ agent = Agent(
54
+ agent_llm=AgentLLM(
55
+ adapter=OpenAIAdapter(
56
+ api_key="YOUR_API_KEY",
57
+ base_url="BASE_URL"
58
+ ),
59
+ model="gpt-4",
60
+ ),
61
+ tools=[get_weather],
62
+ system_prompt="你是一个有用的助手",
63
+ )
64
+
65
+ # 单次对话
66
+ response = agent.talk("北京天气怎么样?")
67
+ print(response)
68
+ ```
69
+
70
+ ### 使用工具
71
+
72
+ ```python
73
+ # 完整对话循环(包含工具调用)
74
+ response = agent.react("帮我查下上海天气")
75
+ print(response)
76
+ ```
77
+
78
+ ### 异步用法
79
+
80
+ ```python
81
+ import asyncio
82
+ from rootdriver import Agent, AgentLLM, OpenAIAdapter
83
+
84
+ async def main():
85
+ agent = Agent(agent_llm=AgentLLM(...))
86
+
87
+ # 单次异步对话
88
+ response = await agent.atalk("你好")
89
+ print(response)
90
+
91
+ # 并发多个 Agent
92
+ results = await asyncio.gather(
93
+ agent.areact("问题1"),
94
+ agent.areact("问题2"),
95
+ agent.areact("问题3"),
96
+ )
97
+
98
+ asyncio.run(main())
99
+ ```
100
+
101
+ ## 核心组件
102
+
103
+ | 组件 | 说明 |
104
+ |------|------|
105
+ | `Agent` | 智能体入口,整合 LLM、工具、会话 |
106
+ | `Engine` | 核心引擎,处理对话循环和工具调用 |
107
+ | `Conversation` | 会话管理,维护消息历史 |
108
+ | `LLM` | LLM 调用封装 |
109
+ | `Tool` | 工具集合,管理所有可调用工具 |
110
+ | `State` | 状态管理,支持检查点和持久化 |
111
+
112
+ ## 项目结构
113
+
114
+ ```
115
+ rootdriver/
116
+ ├── agent.py # Agent 智能体
117
+ ├── engine.py # 引擎核心
118
+ ├── conversation.py # 对话管理
119
+ ├── state.py # 状态管理
120
+ ├── exception.py # 异常定义
121
+ ├── llm/
122
+ │ ├── llm.py # LLM 封装
123
+ │ ├── base_adapter.py # 适配器基类
124
+ │ └── adapter/
125
+ │ └── openai_adapter.py # OpenAI 适配器
126
+ ├── tool/
127
+ │ ├── base_tool.py # 工具基类
128
+ │ └── tools.py # 工具集
129
+ ├── types/ # 类型定义
130
+ └── utils/ # 工具函数
131
+ ```
132
+
133
+ ## License
134
+
135
+ MIT
@@ -6,6 +6,7 @@ rootdriver/constants.py
6
6
  rootdriver/conversation.py
7
7
  rootdriver/engine.py
8
8
  rootdriver/exception.py
9
+ rootdriver/state.py
9
10
  rootdriver.egg-info/PKG-INFO
10
11
  rootdriver.egg-info/SOURCES.txt
11
12
  rootdriver.egg-info/dependency_links.txt
@@ -13,4 +14,5 @@ rootdriver.egg-info/requires.txt
13
14
  rootdriver.egg-info/top_level.txt
14
15
  tests/test_base_tool.py
15
16
  tests/test_conversation.py
16
- tests/test_tool.py
17
+ tests/test_tool.py
18
+ tests/test_tool_async.py
@@ -2,6 +2,7 @@ import pytest
2
2
  from rootdriver.tool.base_tool import BaseTool
3
3
  from rootdriver.tool.tools import Tool
4
4
  from rootdriver.types.tool import ToolCall
5
+ from rootdriver.exception import ToolNotFoundError
5
6
 
6
7
 
7
8
  def get_weather(city: str) -> str:
@@ -52,9 +53,10 @@ def test_tool_invoke_success(tool_registry):
52
53
 
53
54
 
54
55
  def test_tool_invoke_not_found(tool_registry):
55
- result = tool_registry.invoke(ToolCall(id="2", name="not_exist", arguments={}))
56
- assert result.tool_call_id == "2"
57
- assert "not found" in result.content
56
+ with pytest.raises(ToolNotFoundError) as exc_info:
57
+ tool_registry.invoke(ToolCall(id="2", name="not_exist", arguments={}))
58
+ assert exc_info.value.name == "not_exist"
59
+ assert "get_weather" in str(exc_info.value.available)
58
60
 
59
61
 
60
62
  def test_tool_invoke_many(tool_registry):
@@ -0,0 +1,60 @@
1
+ import asyncio
2
+ import time
3
+ import sys
4
+ sys.path.insert(0, "..")
5
+
6
+ import pytest
7
+ from rootdriver.tool import BaseTool, tool
8
+
9
+ @tool
10
+ def sync_weather(city: str) -> str:
11
+ """同步查天气"""
12
+ time.sleep(0.5)
13
+ return f"{city}: 晴天"
14
+
15
+ @tool
16
+ async def async_weather(city: str) -> str:
17
+ """异步查天气"""
18
+ await asyncio.sleep(0.5)
19
+ return f"{city}: 多云"
20
+
21
+ @pytest.mark.asyncio
22
+ async def test_base_tool_ainvoke():
23
+ """测试 BaseTool.ainvoke"""
24
+ result = await sync_weather.ainvoke({"city": "北京"})
25
+ assert "北京" in result and "晴天" in result
26
+
27
+ result = await async_weather.ainvoke({"city": "北京"})
28
+ assert "北京" in result and "多云" in result
29
+
30
+ @pytest.mark.asyncio
31
+ async def test_concurrent():
32
+ """测试并发执行"""
33
+ start = time.time()
34
+ results = await asyncio.gather(
35
+ sync_weather.ainvoke({"city": "北京"}),
36
+ sync_weather.ainvoke({"city": "上海"}),
37
+ async_weather.ainvoke({"city": "广州"}),
38
+ )
39
+ elapsed = time.time() - start
40
+
41
+ assert elapsed < 0.8, f"应该并发执行,但耗时 {elapsed} 秒"
42
+ assert len(results) == 3
43
+
44
+ @pytest.mark.asyncio
45
+ async def test_ainvoke_many():
46
+ """测试批量异步调用"""
47
+ from rootdriver.types.tool import ToolCall
48
+ from rootdriver.tool import Tool
49
+
50
+ tool_calls = [
51
+ ToolCall(id="1", name="sync_weather", arguments={"city": "北京"}),
52
+ ToolCall(id="2", name="async_weather", arguments={"city": "上海"}),
53
+ ]
54
+
55
+ tool_set = Tool([sync_weather, async_weather])
56
+ results = await tool_set.ainvoke_many(tool_calls)
57
+
58
+ assert len(results) == 2
59
+ assert "北京" in results[0].content
60
+ assert "上海" in results[1].content
rootdriver-0.1.0/PKG-INFO DELETED
@@ -1,102 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: rootdriver
3
- Version: 0.1.0
4
- Summary: Rooted in Origin, Driving All Things
5
- Author-email: zimvir <zimvir@qq.com>
6
- License: MIT
7
- Requires-Python: >=3.10
8
- Description-Content-Type: text/markdown
9
- Requires-Dist: openai>=1.0.0
10
- Requires-Dist: pydantic>=2.0.0
11
- Provides-Extra: dev
12
- Requires-Dist: pytest>=7.0.0; extra == "dev"
13
-
14
- # RootDriver
15
-
16
- 根源出发, 驱动万物
17
-
18
- 一个轻量级的 Python AI Agent 开发框架。
19
-
20
- ## 特性
21
-
22
- - **简洁易用**:装饰器方式定义工具,快速构建 Agent
23
- - **模块化设计**:LLM 适配器、工具系统、会话管理解耦
24
- - **工具调用**:支持 function calling,自动执行工具并返回结果
25
- - **多适配器**:基于适配器模式,方便扩展其他 LLM Provider
26
-
27
- ## 安装
28
-
29
- ```bash
30
- pip install rootdriver
31
- ```
32
-
33
- ## 快速开始
34
-
35
- ### 定义工具
36
-
37
- ```python
38
- from rootdriver import tool
39
-
40
- @tool
41
- def get_weather(city: str) -> str:
42
- """获取城市天气"""
43
- return f"{city} 晴天"
44
- ```
45
-
46
- ### 创建 Agent
47
-
48
- ```python
49
- from rootdriver import Agent, AgentLLM, OpenAIAdapter
50
- agent_llm=AgentLLM(
51
- adapter=OpenAIAdapter(
52
- api_key="YOUR_API_KEY",
53
- base_url="BASE_URL"
54
- ),
55
- model="gpt-4",
56
-
57
- ),
58
- agent = Agent(
59
- agent_llm=agent_llm,
60
- tools=[get_weather],
61
- system_prompt="你是一个有用的助手",
62
- )
63
-
64
- # 单次对话
65
- response = agent.talk("北京天气怎么样?")
66
- print(response)
67
- ```
68
-
69
- ### 使用工具
70
-
71
- ```python
72
- # 完整对话循环(包含工具调用)
73
- response = Agent.react("帮我查下上海天气")
74
- print(response)
75
- ```
76
-
77
- ## 核心组件
78
-
79
- | 组件 | 说明 |
80
- |------|------|
81
- | `Agent` | 智能体入口,整合 LLM、工具、会话 |
82
- | `Engine` | 核心引擎,处理对话循环和工具调用 |
83
- | `Conversation` | 会话管理,维护消息历史 |
84
- | `LLM` | LLM 调用封装 |
85
- | `Tool` | 工具集合,管理所有可调用工具 |
86
-
87
- ## 项目结构
88
-
89
- ```
90
- rootdriver/
91
- ├── agent.py # Agent 智能体
92
- ├── engine.py # 引擎核心
93
- ├── conversation.py # 对话管理
94
- ├── llm/ # LLM 适配器
95
- ├── tool/ # 工具系统
96
- ├── types/ # 类型定义
97
- └── utils/ # 工具函数
98
- ```
99
-
100
- ## License
101
-
102
- MIT
@@ -1,89 +0,0 @@
1
- # RootDriver
2
-
3
- 根源出发, 驱动万物
4
-
5
- 一个轻量级的 Python AI Agent 开发框架。
6
-
7
- ## 特性
8
-
9
- - **简洁易用**:装饰器方式定义工具,快速构建 Agent
10
- - **模块化设计**:LLM 适配器、工具系统、会话管理解耦
11
- - **工具调用**:支持 function calling,自动执行工具并返回结果
12
- - **多适配器**:基于适配器模式,方便扩展其他 LLM Provider
13
-
14
- ## 安装
15
-
16
- ```bash
17
- pip install rootdriver
18
- ```
19
-
20
- ## 快速开始
21
-
22
- ### 定义工具
23
-
24
- ```python
25
- from rootdriver import tool
26
-
27
- @tool
28
- def get_weather(city: str) -> str:
29
- """获取城市天气"""
30
- return f"{city} 晴天"
31
- ```
32
-
33
- ### 创建 Agent
34
-
35
- ```python
36
- from rootdriver import Agent, AgentLLM, OpenAIAdapter
37
- agent_llm=AgentLLM(
38
- adapter=OpenAIAdapter(
39
- api_key="YOUR_API_KEY",
40
- base_url="BASE_URL"
41
- ),
42
- model="gpt-4",
43
-
44
- ),
45
- agent = Agent(
46
- agent_llm=agent_llm,
47
- tools=[get_weather],
48
- system_prompt="你是一个有用的助手",
49
- )
50
-
51
- # 单次对话
52
- response = agent.talk("北京天气怎么样?")
53
- print(response)
54
- ```
55
-
56
- ### 使用工具
57
-
58
- ```python
59
- # 完整对话循环(包含工具调用)
60
- response = Agent.react("帮我查下上海天气")
61
- print(response)
62
- ```
63
-
64
- ## 核心组件
65
-
66
- | 组件 | 说明 |
67
- |------|------|
68
- | `Agent` | 智能体入口,整合 LLM、工具、会话 |
69
- | `Engine` | 核心引擎,处理对话循环和工具调用 |
70
- | `Conversation` | 会话管理,维护消息历史 |
71
- | `LLM` | LLM 调用封装 |
72
- | `Tool` | 工具集合,管理所有可调用工具 |
73
-
74
- ## 项目结构
75
-
76
- ```
77
- rootdriver/
78
- ├── agent.py # Agent 智能体
79
- ├── engine.py # 引擎核心
80
- ├── conversation.py # 对话管理
81
- ├── llm/ # LLM 适配器
82
- ├── tool/ # 工具系统
83
- ├── types/ # 类型定义
84
- └── utils/ # 工具函数
85
- ```
86
-
87
- ## License
88
-
89
- MIT
@@ -1,32 +0,0 @@
1
- __version__ = "0.1.0"
2
- __author__ = "zimvir"
3
- __email__ = "zimvir@qq.com"
4
-
5
-
6
-
7
-
8
-
9
- from .agent import Agent
10
- from .engine import Engine
11
- from .conversation import Conversation
12
- from .llm import LLM
13
- from .llm.base_adapter import BaseAdapter
14
- from .llm.adapter import OpenAIAdapter
15
- from .tool import tool, Tool
16
- from .types.agent import AgentLLM
17
- from .types import Message, ToolDefinition, ToolCall
18
-
19
- __all__ = [
20
- "Agent",
21
- "Engine",
22
- "Conversation",
23
- "LLM",
24
- "BaseAdapter",
25
- "OpenAIAdapter",
26
- "tool",
27
- "Tool",
28
- "AgentLLM",
29
- "Message",
30
- "ToolDefinition",
31
- "ToolCall",
32
- ]
@@ -1 +0,0 @@
1
-
@@ -1,102 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: rootdriver
3
- Version: 0.1.0
4
- Summary: Rooted in Origin, Driving All Things
5
- Author-email: zimvir <zimvir@qq.com>
6
- License: MIT
7
- Requires-Python: >=3.10
8
- Description-Content-Type: text/markdown
9
- Requires-Dist: openai>=1.0.0
10
- Requires-Dist: pydantic>=2.0.0
11
- Provides-Extra: dev
12
- Requires-Dist: pytest>=7.0.0; extra == "dev"
13
-
14
- # RootDriver
15
-
16
- 根源出发, 驱动万物
17
-
18
- 一个轻量级的 Python AI Agent 开发框架。
19
-
20
- ## 特性
21
-
22
- - **简洁易用**:装饰器方式定义工具,快速构建 Agent
23
- - **模块化设计**:LLM 适配器、工具系统、会话管理解耦
24
- - **工具调用**:支持 function calling,自动执行工具并返回结果
25
- - **多适配器**:基于适配器模式,方便扩展其他 LLM Provider
26
-
27
- ## 安装
28
-
29
- ```bash
30
- pip install rootdriver
31
- ```
32
-
33
- ## 快速开始
34
-
35
- ### 定义工具
36
-
37
- ```python
38
- from rootdriver import tool
39
-
40
- @tool
41
- def get_weather(city: str) -> str:
42
- """获取城市天气"""
43
- return f"{city} 晴天"
44
- ```
45
-
46
- ### 创建 Agent
47
-
48
- ```python
49
- from rootdriver import Agent, AgentLLM, OpenAIAdapter
50
- agent_llm=AgentLLM(
51
- adapter=OpenAIAdapter(
52
- api_key="YOUR_API_KEY",
53
- base_url="BASE_URL"
54
- ),
55
- model="gpt-4",
56
-
57
- ),
58
- agent = Agent(
59
- agent_llm=agent_llm,
60
- tools=[get_weather],
61
- system_prompt="你是一个有用的助手",
62
- )
63
-
64
- # 单次对话
65
- response = agent.talk("北京天气怎么样?")
66
- print(response)
67
- ```
68
-
69
- ### 使用工具
70
-
71
- ```python
72
- # 完整对话循环(包含工具调用)
73
- response = Agent.react("帮我查下上海天气")
74
- print(response)
75
- ```
76
-
77
- ## 核心组件
78
-
79
- | 组件 | 说明 |
80
- |------|------|
81
- | `Agent` | 智能体入口,整合 LLM、工具、会话 |
82
- | `Engine` | 核心引擎,处理对话循环和工具调用 |
83
- | `Conversation` | 会话管理,维护消息历史 |
84
- | `LLM` | LLM 调用封装 |
85
- | `Tool` | 工具集合,管理所有可调用工具 |
86
-
87
- ## 项目结构
88
-
89
- ```
90
- rootdriver/
91
- ├── agent.py # Agent 智能体
92
- ├── engine.py # 引擎核心
93
- ├── conversation.py # 对话管理
94
- ├── llm/ # LLM 适配器
95
- ├── tool/ # 工具系统
96
- ├── types/ # 类型定义
97
- └── utils/ # 工具函数
98
- ```
99
-
100
- ## License
101
-
102
- MIT
File without changes