agentrun-sdk 0.0.4__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 (128) hide show
  1. agentrun/__init__.py +209 -0
  2. agentrun/agent_runtime/__client_async_template.py +466 -0
  3. agentrun/agent_runtime/__endpoint_async_template.py +345 -0
  4. agentrun/agent_runtime/__init__.py +53 -0
  5. agentrun/agent_runtime/__runtime_async_template.py +477 -0
  6. agentrun/agent_runtime/api/__data_async_template.py +58 -0
  7. agentrun/agent_runtime/api/__init__.py +6 -0
  8. agentrun/agent_runtime/api/control.py +1362 -0
  9. agentrun/agent_runtime/api/data.py +98 -0
  10. agentrun/agent_runtime/client.py +868 -0
  11. agentrun/agent_runtime/endpoint.py +649 -0
  12. agentrun/agent_runtime/model.py +362 -0
  13. agentrun/agent_runtime/runtime.py +904 -0
  14. agentrun/credential/__client_async_template.py +177 -0
  15. agentrun/credential/__credential_async_template.py +216 -0
  16. agentrun/credential/__init__.py +28 -0
  17. agentrun/credential/api/__init__.py +5 -0
  18. agentrun/credential/api/control.py +606 -0
  19. agentrun/credential/client.py +319 -0
  20. agentrun/credential/credential.py +381 -0
  21. agentrun/credential/model.py +248 -0
  22. agentrun/integration/__init__.py +21 -0
  23. agentrun/integration/agentscope/__init__.py +12 -0
  24. agentrun/integration/agentscope/adapter.py +17 -0
  25. agentrun/integration/agentscope/builtin.py +65 -0
  26. agentrun/integration/agentscope/message_adapter.py +185 -0
  27. agentrun/integration/agentscope/model_adapter.py +60 -0
  28. agentrun/integration/agentscope/tool_adapter.py +59 -0
  29. agentrun/integration/builtin/__init__.py +16 -0
  30. agentrun/integration/builtin/model.py +97 -0
  31. agentrun/integration/builtin/sandbox.py +276 -0
  32. agentrun/integration/builtin/toolset.py +47 -0
  33. agentrun/integration/crewai/__init__.py +12 -0
  34. agentrun/integration/crewai/adapter.py +9 -0
  35. agentrun/integration/crewai/builtin.py +65 -0
  36. agentrun/integration/crewai/model_adapter.py +27 -0
  37. agentrun/integration/crewai/tool_adapter.py +26 -0
  38. agentrun/integration/google_adk/__init__.py +12 -0
  39. agentrun/integration/google_adk/adapter.py +15 -0
  40. agentrun/integration/google_adk/builtin.py +65 -0
  41. agentrun/integration/google_adk/message_adapter.py +144 -0
  42. agentrun/integration/google_adk/model_adapter.py +43 -0
  43. agentrun/integration/google_adk/tool_adapter.py +25 -0
  44. agentrun/integration/langchain/__init__.py +9 -0
  45. agentrun/integration/langchain/adapter.py +15 -0
  46. agentrun/integration/langchain/builtin.py +71 -0
  47. agentrun/integration/langchain/message_adapter.py +141 -0
  48. agentrun/integration/langchain/model_adapter.py +37 -0
  49. agentrun/integration/langchain/tool_adapter.py +50 -0
  50. agentrun/integration/langgraph/__init__.py +13 -0
  51. agentrun/integration/langgraph/adapter.py +20 -0
  52. agentrun/integration/langgraph/builtin.py +65 -0
  53. agentrun/integration/pydantic_ai/__init__.py +12 -0
  54. agentrun/integration/pydantic_ai/adapter.py +13 -0
  55. agentrun/integration/pydantic_ai/builtin.py +65 -0
  56. agentrun/integration/pydantic_ai/model_adapter.py +44 -0
  57. agentrun/integration/pydantic_ai/tool_adapter.py +19 -0
  58. agentrun/integration/utils/__init__.py +112 -0
  59. agentrun/integration/utils/adapter.py +167 -0
  60. agentrun/integration/utils/canonical.py +157 -0
  61. agentrun/integration/utils/converter.py +134 -0
  62. agentrun/integration/utils/model.py +107 -0
  63. agentrun/integration/utils/tool.py +1714 -0
  64. agentrun/model/__client_async_template.py +357 -0
  65. agentrun/model/__init__.py +57 -0
  66. agentrun/model/__model_proxy_async_template.py +270 -0
  67. agentrun/model/__model_service_async_template.py +267 -0
  68. agentrun/model/api/__init__.py +6 -0
  69. agentrun/model/api/control.py +1173 -0
  70. agentrun/model/api/data.py +196 -0
  71. agentrun/model/client.py +674 -0
  72. agentrun/model/model.py +218 -0
  73. agentrun/model/model_proxy.py +439 -0
  74. agentrun/model/model_service.py +438 -0
  75. agentrun/sandbox/__browser_sandbox_async_template.py +113 -0
  76. agentrun/sandbox/__client_async_template.py +466 -0
  77. agentrun/sandbox/__code_interpreter_sandbox_async_template.py +466 -0
  78. agentrun/sandbox/__init__.py +54 -0
  79. agentrun/sandbox/__sandbox_async_template.py +398 -0
  80. agentrun/sandbox/__template_async_template.py +150 -0
  81. agentrun/sandbox/api/__browser_data_async_template.py +140 -0
  82. agentrun/sandbox/api/__code_interpreter_data_async_template.py +206 -0
  83. agentrun/sandbox/api/__init__.py +17 -0
  84. agentrun/sandbox/api/__sandbox_data_async_template.py +100 -0
  85. agentrun/sandbox/api/browser_data.py +172 -0
  86. agentrun/sandbox/api/code_interpreter_data.py +396 -0
  87. agentrun/sandbox/api/control.py +1051 -0
  88. agentrun/sandbox/api/playwright_async.py +492 -0
  89. agentrun/sandbox/api/playwright_sync.py +492 -0
  90. agentrun/sandbox/api/sandbox_data.py +140 -0
  91. agentrun/sandbox/browser_sandbox.py +191 -0
  92. agentrun/sandbox/client.py +878 -0
  93. agentrun/sandbox/code_interpreter_sandbox.py +829 -0
  94. agentrun/sandbox/model.py +269 -0
  95. agentrun/sandbox/sandbox.py +737 -0
  96. agentrun/sandbox/template.py +215 -0
  97. agentrun/server/__init__.py +82 -0
  98. agentrun/server/invoker.py +131 -0
  99. agentrun/server/model.py +225 -0
  100. agentrun/server/openai_protocol.py +798 -0
  101. agentrun/server/protocol.py +96 -0
  102. agentrun/server/server.py +192 -0
  103. agentrun/toolset/__client_async_template.py +62 -0
  104. agentrun/toolset/__init__.py +51 -0
  105. agentrun/toolset/__toolset_async_template.py +204 -0
  106. agentrun/toolset/api/__init__.py +17 -0
  107. agentrun/toolset/api/control.py +262 -0
  108. agentrun/toolset/api/mcp.py +100 -0
  109. agentrun/toolset/api/openapi.py +1184 -0
  110. agentrun/toolset/client.py +102 -0
  111. agentrun/toolset/model.py +160 -0
  112. agentrun/toolset/toolset.py +271 -0
  113. agentrun/utils/__data_api_async_template.py +715 -0
  114. agentrun/utils/__init__.py +5 -0
  115. agentrun/utils/__resource_async_template.py +158 -0
  116. agentrun/utils/config.py +258 -0
  117. agentrun/utils/control_api.py +78 -0
  118. agentrun/utils/data_api.py +1110 -0
  119. agentrun/utils/exception.py +149 -0
  120. agentrun/utils/helper.py +34 -0
  121. agentrun/utils/log.py +77 -0
  122. agentrun/utils/model.py +168 -0
  123. agentrun/utils/resource.py +291 -0
  124. agentrun_sdk-0.0.4.dist-info/METADATA +262 -0
  125. agentrun_sdk-0.0.4.dist-info/RECORD +128 -0
  126. agentrun_sdk-0.0.4.dist-info/WHEEL +5 -0
  127. agentrun_sdk-0.0.4.dist-info/licenses/LICENSE +201 -0
  128. agentrun_sdk-0.0.4.dist-info/top_level.txt +1 -0
@@ -0,0 +1,65 @@
1
+ """PydanticAI 内置集成函数 / PydanticAI Built-in Integration Functions
2
+
3
+ 提供快速创建 PydanticAI 兼容模型和工具的便捷函数。
4
+ Provides convenient functions for quickly creating PydanticAI-compatible models and tools.
5
+ """
6
+
7
+ from typing import Any, Callable, List, Optional, Union
8
+
9
+ from typing_extensions import Unpack
10
+
11
+ from agentrun.integration.builtin import model as _model
12
+ from agentrun.integration.builtin import ModelArgs
13
+ from agentrun.integration.builtin import sandbox_toolset as _sandbox_toolset
14
+ from agentrun.integration.builtin import toolset as _toolset
15
+ from agentrun.integration.utils.tool import Tool
16
+ from agentrun.model import ModelProxy, ModelService
17
+ from agentrun.sandbox import TemplateType
18
+ from agentrun.toolset import ToolSet
19
+ from agentrun.utils.config import Config
20
+
21
+
22
+ def model(
23
+ name: Union[str, ModelProxy, ModelService],
24
+ **kwargs: Unpack[ModelArgs],
25
+ ):
26
+ """获取 AgentRun 模型并转换为 LangChain ``BaseChatModel``。 / PydanticAI Built-in Integration Functions"""
27
+
28
+ m = _model(input=name, **kwargs) # type: ignore
29
+ return m.to_pydantic_ai()
30
+
31
+
32
+ def toolset(
33
+ name: Union[str, ToolSet],
34
+ *,
35
+ prefix: Optional[str] = None,
36
+ modify_tool_name: Optional[Callable[[Tool], Tool]] = None,
37
+ filter_tools_by_name: Optional[Callable[[str], bool]] = None,
38
+ config: Optional[Config] = None,
39
+ ) -> List[Any]:
40
+ """将内置工具集封装为 LangChain ``StructuredTool`` 列表。 / PydanticAI Built-in Integration Functions"""
41
+
42
+ ts = _toolset(input=name, config=config)
43
+ return ts.to_pydantic_ai(
44
+ prefix=prefix,
45
+ modify_tool_name=modify_tool_name,
46
+ filter_tools_by_name=filter_tools_by_name,
47
+ )
48
+
49
+
50
+ def sandbox_toolset(
51
+ template_name: str,
52
+ *,
53
+ template_type: TemplateType = TemplateType.CODE_INTERPRETER,
54
+ config: Optional[Config] = None,
55
+ sandbox_idle_timeout_seconds: int = 600,
56
+ prefix: Optional[str] = None,
57
+ ) -> List[Any]:
58
+ """将沙箱模板封装为 LangChain ``StructuredTool`` 列表。 / PydanticAI Built-in Integration Functions"""
59
+
60
+ return _sandbox_toolset(
61
+ template_name=template_name,
62
+ template_type=template_type,
63
+ config=config,
64
+ sandbox_idle_timeout_seconds=sandbox_idle_timeout_seconds,
65
+ ).to_pydantic_ai(prefix=prefix)
@@ -0,0 +1,44 @@
1
+ """PydanticAI 模型适配器 / PydanticAI Model Adapter"""
2
+
3
+ from typing import Any
4
+
5
+ from agentrun.integration.utils.adapter import ModelAdapter
6
+ from agentrun.integration.utils.model import CommonModel
7
+
8
+
9
+ class PydanticAIModelAdapter(ModelAdapter):
10
+ """PydanticAI 模型适配器 / PydanticAI Model Adapter
11
+
12
+ PydanticAI 支持 OpenAI 兼容的接口,我们提供一个轻量级包装。"""
13
+
14
+ def wrap_model(self, common_model: CommonModel) -> Any:
15
+ """将 CommonModel 包装为 PydanticAI 兼容的模型 / PydanticAI Model Adapter"""
16
+
17
+ try:
18
+ from pydantic_ai.models.openai import OpenAIChatModel
19
+ from pydantic_ai.providers.openai import OpenAIProvider
20
+ from pydantic_ai.settings import ModelSettings
21
+ except Exception as e:
22
+ raise ImportError(
23
+ "PydanticAI is not installed. "
24
+ "Install it with: pip install pydantic-ai"
25
+ ) from e
26
+
27
+ from httpx import AsyncClient
28
+
29
+ info = common_model.get_model_info()
30
+
31
+ return OpenAIChatModel(
32
+ info.model or "",
33
+ provider=OpenAIProvider(
34
+ base_url=info.base_url,
35
+ api_key=info.api_key,
36
+ http_client=AsyncClient(headers=info.headers),
37
+ ),
38
+ settings=ModelSettings(
39
+ extra_body={"stream_options": {"include_usage": True}}
40
+ ),
41
+ )
42
+
43
+
44
+ __all__ = ["PydanticAIModelAdapter"]
@@ -0,0 +1,19 @@
1
+ """PydanticAI 工具适配器 / PydanticAI Tool Adapter"""
2
+
3
+ from typing import Any, List
4
+
5
+ from agentrun.integration.utils.adapter import ToolAdapter
6
+ from agentrun.integration.utils.canonical import CanonicalTool
7
+
8
+
9
+ class PydanticAIToolAdapter(ToolAdapter):
10
+ """PydanticAI 工具适配器 / PydanticAI Tool Adapter
11
+
12
+ PydanticAI 使用函数作为工具,需要附加元数据信息。"""
13
+
14
+ def from_canonical(self, tools: List[CanonicalTool]) -> List[Any]:
15
+ """将标准工具转换为 PydanticAI 函数格式 / PydanticAI Tool Adapter"""
16
+ return self.function_tools(tools)
17
+
18
+
19
+ __all__ = ["PydanticAIToolAdapter"]
@@ -0,0 +1,112 @@
1
+ """通用集成工具模块 / 通用集成工具 Module
2
+
3
+ 提供跨框架的通用工具定义和转换功能。 / 提供跨framework的通用工具定义和转换功能。
4
+
5
+ 支持多种工具定义方式:
6
+ 1. 使用 @tool 装饰器 - 最简单,推荐
7
+ 2. 使用 Pydantic BaseModel - 类型安全
8
+ 3. 使用 ToolParameter 列表 - 灵活但繁琐
9
+ 4. 从 AgentRun ToolSet 转换 - 直接使用远程工具集
10
+
11
+ 支持模型集成:
12
+ 1. 使用 model() 函数 - 获取模型并转换为各种框架格式 / 1. 使用 model() 函数 - 获取模型并转换为各种framework格式
13
+ 2. 从已有模型对象创建 - from_agentrun_model()
14
+
15
+ Examples:
16
+ >>> # 工具集成示例
17
+ >>> # 方式 1: 使用装饰器从函数创建 Tool
18
+ >>> from agentrun.integration.common import tool
19
+ >>> from typing import Literal
20
+ >>>
21
+ >>> @tool()
22
+ ... def calculator(
23
+ ... operation: Literal["add", "subtract"],
24
+ ... a: float,
25
+ ... b: float,
26
+ ... ) -> float:
27
+ ... '''执行数学运算'''
28
+ ... if operation == "add":
29
+ ... return a + b
30
+ ... return a - b
31
+ >>>
32
+ >>> # 方式 2: 使用 Pydantic 模型
33
+ >>> from agentrun.integration.common import Tool
34
+ >>> from pydantic import BaseModel, Field
35
+ >>>
36
+ >>> class SearchArgs(BaseModel):
37
+ ... query: str = Field(description="搜索关键词")
38
+ ... limit: int = Field(description="结果数量", ge=1, le=100, default=10)
39
+ >>>
40
+ >>> search_tool = Tool(
41
+ ... name="search",
42
+ ... description="搜索网络信息",
43
+ ... args_schema=SearchArgs,
44
+ ... func=lambda query, limit: f"搜索: {query}"
45
+ ... )
46
+ >>>
47
+ >>> # 方式 3: 使用 ToolParameter
48
+ >>> from agentrun.integration.common import ToolParameter
49
+ >>>
50
+ >>> weather_tool = Tool(
51
+ ... name="weather",
52
+ ... description="获取天气信息",
53
+ ... parameters=[
54
+ ... ToolParameter(
55
+ ... name="city",
56
+ ... param_type="string",
57
+ ... description="城市名称",
58
+ ... required=True
59
+ ... )
60
+ ... ]
61
+ ... )
62
+ >>>
63
+ >>> # 方式 4: 从 AgentRun ToolSet 转换
64
+ >>> from agentrun.toolset.client import ToolSetClient
65
+ >>> from agentrun.integration.common import from_agentrun_toolset
66
+ >>>
67
+ >>> client = ToolSetClient()
68
+ >>> remote_toolset = client.get(name="my-toolset")
69
+ >>> common_toolset = from_agentrun_toolset(remote_toolset)
70
+ >>>
71
+ >>> # 导出为各种框架格式 / >>> # 导出为各种framework格式
72
+ >>> openai_tools = common_toolset.to_openai_function()
73
+ >>> langchain_tools = common_toolset.to_langchain()
74
+ >>>
75
+ >>> # 模型集成示例
76
+ >>> # 方式 1: 使用 model() 函数
77
+ >>> from agentrun.integration.common import model
78
+ >>>
79
+ >>> # 获取模型并转换为 LangChain
80
+ >>> llm = model("my-model").to_langchain()
81
+ >>>
82
+ >>> # 转换为 Google ADK
83
+ >>> google_model = model("my-model").to_google_adk()
84
+ >>>
85
+ >>> # 方式 2: 从已有模型对象创建
86
+ >>> from agentrun.model.client import ModelClient
87
+ >>> from agentrun.integration.common import from_agentrun_model
88
+ >>>
89
+ >>> client = ModelClient()
90
+ >>> remote_model = client.get("my-model")
91
+ >>> common_model = from_agentrun_model(remote_model)
92
+ >>> llm = common_model.to_langchain()"""
93
+
94
+ from agentrun.integration.utils.model import CommonModel
95
+ from agentrun.integration.utils.tool import (
96
+ CommonToolSet,
97
+ from_pydantic,
98
+ Tool,
99
+ tool,
100
+ ToolParameter,
101
+ )
102
+
103
+ __all__ = [
104
+ # Tool related
105
+ "Tool",
106
+ "ToolParameter",
107
+ "CommonToolSet",
108
+ "tool",
109
+ "from_pydantic",
110
+ # Model related
111
+ "CommonModel",
112
+ ]
@@ -0,0 +1,167 @@
1
+ """适配器接口定义 / Adapter Interface Definition
2
+
3
+ 定义统一的适配器接口,所有框架适配器都实现这些接口。
4
+ Defines unified adapter interfaces that all framework adapters implement.
5
+
6
+ 这样可以确保一致的转换行为,并最大化代码复用。
7
+ This ensures consistent conversion behavior and maximizes code reuse.
8
+ """
9
+
10
+ from abc import ABC, abstractmethod
11
+ import inspect
12
+ from typing import Any, Callable, Dict, List, Optional
13
+
14
+ from agentrun.integration.utils.canonical import CanonicalMessage, CanonicalTool
15
+ from agentrun.integration.utils.model import CommonModel
16
+
17
+
18
+ class MessageAdapter(ABC):
19
+ """消息格式适配器接口
20
+
21
+ 用于在 ModelAdapter 内部进行消息格式转换。
22
+ 只需要将框架消息转换为标准 OpenAI 格式。
23
+
24
+ 转换流程:
25
+ - 框架消息 → to_canonical() → CanonicalMessage(OpenAI 格式)
26
+ """
27
+
28
+ @abstractmethod
29
+ def to_canonical(self, messages: Any) -> List[CanonicalMessage]:
30
+ """将框架消息转换为标准格式(供 ModelAdapter 内部使用)
31
+
32
+ Args:
33
+ messages: 框架特定的消息格式
34
+
35
+ Returns:
36
+ 标准格式消息列表
37
+ """
38
+ pass
39
+
40
+
41
+ class ToolAdapter(ABC):
42
+ """工具格式适配器接口 / Utils Adapters
43
+
44
+ 用于将标准工具定义转换为框架特定格式。
45
+ 单向转换:CanonicalTool → 框架工具"""
46
+
47
+ def __init__(self) -> None:
48
+ super().__init__()
49
+
50
+ # 记录工具定义,便于模型适配器回溯参数 schema
51
+ self._registered_tools: Dict[str, CanonicalTool] = {}
52
+
53
+ @abstractmethod
54
+ def from_canonical(self, tools: List[CanonicalTool]) -> Any:
55
+ """将标准工具转换为框架特定格式 / 将标准工具Converts为框架特定格式
56
+
57
+ Args:
58
+ tools: 标准格式工具列表
59
+
60
+ Returns:
61
+ 框架特定的工具格式"""
62
+ pass
63
+
64
+ def function_tools(
65
+ self,
66
+ tools: List[CanonicalTool],
67
+ modify_func: Optional[Callable[..., Any]] = None,
68
+ ):
69
+ """将标准格式转换为 Google ADK 工具 / 将标准格式Converts为 Google ADK 工具
70
+
71
+ Google ADK 通过函数的类型注解推断参数,需要动态创建带注解的函数。"""
72
+ result = []
73
+
74
+ for tool in tools:
75
+ # 记录工具定义
76
+ self._registered_tools[tool.name] = tool
77
+
78
+ # 从 parameters schema 构建函数签名
79
+ parameters_schema = tool.parameters or {
80
+ "type": "object",
81
+ "properties": {},
82
+ }
83
+ properties = parameters_schema.get("properties", {})
84
+ required = set(parameters_schema.get("required", []))
85
+
86
+ # 构建函数参数
87
+ params = []
88
+ annotations = {}
89
+
90
+ for param_name, param_schema in properties.items():
91
+ # 映射 JSON Schema 类型到 Python 类型
92
+ param_type_str = param_schema.get("type", "string")
93
+ type_mapping = {
94
+ "string": str,
95
+ "integer": int,
96
+ "number": float,
97
+ "boolean": bool,
98
+ "array": list,
99
+ "object": dict,
100
+ }
101
+ param_type = type_mapping.get(param_type_str, str)
102
+
103
+ # 设置默认值
104
+ default = (
105
+ inspect.Parameter.empty if param_name in required else None
106
+ )
107
+
108
+ params.append(
109
+ inspect.Parameter(
110
+ param_name,
111
+ inspect.Parameter.KEYWORD_ONLY,
112
+ default=default,
113
+ annotation=param_type,
114
+ )
115
+ )
116
+ annotations[param_name] = param_type
117
+
118
+ # 创建带正确签名的函数
119
+ def make_tool_function(
120
+ canonical_tool: CanonicalTool,
121
+ sig: inspect.Signature,
122
+ annots: dict,
123
+ ):
124
+ def tool_func(**kwargs):
125
+ if canonical_tool.func is None:
126
+ raise NotImplementedError(
127
+ f"Tool function for '{canonical_tool.name}' "
128
+ "is not implemented."
129
+ )
130
+
131
+ if modify_func:
132
+ return modify_func(canonical_tool, **kwargs)
133
+
134
+ return canonical_tool.func(**kwargs)
135
+
136
+ # 设置函数元数据
137
+ tool_func.__name__ = canonical_tool.name
138
+ tool_func.__doc__ = canonical_tool.description
139
+ tool_func.__annotations__ = annots
140
+ object.__setattr__(tool_func, "__signature__", sig)
141
+
142
+ return tool_func
143
+
144
+ # 创建签名
145
+ signature = inspect.Signature(params)
146
+ wrapped_func = make_tool_function(tool, signature, annotations)
147
+
148
+ result.append(wrapped_func)
149
+
150
+ return result
151
+
152
+
153
+ class ModelAdapter(ABC):
154
+ """模型适配器接口 / Utils Model Adapter
155
+
156
+ 用于包装框架模型,使其能够与 CommonModel 协同工作。"""
157
+
158
+ @abstractmethod
159
+ def wrap_model(self, common_model: CommonModel) -> Any:
160
+ """包装 CommonModel 为框架特定的模型格式 / 包装 CommonModel 为framework特定的模型格式
161
+
162
+ Args:
163
+ common_model: CommonModel 实例
164
+
165
+ Returns:
166
+ 框架特定的模型对象"""
167
+ pass
@@ -0,0 +1,157 @@
1
+ """中间格式定义 / Canonical Format Definition
2
+
3
+ 提供统一的中间格式(Canonical Format),作为所有框架转换的桥梁。
4
+ Provides a unified canonical format that serves as a bridge for all framework conversions.
5
+
6
+ 这样可以最大化代码复用,减少重复的转换逻辑。
7
+ This maximizes code reuse and reduces redundant conversion logic.
8
+ """
9
+
10
+ from dataclasses import dataclass
11
+ import json
12
+ from typing import Any, Callable, Dict, List, Optional, TYPE_CHECKING
13
+
14
+ if TYPE_CHECKING:
15
+ from typing import Protocol
16
+ else:
17
+ Protocol = object
18
+
19
+ from enum import Enum
20
+
21
+
22
+ class MessageRole(str, Enum):
23
+ """统一的消息角色枚举"""
24
+
25
+ SYSTEM = "system"
26
+ USER = "user"
27
+ ASSISTANT = "assistant"
28
+ TOOL = "tool"
29
+
30
+
31
+ @dataclass
32
+ class CanonicalToolCall:
33
+ """统一的工具调用格式
34
+
35
+ 所有框架的工具调用都转换为这个格式,然后再转换为目标框架格式。
36
+ """
37
+
38
+ id: str
39
+ name: str
40
+ arguments: Dict[str, Any]
41
+
42
+
43
+ @dataclass
44
+ class CanonicalMessage:
45
+ """统一的消息格式
46
+
47
+ 这是所有框架消息格式的中间表示。
48
+ 转换流程:框架A格式 → CanonicalMessage → 框架B格式
49
+ """
50
+
51
+ role: MessageRole
52
+ content: Optional[str] = None
53
+ name: Optional[str] = None
54
+ tool_calls: Optional[List[CanonicalToolCall]] = None
55
+ tool_call_id: Optional[str] = None
56
+
57
+ def to_dict(self) -> Dict[str, Any]:
58
+ """转换为字典格式(用于序列化)
59
+
60
+ 注意:OpenAI API 要求 tool_calls 中的 arguments 必须是 JSON 字符串,
61
+ 而不是字典。这里会自动转换。
62
+ """
63
+ result = {
64
+ "role": self.role.value,
65
+ }
66
+ if self.content is not None:
67
+ result["content"] = self.content
68
+ if self.name is not None:
69
+ result["name"] = self.name
70
+ if self.tool_calls is not None:
71
+ result["tool_calls"] = [
72
+ {
73
+ "id": call.id,
74
+ "type": "function",
75
+ "function": {
76
+ "name": call.name,
77
+ # arguments 必须是 JSON 字符串(OpenAI API 要求)
78
+ "arguments": (
79
+ json.dumps(call.arguments)
80
+ if isinstance(call.arguments, dict)
81
+ else str(call.arguments)
82
+ ),
83
+ },
84
+ }
85
+ for call in self.tool_calls
86
+ ]
87
+ if self.tool_call_id is not None:
88
+ result["tool_call_id"] = self.tool_call_id
89
+ return result
90
+
91
+
92
+ @dataclass
93
+ class CanonicalTool:
94
+ """统一的工具格式
95
+
96
+ 所有框架的工具都转换为这个格式。
97
+ 参数使用 JSON Schema 格式,这是最通用的工具描述格式。
98
+ """
99
+
100
+ name: str
101
+ description: str
102
+ parameters: Dict[str, Any] # JSON Schema 格式
103
+ func: Optional[Callable] = None
104
+
105
+ def to_openai_function(self) -> Dict[str, Any]:
106
+ """转换为 OpenAI Function Calling 格式"""
107
+ return {
108
+ "name": self.name,
109
+ "description": self.description,
110
+ "parameters": self.parameters,
111
+ }
112
+
113
+ def to_anthropic_tool(self) -> Dict[str, Any]:
114
+ """转换为 Anthropic Claude Tools 格式"""
115
+ return {
116
+ "name": self.name,
117
+ "description": self.description,
118
+ "input_schema": self.parameters,
119
+ }
120
+
121
+
122
+ @dataclass
123
+ class CanonicalModelResponse:
124
+ """统一的模型响应格式"""
125
+
126
+ content: Optional[str] = None
127
+ tool_calls: Optional[List[CanonicalToolCall]] = None
128
+ usage: Optional[Dict[str, int]] = None
129
+
130
+ def to_dict(self) -> Dict[str, Any]:
131
+ """转换为字典格式
132
+
133
+ 注意:OpenAI API 要求 tool_calls 中的 arguments 必须是 JSON 字符串。
134
+ """
135
+ result = {}
136
+ if self.content is not None:
137
+ result["content"] = self.content
138
+ if self.tool_calls is not None:
139
+ result["tool_calls"] = [
140
+ {
141
+ "id": call.id,
142
+ "type": "function",
143
+ "function": {
144
+ "name": call.name,
145
+ # arguments 必须是 JSON 字符串(OpenAI API 要求)
146
+ "arguments": (
147
+ json.dumps(call.arguments)
148
+ if isinstance(call.arguments, dict)
149
+ else str(call.arguments)
150
+ ),
151
+ },
152
+ }
153
+ for call in self.tool_calls
154
+ ]
155
+ if self.usage is not None:
156
+ result["usage"] = self.usage
157
+ return result
@@ -0,0 +1,134 @@
1
+ """框架转换器 / Framework Converter
2
+
3
+ 提供统一的框架适配器注册中心。
4
+ Provides a unified registry for framework adapters.
5
+ """
6
+
7
+ from typing import Dict, Optional
8
+
9
+ from agentrun.integration.utils.adapter import ModelAdapter, ToolAdapter
10
+ from agentrun.utils.log import logger
11
+
12
+
13
+ class FrameworkConverter:
14
+ """框架适配器注册中心
15
+
16
+ 管理所有框架的工具和模型适配器。
17
+ MessageAdapter 不再单独注册,而是作为 ModelAdapter 的内部组件。
18
+ """
19
+
20
+ def __init__(self):
21
+ self._tool_adapters: Dict[str, ToolAdapter] = {}
22
+ self._model_adapters: Dict[str, ModelAdapter] = {}
23
+
24
+ def register_tool_adapter(
25
+ self, framework: str, adapter: ToolAdapter
26
+ ) -> None:
27
+ """注册工具适配器"""
28
+ self._tool_adapters[framework] = adapter
29
+
30
+ def register_model_adapter(
31
+ self, framework: str, adapter: ModelAdapter
32
+ ) -> None:
33
+ """注册模型适配器"""
34
+ self._model_adapters[framework] = adapter
35
+
36
+ def get_model_adapter(self, framework: str) -> Optional[ModelAdapter]:
37
+ """获取模型适配器"""
38
+ return self._model_adapters.get(framework)
39
+
40
+
41
+ # 全局转换器实例
42
+ _converter = FrameworkConverter()
43
+
44
+
45
+ def get_converter() -> FrameworkConverter:
46
+ """获取全局转换器实例"""
47
+ return _converter
48
+
49
+
50
+ def _auto_register_adapters() -> None:
51
+ """自动注册所有可用的适配器
52
+
53
+ 延迟导入,避免循环依赖。
54
+ MessageAdapter 不再单独注册,由 ModelAdapter 内部管理。
55
+ """
56
+ # LangChain 适配器
57
+ try:
58
+ from agentrun.integration.langchain.adapter import (
59
+ LangChainModelAdapter,
60
+ LangChainToolAdapter,
61
+ )
62
+
63
+ _converter.register_tool_adapter("langchain", LangChainToolAdapter())
64
+ _converter.register_model_adapter("langchain", LangChainModelAdapter())
65
+ except (ImportError, AttributeError) as e:
66
+ logger.warning("failed to register LangChain adapters, due to %s", e)
67
+
68
+ # Google ADK 适配器
69
+ try:
70
+ from agentrun.integration.google_adk.adapter import (
71
+ GoogleADKModelAdapter,
72
+ GoogleADKToolAdapter,
73
+ )
74
+
75
+ _converter.register_tool_adapter("google_adk", GoogleADKToolAdapter())
76
+ _converter.register_model_adapter("google_adk", GoogleADKModelAdapter())
77
+ except (ImportError, AttributeError) as e:
78
+ logger.warning("failed to register Google ADK adapters, due to %s", e)
79
+
80
+ # AgentScope 适配器
81
+ try:
82
+ from agentrun.integration.agentscope.adapter import (
83
+ AgentScopeModelAdapter,
84
+ AgentScopeToolAdapter,
85
+ )
86
+
87
+ _converter.register_tool_adapter("agentscope", AgentScopeToolAdapter())
88
+ _converter.register_model_adapter(
89
+ "agentscope", AgentScopeModelAdapter()
90
+ )
91
+ except (ImportError, AttributeError) as e:
92
+ logger.warning("failed to register AgentScope adapters, due to %s", e)
93
+
94
+ # LangGraph 适配器(复用 LangChain)
95
+ try:
96
+ from agentrun.integration.langgraph.adapter import (
97
+ LangGraphModelAdapter,
98
+ LangGraphToolAdapter,
99
+ )
100
+
101
+ _converter.register_tool_adapter("langgraph", LangGraphToolAdapter())
102
+ _converter.register_model_adapter("langgraph", LangGraphModelAdapter())
103
+ except (ImportError, AttributeError) as e:
104
+ logger.warning("failed to register LangGraph adapters, due to %s", e)
105
+
106
+ # CrewAI 适配器(复用 LangChain)
107
+ try:
108
+ from agentrun.integration.crewai.adapter import (
109
+ CrewAIModelAdapter,
110
+ CrewAIToolAdapter,
111
+ )
112
+
113
+ _converter.register_tool_adapter("crewai", CrewAIToolAdapter())
114
+ _converter.register_model_adapter("crewai", CrewAIModelAdapter())
115
+ except (ImportError, AttributeError) as e:
116
+ logger.warning("failed to register CrewAI adapters, due to %s", e)
117
+
118
+ # PydanticAI 适配器
119
+ try:
120
+ from agentrun.integration.pydantic_ai.adapter import (
121
+ PydanticAIModelAdapter,
122
+ PydanticAIToolAdapter,
123
+ )
124
+
125
+ _converter.register_tool_adapter("pydantic_ai", PydanticAIToolAdapter())
126
+ _converter.register_model_adapter(
127
+ "pydantic_ai", PydanticAIModelAdapter()
128
+ )
129
+ except (ImportError, AttributeError) as e:
130
+ logger.warning("failed to register PydanticAI adapters, due to %s", e)
131
+
132
+
133
+ # 初始化时自动注册
134
+ _auto_register_adapters()