agentpool 2.2.3__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 (250) hide show
  1. acp/__init__.py +0 -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/client/connection.py +38 -29
  7. acp/client/implementations/default_client.py +3 -2
  8. acp/client/implementations/headless_client.py +2 -2
  9. acp/connection.py +2 -2
  10. acp/notifications.py +18 -49
  11. acp/schema/__init__.py +2 -0
  12. acp/schema/agent_responses.py +21 -0
  13. acp/schema/client_requests.py +3 -3
  14. acp/schema/session_state.py +63 -29
  15. acp/task/supervisor.py +2 -2
  16. acp/utils.py +2 -2
  17. agentpool/__init__.py +2 -0
  18. agentpool/agents/acp_agent/acp_agent.py +278 -263
  19. agentpool/agents/acp_agent/acp_converters.py +150 -17
  20. agentpool/agents/acp_agent/client_handler.py +35 -24
  21. agentpool/agents/acp_agent/session_state.py +14 -6
  22. agentpool/agents/agent.py +471 -643
  23. agentpool/agents/agui_agent/agui_agent.py +104 -107
  24. agentpool/agents/agui_agent/helpers.py +3 -4
  25. agentpool/agents/base_agent.py +485 -32
  26. agentpool/agents/claude_code_agent/FORKING.md +191 -0
  27. agentpool/agents/claude_code_agent/__init__.py +13 -1
  28. agentpool/agents/claude_code_agent/claude_code_agent.py +654 -334
  29. agentpool/agents/claude_code_agent/converters.py +4 -141
  30. agentpool/agents/claude_code_agent/models.py +77 -0
  31. agentpool/agents/claude_code_agent/static_info.py +100 -0
  32. agentpool/agents/claude_code_agent/usage.py +242 -0
  33. agentpool/agents/events/__init__.py +22 -0
  34. agentpool/agents/events/builtin_handlers.py +65 -0
  35. agentpool/agents/events/event_emitter.py +3 -0
  36. agentpool/agents/events/events.py +84 -3
  37. agentpool/agents/events/infer_info.py +145 -0
  38. agentpool/agents/events/processors.py +254 -0
  39. agentpool/agents/interactions.py +41 -6
  40. agentpool/agents/modes.py +13 -0
  41. agentpool/agents/slashed_agent.py +5 -4
  42. agentpool/agents/tool_wrapping.py +18 -6
  43. agentpool/common_types.py +35 -21
  44. agentpool/config_resources/acp_assistant.yml +2 -2
  45. agentpool/config_resources/agents.yml +3 -0
  46. agentpool/config_resources/agents_template.yml +1 -0
  47. agentpool/config_resources/claude_code_agent.yml +9 -8
  48. agentpool/config_resources/external_acp_agents.yml +2 -1
  49. agentpool/delegation/base_team.py +4 -30
  50. agentpool/delegation/pool.py +104 -265
  51. agentpool/delegation/team.py +57 -57
  52. agentpool/delegation/teamrun.py +50 -55
  53. agentpool/functional/run.py +10 -4
  54. agentpool/mcp_server/client.py +73 -38
  55. agentpool/mcp_server/conversions.py +54 -13
  56. agentpool/mcp_server/manager.py +9 -23
  57. agentpool/mcp_server/registries/official_registry_client.py +10 -1
  58. agentpool/mcp_server/tool_bridge.py +114 -79
  59. agentpool/messaging/connection_manager.py +11 -10
  60. agentpool/messaging/event_manager.py +5 -5
  61. agentpool/messaging/message_container.py +6 -30
  62. agentpool/messaging/message_history.py +87 -8
  63. agentpool/messaging/messagenode.py +52 -14
  64. agentpool/messaging/messages.py +2 -26
  65. agentpool/messaging/processing.py +10 -22
  66. agentpool/models/__init__.py +1 -1
  67. agentpool/models/acp_agents/base.py +6 -2
  68. agentpool/models/acp_agents/mcp_capable.py +124 -15
  69. agentpool/models/acp_agents/non_mcp.py +0 -23
  70. agentpool/models/agents.py +66 -66
  71. agentpool/models/agui_agents.py +1 -1
  72. agentpool/models/claude_code_agents.py +111 -17
  73. agentpool/models/file_parsing.py +0 -1
  74. agentpool/models/manifest.py +70 -50
  75. agentpool/prompts/conversion_manager.py +1 -1
  76. agentpool/prompts/prompts.py +5 -2
  77. agentpool/resource_providers/__init__.py +2 -0
  78. agentpool/resource_providers/aggregating.py +4 -2
  79. agentpool/resource_providers/base.py +13 -3
  80. agentpool/resource_providers/codemode/code_executor.py +72 -5
  81. agentpool/resource_providers/codemode/helpers.py +2 -2
  82. agentpool/resource_providers/codemode/provider.py +64 -12
  83. agentpool/resource_providers/codemode/remote_mcp_execution.py +2 -2
  84. agentpool/resource_providers/codemode/remote_provider.py +9 -12
  85. agentpool/resource_providers/filtering.py +3 -1
  86. agentpool/resource_providers/mcp_provider.py +66 -12
  87. agentpool/resource_providers/plan_provider.py +111 -18
  88. agentpool/resource_providers/pool.py +5 -3
  89. agentpool/resource_providers/resource_info.py +111 -0
  90. agentpool/resource_providers/static.py +2 -2
  91. agentpool/sessions/__init__.py +2 -0
  92. agentpool/sessions/manager.py +2 -3
  93. agentpool/sessions/models.py +9 -6
  94. agentpool/sessions/protocol.py +28 -0
  95. agentpool/sessions/session.py +11 -55
  96. agentpool/storage/manager.py +361 -54
  97. agentpool/talk/registry.py +4 -4
  98. agentpool/talk/talk.py +9 -10
  99. agentpool/testing.py +1 -1
  100. agentpool/tool_impls/__init__.py +6 -0
  101. agentpool/tool_impls/agent_cli/__init__.py +42 -0
  102. agentpool/tool_impls/agent_cli/tool.py +95 -0
  103. agentpool/tool_impls/bash/__init__.py +64 -0
  104. agentpool/tool_impls/bash/helpers.py +35 -0
  105. agentpool/tool_impls/bash/tool.py +171 -0
  106. agentpool/tool_impls/delete_path/__init__.py +70 -0
  107. agentpool/tool_impls/delete_path/tool.py +142 -0
  108. agentpool/tool_impls/download_file/__init__.py +80 -0
  109. agentpool/tool_impls/download_file/tool.py +183 -0
  110. agentpool/tool_impls/execute_code/__init__.py +55 -0
  111. agentpool/tool_impls/execute_code/tool.py +163 -0
  112. agentpool/tool_impls/grep/__init__.py +80 -0
  113. agentpool/tool_impls/grep/tool.py +200 -0
  114. agentpool/tool_impls/list_directory/__init__.py +73 -0
  115. agentpool/tool_impls/list_directory/tool.py +197 -0
  116. agentpool/tool_impls/question/__init__.py +42 -0
  117. agentpool/tool_impls/question/tool.py +127 -0
  118. agentpool/tool_impls/read/__init__.py +104 -0
  119. agentpool/tool_impls/read/tool.py +305 -0
  120. agentpool/tools/__init__.py +2 -1
  121. agentpool/tools/base.py +114 -34
  122. agentpool/tools/manager.py +57 -1
  123. agentpool/ui/base.py +2 -2
  124. agentpool/ui/mock_provider.py +2 -2
  125. agentpool/ui/stdlib_provider.py +2 -2
  126. agentpool/utils/streams.py +21 -96
  127. agentpool/vfs_registry.py +7 -2
  128. {agentpool-2.2.3.dist-info → agentpool-2.5.0.dist-info}/METADATA +16 -22
  129. {agentpool-2.2.3.dist-info → agentpool-2.5.0.dist-info}/RECORD +242 -195
  130. {agentpool-2.2.3.dist-info → agentpool-2.5.0.dist-info}/WHEEL +1 -1
  131. agentpool_cli/__main__.py +20 -0
  132. agentpool_cli/create.py +1 -1
  133. agentpool_cli/serve_acp.py +59 -1
  134. agentpool_cli/serve_opencode.py +1 -1
  135. agentpool_cli/ui.py +557 -0
  136. agentpool_commands/__init__.py +12 -5
  137. agentpool_commands/agents.py +1 -1
  138. agentpool_commands/pool.py +260 -0
  139. agentpool_commands/session.py +1 -1
  140. agentpool_commands/text_sharing/__init__.py +119 -0
  141. agentpool_commands/text_sharing/base.py +123 -0
  142. agentpool_commands/text_sharing/github_gist.py +80 -0
  143. agentpool_commands/text_sharing/opencode.py +462 -0
  144. agentpool_commands/text_sharing/paste_rs.py +59 -0
  145. agentpool_commands/text_sharing/pastebin.py +116 -0
  146. agentpool_commands/text_sharing/shittycodingagent.py +112 -0
  147. agentpool_commands/utils.py +31 -32
  148. agentpool_config/__init__.py +30 -2
  149. agentpool_config/agentpool_tools.py +498 -0
  150. agentpool_config/converters.py +1 -1
  151. agentpool_config/event_handlers.py +42 -0
  152. agentpool_config/events.py +1 -1
  153. agentpool_config/forward_targets.py +1 -4
  154. agentpool_config/jinja.py +3 -3
  155. agentpool_config/mcp_server.py +1 -5
  156. agentpool_config/nodes.py +1 -1
  157. agentpool_config/observability.py +44 -0
  158. agentpool_config/session.py +0 -3
  159. agentpool_config/storage.py +38 -39
  160. agentpool_config/task.py +3 -3
  161. agentpool_config/tools.py +11 -28
  162. agentpool_config/toolsets.py +22 -90
  163. agentpool_server/a2a_server/agent_worker.py +307 -0
  164. agentpool_server/a2a_server/server.py +23 -18
  165. agentpool_server/acp_server/acp_agent.py +125 -56
  166. agentpool_server/acp_server/commands/acp_commands.py +46 -216
  167. agentpool_server/acp_server/commands/docs_commands/fetch_repo.py +8 -7
  168. agentpool_server/acp_server/event_converter.py +651 -0
  169. agentpool_server/acp_server/input_provider.py +53 -10
  170. agentpool_server/acp_server/server.py +1 -11
  171. agentpool_server/acp_server/session.py +90 -410
  172. agentpool_server/acp_server/session_manager.py +8 -34
  173. agentpool_server/agui_server/server.py +3 -1
  174. agentpool_server/mcp_server/server.py +5 -2
  175. agentpool_server/opencode_server/ENDPOINTS.md +53 -14
  176. agentpool_server/opencode_server/OPENCODE_UI_TOOLS_COMPLETE.md +202 -0
  177. agentpool_server/opencode_server/__init__.py +0 -8
  178. agentpool_server/opencode_server/converters.py +132 -26
  179. agentpool_server/opencode_server/input_provider.py +160 -8
  180. agentpool_server/opencode_server/models/__init__.py +42 -20
  181. agentpool_server/opencode_server/models/app.py +12 -0
  182. agentpool_server/opencode_server/models/events.py +203 -29
  183. agentpool_server/opencode_server/models/mcp.py +19 -0
  184. agentpool_server/opencode_server/models/message.py +18 -1
  185. agentpool_server/opencode_server/models/parts.py +134 -1
  186. agentpool_server/opencode_server/models/question.py +56 -0
  187. agentpool_server/opencode_server/models/session.py +13 -1
  188. agentpool_server/opencode_server/routes/__init__.py +4 -0
  189. agentpool_server/opencode_server/routes/agent_routes.py +33 -2
  190. agentpool_server/opencode_server/routes/app_routes.py +66 -3
  191. agentpool_server/opencode_server/routes/config_routes.py +66 -5
  192. agentpool_server/opencode_server/routes/file_routes.py +184 -5
  193. agentpool_server/opencode_server/routes/global_routes.py +1 -1
  194. agentpool_server/opencode_server/routes/lsp_routes.py +1 -1
  195. agentpool_server/opencode_server/routes/message_routes.py +122 -66
  196. agentpool_server/opencode_server/routes/permission_routes.py +63 -0
  197. agentpool_server/opencode_server/routes/pty_routes.py +23 -22
  198. agentpool_server/opencode_server/routes/question_routes.py +128 -0
  199. agentpool_server/opencode_server/routes/session_routes.py +139 -68
  200. agentpool_server/opencode_server/routes/tui_routes.py +1 -1
  201. agentpool_server/opencode_server/server.py +47 -2
  202. agentpool_server/opencode_server/state.py +30 -0
  203. agentpool_storage/__init__.py +0 -4
  204. agentpool_storage/base.py +81 -2
  205. agentpool_storage/claude_provider/ARCHITECTURE.md +433 -0
  206. agentpool_storage/claude_provider/__init__.py +42 -0
  207. agentpool_storage/{claude_provider.py → claude_provider/provider.py} +190 -8
  208. agentpool_storage/file_provider.py +149 -15
  209. agentpool_storage/memory_provider.py +132 -12
  210. agentpool_storage/opencode_provider/ARCHITECTURE.md +386 -0
  211. agentpool_storage/opencode_provider/__init__.py +16 -0
  212. agentpool_storage/opencode_provider/helpers.py +414 -0
  213. agentpool_storage/opencode_provider/provider.py +895 -0
  214. agentpool_storage/session_store.py +20 -6
  215. agentpool_storage/sql_provider/sql_provider.py +135 -2
  216. agentpool_storage/sql_provider/utils.py +2 -12
  217. agentpool_storage/zed_provider/__init__.py +16 -0
  218. agentpool_storage/zed_provider/helpers.py +281 -0
  219. agentpool_storage/zed_provider/models.py +130 -0
  220. agentpool_storage/zed_provider/provider.py +442 -0
  221. agentpool_storage/zed_provider.py +803 -0
  222. agentpool_toolsets/__init__.py +0 -2
  223. agentpool_toolsets/builtin/__init__.py +2 -4
  224. agentpool_toolsets/builtin/code.py +4 -4
  225. agentpool_toolsets/builtin/debug.py +115 -40
  226. agentpool_toolsets/builtin/execution_environment.py +54 -165
  227. agentpool_toolsets/builtin/skills.py +0 -77
  228. agentpool_toolsets/builtin/subagent_tools.py +64 -51
  229. agentpool_toolsets/builtin/workers.py +4 -2
  230. agentpool_toolsets/composio_toolset.py +2 -2
  231. agentpool_toolsets/entry_points.py +3 -1
  232. agentpool_toolsets/fsspec_toolset/grep.py +25 -5
  233. agentpool_toolsets/fsspec_toolset/helpers.py +3 -2
  234. agentpool_toolsets/fsspec_toolset/toolset.py +350 -66
  235. agentpool_toolsets/mcp_discovery/data/mcp_servers.parquet +0 -0
  236. agentpool_toolsets/mcp_discovery/toolset.py +74 -17
  237. agentpool_toolsets/mcp_run_toolset.py +8 -11
  238. agentpool_toolsets/notifications.py +33 -33
  239. agentpool_toolsets/openapi.py +3 -1
  240. agentpool_toolsets/search_toolset.py +3 -1
  241. agentpool_config/resources.py +0 -33
  242. agentpool_server/acp_server/acp_tools.py +0 -43
  243. agentpool_server/acp_server/commands/spawn.py +0 -210
  244. agentpool_storage/opencode_provider.py +0 -730
  245. agentpool_storage/text_log_provider.py +0 -276
  246. agentpool_toolsets/builtin/chain.py +0 -288
  247. agentpool_toolsets/builtin/user_interaction.py +0 -52
  248. agentpool_toolsets/semantic_memory_toolset.py +0 -536
  249. {agentpool-2.2.3.dist-info → agentpool-2.5.0.dist-info}/entry_points.txt +0 -0
  250. {agentpool-2.2.3.dist-info → agentpool-2.5.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,498 @@
1
+ """Models for agentpool standalone tool configuration."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Literal
6
+
7
+ from exxec_config import ExecutionEnvironmentConfig # noqa: TC002
8
+ from pydantic import ConfigDict, Field
9
+
10
+ from agentpool_config.converters import ConversionConfig # noqa: TC001
11
+ from agentpool_config.tools import BaseToolConfig
12
+
13
+
14
+ if TYPE_CHECKING:
15
+ from agentpool.tools.base import Tool
16
+
17
+
18
+ class BashToolConfig(BaseToolConfig):
19
+ """Configuration for bash command execution tool.
20
+
21
+ Example:
22
+ ```yaml
23
+ tools:
24
+ - type: bash
25
+ timeout: 30.0
26
+ output_limit: 10000
27
+ requires_confirmation: true
28
+ environment:
29
+ type: mock
30
+ deterministic_ids: true
31
+ ```
32
+ """
33
+
34
+ model_config = ConfigDict(title="Bash Tool")
35
+
36
+ type: Literal["bash"] = Field("bash", init=False)
37
+ """Bash command execution tool."""
38
+
39
+ timeout: float | None = Field(
40
+ default=None,
41
+ examples=[30.0, 60.0, 120.0],
42
+ title="Command timeout",
43
+ )
44
+ """Command timeout in seconds. None means no timeout."""
45
+
46
+ output_limit: int | None = Field(
47
+ default=None,
48
+ examples=[10000, 50000, 100000],
49
+ title="Output limit",
50
+ )
51
+ """Maximum bytes of output to return."""
52
+
53
+ environment: ExecutionEnvironmentConfig | None = Field(
54
+ default=None,
55
+ title="Execution environment",
56
+ )
57
+ """Execution environment for command execution. Falls back to agent's env if not set."""
58
+
59
+ def get_tool(self) -> Tool:
60
+ """Convert config to BashTool instance."""
61
+ from agentpool.tool_impls.bash import create_bash_tool
62
+
63
+ env = self.environment.get_provider() if self.environment else None
64
+ return create_bash_tool(
65
+ env=env,
66
+ timeout=self.timeout,
67
+ output_limit=self.output_limit,
68
+ name=self.name or "bash",
69
+ description=self.description or "Execute a shell command and return the output.",
70
+ requires_confirmation=self.requires_confirmation,
71
+ )
72
+
73
+
74
+ class AgentCliToolConfig(BaseToolConfig):
75
+ """Configuration for agent CLI tool.
76
+
77
+ Example:
78
+ ```yaml
79
+ tools:
80
+ - type: agent_cli
81
+ ```
82
+ """
83
+
84
+ model_config = ConfigDict(title="Agent CLI Tool")
85
+
86
+ type: Literal["agent_cli"] = Field("agent_cli", init=False)
87
+ """Agent CLI tool."""
88
+
89
+ def get_tool(self) -> Tool:
90
+ """Convert config to AgentCliTool instance."""
91
+ from agentpool.tool_impls.agent_cli import create_agent_cli_tool
92
+
93
+ return create_agent_cli_tool(
94
+ name=self.name or "run_agent_cli_command",
95
+ description=self.description or "Execute an internal agent management command.",
96
+ requires_confirmation=self.requires_confirmation,
97
+ )
98
+
99
+
100
+ class QuestionToolConfig(BaseToolConfig):
101
+ """Configuration for user interaction tool.
102
+
103
+ Example:
104
+ ```yaml
105
+ tools:
106
+ - type: question
107
+ ```
108
+ """
109
+
110
+ model_config = ConfigDict(title="Ask User Tool")
111
+
112
+ type: Literal["question"] = Field("question", init=False)
113
+ """User interaction tool."""
114
+
115
+ def get_tool(self) -> Tool:
116
+ """Convert config to QuestionTool instance."""
117
+ from agentpool.tool_impls.question import create_question_tool
118
+
119
+ return create_question_tool(
120
+ name=self.name or "question",
121
+ description=self.description or "Ask the user a clarifying question.",
122
+ requires_confirmation=self.requires_confirmation,
123
+ )
124
+
125
+
126
+ class ExecuteCodeToolConfig(BaseToolConfig):
127
+ """Configuration for Python code execution tool.
128
+
129
+ Example:
130
+ ```yaml
131
+ tools:
132
+ - type: execute_code
133
+ requires_confirmation: true
134
+ environment:
135
+ type: mock
136
+ deterministic_ids: true
137
+ ```
138
+ """
139
+
140
+ model_config = ConfigDict(title="Execute Code Tool")
141
+
142
+ type: Literal["execute_code"] = Field("execute_code", init=False)
143
+ """Python code execution tool."""
144
+
145
+ environment: ExecutionEnvironmentConfig | None = Field(
146
+ default=None,
147
+ title="Execution environment",
148
+ )
149
+ """Execution environment for code execution. Falls back to agent's env if not set."""
150
+
151
+ def get_tool(self) -> Tool:
152
+ """Convert config to ExecuteCodeTool instance."""
153
+ from agentpool.tool_impls.execute_code import create_execute_code_tool
154
+
155
+ env = self.environment.get_provider() if self.environment else None
156
+ return create_execute_code_tool(
157
+ env=env,
158
+ name=self.name or "execute_code",
159
+ description=self.description or "Execute Python code and return the result.",
160
+ requires_confirmation=self.requires_confirmation,
161
+ )
162
+
163
+
164
+ class ReadToolConfig(BaseToolConfig):
165
+ """Configuration for file reading tool.
166
+
167
+ Example:
168
+ ```yaml
169
+ tools:
170
+ - type: read
171
+ max_file_size_kb: 128
172
+ max_image_size: 1500
173
+ large_file_tokens: 10000
174
+ conversion:
175
+ default_provider: markitdown
176
+ environment:
177
+ type: local
178
+ ```
179
+ """
180
+
181
+ model_config = ConfigDict(title="Read Tool")
182
+
183
+ type: Literal["read"] = Field("read", init=False)
184
+ """File reading tool."""
185
+
186
+ environment: ExecutionEnvironmentConfig | None = Field(
187
+ default=None,
188
+ title="Execution environment",
189
+ )
190
+ """Execution environment for filesystem access. Falls back to agent's env if not set."""
191
+
192
+ cwd: str | None = Field(
193
+ default=None,
194
+ title="Working directory",
195
+ )
196
+ """Working directory for resolving relative paths."""
197
+
198
+ max_file_size_kb: int = Field(
199
+ default=64,
200
+ examples=[64, 128, 256],
201
+ title="Max file size",
202
+ )
203
+ """Maximum file size in KB for read operations."""
204
+
205
+ max_image_size: int | None = Field(
206
+ default=2000,
207
+ examples=[1500, 2000, 2500],
208
+ title="Max image dimensions",
209
+ )
210
+ """Max width/height for images in pixels. Images are auto-resized if larger."""
211
+
212
+ max_image_bytes: int | None = Field(
213
+ default=None,
214
+ title="Max image file size",
215
+ )
216
+ """Max file size for images in bytes. Images are compressed if larger."""
217
+
218
+ large_file_tokens: int = Field(
219
+ default=12_000,
220
+ examples=[10_000, 12_000, 15_000],
221
+ title="Large file threshold",
222
+ )
223
+ """Token threshold for switching to structure map for large files."""
224
+
225
+ map_max_tokens: int = Field(
226
+ default=2048,
227
+ examples=[1024, 2048, 4096],
228
+ title="Structure map max tokens",
229
+ )
230
+ """Maximum tokens for structure map output."""
231
+
232
+ conversion: ConversionConfig | None = Field(
233
+ default=None,
234
+ title="Conversion config",
235
+ )
236
+ """Optional conversion config for binary files. If set, converts supported files to markdown."""
237
+
238
+ def get_tool(self) -> Tool:
239
+ """Convert config to ReadTool instance."""
240
+ from agentpool.tool_impls.read import create_read_tool
241
+
242
+ env = self.environment.get_provider() if self.environment else None
243
+
244
+ # Create converter if conversion config is provided
245
+ converter = None
246
+ if self.conversion is not None:
247
+ try:
248
+ from agentpool.prompts.conversion_manager import ConversionManager
249
+
250
+ converter = ConversionManager(self.conversion)
251
+ except Exception: # noqa: BLE001
252
+ # ConversionManager not available, continue without it
253
+ pass
254
+
255
+ return create_read_tool(
256
+ env=env,
257
+ converter=converter,
258
+ cwd=self.cwd,
259
+ max_file_size_kb=self.max_file_size_kb,
260
+ max_image_size=self.max_image_size,
261
+ max_image_bytes=self.max_image_bytes,
262
+ large_file_tokens=self.large_file_tokens,
263
+ map_max_tokens=self.map_max_tokens,
264
+ name=self.name or "read",
265
+ description=self.description or "Read file contents with automatic format detection.",
266
+ requires_confirmation=self.requires_confirmation,
267
+ )
268
+
269
+
270
+ class ListDirectoryToolConfig(BaseToolConfig):
271
+ """Configuration for directory listing tool.
272
+
273
+ Example:
274
+ ```yaml
275
+ tools:
276
+ - type: list_directory
277
+ max_items: 1000
278
+ environment:
279
+ type: local
280
+ ```
281
+ """
282
+
283
+ model_config = ConfigDict(title="List Directory Tool")
284
+
285
+ type: Literal["list_directory"] = Field("list_directory", init=False)
286
+ """Directory listing tool."""
287
+
288
+ environment: ExecutionEnvironmentConfig | None = Field(
289
+ default=None,
290
+ title="Execution environment",
291
+ )
292
+ """Execution environment for filesystem access. Falls back to agent's env if not set."""
293
+
294
+ cwd: str | None = Field(
295
+ default=None,
296
+ title="Working directory",
297
+ )
298
+ """Working directory for resolving relative paths."""
299
+
300
+ max_items: int = Field(
301
+ default=500,
302
+ examples=[500, 1000, 2000],
303
+ title="Max items",
304
+ )
305
+ """Maximum number of items to return (safety limit)."""
306
+
307
+ def get_tool(self) -> Tool:
308
+ """Convert config to ListDirectoryTool instance."""
309
+ from agentpool.tool_impls.list_directory import create_list_directory_tool
310
+
311
+ env = self.environment.get_provider() if self.environment else None
312
+ return create_list_directory_tool(
313
+ env=env,
314
+ cwd=self.cwd,
315
+ max_items=self.max_items,
316
+ name=self.name or "list_directory",
317
+ description=self.description or "List files in a directory with filtering support.",
318
+ requires_confirmation=self.requires_confirmation,
319
+ )
320
+
321
+
322
+ class GrepToolConfig(BaseToolConfig):
323
+ """Configuration for grep search tool.
324
+
325
+ Example:
326
+ ```yaml
327
+ tools:
328
+ - type: grep
329
+ max_output_kb: 128
330
+ use_subprocess_grep: true
331
+ environment:
332
+ type: local
333
+ ```
334
+ """
335
+
336
+ model_config = ConfigDict(title="Grep Tool")
337
+
338
+ type: Literal["grep"] = Field("grep", init=False)
339
+ """Grep search tool."""
340
+
341
+ environment: ExecutionEnvironmentConfig | None = Field(
342
+ default=None,
343
+ title="Execution environment",
344
+ )
345
+ """Execution environment for filesystem access. Falls back to agent's env if not set."""
346
+
347
+ cwd: str | None = Field(
348
+ default=None,
349
+ title="Working directory",
350
+ )
351
+ """Working directory for resolving relative paths."""
352
+
353
+ max_output_kb: int = Field(
354
+ default=64,
355
+ examples=[64, 128, 256],
356
+ title="Max output size",
357
+ )
358
+ """Maximum output size in KB."""
359
+
360
+ use_subprocess_grep: bool = Field(
361
+ default=True,
362
+ title="Use subprocess grep",
363
+ )
364
+ """Use ripgrep/grep subprocess if available (faster for large codebases)."""
365
+
366
+ def get_tool(self) -> Tool:
367
+ """Convert config to GrepTool instance."""
368
+ from agentpool.tool_impls.grep import create_grep_tool
369
+
370
+ env = self.environment.get_provider() if self.environment else None
371
+ return create_grep_tool(
372
+ env=env,
373
+ cwd=self.cwd,
374
+ max_output_kb=self.max_output_kb,
375
+ use_subprocess_grep=self.use_subprocess_grep,
376
+ name=self.name or "grep",
377
+ description=self.description or "Search file contents for patterns.",
378
+ requires_confirmation=self.requires_confirmation,
379
+ )
380
+
381
+
382
+ class DeletePathToolConfig(BaseToolConfig):
383
+ """Configuration for delete path tool.
384
+
385
+ Example:
386
+ ```yaml
387
+ tools:
388
+ - type: delete_path
389
+ requires_confirmation: true
390
+ environment:
391
+ type: local
392
+ ```
393
+ """
394
+
395
+ model_config = ConfigDict(title="Delete Path Tool")
396
+
397
+ type: Literal["delete_path"] = Field("delete_path", init=False)
398
+ """Delete path tool."""
399
+
400
+ environment: ExecutionEnvironmentConfig | None = Field(
401
+ default=None,
402
+ title="Execution environment",
403
+ )
404
+ """Execution environment for filesystem access. Falls back to agent's env if not set."""
405
+
406
+ cwd: str | None = Field(
407
+ default=None,
408
+ title="Working directory",
409
+ )
410
+ """Working directory for resolving relative paths."""
411
+
412
+ def get_tool(self) -> Tool:
413
+ """Convert config to DeletePathTool instance."""
414
+ from agentpool.tool_impls.delete_path import create_delete_path_tool
415
+
416
+ env = self.environment.get_provider() if self.environment else None
417
+ return create_delete_path_tool(
418
+ env=env,
419
+ cwd=self.cwd,
420
+ name=self.name or "delete_path",
421
+ description=self.description or "Delete a file or directory.",
422
+ requires_confirmation=self.requires_confirmation,
423
+ )
424
+
425
+
426
+ class DownloadFileToolConfig(BaseToolConfig):
427
+ """Configuration for file download tool.
428
+
429
+ Example:
430
+ ```yaml
431
+ tools:
432
+ - type: download_file
433
+ chunk_size: 16384
434
+ timeout: 60.0
435
+ environment:
436
+ type: local
437
+ ```
438
+ """
439
+
440
+ model_config = ConfigDict(title="Download File Tool")
441
+
442
+ type: Literal["download_file"] = Field("download_file", init=False)
443
+ """File download tool."""
444
+
445
+ environment: ExecutionEnvironmentConfig | None = Field(
446
+ default=None,
447
+ title="Execution environment",
448
+ )
449
+ """Execution environment for filesystem access. Falls back to agent's env if not set."""
450
+
451
+ cwd: str | None = Field(
452
+ default=None,
453
+ title="Working directory",
454
+ )
455
+ """Working directory for resolving relative paths."""
456
+
457
+ chunk_size: int = Field(
458
+ default=8192,
459
+ examples=[8192, 16384, 32768],
460
+ title="Chunk size",
461
+ )
462
+ """Size of chunks to download in bytes."""
463
+
464
+ timeout: float = Field(
465
+ default=30.0,
466
+ examples=[30.0, 60.0, 120.0],
467
+ title="Request timeout",
468
+ )
469
+ """Request timeout in seconds."""
470
+
471
+ def get_tool(self) -> Tool:
472
+ """Convert config to DownloadFileTool instance."""
473
+ from agentpool.tool_impls.download_file import create_download_file_tool
474
+
475
+ env = self.environment.get_provider() if self.environment else None
476
+ return create_download_file_tool(
477
+ env=env,
478
+ cwd=self.cwd,
479
+ chunk_size=self.chunk_size,
480
+ timeout=self.timeout,
481
+ name=self.name or "download_file",
482
+ description=self.description or "Download a file from a URL.",
483
+ requires_confirmation=self.requires_confirmation,
484
+ )
485
+
486
+
487
+ # Union type for agentpool tool configs
488
+ AgentpoolToolConfig = (
489
+ AgentCliToolConfig
490
+ | QuestionToolConfig
491
+ | BashToolConfig
492
+ | DeletePathToolConfig
493
+ | DownloadFileToolConfig
494
+ | ExecuteCodeToolConfig
495
+ | GrepToolConfig
496
+ | ListDirectoryToolConfig
497
+ | ReadToolConfig
498
+ )
@@ -2,7 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from docler.configs import ConverterConfig
5
+ from docler_config import ConverterConfig
6
6
  from pydantic import ConfigDict, Field
7
7
  from schemez import Schema
8
8
 
@@ -392,6 +392,47 @@ class CallbackEventHandlerConfig(BaseEventHandlerConfig):
392
392
  return import_callable(self.import_path)
393
393
 
394
394
 
395
+ class FileStreamEventHandlerConfig(BaseEventHandlerConfig):
396
+ """Configuration for streaming agent output to a file."""
397
+
398
+ model_config = ConfigDict(title="File Stream Event Handler")
399
+
400
+ type: Literal["file"] = Field("file", init=False)
401
+ """File stream event handler."""
402
+
403
+ path: str = Field(
404
+ examples=["~/agent_output.txt", "/tmp/agent.log", "./output.md"],
405
+ )
406
+ """Path to the output file. Supports ~ expansion."""
407
+
408
+ mode: Literal["w", "a"] = Field(
409
+ default="a",
410
+ examples=["w", "a"],
411
+ )
412
+ """File open mode.
413
+
414
+ - w: Overwrite file on each run
415
+ - a: Append to existing file
416
+ """
417
+
418
+ include_tools: bool = Field(default=False)
419
+ """Whether to include tool call and result information."""
420
+
421
+ include_thinking: bool = Field(default=False)
422
+ """Whether to include thinking/reasoning content."""
423
+
424
+ def get_handler(self) -> IndividualEventHandler:
425
+ """Create and return the file stream handler."""
426
+ from agentpool.agents.events.builtin_handlers import create_file_stream_handler
427
+
428
+ return create_file_stream_handler(
429
+ path=self.path,
430
+ mode=self.mode,
431
+ include_tools=self.include_tools,
432
+ include_thinking=self.include_thinking,
433
+ )
434
+
435
+
395
436
  class TTSEventHandlerConfig(BaseEventHandlerConfig):
396
437
  """Configuration for Text-to-Speech event handler with OpenAI streaming."""
397
438
 
@@ -578,6 +619,7 @@ class EdgeTTSEventHandlerConfig(BaseEventHandlerConfig):
578
619
  EventHandlerConfig = Annotated[
579
620
  StdoutEventHandlerConfig
580
621
  | CallbackEventHandlerConfig
622
+ | FileStreamEventHandlerConfig
581
623
  | TTSEventHandlerConfig
582
624
  | EdgeTTSEventHandlerConfig,
583
625
  Field(discriminator="type"),
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  from typing import TYPE_CHECKING, Annotated, Any, Literal
6
6
 
7
- from evented.configs import (
7
+ from evented_config import (
8
8
  EmailConfig,
9
9
  EventSourceConfig,
10
10
  FileWatchConfig,
@@ -118,9 +118,6 @@ class NodeConnectionConfig(ConnectionConfig):
118
118
 
119
119
  DEFAULT_MESSAGE_TEMPLATE = """
120
120
  [{{ message.timestamp.strftime('%Y-%m-%d %H:%M:%S') }}] {{ message.name }}: {{ message.content }}
121
- {%- if message.forwarded_from %}
122
- (via: {{ message.forwarded_from|join(' -> ') }})
123
- {%- endif %}
124
121
  """
125
122
 
126
123
 
@@ -135,7 +132,7 @@ class FileConnectionConfig(ConnectionConfig):
135
132
  - role: Message role (user/assistant/system)
136
133
  - model: Model used (if any)
137
134
  - cost_info: Token usage and cost info
138
- - forwarded_from: Chain of message forwarding
135
+ - parent_id: ID of parent message for tracking chains
139
136
  """
140
137
 
141
138
  model_config = ConfigDict(json_schema_extra={"title": "File Connection Configuration"})
agentpool_config/jinja.py CHANGED
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING, Any, Literal
7
7
  from pydantic import BaseModel, ConfigDict, Field
8
8
  from schemez import Schema
9
9
 
10
- from agentpool_config.tools import ToolConfig
10
+ from agentpool_config import ToolConfig
11
11
 
12
12
 
13
13
  if TYPE_CHECKING:
@@ -141,9 +141,9 @@ class Jinja2EnvironmentConfig(Schema):
141
141
  try:
142
142
  # Convert filters - use tool name as filter name
143
143
  tools = [cfg.get_tool() for cfg in self.filters]
144
- kwargs["filters"] = {tool.name: tool.callable for tool in tools}
144
+ kwargs["filters"] = {tool.name: tool.get_callable() for tool in tools}
145
145
  tools = [cfg.get_tool() for cfg in self.tests]
146
- kwargs["tests"] = {tool.name: tool.callable for tool in tools}
146
+ kwargs["tests"] = {tool.name: tool.get_callable() for tool in tools}
147
147
 
148
148
  except Exception as exc:
149
149
  msg = f"Failed to import Jinja2 filters/tests: {exc}"
@@ -138,11 +138,7 @@ class BaseMCPServerConfig(Schema):
138
138
  return env
139
139
 
140
140
  def to_pydantic_ai(self) -> MCPServer:
141
- """Convert to pydantic-ai MCP server instance.
142
-
143
- Returns:
144
- A pydantic-ai MCP server instance
145
- """
141
+ """Convert to pydantic-ai MCP server instance."""
146
142
  raise NotImplementedError
147
143
 
148
144
  @property
agentpool_config/nodes.py CHANGED
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  from typing import TYPE_CHECKING, Any, Literal
6
6
 
7
- from evented.configs import EventConfig
7
+ from evented_config import EventConfig
8
8
  from pydantic import ConfigDict, Field, ImportString
9
9
  from schemez import Schema
10
10
 
@@ -149,6 +149,49 @@ class ArizePhoenixObservabilityConfig(BaseObservabilityConfig):
149
149
  object.__setattr__(self, "_headers", headers)
150
150
 
151
151
 
152
+ class AxiomObservabilityConfig(BaseObservabilityConfig):
153
+ """Configuration for Axiom endpoint."""
154
+
155
+ model_config = ConfigDict(json_schema_extra={"x-doc-title": "Axiom"})
156
+
157
+ type: Literal["axiom"] = "axiom"
158
+ """Axiom observability configuration."""
159
+
160
+ api_token: SecretStr | None = Field(default=None, title="Axiom API token")
161
+ """Axiom API token with ingest permissions."""
162
+
163
+ dataset: str = Field(
164
+ examples=["traces", "otel-traces", "my-service-traces"],
165
+ title="Dataset name",
166
+ )
167
+ """Axiom dataset name where traces are sent."""
168
+
169
+ region: Literal["us", "eu"] | None = Field(
170
+ default=None,
171
+ examples=["us", "eu"],
172
+ title="Region",
173
+ )
174
+ """Axiom region. If not set, uses default cloud endpoint."""
175
+
176
+ _endpoint: str = PrivateAttr()
177
+ _headers: dict[str, str] = PrivateAttr(default_factory=dict)
178
+
179
+ def model_post_init(self, __context: Any, /) -> None:
180
+ """Compute private attributes from user config."""
181
+ # Axiom uses /v1/traces endpoint for OTLP
182
+ if self.region == "eu":
183
+ endpoint = "https://api.eu.axiom.co/v1/traces"
184
+ else:
185
+ endpoint = "https://api.axiom.co/v1/traces"
186
+ object.__setattr__(self, "_endpoint", endpoint)
187
+
188
+ headers: dict[str, str] = {}
189
+ if self.api_token:
190
+ headers["Authorization"] = f"Bearer {self.api_token.get_secret_value()}"
191
+ headers["X-Axiom-Dataset"] = self.dataset
192
+ object.__setattr__(self, "_headers", headers)
193
+
194
+
152
195
  class CustomObservabilityConfig(BaseObservabilityConfig):
153
196
  """Configuration for custom OTEL endpoint."""
154
197
 
@@ -173,6 +216,7 @@ ObservabilityProviderConfig = Annotated[
173
216
  | LangsmithObservabilityConfig
174
217
  | AgentOpsObservabilityConfig
175
218
  | ArizePhoenixObservabilityConfig
219
+ | AxiomObservabilityConfig
176
220
  | CustomObservabilityConfig,
177
221
  Field(discriminator="type"),
178
222
  ]