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
acp/__init__.py CHANGED
@@ -3,7 +3,6 @@
3
3
  from acp.client import DefaultACPClient, HeadlessACPClient, NoOpClient, ClientSideConnection
4
4
  from acp.agent import AgentSideConnection
5
5
  from acp.bridge import ACPBridge, BridgeSettings
6
- from acp.filesystem import ACPFileSystem, ACPPath
7
6
  from acp.agent.protocol import Agent
8
7
  from acp.client.protocol import Client
9
8
  from acp.terminal_handle import TerminalHandle
@@ -173,9 +172,6 @@ __all__ = [ # noqa: RUF022
173
172
  "FileSystemCapability",
174
173
  # stdio helper
175
174
  "stdio_streams",
176
- # filesystem
177
- "ACPFileSystem",
178
- "ACPPath",
179
175
  # transport
180
176
  "serve",
181
177
  "StdioTransport",
acp/acp_requests.py CHANGED
@@ -3,7 +3,9 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import asyncio
6
- from typing import TYPE_CHECKING
6
+ from typing import TYPE_CHECKING, Any
7
+
8
+ import structlog
7
9
 
8
10
  from acp.schema import (
9
11
  CreateTerminalRequest,
@@ -19,7 +21,6 @@ from acp.schema import (
19
21
  WriteTextFileRequest,
20
22
  )
21
23
  from acp.terminal_handle import TerminalHandle
22
- from agentpool.log import get_logger
23
24
 
24
25
 
25
26
  if TYPE_CHECKING:
@@ -30,20 +31,10 @@ if TYPE_CHECKING:
30
31
  WaitForTerminalExitResponse,
31
32
  )
32
33
 
33
- logger = get_logger(__name__)
34
+ logger = structlog.get_logger(__name__)
34
35
 
35
36
 
36
- RULES_FILE_NAMES = [
37
- ".rules",
38
- "CLAUDE.md",
39
- "AGENT.md",
40
- "AGENTS.md",
41
- "GEMINI.md",
42
- ".cursorrules",
43
- ".windsurfrules",
44
- ".clinerules",
45
- ".github/copilot-instructions.md",
46
- ]
37
+ RULES_FILE_NAMES = ["CLAUDE.md", "AGENTS.md"]
47
38
 
48
39
 
49
40
  class ACPRequests:
@@ -54,12 +45,7 @@ class ACPRequests:
54
45
  """
55
46
 
56
47
  def __init__(self, client: Client, session_id: str) -> None:
57
- """Initialize requests helper.
58
-
59
- Args:
60
- client: ACP client
61
- session_id: Session ID
62
- """
48
+ """Initialize requests helper."""
63
49
  self.client = client
64
50
  self.id = session_id
65
51
 
@@ -80,12 +66,7 @@ class ACPRequests:
80
66
  Returns:
81
67
  File content as string
82
68
  """
83
- request = ReadTextFileRequest(
84
- session_id=self.id,
85
- path=path,
86
- limit=limit,
87
- line=line,
88
- )
69
+ request = ReadTextFileRequest(session_id=self.id, path=path, limit=limit, line=line)
89
70
  response = await self.client.read_text_file(request)
90
71
  return response.content
91
72
 
@@ -104,12 +85,7 @@ class ACPRequests:
104
85
  return None
105
86
 
106
87
  async def write_text_file(self, path: str, content: str) -> None:
107
- """Write text content to a file.
108
-
109
- Args:
110
- path: File path to write
111
- content: Text content to write
112
- """
88
+ """Write text content to a file."""
113
89
  request = WriteTextFileRequest(session_id=self.id, path=path, content=content)
114
90
  await self.client.write_text_file(request)
115
91
 
@@ -146,47 +122,22 @@ class ACPRequests:
146
122
  return TerminalHandle(terminal_id=response.terminal_id, requests=self)
147
123
 
148
124
  async def terminal_output(self, terminal_id: str) -> TerminalOutputResponse:
149
- """Get output from a terminal session.
150
-
151
- Args:
152
- terminal_id: Terminal identifier
153
-
154
- Returns:
155
- Terminal output response
156
- """
125
+ """Get output from a terminal session."""
157
126
  request = TerminalOutputRequest(session_id=self.id, terminal_id=terminal_id)
158
127
  return await self.client.terminal_output(request)
159
128
 
160
- async def wait_for_terminal_exit(
161
- self,
162
- terminal_id: str,
163
- ) -> WaitForTerminalExitResponse:
164
- """Wait for a terminal to exit.
165
-
166
- Args:
167
- terminal_id: Terminal identifier
168
-
169
- Returns:
170
- Terminal exit response with exit_code
171
- """
129
+ async def wait_for_terminal_exit(self, terminal_id: str) -> WaitForTerminalExitResponse:
130
+ """Wait for a terminal to exit."""
172
131
  request = WaitForTerminalExitRequest(session_id=self.id, terminal_id=terminal_id)
173
132
  return await self.client.wait_for_terminal_exit(request)
174
133
 
175
134
  async def kill_terminal(self, terminal_id: str) -> None:
176
- """Kill a terminal session.
177
-
178
- Args:
179
- terminal_id: Terminal identifier to kill
180
- """
135
+ """Kill a terminal session."""
181
136
  request = KillTerminalCommandRequest(session_id=self.id, terminal_id=terminal_id)
182
137
  await self.client.kill_terminal(request)
183
138
 
184
139
  async def release_terminal(self, terminal_id: str) -> None:
185
- """Release a terminal session.
186
-
187
- Args:
188
- terminal_id: Terminal identifier to release
189
- """
140
+ """Release a terminal session."""
190
141
  request = ReleaseTerminalRequest(session_id=self.id, terminal_id=terminal_id)
191
142
  await self.client.release_terminal(request)
192
143
 
@@ -228,10 +179,8 @@ class ACPRequests:
228
179
  try:
229
180
  if timeout_seconds: # Wait for completion (with optional timeout)
230
181
  try:
231
- exit_result = await asyncio.wait_for(
232
- self.wait_for_terminal_exit(terminal_id),
233
- timeout=timeout_seconds,
234
- )
182
+ coro = self.wait_for_terminal_exit(terminal_id)
183
+ exit_result = await asyncio.wait_for(coro, timeout=timeout_seconds)
235
184
  except TimeoutError: # Kill on timeout and get partial output
236
185
  await self.kill_terminal(terminal_id)
237
186
  output_response = await self.terminal_output(terminal_id)
@@ -250,6 +199,7 @@ class ACPRequests:
250
199
  tool_call_id: str,
251
200
  *,
252
201
  title: str | None = None,
202
+ raw_input: Any | None = None,
253
203
  options: list[PermissionOption] | None = None,
254
204
  ) -> RequestPermissionResponse:
255
205
  """Request permission from user before executing a tool call.
@@ -257,6 +207,7 @@ class ACPRequests:
257
207
  Args:
258
208
  tool_call_id: Unique identifier for the tool call
259
209
  title: Human-readable description of the operation
210
+ raw_input: The raw input parameters for the tool call
260
211
  options: Available permission options (defaults to allow/reject once)
261
212
 
262
213
  Returns:
@@ -264,19 +215,11 @@ class ACPRequests:
264
215
  """
265
216
  if options is None:
266
217
  options = [
267
- PermissionOption(
268
- option_id="allow-once",
269
- name="Allow once",
270
- kind="allow_once",
271
- ),
272
- PermissionOption(
273
- option_id="reject-once",
274
- name="Reject",
275
- kind="reject_once",
276
- ),
218
+ PermissionOption(option_id="allow-once", name="Allow once", kind="allow_once"),
219
+ PermissionOption(option_id="reject-once", name="Reject", kind="reject_once"),
277
220
  ]
278
221
 
279
- tool_call = ToolCall(tool_call_id=tool_call_id, title=title)
222
+ tool_call = ToolCall(tool_call_id=tool_call_id, title=title, raw_input=raw_input)
280
223
  request = RequestPermissionRequest(
281
224
  session_id=self.id,
282
225
  tool_call=tool_call,
acp/agent/connection.py CHANGED
@@ -30,6 +30,7 @@ from acp.schema import (
30
30
  RequestPermissionRequest,
31
31
  RequestPermissionResponse,
32
32
  SessionNotification,
33
+ SetSessionConfigOptionRequest,
33
34
  SetSessionModelRequest,
34
35
  SetSessionModeRequest,
35
36
  TerminalOutputRequest,
@@ -243,6 +244,13 @@ async def _agent_handler( # noqa: PLR0911
243
244
  if (model_result := await agent.set_session_model(set_model_request))
244
245
  else {}
245
246
  )
247
+ case "session/set_config_option":
248
+ set_config_request = SetSessionConfigOptionRequest.model_validate(params)
249
+ return (
250
+ config_result.model_dump(by_alias=True, exclude_none=True)
251
+ if (config_result := await agent.set_session_config_option(set_config_request))
252
+ else {}
253
+ )
246
254
  case "authenticate":
247
255
  p = AuthenticateRequest.model_validate(params)
248
256
  result = await agent.authenticate(p)
@@ -25,6 +25,7 @@ import anyio
25
25
  from fastapi import FastAPI, HTTPException
26
26
  from fastapi.responses import HTMLResponse
27
27
  from pydantic import BaseModel, Field
28
+ import structlog
28
29
  import uvicorn
29
30
 
30
31
  from acp import AgentSideConnection
@@ -57,7 +58,6 @@ from acp.schema import (
57
58
  WriteTextFileResponse,
58
59
  )
59
60
  from acp.stdio import stdio_streams
60
- from agentpool.log import get_logger
61
61
 
62
62
 
63
63
  if TYPE_CHECKING:
@@ -81,7 +81,7 @@ if TYPE_CHECKING:
81
81
  )
82
82
 
83
83
 
84
- logger = get_logger(__name__)
84
+ logger = structlog.get_logger(__name__)
85
85
  MOCK_FILE = """\
86
86
  # Mock file: {path}
87
87
  # Generated by ACP Debug Server
@@ -190,6 +190,10 @@ class MockAgent(Agent):
190
190
  """Mock session model change."""
191
191
  logger.info("Mock session model change")
192
192
 
193
+ async def set_session_config_option(self, params: Any) -> None:
194
+ """Mock session config option change."""
195
+ logger.info("Mock session config option change")
196
+
193
197
  async def ext_notification(self, method: str, params: dict[str, Any]) -> None:
194
198
  """Mock extensibility notification."""
195
199
  logger.info("Mock ext notification", method=method)
acp/agent/protocol.py CHANGED
@@ -24,6 +24,8 @@ if TYPE_CHECKING:
24
24
  PromptResponse,
25
25
  ResumeSessionRequest,
26
26
  ResumeSessionResponse,
27
+ SetSessionConfigOptionRequest,
28
+ SetSessionConfigOptionResponse,
27
29
  SetSessionModelRequest,
28
30
  SetSessionModelResponse,
29
31
  SetSessionModeRequest,
@@ -60,6 +62,10 @@ class Agent(Protocol):
60
62
  self, params: SetSessionModelRequest
61
63
  ) -> SetSessionModelResponse | None: ...
62
64
 
65
+ async def set_session_config_option(
66
+ self, params: SetSessionConfigOptionRequest
67
+ ) -> SetSessionConfigOptionResponse | None: ...
68
+
63
69
  async def ext_method(self, method: str, params: dict[str, Any]) -> dict[str, Any]: ...
64
70
 
65
71
  async def ext_notification(self, method: str, params: dict[str, Any]) -> None: ...
acp/client/connection.py CHANGED
@@ -7,8 +7,35 @@ from typing import TYPE_CHECKING, Any, Self
7
7
 
8
8
  import logfire
9
9
 
10
+ from acp.agent.protocol import Agent
11
+ from acp.connection import Connection
12
+ from acp.exceptions import RequestError
13
+ from acp.schema import (
14
+ AuthenticateResponse,
15
+ CreateTerminalRequest,
16
+ ForkSessionResponse,
17
+ InitializeResponse,
18
+ KillTerminalCommandRequest,
19
+ ListSessionsResponse,
20
+ LoadSessionResponse,
21
+ NewSessionResponse,
22
+ PromptResponse,
23
+ ReadTextFileRequest,
24
+ ReleaseTerminalRequest,
25
+ RequestPermissionRequest,
26
+ ResumeSessionResponse,
27
+ SessionNotification,
28
+ SetSessionConfigOptionResponse,
29
+ SetSessionModelResponse,
30
+ SetSessionModeResponse,
31
+ TerminalOutputRequest,
32
+ WaitForTerminalExitRequest,
33
+ WriteTextFileRequest,
34
+ )
35
+
10
36
 
11
37
  if TYPE_CHECKING:
38
+ from collections.abc import Callable
12
39
  from types import TracebackType
13
40
 
14
41
  from anyio.abc import ByteReceiveStream, ByteSendStream
@@ -31,6 +58,7 @@ if TYPE_CHECKING:
31
58
  ReleaseTerminalResponse,
32
59
  RequestPermissionResponse,
33
60
  ResumeSessionRequest,
61
+ SetSessionConfigOptionRequest,
34
62
  SetSessionModelRequest,
35
63
  SetSessionModeRequest,
36
64
  TerminalOutputResponse,
@@ -38,35 +66,6 @@ if TYPE_CHECKING:
38
66
  WriteTextFileResponse,
39
67
  )
40
68
 
41
- from acp.agent.protocol import Agent
42
- from acp.connection import Connection
43
- from acp.exceptions import RequestError
44
- from acp.schema import (
45
- AuthenticateResponse,
46
- CreateTerminalRequest,
47
- ForkSessionResponse,
48
- InitializeResponse,
49
- KillTerminalCommandRequest,
50
- ListSessionsResponse,
51
- LoadSessionResponse,
52
- NewSessionResponse,
53
- PromptResponse,
54
- ReadTextFileRequest,
55
- ReleaseTerminalRequest,
56
- RequestPermissionRequest,
57
- ResumeSessionResponse,
58
- SessionNotification,
59
- SetSessionModelResponse,
60
- SetSessionModeResponse,
61
- TerminalOutputRequest,
62
- WaitForTerminalExitRequest,
63
- WriteTextFileRequest,
64
- )
65
-
66
-
67
- if TYPE_CHECKING:
68
- from collections.abc import Callable
69
-
70
69
 
71
70
  class ClientSideConnection(Agent):
72
71
  """Client-side connection.
@@ -151,6 +150,16 @@ class ClientSideConnection(Agent):
151
150
  payload = resp if isinstance(resp, dict) else {}
152
151
  return SetSessionModelResponse.model_validate(payload)
153
152
 
153
+ async def set_session_config_option(
154
+ self, params: SetSessionConfigOptionRequest
155
+ ) -> SetSessionConfigOptionResponse:
156
+ dct = params.model_dump(
157
+ mode="json", by_alias=True, exclude_none=True, exclude_defaults=True
158
+ )
159
+ resp = await self._conn.send_request("session/set_config_option", dct)
160
+ payload = resp if isinstance(resp, dict) else {}
161
+ return SetSessionConfigOptionResponse.model_validate(payload)
162
+
154
163
  async def authenticate(self, params: AuthenticateRequest) -> AuthenticateResponse:
155
164
  dct = params.model_dump(
156
165
  mode="json", by_alias=True, exclude_none=True, exclude_defaults=True
@@ -9,9 +9,10 @@ from __future__ import annotations
9
9
  from pathlib import Path
10
10
  from typing import TYPE_CHECKING, Any
11
11
 
12
+ import structlog
13
+
12
14
  from acp.client import Client
13
15
  from acp.schema import ReadTextFileResponse, RequestPermissionResponse, WriteTextFileResponse
14
- from agentpool import log
15
16
 
16
17
 
17
18
  if TYPE_CHECKING:
@@ -34,7 +35,7 @@ if TYPE_CHECKING:
34
35
  WriteTextFileRequest,
35
36
  )
36
37
 
37
- logger = log.get_logger(__name__)
38
+ logger = structlog.get_logger(__name__)
38
39
 
39
40
 
40
41
  class DefaultACPClient(Client):
@@ -12,6 +12,7 @@ from typing import TYPE_CHECKING, Any
12
12
  import uuid
13
13
 
14
14
  from anyenv import ProcessManager
15
+ import structlog
15
16
 
16
17
  from acp.client.protocol import Client
17
18
  from acp.schema import (
@@ -24,7 +25,6 @@ from acp.schema import (
24
25
  WaitForTerminalExitResponse,
25
26
  WriteTextFileResponse,
26
27
  )
27
- from agentpool.log import get_logger
28
28
 
29
29
 
30
30
  if TYPE_CHECKING:
@@ -40,7 +40,7 @@ if TYPE_CHECKING:
40
40
  WriteTextFileRequest,
41
41
  )
42
42
 
43
- logger = get_logger(__name__)
43
+ logger = structlog.get_logger(__name__)
44
44
 
45
45
 
46
46
  class HeadlessACPClient(Client):
acp/connection.py CHANGED
@@ -15,6 +15,7 @@ import anyenv
15
15
  import anyio
16
16
  from anyio.streams.text import TextReceiveStream
17
17
  from pydantic import BaseModel, ValidationError
18
+ import structlog
18
19
 
19
20
  from acp.exceptions import RequestError
20
21
  from acp.task import (
@@ -31,7 +32,6 @@ from acp.task import (
31
32
  RpcTaskKind,
32
33
  TaskSupervisor,
33
34
  )
34
- from agentpool import log
35
35
 
36
36
 
37
37
  if TYPE_CHECKING:
@@ -49,7 +49,7 @@ DispatcherFactory = Callable[
49
49
  ]
50
50
 
51
51
 
52
- logger = log.get_logger(__name__)
52
+ logger = structlog.get_logger(__name__)
53
53
 
54
54
 
55
55
  StreamDirection = Literal["incoming", "outgoing"]
acp/notifications.py CHANGED
@@ -6,6 +6,7 @@ from collections.abc import Sequence
6
6
  from typing import TYPE_CHECKING, Any, assert_never
7
7
 
8
8
  from pydantic_ai import ModelRequest, ModelResponse, ToolReturnPart, UserPromptPart
9
+ import structlog
9
10
 
10
11
  from acp.schema import (
11
12
  AgentMessageChunk,
@@ -33,7 +34,6 @@ from acp.schema import (
33
34
  from acp.schema.tool_call import ToolCallLocation
34
35
  from acp.tool_call_reporter import ToolCallReporter
35
36
  from acp.utils import generate_tool_title, infer_tool_kind, to_acp_content_blocks
36
- from agentpool.log import get_logger
37
37
  from agentpool.utils.pydantic_ai_helpers import safe_args_as_dict
38
38
 
39
39
 
@@ -53,7 +53,7 @@ if TYPE_CHECKING:
53
53
 
54
54
  ContentType = Sequence[ToolCallContent | str]
55
55
 
56
- logger = get_logger(__name__)
56
+ logger = structlog.get_logger(__name__)
57
57
 
58
58
 
59
59
  class ACPNotifications:
@@ -134,11 +134,11 @@ class ACPNotifications:
134
134
  async def tool_call(
135
135
  self,
136
136
  tool_name: str,
137
+ tool_call_id: str,
137
138
  *,
138
139
  tool_input: dict[str, Any],
139
140
  tool_output: Any,
140
141
  status: ToolCallStatus = "completed",
141
- tool_call_id: str | None = None,
142
142
  ) -> None:
143
143
  """Send tool execution as ACP tool call update.
144
144
 
@@ -176,11 +176,10 @@ class ACPNotifications:
176
176
 
177
177
  # Generate a descriptive title from tool name and inputs
178
178
  title = generate_tool_title(tool_name, tool_input)
179
-
180
179
  # Use appropriate notification type based on status
181
180
  if status == "pending":
182
181
  await self.tool_call_start(
183
- tool_call_id=tool_call_id or f"{tool_name}_{hash(str(tool_input))}",
182
+ tool_call_id=tool_call_id,
184
183
  title=title,
185
184
  kind=infer_tool_kind(tool_name),
186
185
  locations=locations or None,
@@ -190,7 +189,7 @@ class ACPNotifications:
190
189
  else:
191
190
  # For in_progress, completed, and failed statuses
192
191
  await self.tool_call_progress(
193
- tool_call_id=tool_call_id or f"{tool_name}_{hash(str(tool_input))}",
192
+ tool_call_id=tool_call_id,
194
193
  title=title,
195
194
  status=status,
196
195
  locations=locations or None,
@@ -607,36 +606,24 @@ class ACPNotifications:
607
606
  match block:
608
607
  case TextContentBlock(text=text):
609
608
  await self.send_user_message(text)
610
- case ImageContentBlock() as img_block:
609
+ case ImageContentBlock(annotations=annots) as img_block:
611
610
  await self.send_user_image(
612
611
  data=img_block.data,
613
612
  mime_type=img_block.mime_type,
614
613
  uri=img_block.uri,
615
- audience=img_block.annotations.audience
616
- if img_block.annotations
617
- else None,
618
- last_modified=img_block.annotations.last_modified
619
- if img_block.annotations
620
- else None,
621
- priority=img_block.annotations.priority
622
- if img_block.annotations
623
- else None,
614
+ audience=annots.audience if annots else None,
615
+ last_modified=annots.last_modified if annots else None,
616
+ priority=annots.priority if annots else None,
624
617
  )
625
- case AudioContentBlock() as audio_block:
618
+ case AudioContentBlock(annotations=annots) as audio_block:
626
619
  await self.send_user_audio(
627
620
  data=audio_block.data,
628
621
  mime_type=audio_block.mime_type,
629
- audience=audio_block.annotations.audience
630
- if audio_block.annotations
631
- else None,
632
- last_modified=audio_block.annotations.last_modified
633
- if audio_block.annotations
634
- else None,
635
- priority=audio_block.annotations.priority
636
- if audio_block.annotations
637
- else None,
622
+ audience=annots.audience if annots else None,
623
+ last_modified=annots.last_modified if annots else None,
624
+ priority=annots.priority if annots else None,
638
625
  )
639
- case ResourceContentBlock() as resource_block:
626
+ case ResourceContentBlock(annotations=annots) as resource_block:
640
627
  await self.send_user_resource(
641
628
  uri=resource_block.uri,
642
629
  name=resource_block.name,
@@ -644,15 +631,9 @@ class ACPNotifications:
644
631
  mime_type=resource_block.mime_type,
645
632
  size=resource_block.size,
646
633
  title=resource_block.title,
647
- audience=resource_block.annotations.audience
648
- if resource_block.annotations
649
- else None,
650
- last_modified=resource_block.annotations.last_modified
651
- if resource_block.annotations
652
- else None,
653
- priority=resource_block.annotations.priority
654
- if resource_block.annotations
655
- else None,
634
+ audience=annots.audience if annots else None,
635
+ last_modified=annots.last_modified if annots else None,
636
+ priority=annots.priority if annots else None,
656
637
  )
657
638
  case EmbeddedResourceContentBlock() as embedded_block:
658
639
  # Handle embedded resources with proper
@@ -678,14 +659,12 @@ class ACPNotifications:
678
659
  tool_input = self._tool_call_inputs.get(tool_call_id, {})
679
660
  await self.tool_call(
680
661
  tool_name=tool_name,
662
+ tool_call_id=tool_call_id,
681
663
  tool_input=tool_input,
682
664
  tool_output=converted_content,
683
665
  status="completed",
684
- tool_call_id=tool_call_id,
685
666
  )
686
- # Clean up stored input
687
667
  self._tool_call_inputs.pop(tool_call_id, None)
688
-
689
668
  case _:
690
669
  typ = type(part).__name__
691
670
  self.log.debug("Unhandled request part type", part_type=typ)
@@ -754,16 +733,6 @@ class ACPNotifications:
754
733
  notification = SessionNotification(session_id=self.id, update=update)
755
734
  await self.client.session_update(notification) # pyright: ignore[reportArgumentType] # ty: ignore[invalid-argument-type]
756
735
 
757
- # async def update_session_model(self, model_id: str) -> None:
758
- # """Send a session model update notification.
759
-
760
- # Args:
761
- # model_id: Unique identifier for the model
762
- # """
763
- # update = CurrentModelUpdate(current_model_id=model_id)
764
- # notification = SessionNotification(session_id=self.id, update=update)
765
- # await self.client.session_update(notification)
766
-
767
736
  async def send_agent_audio(
768
737
  self,
769
738
  data: str | bytes,
acp/schema/__init__.py CHANGED
@@ -96,6 +96,7 @@ from acp.schema.notifications import (
96
96
  from acp.schema.session_state import (
97
97
  ModelInfo,
98
98
  SessionConfigOption,
99
+ SessionConfigOptionCategory,
99
100
  SessionConfigSelect,
100
101
  SessionConfigSelectGroup,
101
102
  SessionConfigSelectOption,
@@ -222,6 +223,7 @@ __all__ = [
222
223
  "ResumeSessionResponse",
223
224
  "SessionCapabilities",
224
225
  "SessionConfigOption",
226
+ "SessionConfigOptionCategory",
225
227
  "SessionConfigSelect",
226
228
  "SessionConfigSelectGroup",
227
229
  "SessionConfigSelectOption",
@@ -9,6 +9,7 @@ from acp.schema.base import Response
9
9
  from acp.schema.capabilities import AgentCapabilities
10
10
  from acp.schema.common import AuthMethod, Implementation # noqa: TC001
11
11
  from acp.schema.session_state import ( # noqa: TC001
12
+ SessionConfigOption,
12
13
  SessionInfo,
13
14
  SessionModelState,
14
15
  SessionModeState,
@@ -58,6 +59,14 @@ class NewSessionResponse(Response):
58
59
  See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
59
60
  """
60
61
 
62
+ config_options: Sequence[SessionConfigOption] | None = None
63
+ """**UNSTABLE**
64
+
65
+ Configuration options for this session.
66
+
67
+ See RFD: Session Config Options
68
+ """
69
+
61
70
  session_id: str
62
71
  """Unique identifier for the created session.
63
72
 
@@ -82,6 +91,9 @@ class LoadSessionResponse(Response):
82
91
  See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
83
92
  """
84
93
 
94
+ config_options: Sequence[SessionConfigOption] = []
95
+ """The full list of config options with updated values."""
96
+
85
97
 
86
98
  class ForkSessionResponse(Response):
87
99
  """**UNSTABLE**: This capability is not part of the spec yet.
@@ -106,6 +118,9 @@ class ForkSessionResponse(Response):
106
118
  session_id: str
107
119
  """Unique identifier for the newly created forked session."""
108
120
 
121
+ config_options: Sequence[SessionConfigOption] = []
122
+ """The full list of config options with updated values."""
123
+
109
124
 
110
125
  class ResumeSessionResponse(Response):
111
126
  """**UNSTABLE**: This capability is not part of the spec yet.
@@ -127,6 +142,9 @@ class ResumeSessionResponse(Response):
127
142
  See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
128
143
  """
129
144
 
145
+ config_options: Sequence[SessionConfigOption] = []
146
+ """The full list of config options with updated values."""
147
+
130
148
 
131
149
  class SetSessionModeResponse(Response):
132
150
  """Response to `session/set_mode` method."""
@@ -135,6 +153,9 @@ class SetSessionModeResponse(Response):
135
153
  class SetSessionConfigOptionResponse(Response):
136
154
  """Response to `session/set_config_option` method."""
137
155
 
156
+ config_options: Sequence[SessionConfigOption] = []
157
+ """The full list of config options with updated values."""
158
+
138
159
 
139
160
  class PromptResponse(Response):
140
161
  """Response from processing a user prompt.