agent-runtime-sdk 0.1.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.
- agent_runtime_sdk-0.1.0/MANIFEST.in +12 -0
- agent_runtime_sdk-0.1.0/PKG-INFO +125 -0
- agent_runtime_sdk-0.1.0/README_PACKAGE.md +99 -0
- agent_runtime_sdk-0.1.0/agent_runtime/__init__.py +84 -0
- agent_runtime_sdk-0.1.0/agent_runtime/builder.py +317 -0
- agent_runtime_sdk-0.1.0/agent_runtime/config/__init__.py +29 -0
- agent_runtime_sdk-0.1.0/agent_runtime/config/definitions.py +144 -0
- agent_runtime_sdk-0.1.0/agent_runtime/config/policies.py +63 -0
- agent_runtime_sdk-0.1.0/agent_runtime/config/storage.py +117 -0
- agent_runtime_sdk-0.1.0/agent_runtime/context.py +10 -0
- agent_runtime_sdk-0.1.0/agent_runtime/definitions.py +33 -0
- agent_runtime_sdk-0.1.0/agent_runtime/discovery.py +16 -0
- agent_runtime_sdk-0.1.0/agent_runtime/exceptions.py +74 -0
- agent_runtime_sdk-0.1.0/agent_runtime/mcp/__init__.py +28 -0
- agent_runtime_sdk-0.1.0/agent_runtime/mcp/discovery.py +146 -0
- agent_runtime_sdk-0.1.0/agent_runtime/mcp/metadata.py +68 -0
- agent_runtime_sdk-0.1.0/agent_runtime/mcp/utils.py +52 -0
- agent_runtime_sdk-0.1.0/agent_runtime/model_registry.py +40 -0
- agent_runtime_sdk-0.1.0/agent_runtime/plugins/__init__.py +4 -0
- agent_runtime_sdk-0.1.0/agent_runtime/plugins/base.py +90 -0
- agent_runtime_sdk-0.1.0/agent_runtime/plugins/default.py +19 -0
- agent_runtime_sdk-0.1.0/agent_runtime/plugins/instructions.py +38 -0
- agent_runtime_sdk-0.1.0/agent_runtime/plugins/loader.py +59 -0
- agent_runtime_sdk-0.1.0/agent_runtime/policies.py +15 -0
- agent_runtime_sdk-0.1.0/agent_runtime/runtime.py +110 -0
- agent_runtime_sdk-0.1.0/agent_runtime/runtime_engine/__init__.py +22 -0
- agent_runtime_sdk-0.1.0/agent_runtime/runtime_engine/a2a_bridge.py +190 -0
- agent_runtime_sdk-0.1.0/agent_runtime/runtime_engine/a2a_task_io.py +165 -0
- agent_runtime_sdk-0.1.0/agent_runtime/runtime_engine/agent_build.py +315 -0
- agent_runtime_sdk-0.1.0/agent_runtime/runtime_engine/context.py +469 -0
- agent_runtime_sdk-0.1.0/agent_runtime/runtime_engine/loading.py +170 -0
- agent_runtime_sdk-0.1.0/agent_runtime/runtime_engine/observability.py +154 -0
- agent_runtime_sdk-0.1.0/agent_runtime/runtime_engine/policy_registry.py +98 -0
- agent_runtime_sdk-0.1.0/agent_runtime/runtime_engine/protocol_tools.py +94 -0
- agent_runtime_sdk-0.1.0/agent_runtime/runtime_engine/task_flow.py +897 -0
- agent_runtime_sdk-0.1.0/agent_runtime/runtime_engine/tool_flow.py +332 -0
- agent_runtime_sdk-0.1.0/agent_runtime/sdk_agent.py +548 -0
- agent_runtime_sdk-0.1.0/agent_runtime/server/__init__.py +15 -0
- agent_runtime_sdk-0.1.0/agent_runtime/server/app_factory.py +37 -0
- agent_runtime_sdk-0.1.0/agent_runtime/server/bootstrap.py +48 -0
- agent_runtime_sdk-0.1.0/agent_runtime/server/endpoint_utils.py +37 -0
- agent_runtime_sdk-0.1.0/agent_runtime/server/management.py +107 -0
- agent_runtime_sdk-0.1.0/agent_runtime/smol/__init__.py +4 -0
- agent_runtime_sdk-0.1.0/agent_runtime/smol/agents.py +431 -0
- agent_runtime_sdk-0.1.0/agent_runtime/smol/llm_models.py +212 -0
- agent_runtime_sdk-0.1.0/agent_runtime/smol/memory.py +111 -0
- agent_runtime_sdk-0.1.0/agent_runtime/smol/models.py +69 -0
- agent_runtime_sdk-0.1.0/agent_runtime/standalone.py +57 -0
- agent_runtime_sdk-0.1.0/agent_runtime/storage.py +5 -0
- agent_runtime_sdk-0.1.0/agent_runtime/tools.py +5 -0
- agent_runtime_sdk-0.1.0/agent_runtime_sdk.egg-info/PKG-INFO +125 -0
- agent_runtime_sdk-0.1.0/agent_runtime_sdk.egg-info/SOURCES.txt +55 -0
- agent_runtime_sdk-0.1.0/agent_runtime_sdk.egg-info/dependency_links.txt +1 -0
- agent_runtime_sdk-0.1.0/agent_runtime_sdk.egg-info/requires.txt +20 -0
- agent_runtime_sdk-0.1.0/agent_runtime_sdk.egg-info/top_level.txt +1 -0
- agent_runtime_sdk-0.1.0/pyproject.toml +44 -0
- agent_runtime_sdk-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
include README_PACKAGE.md
|
|
2
|
+
include pyproject.toml
|
|
3
|
+
recursive-include agent_runtime *.py
|
|
4
|
+
recursive-exclude agent_app *
|
|
5
|
+
recursive-exclude tests *
|
|
6
|
+
global-exclude __pycache__
|
|
7
|
+
global-exclude *.py[cod]
|
|
8
|
+
exclude README.md
|
|
9
|
+
exclude Dockerfile
|
|
10
|
+
exclude CSK_AGENT_API_FLOW.md
|
|
11
|
+
exclude main.py
|
|
12
|
+
exclude requirements.txt
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agent-runtime-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Single-agent runtime SDK for A2A agents backed by MCP tools.
|
|
5
|
+
Project-URL: Homepage, https://pypi.org/project/agent-runtime-sdk/
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: a2a-sdk==0.3.22
|
|
9
|
+
Requires-Dist: smolagents[mcp]
|
|
10
|
+
Requires-Dist: openai
|
|
11
|
+
Requires-Dist: fastapi
|
|
12
|
+
Requires-Dist: uvicorn
|
|
13
|
+
Requires-Dist: httpx
|
|
14
|
+
Requires-Dist: jinja2
|
|
15
|
+
Requires-Dist: pyyaml
|
|
16
|
+
Requires-Dist: loguru
|
|
17
|
+
Requires-Dist: pydantic
|
|
18
|
+
Requires-Dist: rich
|
|
19
|
+
Provides-Extra: observability
|
|
20
|
+
Requires-Dist: langfuse; extra == "observability"
|
|
21
|
+
Requires-Dist: openinference-instrumentation-smolagents; extra == "observability"
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: build; extra == "dev"
|
|
24
|
+
Requires-Dist: pytest; extra == "dev"
|
|
25
|
+
Requires-Dist: twine; extra == "dev"
|
|
26
|
+
|
|
27
|
+
# agent-runtime-sdk
|
|
28
|
+
|
|
29
|
+
Single-agent runtime SDK for exposing MCP tools as an A2A-compatible agent service.
|
|
30
|
+
|
|
31
|
+
## Install
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install agent-runtime-sdk
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Install optional Langfuse/smolagents observability support:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install "agent-runtime-sdk[observability]"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Basic Usage
|
|
44
|
+
|
|
45
|
+
Create an agent project:
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
my-agent/
|
|
49
|
+
├── agent_app/
|
|
50
|
+
│ ├── agent.yaml
|
|
51
|
+
│ └── plugin.py
|
|
52
|
+
└── main.py
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Example `main.py`:
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from pathlib import Path
|
|
59
|
+
|
|
60
|
+
from agent_runtime.standalone import build_single_agent_app, run_single_agent_app
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
app = build_single_agent_app(
|
|
64
|
+
Path(__file__).resolve().parent / "agent_app" / "agent.yaml"
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
if __name__ == "__main__":
|
|
69
|
+
run_single_agent_app(app)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Example SDK import:
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from agent_runtime import AgentBuilder
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Minimal Configuration
|
|
79
|
+
|
|
80
|
+
Example `agent_app/agent.yaml`:
|
|
81
|
+
|
|
82
|
+
```yaml
|
|
83
|
+
agent:
|
|
84
|
+
agent_id: example-agent
|
|
85
|
+
name: Example Agent
|
|
86
|
+
description: Example A2A agent backed by MCP tools.
|
|
87
|
+
|
|
88
|
+
runtime:
|
|
89
|
+
public_base_url: ${AGENT_PUBLIC_BASE_URL:-http://127.0.0.1:10020}
|
|
90
|
+
model:
|
|
91
|
+
provider: openai_compatible
|
|
92
|
+
api_base: ${MODEL_SOURCE_API_BASE}
|
|
93
|
+
model_id: ${MODEL_SOURCE_MODEL_ID}
|
|
94
|
+
api_key_env: MODEL_SOURCE_API_KEY
|
|
95
|
+
|
|
96
|
+
mcps:
|
|
97
|
+
- name: example
|
|
98
|
+
url: ${MCP_EXAMPLE_URL}
|
|
99
|
+
transport: streamable-http
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Run:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
export MODEL_SOURCE_API_BASE="https://your-model-api.example.com"
|
|
106
|
+
export MODEL_SOURCE_MODEL_ID="your-model-id"
|
|
107
|
+
export MODEL_SOURCE_API_KEY="your-api-key"
|
|
108
|
+
export MCP_EXAMPLE_URL="http://127.0.0.1:8000/mcp"
|
|
109
|
+
export AGENT_PUBLIC_BASE_URL="http://127.0.0.1:10020"
|
|
110
|
+
|
|
111
|
+
python main.py
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Langfuse
|
|
115
|
+
|
|
116
|
+
After installing `agent-runtime-sdk[observability]`, configure:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
export MCP_AGENT_LANGFUSE_ENABLED=true
|
|
120
|
+
export LANGFUSE_BASE_URL="http://your-langfuse-host:3000"
|
|
121
|
+
export LANGFUSE_PUBLIC_KEY="pk-lf-..."
|
|
122
|
+
export LANGFUSE_SECRET_KEY="sk-lf-..."
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Set `MCP_AGENT_LANGFUSE_ENABLED=false` to disable instrumentation.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# agent-runtime-sdk
|
|
2
|
+
|
|
3
|
+
Single-agent runtime SDK for exposing MCP tools as an A2A-compatible agent service.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install agent-runtime-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Install optional Langfuse/smolagents observability support:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install "agent-runtime-sdk[observability]"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Basic Usage
|
|
18
|
+
|
|
19
|
+
Create an agent project:
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
my-agent/
|
|
23
|
+
├── agent_app/
|
|
24
|
+
│ ├── agent.yaml
|
|
25
|
+
│ └── plugin.py
|
|
26
|
+
└── main.py
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Example `main.py`:
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
from pathlib import Path
|
|
33
|
+
|
|
34
|
+
from agent_runtime.standalone import build_single_agent_app, run_single_agent_app
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
app = build_single_agent_app(
|
|
38
|
+
Path(__file__).resolve().parent / "agent_app" / "agent.yaml"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
if __name__ == "__main__":
|
|
43
|
+
run_single_agent_app(app)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Example SDK import:
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from agent_runtime import AgentBuilder
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Minimal Configuration
|
|
53
|
+
|
|
54
|
+
Example `agent_app/agent.yaml`:
|
|
55
|
+
|
|
56
|
+
```yaml
|
|
57
|
+
agent:
|
|
58
|
+
agent_id: example-agent
|
|
59
|
+
name: Example Agent
|
|
60
|
+
description: Example A2A agent backed by MCP tools.
|
|
61
|
+
|
|
62
|
+
runtime:
|
|
63
|
+
public_base_url: ${AGENT_PUBLIC_BASE_URL:-http://127.0.0.1:10020}
|
|
64
|
+
model:
|
|
65
|
+
provider: openai_compatible
|
|
66
|
+
api_base: ${MODEL_SOURCE_API_BASE}
|
|
67
|
+
model_id: ${MODEL_SOURCE_MODEL_ID}
|
|
68
|
+
api_key_env: MODEL_SOURCE_API_KEY
|
|
69
|
+
|
|
70
|
+
mcps:
|
|
71
|
+
- name: example
|
|
72
|
+
url: ${MCP_EXAMPLE_URL}
|
|
73
|
+
transport: streamable-http
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Run:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
export MODEL_SOURCE_API_BASE="https://your-model-api.example.com"
|
|
80
|
+
export MODEL_SOURCE_MODEL_ID="your-model-id"
|
|
81
|
+
export MODEL_SOURCE_API_KEY="your-api-key"
|
|
82
|
+
export MCP_EXAMPLE_URL="http://127.0.0.1:8000/mcp"
|
|
83
|
+
export AGENT_PUBLIC_BASE_URL="http://127.0.0.1:10020"
|
|
84
|
+
|
|
85
|
+
python main.py
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Langfuse
|
|
89
|
+
|
|
90
|
+
After installing `agent-runtime-sdk[observability]`, configure:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
export MCP_AGENT_LANGFUSE_ENABLED=true
|
|
94
|
+
export LANGFUSE_BASE_URL="http://your-langfuse-host:3000"
|
|
95
|
+
export LANGFUSE_PUBLIC_KEY="pk-lf-..."
|
|
96
|
+
export LANGFUSE_SECRET_KEY="sk-lf-..."
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Set `MCP_AGENT_LANGFUSE_ENABLED=false` to disable instrumentation.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
2
|
+
|
|
3
|
+
from .builder import AgentBuilder
|
|
4
|
+
from .definitions import (
|
|
5
|
+
A2ASettings,
|
|
6
|
+
AgentConfig,
|
|
7
|
+
AgentDefinition,
|
|
8
|
+
InputFieldDefinition,
|
|
9
|
+
MCPSettings,
|
|
10
|
+
ModelSettings,
|
|
11
|
+
PluginSettings,
|
|
12
|
+
RuntimeConfig,
|
|
13
|
+
SkillDefinition,
|
|
14
|
+
ToolPolicy,
|
|
15
|
+
)
|
|
16
|
+
from .discovery import DiscoveredTool
|
|
17
|
+
from .exceptions import (
|
|
18
|
+
AgentBuildError,
|
|
19
|
+
AgentRuntimeError,
|
|
20
|
+
DefinitionLoadError,
|
|
21
|
+
MCPToolLoadError,
|
|
22
|
+
PluginLoadError,
|
|
23
|
+
TaskCancelledError,
|
|
24
|
+
TaskWaitTimeoutError,
|
|
25
|
+
UserCancelledError,
|
|
26
|
+
)
|
|
27
|
+
from .model_registry import ModelRegistry
|
|
28
|
+
from .plugins.base import BaseAgentPlugin, BeforeToolDecision, ToolExecutionContext
|
|
29
|
+
from .plugins.default import DefaultPlugin
|
|
30
|
+
from .runtime import ManagedAgentRuntime
|
|
31
|
+
from .sdk_agent import (
|
|
32
|
+
BaseSDKAgent,
|
|
33
|
+
ConfiguredSDKAgent,
|
|
34
|
+
DeclarativeSDKAgent,
|
|
35
|
+
OpenAICompatibleSingleMCPAgent,
|
|
36
|
+
SingleMCPAgent,
|
|
37
|
+
)
|
|
38
|
+
from .server.bootstrap import load_single_agent_runtime
|
|
39
|
+
from .standalone import build_single_agent_app, run_single_agent_app
|
|
40
|
+
from .storage import AgentDefinitionStore
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
__version__ = version("agent-runtime-sdk")
|
|
44
|
+
except PackageNotFoundError: # pragma: no cover - source tree without installed metadata
|
|
45
|
+
__version__ = "0.1.0"
|
|
46
|
+
|
|
47
|
+
__all__ = [
|
|
48
|
+
"__version__",
|
|
49
|
+
"A2ASettings",
|
|
50
|
+
"AgentConfig",
|
|
51
|
+
"AgentBuilder",
|
|
52
|
+
"AgentBuildError",
|
|
53
|
+
"AgentDefinition",
|
|
54
|
+
"AgentDefinitionStore",
|
|
55
|
+
"AgentRuntimeError",
|
|
56
|
+
"BaseAgentPlugin",
|
|
57
|
+
"BaseSDKAgent",
|
|
58
|
+
"ConfiguredSDKAgent",
|
|
59
|
+
"DeclarativeSDKAgent",
|
|
60
|
+
"BeforeToolDecision",
|
|
61
|
+
"DefinitionLoadError",
|
|
62
|
+
"DefaultPlugin",
|
|
63
|
+
"InputFieldDefinition",
|
|
64
|
+
"MCPToolLoadError",
|
|
65
|
+
"MCPSettings",
|
|
66
|
+
"ManagedAgentRuntime",
|
|
67
|
+
"ModelSettings",
|
|
68
|
+
"ModelRegistry",
|
|
69
|
+
"OpenAICompatibleSingleMCPAgent",
|
|
70
|
+
"PluginSettings",
|
|
71
|
+
"PluginLoadError",
|
|
72
|
+
"RuntimeConfig",
|
|
73
|
+
"SkillDefinition",
|
|
74
|
+
"SingleMCPAgent",
|
|
75
|
+
"TaskCancelledError",
|
|
76
|
+
"TaskWaitTimeoutError",
|
|
77
|
+
"DiscoveredTool",
|
|
78
|
+
"ToolExecutionContext",
|
|
79
|
+
"ToolPolicy",
|
|
80
|
+
"UserCancelledError",
|
|
81
|
+
"build_single_agent_app",
|
|
82
|
+
"load_single_agent_runtime",
|
|
83
|
+
"run_single_agent_app",
|
|
84
|
+
]
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
"""面向使用者的代码式构建入口。"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import re
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any, Callable
|
|
9
|
+
from urllib.parse import urlparse
|
|
10
|
+
|
|
11
|
+
from .config.definitions import (
|
|
12
|
+
DEFAULT_PASS_THROUGH_HEADERS,
|
|
13
|
+
AgentConfig,
|
|
14
|
+
AgentDefinition,
|
|
15
|
+
InputFieldDefinition,
|
|
16
|
+
MCPSettings,
|
|
17
|
+
ModelSettings,
|
|
18
|
+
PluginSettings,
|
|
19
|
+
RuntimeConfig,
|
|
20
|
+
SkillDefinition,
|
|
21
|
+
ToolPolicy,
|
|
22
|
+
)
|
|
23
|
+
from .mcp.metadata import DiscoveredTool
|
|
24
|
+
from .plugins.base import BaseAgentPlugin
|
|
25
|
+
from .runtime import ManagedAgentRuntime
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class AgentBuilder:
|
|
29
|
+
"""代码式配置入口。"""
|
|
30
|
+
|
|
31
|
+
def __init__(self):
|
|
32
|
+
self._agent = AgentConfig(
|
|
33
|
+
agent_id="mcp_agent",
|
|
34
|
+
name="",
|
|
35
|
+
description="",
|
|
36
|
+
version="0.1.0",
|
|
37
|
+
)
|
|
38
|
+
self._runtime = RuntimeConfig(
|
|
39
|
+
base_path=".",
|
|
40
|
+
public_base_url=None,
|
|
41
|
+
model=ModelSettings(),
|
|
42
|
+
)
|
|
43
|
+
self._mcps: list[MCPSettings] = []
|
|
44
|
+
|
|
45
|
+
self._plugin_instance: BaseAgentPlugin | None = None
|
|
46
|
+
self._discoverer: Callable[..., list[DiscoveredTool]] | None = None
|
|
47
|
+
self._explicit_model_api_key: str | None = None
|
|
48
|
+
self._auto_agent_id = True
|
|
49
|
+
|
|
50
|
+
def model(
|
|
51
|
+
self,
|
|
52
|
+
*,
|
|
53
|
+
provider: str | None = None,
|
|
54
|
+
api_base: str | None = None,
|
|
55
|
+
model_id: str | None = None,
|
|
56
|
+
api_key: str | None = None,
|
|
57
|
+
api_key_env: str | None = None,
|
|
58
|
+
max_steps: int | None = None,
|
|
59
|
+
flatten_messages_as_text: bool | None = None,
|
|
60
|
+
) -> AgentBuilder:
|
|
61
|
+
model = self._runtime.model
|
|
62
|
+
if provider is not None:
|
|
63
|
+
model.provider = provider
|
|
64
|
+
if api_base is not None:
|
|
65
|
+
model.api_base = api_base
|
|
66
|
+
if model_id is not None:
|
|
67
|
+
model.model_id = model_id
|
|
68
|
+
if api_key is not None:
|
|
69
|
+
self._explicit_model_api_key = api_key
|
|
70
|
+
if api_key_env is not None:
|
|
71
|
+
model.api_key_env = api_key_env
|
|
72
|
+
if max_steps is not None:
|
|
73
|
+
model.max_steps = max_steps
|
|
74
|
+
if flatten_messages_as_text is not None:
|
|
75
|
+
model.flatten_messages_as_text = flatten_messages_as_text
|
|
76
|
+
return self
|
|
77
|
+
|
|
78
|
+
def tool_policy(
|
|
79
|
+
self,
|
|
80
|
+
tool_name: str,
|
|
81
|
+
*,
|
|
82
|
+
mcp_name: str | None = None,
|
|
83
|
+
requires_confirmation: bool = False,
|
|
84
|
+
prompt: str | None = None,
|
|
85
|
+
enabled: bool = True,
|
|
86
|
+
allow_arg_override: bool = True,
|
|
87
|
+
input_fields: list[InputFieldDefinition | dict[str, Any]] | None = None,
|
|
88
|
+
) -> AgentBuilder:
|
|
89
|
+
fields: list[InputFieldDefinition] = []
|
|
90
|
+
if input_fields:
|
|
91
|
+
for field in input_fields:
|
|
92
|
+
if isinstance(field, InputFieldDefinition):
|
|
93
|
+
fields.append(field)
|
|
94
|
+
else:
|
|
95
|
+
fields.append(InputFieldDefinition.model_validate(field))
|
|
96
|
+
target_mcp = self._resolve_policy_target_mcp(mcp_name)
|
|
97
|
+
target_mcp.tool_policies[tool_name] = ToolPolicy(
|
|
98
|
+
enabled=enabled,
|
|
99
|
+
requires_confirmation=requires_confirmation,
|
|
100
|
+
input_fields=fields,
|
|
101
|
+
prompt=prompt,
|
|
102
|
+
allow_arg_override=allow_arg_override,
|
|
103
|
+
)
|
|
104
|
+
return self
|
|
105
|
+
|
|
106
|
+
def plugin(self, plugin: BaseAgentPlugin) -> AgentBuilder:
|
|
107
|
+
self._plugin_instance = plugin
|
|
108
|
+
return self
|
|
109
|
+
|
|
110
|
+
def instructions(self, text: str) -> AgentBuilder:
|
|
111
|
+
self._agent.extra_instructions = text
|
|
112
|
+
return self
|
|
113
|
+
|
|
114
|
+
def max_steps(self, n: int) -> AgentBuilder:
|
|
115
|
+
self._runtime.model.max_steps = n
|
|
116
|
+
return self
|
|
117
|
+
|
|
118
|
+
def agent_info(
|
|
119
|
+
self,
|
|
120
|
+
*,
|
|
121
|
+
agent_id: str | None = None,
|
|
122
|
+
name: str | None = None,
|
|
123
|
+
description: str | None = None,
|
|
124
|
+
version: str | None = None,
|
|
125
|
+
) -> AgentBuilder:
|
|
126
|
+
if agent_id is not None:
|
|
127
|
+
self._agent.agent_id = agent_id
|
|
128
|
+
self._auto_agent_id = False
|
|
129
|
+
if name is not None:
|
|
130
|
+
self._agent.name = name
|
|
131
|
+
if description is not None:
|
|
132
|
+
self._agent.description = description
|
|
133
|
+
if version is not None:
|
|
134
|
+
self._agent.version = version
|
|
135
|
+
return self
|
|
136
|
+
|
|
137
|
+
def add_mcp(
|
|
138
|
+
self,
|
|
139
|
+
*,
|
|
140
|
+
name: str,
|
|
141
|
+
url: str,
|
|
142
|
+
transport: str = "streamable-http",
|
|
143
|
+
enabled: bool = True,
|
|
144
|
+
retry_count: int = 3,
|
|
145
|
+
retry_delay_seconds: float = 1.0,
|
|
146
|
+
static_headers: dict[str, str] | None = None,
|
|
147
|
+
pass_through_headers: list[str] | None = None,
|
|
148
|
+
tool_policies: dict[str, ToolPolicy | dict[str, Any]] | None = None,
|
|
149
|
+
) -> AgentBuilder:
|
|
150
|
+
policies: dict[str, ToolPolicy] = {}
|
|
151
|
+
if tool_policies:
|
|
152
|
+
for tool_name, policy in tool_policies.items():
|
|
153
|
+
policies[tool_name] = (
|
|
154
|
+
policy
|
|
155
|
+
if isinstance(policy, ToolPolicy)
|
|
156
|
+
else ToolPolicy.model_validate(policy)
|
|
157
|
+
)
|
|
158
|
+
self._mcps.append(
|
|
159
|
+
MCPSettings(
|
|
160
|
+
name=name,
|
|
161
|
+
url=url,
|
|
162
|
+
transport=transport,
|
|
163
|
+
enabled=enabled,
|
|
164
|
+
retry_count=retry_count,
|
|
165
|
+
retry_delay_seconds=retry_delay_seconds,
|
|
166
|
+
static_headers=static_headers or {},
|
|
167
|
+
pass_through_headers=pass_through_headers
|
|
168
|
+
or list(DEFAULT_PASS_THROUGH_HEADERS),
|
|
169
|
+
tool_policies=policies,
|
|
170
|
+
)
|
|
171
|
+
)
|
|
172
|
+
return self
|
|
173
|
+
|
|
174
|
+
def a2a_skill(
|
|
175
|
+
self,
|
|
176
|
+
*,
|
|
177
|
+
id: str,
|
|
178
|
+
name: str,
|
|
179
|
+
description: str,
|
|
180
|
+
tags: list[str] | None = None,
|
|
181
|
+
examples: list[str] | None = None,
|
|
182
|
+
) -> AgentBuilder:
|
|
183
|
+
self._agent.a2a.skills.append(
|
|
184
|
+
SkillDefinition(
|
|
185
|
+
id=id,
|
|
186
|
+
name=name,
|
|
187
|
+
description=description,
|
|
188
|
+
tags=tags or [],
|
|
189
|
+
examples=examples or [],
|
|
190
|
+
)
|
|
191
|
+
)
|
|
192
|
+
return self
|
|
193
|
+
|
|
194
|
+
def public_base_url(self, url: str) -> AgentBuilder:
|
|
195
|
+
self._runtime.public_base_url = url
|
|
196
|
+
return self
|
|
197
|
+
|
|
198
|
+
def discoverer(self, func: Callable[..., list[DiscoveredTool]]) -> AgentBuilder:
|
|
199
|
+
self._discoverer = func
|
|
200
|
+
return self
|
|
201
|
+
|
|
202
|
+
def build(self) -> ManagedAgentRuntime:
|
|
203
|
+
definition = self.build_definition()
|
|
204
|
+
if self._explicit_model_api_key is not None:
|
|
205
|
+
os.environ[definition.runtime.model.api_key_env] = (
|
|
206
|
+
self._explicit_model_api_key
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
runtime = ManagedAgentRuntime(
|
|
210
|
+
definition=definition,
|
|
211
|
+
public_base_url=definition.runtime.public_base_url or "",
|
|
212
|
+
discoverer=self._discoverer,
|
|
213
|
+
)
|
|
214
|
+
if self._plugin_instance is not None:
|
|
215
|
+
runtime.plugin = self._plugin_instance
|
|
216
|
+
runtime.reload(discover=True, skip_plugin_load=True)
|
|
217
|
+
else:
|
|
218
|
+
runtime.reload(discover=True)
|
|
219
|
+
if runtime.load_error:
|
|
220
|
+
raise RuntimeError(runtime.load_error)
|
|
221
|
+
return runtime
|
|
222
|
+
|
|
223
|
+
def build_a2a_app(
|
|
224
|
+
self, *, public_url: str | None = None, enable_management: bool = True
|
|
225
|
+
):
|
|
226
|
+
from .server.app_factory import build_app_from_runtime
|
|
227
|
+
|
|
228
|
+
if public_url is not None:
|
|
229
|
+
self.public_base_url(public_url)
|
|
230
|
+
runtime = self.build()
|
|
231
|
+
return build_app_from_runtime(runtime, enable_management=enable_management)
|
|
232
|
+
|
|
233
|
+
@classmethod
|
|
234
|
+
def from_yaml(cls, path: str | Path) -> AgentBuilder:
|
|
235
|
+
from .config.storage import AgentDefinitionStore
|
|
236
|
+
|
|
237
|
+
resolved = Path(path).resolve()
|
|
238
|
+
definition = AgentDefinitionStore(resolved.parent).load_path(resolved)
|
|
239
|
+
return cls.from_definition(definition)
|
|
240
|
+
|
|
241
|
+
@classmethod
|
|
242
|
+
def from_definition(cls, definition: AgentDefinition) -> AgentBuilder:
|
|
243
|
+
builder = cls()
|
|
244
|
+
builder._agent = definition.agent.model_copy(deep=True)
|
|
245
|
+
builder._runtime = definition.runtime.model_copy(deep=True)
|
|
246
|
+
builder._mcps = [mcp.model_copy(deep=True) for mcp in definition.mcps]
|
|
247
|
+
builder._auto_agent_id = False
|
|
248
|
+
return builder
|
|
249
|
+
|
|
250
|
+
def build_definition(self) -> AgentDefinition:
|
|
251
|
+
"""返回当前 builder 收敛后的 `AgentDefinition`。
|
|
252
|
+
|
|
253
|
+
这个方法适合:
|
|
254
|
+
|
|
255
|
+
- 需要在真正 `build()` 前检查最终配置
|
|
256
|
+
- Python SDK 层希望把 YAML / 类配置统一收敛到同一个 definition 规格
|
|
257
|
+
"""
|
|
258
|
+
|
|
259
|
+
if not self._mcps:
|
|
260
|
+
raise ValueError("at least one MCP server must be added before build()")
|
|
261
|
+
|
|
262
|
+
agent = self._agent.model_copy(deep=True)
|
|
263
|
+
runtime = self._runtime.model_copy(deep=True)
|
|
264
|
+
mcps = [mcp.model_copy(deep=True) for mcp in self._mcps]
|
|
265
|
+
|
|
266
|
+
if self._auto_agent_id:
|
|
267
|
+
agent.agent_id = self._auto_agent_id_from_mcps(mcps)
|
|
268
|
+
if not agent.name:
|
|
269
|
+
agent.name = agent.agent_id
|
|
270
|
+
if not agent.description:
|
|
271
|
+
agent.description = agent.name
|
|
272
|
+
|
|
273
|
+
if runtime.model.api_base is None:
|
|
274
|
+
runtime.model.api_base = os.getenv("MODEL_SOURCE_API_BASE")
|
|
275
|
+
if runtime.model.model_id is None:
|
|
276
|
+
runtime.model.model_id = os.getenv("MODEL_SOURCE_MODEL_ID")
|
|
277
|
+
|
|
278
|
+
if self._plugin_instance is not None:
|
|
279
|
+
runtime.plugin = None
|
|
280
|
+
|
|
281
|
+
return AgentDefinition(
|
|
282
|
+
agent=agent,
|
|
283
|
+
runtime=runtime,
|
|
284
|
+
mcps=mcps,
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
def _build_definition(self) -> AgentDefinition:
|
|
288
|
+
"""兼容旧内部调用;新代码请优先使用 `build_definition()`。"""
|
|
289
|
+
|
|
290
|
+
return self.build_definition()
|
|
291
|
+
|
|
292
|
+
@staticmethod
|
|
293
|
+
def _auto_agent_id_from_mcps(mcps: list[MCPSettings]) -> str:
|
|
294
|
+
parsed = urlparse(mcps[0].url)
|
|
295
|
+
path_part = (
|
|
296
|
+
parsed.path.strip("/").split("/")[-1] if parsed.path.strip("/") else ""
|
|
297
|
+
)
|
|
298
|
+
if path_part:
|
|
299
|
+
normalized = re.sub(r"[^0-9a-zA-Z_]", "_", path_part)
|
|
300
|
+
return f"mcp_{normalized}" if normalized else "mcp_agent"
|
|
301
|
+
return "mcp_agent"
|
|
302
|
+
|
|
303
|
+
def _resolve_policy_target_mcp(self, mcp_name: str | None) -> MCPSettings:
|
|
304
|
+
if mcp_name is not None:
|
|
305
|
+
for mcp in self._mcps:
|
|
306
|
+
if mcp.name == mcp_name:
|
|
307
|
+
return mcp
|
|
308
|
+
raise ValueError(f"mcp '{mcp_name}' not found")
|
|
309
|
+
if len(self._mcps) == 1:
|
|
310
|
+
return self._mcps[0]
|
|
311
|
+
if not self._mcps:
|
|
312
|
+
raise ValueError(
|
|
313
|
+
"add an MCP before tool_policy(), or pass mcp_name after configuring MCPs"
|
|
314
|
+
)
|
|
315
|
+
raise ValueError(
|
|
316
|
+
"multiple MCPs configured; please specify mcp_name when setting tool_policy()"
|
|
317
|
+
)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""配置层内部实现。"""
|
|
2
|
+
|
|
3
|
+
from .definitions import (
|
|
4
|
+
A2ASettings,
|
|
5
|
+
AgentConfig,
|
|
6
|
+
AgentDefinition,
|
|
7
|
+
InputFieldDefinition,
|
|
8
|
+
MCPSettings,
|
|
9
|
+
ModelSettings,
|
|
10
|
+
PluginSettings,
|
|
11
|
+
RuntimeConfig,
|
|
12
|
+
SkillDefinition,
|
|
13
|
+
ToolPolicy,
|
|
14
|
+
)
|
|
15
|
+
from .storage import AgentDefinitionStore
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"A2ASettings",
|
|
19
|
+
"AgentConfig",
|
|
20
|
+
"AgentDefinition",
|
|
21
|
+
"AgentDefinitionStore",
|
|
22
|
+
"InputFieldDefinition",
|
|
23
|
+
"MCPSettings",
|
|
24
|
+
"ModelSettings",
|
|
25
|
+
"PluginSettings",
|
|
26
|
+
"RuntimeConfig",
|
|
27
|
+
"SkillDefinition",
|
|
28
|
+
"ToolPolicy",
|
|
29
|
+
]
|