agentpool 2.1.9__py3-none-any.whl → 2.5.0__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 (311) hide show
  1. acp/__init__.py +13 -4
  2. acp/acp_requests.py +20 -77
  3. acp/agent/connection.py +8 -0
  4. acp/agent/implementations/debug_server/debug_server.py +6 -2
  5. acp/agent/protocol.py +6 -0
  6. acp/bridge/README.md +15 -2
  7. acp/bridge/__init__.py +3 -2
  8. acp/bridge/__main__.py +60 -19
  9. acp/bridge/ws_server.py +173 -0
  10. acp/bridge/ws_server_cli.py +89 -0
  11. acp/client/connection.py +38 -29
  12. acp/client/implementations/default_client.py +3 -2
  13. acp/client/implementations/headless_client.py +2 -2
  14. acp/connection.py +2 -2
  15. acp/notifications.py +20 -50
  16. acp/schema/__init__.py +2 -0
  17. acp/schema/agent_responses.py +21 -0
  18. acp/schema/client_requests.py +3 -3
  19. acp/schema/session_state.py +63 -29
  20. acp/stdio.py +39 -9
  21. acp/task/supervisor.py +2 -2
  22. acp/transports.py +362 -2
  23. acp/utils.py +17 -4
  24. agentpool/__init__.py +6 -1
  25. agentpool/agents/__init__.py +2 -0
  26. agentpool/agents/acp_agent/acp_agent.py +407 -277
  27. agentpool/agents/acp_agent/acp_converters.py +196 -38
  28. agentpool/agents/acp_agent/client_handler.py +191 -26
  29. agentpool/agents/acp_agent/session_state.py +17 -6
  30. agentpool/agents/agent.py +607 -572
  31. agentpool/agents/agui_agent/__init__.py +0 -2
  32. agentpool/agents/agui_agent/agui_agent.py +176 -110
  33. agentpool/agents/agui_agent/agui_converters.py +0 -131
  34. agentpool/agents/agui_agent/helpers.py +3 -4
  35. agentpool/agents/base_agent.py +632 -17
  36. agentpool/agents/claude_code_agent/FORKING.md +191 -0
  37. agentpool/agents/claude_code_agent/__init__.py +13 -1
  38. agentpool/agents/claude_code_agent/claude_code_agent.py +1058 -291
  39. agentpool/agents/claude_code_agent/converters.py +74 -143
  40. agentpool/agents/claude_code_agent/history.py +474 -0
  41. agentpool/agents/claude_code_agent/models.py +77 -0
  42. agentpool/agents/claude_code_agent/static_info.py +100 -0
  43. agentpool/agents/claude_code_agent/usage.py +242 -0
  44. agentpool/agents/context.py +40 -0
  45. agentpool/agents/events/__init__.py +24 -0
  46. agentpool/agents/events/builtin_handlers.py +67 -1
  47. agentpool/agents/events/event_emitter.py +32 -2
  48. agentpool/agents/events/events.py +104 -3
  49. agentpool/agents/events/infer_info.py +145 -0
  50. agentpool/agents/events/processors.py +254 -0
  51. agentpool/agents/interactions.py +41 -6
  52. agentpool/agents/modes.py +67 -0
  53. agentpool/agents/slashed_agent.py +5 -4
  54. agentpool/agents/tool_call_accumulator.py +213 -0
  55. agentpool/agents/tool_wrapping.py +18 -6
  56. agentpool/common_types.py +56 -21
  57. agentpool/config_resources/__init__.py +38 -1
  58. agentpool/config_resources/acp_assistant.yml +2 -2
  59. agentpool/config_resources/agents.yml +3 -0
  60. agentpool/config_resources/agents_template.yml +1 -0
  61. agentpool/config_resources/claude_code_agent.yml +10 -6
  62. agentpool/config_resources/external_acp_agents.yml +2 -1
  63. agentpool/delegation/base_team.py +4 -30
  64. agentpool/delegation/pool.py +136 -289
  65. agentpool/delegation/team.py +58 -57
  66. agentpool/delegation/teamrun.py +51 -55
  67. agentpool/diagnostics/__init__.py +53 -0
  68. agentpool/diagnostics/lsp_manager.py +1593 -0
  69. agentpool/diagnostics/lsp_proxy.py +41 -0
  70. agentpool/diagnostics/lsp_proxy_script.py +229 -0
  71. agentpool/diagnostics/models.py +398 -0
  72. agentpool/functional/run.py +10 -4
  73. agentpool/mcp_server/__init__.py +0 -2
  74. agentpool/mcp_server/client.py +76 -32
  75. agentpool/mcp_server/conversions.py +54 -13
  76. agentpool/mcp_server/manager.py +34 -54
  77. agentpool/mcp_server/registries/official_registry_client.py +35 -1
  78. agentpool/mcp_server/tool_bridge.py +186 -139
  79. agentpool/messaging/__init__.py +0 -2
  80. agentpool/messaging/compaction.py +72 -197
  81. agentpool/messaging/connection_manager.py +11 -10
  82. agentpool/messaging/event_manager.py +5 -5
  83. agentpool/messaging/message_container.py +6 -30
  84. agentpool/messaging/message_history.py +99 -8
  85. agentpool/messaging/messagenode.py +52 -14
  86. agentpool/messaging/messages.py +54 -35
  87. agentpool/messaging/processing.py +12 -22
  88. agentpool/models/__init__.py +1 -1
  89. agentpool/models/acp_agents/base.py +6 -24
  90. agentpool/models/acp_agents/mcp_capable.py +126 -157
  91. agentpool/models/acp_agents/non_mcp.py +129 -95
  92. agentpool/models/agents.py +98 -76
  93. agentpool/models/agui_agents.py +1 -1
  94. agentpool/models/claude_code_agents.py +144 -19
  95. agentpool/models/file_parsing.py +0 -1
  96. agentpool/models/manifest.py +113 -50
  97. agentpool/prompts/conversion_manager.py +1 -1
  98. agentpool/prompts/prompts.py +5 -2
  99. agentpool/repomap.py +1 -1
  100. agentpool/resource_providers/__init__.py +11 -1
  101. agentpool/resource_providers/aggregating.py +56 -5
  102. agentpool/resource_providers/base.py +70 -4
  103. agentpool/resource_providers/codemode/code_executor.py +72 -5
  104. agentpool/resource_providers/codemode/helpers.py +2 -2
  105. agentpool/resource_providers/codemode/provider.py +64 -12
  106. agentpool/resource_providers/codemode/remote_mcp_execution.py +2 -2
  107. agentpool/resource_providers/codemode/remote_provider.py +9 -12
  108. agentpool/resource_providers/filtering.py +3 -1
  109. agentpool/resource_providers/mcp_provider.py +89 -12
  110. agentpool/resource_providers/plan_provider.py +228 -46
  111. agentpool/resource_providers/pool.py +7 -3
  112. agentpool/resource_providers/resource_info.py +111 -0
  113. agentpool/resource_providers/static.py +4 -2
  114. agentpool/sessions/__init__.py +4 -1
  115. agentpool/sessions/manager.py +33 -5
  116. agentpool/sessions/models.py +59 -6
  117. agentpool/sessions/protocol.py +28 -0
  118. agentpool/sessions/session.py +11 -55
  119. agentpool/skills/registry.py +13 -8
  120. agentpool/storage/manager.py +572 -49
  121. agentpool/talk/registry.py +4 -4
  122. agentpool/talk/talk.py +9 -10
  123. agentpool/testing.py +538 -20
  124. agentpool/tool_impls/__init__.py +6 -0
  125. agentpool/tool_impls/agent_cli/__init__.py +42 -0
  126. agentpool/tool_impls/agent_cli/tool.py +95 -0
  127. agentpool/tool_impls/bash/__init__.py +64 -0
  128. agentpool/tool_impls/bash/helpers.py +35 -0
  129. agentpool/tool_impls/bash/tool.py +171 -0
  130. agentpool/tool_impls/delete_path/__init__.py +70 -0
  131. agentpool/tool_impls/delete_path/tool.py +142 -0
  132. agentpool/tool_impls/download_file/__init__.py +80 -0
  133. agentpool/tool_impls/download_file/tool.py +183 -0
  134. agentpool/tool_impls/execute_code/__init__.py +55 -0
  135. agentpool/tool_impls/execute_code/tool.py +163 -0
  136. agentpool/tool_impls/grep/__init__.py +80 -0
  137. agentpool/tool_impls/grep/tool.py +200 -0
  138. agentpool/tool_impls/list_directory/__init__.py +73 -0
  139. agentpool/tool_impls/list_directory/tool.py +197 -0
  140. agentpool/tool_impls/question/__init__.py +42 -0
  141. agentpool/tool_impls/question/tool.py +127 -0
  142. agentpool/tool_impls/read/__init__.py +104 -0
  143. agentpool/tool_impls/read/tool.py +305 -0
  144. agentpool/tools/__init__.py +2 -1
  145. agentpool/tools/base.py +114 -34
  146. agentpool/tools/manager.py +57 -1
  147. agentpool/ui/base.py +2 -2
  148. agentpool/ui/mock_provider.py +2 -2
  149. agentpool/ui/stdlib_provider.py +2 -2
  150. agentpool/utils/file_watcher.py +269 -0
  151. agentpool/utils/identifiers.py +121 -0
  152. agentpool/utils/pydantic_ai_helpers.py +46 -0
  153. agentpool/utils/streams.py +616 -2
  154. agentpool/utils/subprocess_utils.py +155 -0
  155. agentpool/utils/token_breakdown.py +461 -0
  156. agentpool/vfs_registry.py +7 -2
  157. {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/METADATA +41 -27
  158. agentpool-2.5.0.dist-info/RECORD +579 -0
  159. {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/WHEEL +1 -1
  160. agentpool_cli/__main__.py +24 -0
  161. agentpool_cli/create.py +1 -1
  162. agentpool_cli/serve_acp.py +100 -21
  163. agentpool_cli/serve_agui.py +87 -0
  164. agentpool_cli/serve_opencode.py +119 -0
  165. agentpool_cli/ui.py +557 -0
  166. agentpool_commands/__init__.py +42 -5
  167. agentpool_commands/agents.py +75 -2
  168. agentpool_commands/history.py +62 -0
  169. agentpool_commands/mcp.py +176 -0
  170. agentpool_commands/models.py +56 -3
  171. agentpool_commands/pool.py +260 -0
  172. agentpool_commands/session.py +1 -1
  173. agentpool_commands/text_sharing/__init__.py +119 -0
  174. agentpool_commands/text_sharing/base.py +123 -0
  175. agentpool_commands/text_sharing/github_gist.py +80 -0
  176. agentpool_commands/text_sharing/opencode.py +462 -0
  177. agentpool_commands/text_sharing/paste_rs.py +59 -0
  178. agentpool_commands/text_sharing/pastebin.py +116 -0
  179. agentpool_commands/text_sharing/shittycodingagent.py +112 -0
  180. agentpool_commands/tools.py +57 -0
  181. agentpool_commands/utils.py +80 -30
  182. agentpool_config/__init__.py +30 -2
  183. agentpool_config/agentpool_tools.py +498 -0
  184. agentpool_config/builtin_tools.py +77 -22
  185. agentpool_config/commands.py +24 -1
  186. agentpool_config/compaction.py +258 -0
  187. agentpool_config/converters.py +1 -1
  188. agentpool_config/event_handlers.py +42 -0
  189. agentpool_config/events.py +1 -1
  190. agentpool_config/forward_targets.py +1 -4
  191. agentpool_config/jinja.py +3 -3
  192. agentpool_config/mcp_server.py +132 -6
  193. agentpool_config/nodes.py +1 -1
  194. agentpool_config/observability.py +44 -0
  195. agentpool_config/session.py +0 -3
  196. agentpool_config/storage.py +82 -38
  197. agentpool_config/task.py +3 -3
  198. agentpool_config/tools.py +11 -22
  199. agentpool_config/toolsets.py +109 -233
  200. agentpool_server/a2a_server/agent_worker.py +307 -0
  201. agentpool_server/a2a_server/server.py +23 -18
  202. agentpool_server/acp_server/acp_agent.py +234 -181
  203. agentpool_server/acp_server/commands/acp_commands.py +151 -156
  204. agentpool_server/acp_server/commands/docs_commands/fetch_repo.py +18 -17
  205. agentpool_server/acp_server/event_converter.py +651 -0
  206. agentpool_server/acp_server/input_provider.py +53 -10
  207. agentpool_server/acp_server/server.py +24 -90
  208. agentpool_server/acp_server/session.py +173 -331
  209. agentpool_server/acp_server/session_manager.py +8 -34
  210. agentpool_server/agui_server/server.py +3 -1
  211. agentpool_server/mcp_server/server.py +5 -2
  212. agentpool_server/opencode_server/.rules +95 -0
  213. agentpool_server/opencode_server/ENDPOINTS.md +401 -0
  214. agentpool_server/opencode_server/OPENCODE_UI_TOOLS_COMPLETE.md +202 -0
  215. agentpool_server/opencode_server/__init__.py +19 -0
  216. agentpool_server/opencode_server/command_validation.py +172 -0
  217. agentpool_server/opencode_server/converters.py +975 -0
  218. agentpool_server/opencode_server/dependencies.py +24 -0
  219. agentpool_server/opencode_server/input_provider.py +421 -0
  220. agentpool_server/opencode_server/models/__init__.py +250 -0
  221. agentpool_server/opencode_server/models/agent.py +53 -0
  222. agentpool_server/opencode_server/models/app.py +72 -0
  223. agentpool_server/opencode_server/models/base.py +26 -0
  224. agentpool_server/opencode_server/models/common.py +23 -0
  225. agentpool_server/opencode_server/models/config.py +37 -0
  226. agentpool_server/opencode_server/models/events.py +821 -0
  227. agentpool_server/opencode_server/models/file.py +88 -0
  228. agentpool_server/opencode_server/models/mcp.py +44 -0
  229. agentpool_server/opencode_server/models/message.py +179 -0
  230. agentpool_server/opencode_server/models/parts.py +323 -0
  231. agentpool_server/opencode_server/models/provider.py +81 -0
  232. agentpool_server/opencode_server/models/pty.py +43 -0
  233. agentpool_server/opencode_server/models/question.py +56 -0
  234. agentpool_server/opencode_server/models/session.py +111 -0
  235. agentpool_server/opencode_server/routes/__init__.py +29 -0
  236. agentpool_server/opencode_server/routes/agent_routes.py +473 -0
  237. agentpool_server/opencode_server/routes/app_routes.py +202 -0
  238. agentpool_server/opencode_server/routes/config_routes.py +302 -0
  239. agentpool_server/opencode_server/routes/file_routes.py +571 -0
  240. agentpool_server/opencode_server/routes/global_routes.py +94 -0
  241. agentpool_server/opencode_server/routes/lsp_routes.py +319 -0
  242. agentpool_server/opencode_server/routes/message_routes.py +761 -0
  243. agentpool_server/opencode_server/routes/permission_routes.py +63 -0
  244. agentpool_server/opencode_server/routes/pty_routes.py +300 -0
  245. agentpool_server/opencode_server/routes/question_routes.py +128 -0
  246. agentpool_server/opencode_server/routes/session_routes.py +1276 -0
  247. agentpool_server/opencode_server/routes/tui_routes.py +139 -0
  248. agentpool_server/opencode_server/server.py +475 -0
  249. agentpool_server/opencode_server/state.py +151 -0
  250. agentpool_server/opencode_server/time_utils.py +8 -0
  251. agentpool_storage/__init__.py +12 -0
  252. agentpool_storage/base.py +184 -2
  253. agentpool_storage/claude_provider/ARCHITECTURE.md +433 -0
  254. agentpool_storage/claude_provider/__init__.py +42 -0
  255. agentpool_storage/claude_provider/provider.py +1089 -0
  256. agentpool_storage/file_provider.py +278 -15
  257. agentpool_storage/memory_provider.py +193 -12
  258. agentpool_storage/models.py +3 -0
  259. agentpool_storage/opencode_provider/ARCHITECTURE.md +386 -0
  260. agentpool_storage/opencode_provider/__init__.py +16 -0
  261. agentpool_storage/opencode_provider/helpers.py +414 -0
  262. agentpool_storage/opencode_provider/provider.py +895 -0
  263. agentpool_storage/project_store.py +325 -0
  264. agentpool_storage/session_store.py +26 -6
  265. agentpool_storage/sql_provider/__init__.py +4 -2
  266. agentpool_storage/sql_provider/models.py +48 -0
  267. agentpool_storage/sql_provider/sql_provider.py +269 -3
  268. agentpool_storage/sql_provider/utils.py +12 -13
  269. agentpool_storage/zed_provider/__init__.py +16 -0
  270. agentpool_storage/zed_provider/helpers.py +281 -0
  271. agentpool_storage/zed_provider/models.py +130 -0
  272. agentpool_storage/zed_provider/provider.py +442 -0
  273. agentpool_storage/zed_provider.py +803 -0
  274. agentpool_toolsets/__init__.py +0 -2
  275. agentpool_toolsets/builtin/__init__.py +2 -12
  276. agentpool_toolsets/builtin/code.py +96 -57
  277. agentpool_toolsets/builtin/debug.py +118 -48
  278. agentpool_toolsets/builtin/execution_environment.py +115 -230
  279. agentpool_toolsets/builtin/file_edit/file_edit.py +115 -7
  280. agentpool_toolsets/builtin/skills.py +9 -4
  281. agentpool_toolsets/builtin/subagent_tools.py +64 -51
  282. agentpool_toolsets/builtin/workers.py +4 -2
  283. agentpool_toolsets/composio_toolset.py +2 -2
  284. agentpool_toolsets/entry_points.py +3 -1
  285. agentpool_toolsets/fsspec_toolset/__init__.py +13 -1
  286. agentpool_toolsets/fsspec_toolset/diagnostics.py +860 -73
  287. agentpool_toolsets/fsspec_toolset/grep.py +99 -7
  288. agentpool_toolsets/fsspec_toolset/helpers.py +3 -2
  289. agentpool_toolsets/fsspec_toolset/image_utils.py +161 -0
  290. agentpool_toolsets/fsspec_toolset/toolset.py +500 -95
  291. agentpool_toolsets/mcp_discovery/__init__.py +5 -0
  292. agentpool_toolsets/mcp_discovery/data/mcp_servers.parquet +0 -0
  293. agentpool_toolsets/mcp_discovery/toolset.py +511 -0
  294. agentpool_toolsets/mcp_run_toolset.py +87 -12
  295. agentpool_toolsets/notifications.py +33 -33
  296. agentpool_toolsets/openapi.py +3 -1
  297. agentpool_toolsets/search_toolset.py +3 -1
  298. agentpool-2.1.9.dist-info/RECORD +0 -474
  299. agentpool_config/resources.py +0 -33
  300. agentpool_server/acp_server/acp_tools.py +0 -43
  301. agentpool_server/acp_server/commands/spawn.py +0 -210
  302. agentpool_storage/text_log_provider.py +0 -275
  303. agentpool_toolsets/builtin/agent_management.py +0 -239
  304. agentpool_toolsets/builtin/chain.py +0 -288
  305. agentpool_toolsets/builtin/history.py +0 -36
  306. agentpool_toolsets/builtin/integration.py +0 -85
  307. agentpool_toolsets/builtin/tool_management.py +0 -90
  308. agentpool_toolsets/builtin/user_interaction.py +0 -52
  309. agentpool_toolsets/semantic_memory_toolset.py +0 -536
  310. {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/entry_points.txt +0 -0
  311. {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,239 +0,0 @@
1
- """Provider for agent pool building tools."""
2
-
3
- from __future__ import annotations
4
-
5
- from datetime import timedelta
6
- from typing import TYPE_CHECKING, Any, Literal
7
-
8
- import anyio
9
- from pydantic_ai import ModelRetry
10
-
11
- from agentpool.agents.context import AgentContext # noqa: TC001
12
- from agentpool.log import get_logger
13
- from agentpool.resource_providers import StaticResourceProvider
14
- from agentpool.tools.exceptions import ToolError
15
- from agentpool.utils.result_utils import to_type
16
-
17
-
18
- if TYPE_CHECKING:
19
- from agentpool.agents import Agent
20
-
21
- logger = get_logger(__name__)
22
-
23
-
24
- async def create_worker_agent[TDeps](
25
- ctx: AgentContext[TDeps],
26
- name: str,
27
- system_prompt: str,
28
- model: str | None = None,
29
- ) -> str:
30
- """Create a new agent and register it as a tool.
31
-
32
- The new agent will be available as a tool for delegating specific tasks.
33
- It inherits the current model unless overridden.
34
- """
35
- from agentpool import Agent
36
-
37
- if not ctx.pool:
38
- msg = "Agent needs to be in a pool to list agents"
39
- raise ToolError(msg)
40
-
41
- model = model or ctx.agent.model_name
42
- agent = Agent[TDeps](name=name, model=model, system_prompt=system_prompt, agent_pool=ctx.pool)
43
- assert ctx.agent
44
- tool_info = ctx.native_agent.register_worker(agent)
45
- return f"Created worker agent and registered as tool: {tool_info.name}"
46
-
47
-
48
- async def add_agent( # noqa: D417
49
- ctx: AgentContext,
50
- name: str,
51
- system_prompt: str,
52
- model: str | None = None,
53
- tools: list[str] | None = None,
54
- session: str | None = None,
55
- output_type: str | None = None,
56
- ) -> str:
57
- """Add a new agent to the pool.
58
-
59
- Args:
60
- name: Name for the new agent
61
- system_prompt: System prompt defining agent's role/behavior
62
- model: Optional model override (uses default if not specified)
63
- tools: Imort paths of the tools the agent should have, if any.
64
- session: Session ID to recover conversation state from
65
- output_type: Name of response type from manifest (for structured output)
66
-
67
- Returns:
68
- Confirmation message about the created agent
69
- """
70
- assert ctx.pool, "No agent pool available"
71
- try:
72
- agent: Agent[Any, Any] = await ctx.pool.add_agent(
73
- name=name,
74
- system_prompt=system_prompt,
75
- model=model,
76
- tools=tools,
77
- output_type=to_type(output_type, responses=ctx.pool.manifest.responses),
78
- session=session,
79
- )
80
- except ValueError as e: # for wrong tool imports
81
- raise ModelRetry(message=f"Error creating agent: {e}") from None
82
- return f"Created agent **{agent.name}** using model **{agent.model_name}**"
83
-
84
-
85
- async def add_team( # noqa: D417
86
- ctx: AgentContext,
87
- nodes: list[str],
88
- mode: Literal["sequential", "parallel"] = "sequential",
89
- name: str | None = None,
90
- ) -> str:
91
- """Create a team from existing agents.
92
-
93
- Args:
94
- nodes: Names of agents / sub-teams to include in team
95
- mode: How the team should operate:
96
- - sequential: Agents process in sequence (pipeline)
97
- - parallel: Agents process simultaneously
98
- name: Optional name for the team
99
- """
100
- if not ctx.pool:
101
- msg = "No agent pool available"
102
- raise ToolError(msg)
103
-
104
- # Verify all agents exist
105
- for node_name in nodes:
106
- if node_name not in ctx.pool.nodes:
107
- msg = (
108
- f"No agent or team found with name: {node_name}. "
109
- f"Available nodes: {', '.join(ctx.pool.nodes.keys())}"
110
- )
111
- raise ModelRetry(msg)
112
- if mode == "sequential":
113
- ctx.pool.create_team_run(nodes, name=name)
114
- else:
115
- ctx.pool.create_team(nodes, name=name)
116
- mode_str = "pipeline" if mode == "sequential" else "parallel"
117
- return f"Created **{mode_str}** team with nodes: **{', '.join(nodes)}**"
118
-
119
-
120
- async def connect_nodes( # noqa: D417
121
- ctx: AgentContext,
122
- source: str,
123
- target: str,
124
- *,
125
- connection_type: Literal["run", "context", "forward"] = "run",
126
- priority: int = 0,
127
- delay_seconds: float | None = None,
128
- queued: bool = False,
129
- queue_strategy: Literal["concat", "latest", "buffer"] = "latest",
130
- wait_for_completion: bool = True,
131
- name: str | None = None,
132
- ) -> str:
133
- """Connect two nodes to enable message flow between them.
134
-
135
- Nodes can be agents or teams.
136
-
137
- Args:
138
- source: Name of the source node
139
- target: Name of the target node
140
- connection_type: How messages should be handled:
141
- - run: Execute message as a new run in target
142
- - context: Add message as context to target
143
- - forward: Forward message to target's outbox
144
- priority: Task priority (lower = higher priority)
145
- delay_seconds: Optional delay before processing messages
146
- queued: Whether messages should be queued for manual processing
147
- queue_strategy: How to process queued messages:
148
- - concat: Combine all messages with newlines
149
- - latest: Use only the most recent message
150
- - buffer: Process all messages individually
151
- wait_for_completion: Whether to wait for target to complete
152
- name: Optional name for this connection
153
-
154
- Returns:
155
- Description of the created connection
156
- """
157
- if not ctx.pool:
158
- msg = "No agent pool available"
159
- raise ToolError(msg)
160
-
161
- # Get the nodes
162
- if source not in ctx.pool.nodes:
163
- msg = (
164
- f"No agent or team found with name: {source}. "
165
- f"Available nodes: {', '.join(ctx.pool.nodes.keys())}"
166
- )
167
- raise ModelRetry(msg)
168
- if target not in ctx.pool.nodes:
169
- msg = (
170
- f"No agent or team found with name: {target}. "
171
- f"Available nodes: {', '.join(ctx.pool.nodes.keys())}"
172
- )
173
- raise ModelRetry(msg)
174
-
175
- source_node = ctx.pool.nodes[source]
176
- target_node = ctx.pool.nodes[target]
177
-
178
- # Create the connection
179
- delay = timedelta(seconds=delay_seconds) if delay_seconds is not None else None
180
- _talk = source_node.connect_to(
181
- target_node,
182
- connection_type=connection_type,
183
- priority=priority,
184
- delay=delay,
185
- queued=queued,
186
- queue_strategy=queue_strategy,
187
- name=name,
188
- )
189
- source_node.connections.set_wait_state(target_node, wait=wait_for_completion)
190
-
191
- return (
192
- f"Created connection from **{source}** to **{target}** "
193
- f"*(type={connection_type}, queued={queued}, "
194
- f"strategy={queue_strategy if queued else 'n/a'})*"
195
- )
196
-
197
-
198
- class AgentManagementTools(StaticResourceProvider):
199
- """Provider for agent pool building tools."""
200
-
201
- def __init__(self, name: str = "agent_management") -> None:
202
- super().__init__(name=name)
203
- for tool in [
204
- self.create_tool(create_worker_agent, category="other", destructive=False),
205
- self.create_tool(add_agent, category="other", destructive=False),
206
- self.create_tool(add_team, category="other", destructive=False),
207
- self.create_tool(connect_nodes, category="other", destructive=False),
208
- ]:
209
- self.add_tool(tool)
210
-
211
-
212
- if __name__ == "__main__":
213
- # import logging
214
- from agentpool import AgentPool
215
-
216
- user_prompt = """Add a stdio MCP server:
217
- // "command": "npx",
218
- // "args": ["mcp-graphql"],
219
- // "env": { "ENDPOINT": "https://diego.one/graphql" }
220
-
221
- ."""
222
-
223
- async def main() -> None:
224
- from agentpool_config.toolsets import IntegrationToolsetConfig
225
-
226
- async with AgentPool() as pool:
227
- toolsets = [IntegrationToolsetConfig()]
228
- toolset_providers = [config.get_provider() for config in toolsets]
229
- agent = await pool.add_agent(
230
- "X",
231
- toolsets=toolset_providers,
232
- model="openai:gpt-5-nano",
233
- )
234
- result = await agent.run(user_prompt)
235
- print(result)
236
- result = await agent.run("Which tools does it have?")
237
- print(result)
238
-
239
- anyio.run(main)
@@ -1,288 +0,0 @@
1
- """Tool to chain multiple function calls."""
2
-
3
- from __future__ import annotations
4
-
5
- import asyncio
6
- from dataclasses import dataclass
7
- from enum import StrEnum
8
- from typing import Any, Literal, assert_never
9
-
10
- import anyio
11
- from pydantic import Field
12
- from pydantic_ai import ModelRetry
13
- from schemez import Schema
14
-
15
- from agentpool.agents.context import AgentContext # noqa: TC001
16
-
17
-
18
- class ErrorStrategy(StrEnum):
19
- """Strategy for handling errors in the pipeline."""
20
-
21
- STOP = "stop" # Stop pipeline on error
22
- SKIP = "skip" # Skip failed step, continue with previous result
23
- DEFAULT = "default" # Use provided default value
24
- RETRY = "retry" # Retry the step
25
-
26
-
27
- class StepCondition(Schema):
28
- """Condition for conditional execution."""
29
-
30
- field: str # Field to check in result
31
- operator: Literal["eq", "gt", "lt", "contains", "exists"]
32
- value: Any = None
33
-
34
- def evaluate_with_value(self, value: Any) -> bool:
35
- """Evaluate this condition against a value.
36
-
37
- Args:
38
- value: The value to evaluate against the condition.
39
-
40
- Returns:
41
- bool: True if the condition is met, False otherwise.
42
- """
43
- field_value = value.get(self.field) if isinstance(value, dict) else value
44
-
45
- match self.operator:
46
- case "eq":
47
- return bool(field_value == self.value)
48
- case "gt":
49
- return bool(field_value > self.value)
50
- case "lt":
51
- return bool(field_value < self.value)
52
- case "contains":
53
- try:
54
- return self.value in field_value # type: ignore[operator]
55
- except TypeError:
56
- return False
57
- case "exists":
58
- return field_value is not None
59
- case _ as unreachable:
60
- assert_never(unreachable)
61
-
62
-
63
- @dataclass
64
- class StepResult:
65
- """Result of a pipeline step execution."""
66
-
67
- success: bool
68
- result: Any
69
- error: Exception | None = None
70
- retries: int = 0
71
- duration: float = 0.0
72
-
73
-
74
- # Type alias for step results during execution
75
- type StepResults = dict[str, StepResult]
76
-
77
-
78
- class PipelineStep(Schema):
79
- """Single step in a tool pipeline."""
80
-
81
- tool: str
82
- input_kwarg: str = "text"
83
- keyword_args: dict[str, Any] = Field(default_factory=dict)
84
- name: str | None = None # Optional step name for referencing
85
- condition: StepCondition | None = None # Conditional execution
86
- error_strategy: ErrorStrategy = ErrorStrategy.STOP
87
- default_value: Any = None # Used with ErrorStrategy.DEFAULT
88
- max_retries: int = 0
89
- retry_delay: float = 1.0
90
- timeout: float | None = None
91
- depends_on: list[str] = Field(default_factory=list) # Step dependencies
92
-
93
-
94
- class Pipeline(Schema):
95
- """A pipeline of tool operations."""
96
-
97
- input: str | dict[str, Any]
98
- steps: list[PipelineStep]
99
- mode: Literal["sequential", "parallel"] = "sequential"
100
- max_parallel: int = 5 # Max concurrent steps
101
- collect_metrics: bool = False # Collect execution metrics
102
-
103
-
104
- async def _execute_step(
105
- ctx: AgentContext,
106
- step: PipelineStep,
107
- input_value: Any,
108
- results: StepResults,
109
- ) -> StepResult:
110
- """Execute a single pipeline step."""
111
- start_time = asyncio.get_event_loop().time()
112
- retries = 0
113
-
114
- while True:
115
- try:
116
- # Check condition if any
117
- if step.condition and not step.condition.evaluate_with_value(input_value):
118
- return StepResult(success=True, result=input_value, duration=0)
119
-
120
- tool_info = await ctx.agent.tools.get_tool(step.tool) # Get the tool
121
- if isinstance(input_value, dict): # Prepare kwargs
122
- kwargs = {**input_value, **step.keyword_args}
123
- else:
124
- kwargs = {step.input_kwarg: input_value, **step.keyword_args}
125
-
126
- # Execute with timeout if specified
127
- if step.timeout:
128
- fut = tool_info.execute(ctx, **kwargs)
129
- result = await asyncio.wait_for(fut, timeout=step.timeout)
130
- else:
131
- result = await tool_info.execute(ctx, **kwargs)
132
-
133
- duration = asyncio.get_event_loop().time() - start_time
134
- return StepResult(success=True, result=result, duration=duration)
135
-
136
- except Exception as exc:
137
- match step.error_strategy:
138
- case ErrorStrategy.STOP:
139
- raise
140
-
141
- case ErrorStrategy.SKIP:
142
- duration = asyncio.get_event_loop().time() - start_time
143
- return StepResult(
144
- success=False,
145
- result=input_value,
146
- error=exc,
147
- duration=duration,
148
- )
149
-
150
- case ErrorStrategy.DEFAULT:
151
- duration = asyncio.get_event_loop().time() - start_time
152
- return StepResult(
153
- success=False,
154
- result=step.default_value,
155
- error=exc,
156
- duration=duration,
157
- )
158
-
159
- case ErrorStrategy.RETRY:
160
- retries += 1
161
- if retries <= step.max_retries:
162
- await anyio.sleep(step.retry_delay)
163
- continue
164
- raise # Max retries exceeded
165
-
166
-
167
- async def _execute_sequential(ctx: AgentContext, pipeline: Pipeline, results: StepResults) -> Any:
168
- """Execute steps sequentially."""
169
- current = pipeline.input
170
- for step in pipeline.steps:
171
- result = await _execute_step(ctx, step, current, results)
172
- if step.name:
173
- results[step.name] = result
174
- current = result.result
175
- return current
176
-
177
-
178
- async def _execute_parallel(ctx: AgentContext, pipeline: Pipeline, results: StepResults) -> Any:
179
- """Execute independent steps in parallel."""
180
- semaphore = asyncio.Semaphore(pipeline.max_parallel)
181
-
182
- async def run_step(step: PipelineStep) -> None:
183
- async with semaphore:
184
- # Wait for dependencies
185
- for dep in step.depends_on:
186
- while dep not in results:
187
- await anyio.sleep(0.1)
188
-
189
- # Get input from dependency or pipeline input
190
- input_value = results[step.depends_on[-1]].result if step.depends_on else pipeline.input
191
- result = await _execute_step(ctx, step, input_value, results)
192
- if step.name:
193
- results[step.name] = result
194
-
195
- # Create tasks for all steps
196
- tasks = [run_step(step) for step in pipeline.steps]
197
- await asyncio.gather(*tasks)
198
- # Return last result
199
- return results[name].result if (name := pipeline.steps[-1].name) else None
200
-
201
-
202
- async def chain_tools(
203
- ctx: AgentContext,
204
- input_data: str | dict[str, Any],
205
- steps: list[dict[str, Any]],
206
- mode: Literal["sequential", "parallel"] = "sequential",
207
- max_parallel: int = 5,
208
- collect_metrics: bool = False,
209
- ) -> Any:
210
- """Execute multiple tool operations in sequence or parallel.
211
-
212
- WHEN TO USE THIS TOOL:
213
- - Use this when you can plan multiple operations confidently in advance
214
- - Use this for common sequences you've successfully used before
215
- - Use this to reduce interaction rounds for known operation patterns
216
- - Use this when all steps are independent of intermediate results
217
-
218
- DO NOT USE THIS TOOL:
219
- - When you need to inspect intermediate results
220
- - When next steps depend on analyzing previous results
221
- - When you're unsure about the complete sequence
222
- - When you need to handle errors at each step individually
223
-
224
- Args:
225
- ctx: Agent context for tool execution
226
- input_data: Initial input for the pipeline
227
- steps: List of step configurations, each containing:
228
- - tool: Name of the tool to execute
229
- - input_kwarg: Keyword argument name for input (default: "text")
230
- - keyword_args: Additional keyword arguments
231
- - name: Optional step name for referencing
232
- - condition: Optional execution condition
233
- - error_strategy: How to handle errors ("stop", "skip", "default", "retry")
234
- - default_value: Value to use with "default" error strategy
235
- - max_retries: Maximum retry attempts
236
- - retry_delay: Delay between retries in seconds
237
- - timeout: Step timeout in seconds
238
- - depends_on: List of step names this depends on
239
- mode: Execution mode - "sequential" or "parallel"
240
- max_parallel: Maximum concurrent steps for parallel mode
241
- collect_metrics: Whether to collect execution metrics
242
-
243
- Examples:
244
- # Sequential processing
245
- await chain_tools(
246
- ctx,
247
- input_data="main.py",
248
- steps=[
249
- {"tool": "load_resource", "input_kwarg": "name"},
250
- {"tool": "analyze_code", "input_kwarg": "code"},
251
- {"tool": "format_output", "input_kwarg": "text"}
252
- ]
253
- )
254
-
255
- # Parallel processing with dependencies
256
- await chain_tools(
257
- ctx,
258
- input_data="test.py",
259
- mode="parallel",
260
- steps=[
261
- {"tool": "load_resource", "input_kwarg": "name", "name": "load"},
262
- {"tool": "analyze_code", "input_kwarg": "code", "depends_on": ["load"]},
263
- {"tool": "count_tokens", "input_kwarg": "text", "depends_on": ["load"]}
264
- ]
265
- )
266
- """
267
- try:
268
- pipeline = Pipeline(
269
- input=input_data,
270
- steps=[PipelineStep.model_validate(step) for step in steps],
271
- mode=mode,
272
- max_parallel=max_parallel,
273
- collect_metrics=collect_metrics,
274
- )
275
- except Exception as e:
276
- msg = f"Invalid pipeline configuration: {e}"
277
- raise ModelRetry(msg) from e
278
- results: StepResults = {}
279
-
280
- try:
281
- match pipeline.mode:
282
- case "sequential":
283
- return await _execute_sequential(ctx, pipeline, results)
284
- case "parallel":
285
- return await _execute_parallel(ctx, pipeline, results)
286
- except Exception as e:
287
- msg = f"Failed to execute pipeline: {e}"
288
- raise ModelRetry(msg) from e
@@ -1,36 +0,0 @@
1
- """Provider for history tools."""
2
-
3
- from __future__ import annotations
4
-
5
- from agentpool.agents.context import AgentContext # noqa: TC001
6
- from agentpool.resource_providers import StaticResourceProvider
7
-
8
-
9
- async def search_history(
10
- ctx: AgentContext,
11
- query: str | None = None,
12
- hours: int = 24,
13
- limit: int = 5,
14
- ) -> str:
15
- """Search conversation history."""
16
- from agentpool_storage.formatters import format_output
17
-
18
- if not ctx.pool:
19
- return "No agent pool available for history search"
20
- provider = ctx.pool.storage.get_history_provider()
21
- results = await provider.get_filtered_conversations(
22
- query=query,
23
- period=f"{hours}h",
24
- limit=limit,
25
- )
26
- return format_output(results)
27
-
28
-
29
- class HistoryTools(StaticResourceProvider):
30
- """Provider for history tools."""
31
-
32
- def __init__(self, name: str = "history") -> None:
33
- super().__init__(name=name)
34
- self._tools = [
35
- self.create_tool(search_history, category="search", read_only=True, idempotent=True),
36
- ]
@@ -1,85 +0,0 @@
1
- """Provider for integration tools."""
2
-
3
- from __future__ import annotations
4
-
5
- from typing import TYPE_CHECKING, Literal
6
-
7
- from pydantic import HttpUrl
8
-
9
- from agentpool.agents.context import AgentContext # noqa: TC001
10
- from agentpool.resource_providers import ResourceProvider
11
-
12
-
13
- if TYPE_CHECKING:
14
- from agentpool.tools.base import Tool
15
- from agentpool_config.mcp_server import MCPServerConfig
16
-
17
-
18
- async def add_local_mcp_server( # noqa: D417
19
- ctx: AgentContext,
20
- name: str,
21
- command: str,
22
- args: list[str] | None = None,
23
- env_vars: dict[str, str] | None = None,
24
- ) -> str:
25
- """Add a local MCP server via stdio transport.
26
-
27
- Args:
28
- name: Unique name for the MCP server
29
- command: Command to execute for the server
30
- args: Command arguments
31
- env_vars: Environment variables to pass to the server
32
-
33
- Returns:
34
- Confirmation message about the added server
35
- """
36
- from agentpool_config.mcp_server import StdioMCPServerConfig
37
-
38
- env = env_vars or {}
39
- config = StdioMCPServerConfig(name=name, command=command, args=args or [], env=env)
40
- await ctx.agent.mcp.setup_server_runtime(config)
41
- # New provider automatically available via aggregating provider
42
- return f"Added local MCP server **{name}** with command: **{command}**"
43
-
44
-
45
- async def add_remote_mcp_server( # noqa: D417
46
- ctx: AgentContext,
47
- name: str,
48
- url: str,
49
- transport: Literal["sse", "streamable-http"] = "streamable-http",
50
- ) -> str:
51
- """Add a remote MCP server via HTTP-based transport.
52
-
53
- Args:
54
- name: Unique name for the MCP server
55
- url: Server URL endpoint
56
- transport: HTTP transport type to use (http is preferred)
57
-
58
- Returns:
59
- Confirmation message about the added server
60
- """
61
- from agentpool_config.mcp_server import SSEMCPServerConfig, StreamableHTTPMCPServerConfig
62
-
63
- match transport:
64
- case "sse":
65
- config: MCPServerConfig = SSEMCPServerConfig(name=name, url=HttpUrl(url))
66
- case "streamable-http":
67
- config = StreamableHTTPMCPServerConfig(name=name, url=HttpUrl(url))
68
-
69
- await ctx.agent.mcp.setup_server_runtime(config)
70
- # New provider automatically available via aggregating provider
71
- return f"Added remote MCP server **{name}** at *{url}* using {transport} transport"
72
-
73
-
74
- class IntegrationTools(ResourceProvider):
75
- """Provider for integration tools."""
76
-
77
- def __init__(self, name: str = "integrations") -> None:
78
- super().__init__(name)
79
-
80
- async def get_tools(self) -> list[Tool]:
81
- """Get integration tools."""
82
- return [
83
- self.create_tool(add_local_mcp_server, category="other"),
84
- self.create_tool(add_remote_mcp_server, category="other", open_world=True),
85
- ]