agentpool 2.1.9__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.

Potentially problematic release.


This version of agentpool might be problematic. Click here for more details.

Files changed (474) hide show
  1. acp/README.md +64 -0
  2. acp/__init__.py +172 -0
  3. acp/__main__.py +10 -0
  4. acp/acp_requests.py +285 -0
  5. acp/agent/__init__.py +6 -0
  6. acp/agent/connection.py +256 -0
  7. acp/agent/implementations/__init__.py +6 -0
  8. acp/agent/implementations/debug_server/__init__.py +1 -0
  9. acp/agent/implementations/debug_server/cli.py +79 -0
  10. acp/agent/implementations/debug_server/debug.html +234 -0
  11. acp/agent/implementations/debug_server/debug_server.py +496 -0
  12. acp/agent/implementations/testing.py +91 -0
  13. acp/agent/protocol.py +65 -0
  14. acp/bridge/README.md +162 -0
  15. acp/bridge/__init__.py +6 -0
  16. acp/bridge/__main__.py +91 -0
  17. acp/bridge/bridge.py +246 -0
  18. acp/bridge/py.typed +0 -0
  19. acp/bridge/settings.py +15 -0
  20. acp/client/__init__.py +7 -0
  21. acp/client/connection.py +251 -0
  22. acp/client/implementations/__init__.py +7 -0
  23. acp/client/implementations/default_client.py +185 -0
  24. acp/client/implementations/headless_client.py +266 -0
  25. acp/client/implementations/noop_client.py +110 -0
  26. acp/client/protocol.py +61 -0
  27. acp/connection.py +280 -0
  28. acp/exceptions.py +46 -0
  29. acp/filesystem.py +524 -0
  30. acp/notifications.py +832 -0
  31. acp/py.typed +0 -0
  32. acp/schema/__init__.py +265 -0
  33. acp/schema/agent_plan.py +30 -0
  34. acp/schema/agent_requests.py +126 -0
  35. acp/schema/agent_responses.py +256 -0
  36. acp/schema/base.py +39 -0
  37. acp/schema/capabilities.py +230 -0
  38. acp/schema/client_requests.py +247 -0
  39. acp/schema/client_responses.py +96 -0
  40. acp/schema/common.py +81 -0
  41. acp/schema/content_blocks.py +188 -0
  42. acp/schema/mcp.py +82 -0
  43. acp/schema/messages.py +171 -0
  44. acp/schema/notifications.py +82 -0
  45. acp/schema/protocol_stuff.md +3 -0
  46. acp/schema/session_state.py +160 -0
  47. acp/schema/session_updates.py +419 -0
  48. acp/schema/slash_commands.py +51 -0
  49. acp/schema/terminal.py +15 -0
  50. acp/schema/tool_call.py +347 -0
  51. acp/stdio.py +250 -0
  52. acp/task/__init__.py +53 -0
  53. acp/task/debug.py +197 -0
  54. acp/task/dispatcher.py +93 -0
  55. acp/task/queue.py +69 -0
  56. acp/task/sender.py +82 -0
  57. acp/task/state.py +87 -0
  58. acp/task/supervisor.py +93 -0
  59. acp/terminal_handle.py +30 -0
  60. acp/tool_call_reporter.py +199 -0
  61. acp/tool_call_state.py +178 -0
  62. acp/transports.py +104 -0
  63. acp/utils.py +240 -0
  64. agentpool/__init__.py +63 -0
  65. agentpool/__main__.py +7 -0
  66. agentpool/agents/__init__.py +30 -0
  67. agentpool/agents/acp_agent/__init__.py +5 -0
  68. agentpool/agents/acp_agent/acp_agent.py +837 -0
  69. agentpool/agents/acp_agent/acp_converters.py +294 -0
  70. agentpool/agents/acp_agent/client_handler.py +317 -0
  71. agentpool/agents/acp_agent/session_state.py +44 -0
  72. agentpool/agents/agent.py +1264 -0
  73. agentpool/agents/agui_agent/__init__.py +19 -0
  74. agentpool/agents/agui_agent/agui_agent.py +677 -0
  75. agentpool/agents/agui_agent/agui_converters.py +423 -0
  76. agentpool/agents/agui_agent/chunk_transformer.py +204 -0
  77. agentpool/agents/agui_agent/event_types.py +83 -0
  78. agentpool/agents/agui_agent/helpers.py +192 -0
  79. agentpool/agents/architect.py +71 -0
  80. agentpool/agents/base_agent.py +177 -0
  81. agentpool/agents/claude_code_agent/__init__.py +11 -0
  82. agentpool/agents/claude_code_agent/claude_code_agent.py +1021 -0
  83. agentpool/agents/claude_code_agent/converters.py +243 -0
  84. agentpool/agents/context.py +105 -0
  85. agentpool/agents/events/__init__.py +61 -0
  86. agentpool/agents/events/builtin_handlers.py +129 -0
  87. agentpool/agents/events/event_emitter.py +320 -0
  88. agentpool/agents/events/events.py +561 -0
  89. agentpool/agents/events/tts_handlers.py +186 -0
  90. agentpool/agents/interactions.py +419 -0
  91. agentpool/agents/slashed_agent.py +244 -0
  92. agentpool/agents/sys_prompts.py +178 -0
  93. agentpool/agents/tool_wrapping.py +184 -0
  94. agentpool/base_provider.py +28 -0
  95. agentpool/common_types.py +226 -0
  96. agentpool/config_resources/__init__.py +16 -0
  97. agentpool/config_resources/acp_assistant.yml +24 -0
  98. agentpool/config_resources/agents.yml +109 -0
  99. agentpool/config_resources/agents_template.yml +18 -0
  100. agentpool/config_resources/agui_test.yml +18 -0
  101. agentpool/config_resources/claude_code_agent.yml +16 -0
  102. agentpool/config_resources/claude_style_subagent.md +30 -0
  103. agentpool/config_resources/external_acp_agents.yml +77 -0
  104. agentpool/config_resources/opencode_style_subagent.md +19 -0
  105. agentpool/config_resources/tts_test_agents.yml +78 -0
  106. agentpool/delegation/__init__.py +8 -0
  107. agentpool/delegation/base_team.py +504 -0
  108. agentpool/delegation/message_flow_tracker.py +39 -0
  109. agentpool/delegation/pool.py +1129 -0
  110. agentpool/delegation/team.py +325 -0
  111. agentpool/delegation/teamrun.py +343 -0
  112. agentpool/docs/__init__.py +5 -0
  113. agentpool/docs/gen_examples.py +42 -0
  114. agentpool/docs/utils.py +370 -0
  115. agentpool/functional/__init__.py +20 -0
  116. agentpool/functional/py.typed +0 -0
  117. agentpool/functional/run.py +80 -0
  118. agentpool/functional/structure.py +136 -0
  119. agentpool/hooks/__init__.py +20 -0
  120. agentpool/hooks/agent_hooks.py +247 -0
  121. agentpool/hooks/base.py +119 -0
  122. agentpool/hooks/callable.py +140 -0
  123. agentpool/hooks/command.py +180 -0
  124. agentpool/hooks/prompt.py +122 -0
  125. agentpool/jinja_filters.py +132 -0
  126. agentpool/log.py +224 -0
  127. agentpool/mcp_server/__init__.py +17 -0
  128. agentpool/mcp_server/client.py +429 -0
  129. agentpool/mcp_server/constants.py +32 -0
  130. agentpool/mcp_server/conversions.py +172 -0
  131. agentpool/mcp_server/helpers.py +47 -0
  132. agentpool/mcp_server/manager.py +232 -0
  133. agentpool/mcp_server/message_handler.py +164 -0
  134. agentpool/mcp_server/registries/__init__.py +1 -0
  135. agentpool/mcp_server/registries/official_registry_client.py +345 -0
  136. agentpool/mcp_server/registries/pulsemcp_client.py +88 -0
  137. agentpool/mcp_server/tool_bridge.py +548 -0
  138. agentpool/messaging/__init__.py +58 -0
  139. agentpool/messaging/compaction.py +928 -0
  140. agentpool/messaging/connection_manager.py +319 -0
  141. agentpool/messaging/context.py +66 -0
  142. agentpool/messaging/event_manager.py +426 -0
  143. agentpool/messaging/events.py +39 -0
  144. agentpool/messaging/message_container.py +209 -0
  145. agentpool/messaging/message_history.py +491 -0
  146. agentpool/messaging/messagenode.py +377 -0
  147. agentpool/messaging/messages.py +655 -0
  148. agentpool/messaging/processing.py +76 -0
  149. agentpool/mime_utils.py +95 -0
  150. agentpool/models/__init__.py +21 -0
  151. agentpool/models/acp_agents/__init__.py +22 -0
  152. agentpool/models/acp_agents/base.py +308 -0
  153. agentpool/models/acp_agents/mcp_capable.py +790 -0
  154. agentpool/models/acp_agents/non_mcp.py +842 -0
  155. agentpool/models/agents.py +450 -0
  156. agentpool/models/agui_agents.py +89 -0
  157. agentpool/models/claude_code_agents.py +238 -0
  158. agentpool/models/file_agents.py +116 -0
  159. agentpool/models/file_parsing.py +367 -0
  160. agentpool/models/manifest.py +658 -0
  161. agentpool/observability/__init__.py +9 -0
  162. agentpool/observability/observability_registry.py +97 -0
  163. agentpool/prompts/__init__.py +1 -0
  164. agentpool/prompts/base.py +27 -0
  165. agentpool/prompts/builtin_provider.py +75 -0
  166. agentpool/prompts/conversion_manager.py +95 -0
  167. agentpool/prompts/convert.py +96 -0
  168. agentpool/prompts/manager.py +204 -0
  169. agentpool/prompts/parts/zed.md +33 -0
  170. agentpool/prompts/prompts.py +581 -0
  171. agentpool/py.typed +0 -0
  172. agentpool/queries/tree-sitter-language-pack/README.md +7 -0
  173. agentpool/queries/tree-sitter-language-pack/arduino-tags.scm +5 -0
  174. agentpool/queries/tree-sitter-language-pack/c-tags.scm +9 -0
  175. agentpool/queries/tree-sitter-language-pack/chatito-tags.scm +16 -0
  176. agentpool/queries/tree-sitter-language-pack/clojure-tags.scm +7 -0
  177. agentpool/queries/tree-sitter-language-pack/commonlisp-tags.scm +122 -0
  178. agentpool/queries/tree-sitter-language-pack/cpp-tags.scm +15 -0
  179. agentpool/queries/tree-sitter-language-pack/csharp-tags.scm +26 -0
  180. agentpool/queries/tree-sitter-language-pack/d-tags.scm +26 -0
  181. agentpool/queries/tree-sitter-language-pack/dart-tags.scm +92 -0
  182. agentpool/queries/tree-sitter-language-pack/elisp-tags.scm +5 -0
  183. agentpool/queries/tree-sitter-language-pack/elixir-tags.scm +54 -0
  184. agentpool/queries/tree-sitter-language-pack/elm-tags.scm +19 -0
  185. agentpool/queries/tree-sitter-language-pack/gleam-tags.scm +41 -0
  186. agentpool/queries/tree-sitter-language-pack/go-tags.scm +42 -0
  187. agentpool/queries/tree-sitter-language-pack/java-tags.scm +20 -0
  188. agentpool/queries/tree-sitter-language-pack/javascript-tags.scm +88 -0
  189. agentpool/queries/tree-sitter-language-pack/lua-tags.scm +34 -0
  190. agentpool/queries/tree-sitter-language-pack/matlab-tags.scm +10 -0
  191. agentpool/queries/tree-sitter-language-pack/ocaml-tags.scm +115 -0
  192. agentpool/queries/tree-sitter-language-pack/ocaml_interface-tags.scm +98 -0
  193. agentpool/queries/tree-sitter-language-pack/pony-tags.scm +39 -0
  194. agentpool/queries/tree-sitter-language-pack/properties-tags.scm +5 -0
  195. agentpool/queries/tree-sitter-language-pack/python-tags.scm +14 -0
  196. agentpool/queries/tree-sitter-language-pack/r-tags.scm +21 -0
  197. agentpool/queries/tree-sitter-language-pack/racket-tags.scm +12 -0
  198. agentpool/queries/tree-sitter-language-pack/ruby-tags.scm +64 -0
  199. agentpool/queries/tree-sitter-language-pack/rust-tags.scm +60 -0
  200. agentpool/queries/tree-sitter-language-pack/solidity-tags.scm +43 -0
  201. agentpool/queries/tree-sitter-language-pack/swift-tags.scm +51 -0
  202. agentpool/queries/tree-sitter-language-pack/udev-tags.scm +20 -0
  203. agentpool/queries/tree-sitter-languages/README.md +24 -0
  204. agentpool/queries/tree-sitter-languages/c-tags.scm +9 -0
  205. agentpool/queries/tree-sitter-languages/c_sharp-tags.scm +46 -0
  206. agentpool/queries/tree-sitter-languages/cpp-tags.scm +15 -0
  207. agentpool/queries/tree-sitter-languages/dart-tags.scm +91 -0
  208. agentpool/queries/tree-sitter-languages/elisp-tags.scm +8 -0
  209. agentpool/queries/tree-sitter-languages/elixir-tags.scm +54 -0
  210. agentpool/queries/tree-sitter-languages/elm-tags.scm +19 -0
  211. agentpool/queries/tree-sitter-languages/fortran-tags.scm +15 -0
  212. agentpool/queries/tree-sitter-languages/go-tags.scm +30 -0
  213. agentpool/queries/tree-sitter-languages/haskell-tags.scm +3 -0
  214. agentpool/queries/tree-sitter-languages/hcl-tags.scm +77 -0
  215. agentpool/queries/tree-sitter-languages/java-tags.scm +20 -0
  216. agentpool/queries/tree-sitter-languages/javascript-tags.scm +88 -0
  217. agentpool/queries/tree-sitter-languages/julia-tags.scm +60 -0
  218. agentpool/queries/tree-sitter-languages/kotlin-tags.scm +27 -0
  219. agentpool/queries/tree-sitter-languages/matlab-tags.scm +10 -0
  220. agentpool/queries/tree-sitter-languages/ocaml-tags.scm +115 -0
  221. agentpool/queries/tree-sitter-languages/ocaml_interface-tags.scm +98 -0
  222. agentpool/queries/tree-sitter-languages/php-tags.scm +26 -0
  223. agentpool/queries/tree-sitter-languages/python-tags.scm +12 -0
  224. agentpool/queries/tree-sitter-languages/ql-tags.scm +26 -0
  225. agentpool/queries/tree-sitter-languages/ruby-tags.scm +64 -0
  226. agentpool/queries/tree-sitter-languages/rust-tags.scm +60 -0
  227. agentpool/queries/tree-sitter-languages/scala-tags.scm +65 -0
  228. agentpool/queries/tree-sitter-languages/typescript-tags.scm +41 -0
  229. agentpool/queries/tree-sitter-languages/zig-tags.scm +3 -0
  230. agentpool/repomap.py +1231 -0
  231. agentpool/resource_providers/__init__.py +17 -0
  232. agentpool/resource_providers/aggregating.py +54 -0
  233. agentpool/resource_providers/base.py +172 -0
  234. agentpool/resource_providers/codemode/__init__.py +9 -0
  235. agentpool/resource_providers/codemode/code_executor.py +215 -0
  236. agentpool/resource_providers/codemode/default_prompt.py +19 -0
  237. agentpool/resource_providers/codemode/helpers.py +83 -0
  238. agentpool/resource_providers/codemode/progress_executor.py +212 -0
  239. agentpool/resource_providers/codemode/provider.py +150 -0
  240. agentpool/resource_providers/codemode/remote_mcp_execution.py +143 -0
  241. agentpool/resource_providers/codemode/remote_provider.py +171 -0
  242. agentpool/resource_providers/filtering.py +42 -0
  243. agentpool/resource_providers/mcp_provider.py +246 -0
  244. agentpool/resource_providers/plan_provider.py +196 -0
  245. agentpool/resource_providers/pool.py +69 -0
  246. agentpool/resource_providers/static.py +289 -0
  247. agentpool/running/__init__.py +20 -0
  248. agentpool/running/decorators.py +56 -0
  249. agentpool/running/discovery.py +101 -0
  250. agentpool/running/executor.py +284 -0
  251. agentpool/running/injection.py +111 -0
  252. agentpool/running/py.typed +0 -0
  253. agentpool/running/run_nodes.py +87 -0
  254. agentpool/server.py +122 -0
  255. agentpool/sessions/__init__.py +13 -0
  256. agentpool/sessions/manager.py +302 -0
  257. agentpool/sessions/models.py +71 -0
  258. agentpool/sessions/session.py +239 -0
  259. agentpool/sessions/store.py +163 -0
  260. agentpool/skills/__init__.py +5 -0
  261. agentpool/skills/manager.py +120 -0
  262. agentpool/skills/registry.py +210 -0
  263. agentpool/skills/skill.py +36 -0
  264. agentpool/storage/__init__.py +17 -0
  265. agentpool/storage/manager.py +419 -0
  266. agentpool/storage/serialization.py +136 -0
  267. agentpool/talk/__init__.py +13 -0
  268. agentpool/talk/registry.py +128 -0
  269. agentpool/talk/stats.py +159 -0
  270. agentpool/talk/talk.py +604 -0
  271. agentpool/tasks/__init__.py +20 -0
  272. agentpool/tasks/exceptions.py +25 -0
  273. agentpool/tasks/registry.py +33 -0
  274. agentpool/testing.py +129 -0
  275. agentpool/text_templates/__init__.py +39 -0
  276. agentpool/text_templates/system_prompt.jinja +30 -0
  277. agentpool/text_templates/tool_call_default.jinja +13 -0
  278. agentpool/text_templates/tool_call_markdown.jinja +25 -0
  279. agentpool/text_templates/tool_call_simple.jinja +5 -0
  280. agentpool/tools/__init__.py +16 -0
  281. agentpool/tools/base.py +269 -0
  282. agentpool/tools/exceptions.py +9 -0
  283. agentpool/tools/manager.py +255 -0
  284. agentpool/tools/tool_call_info.py +87 -0
  285. agentpool/ui/__init__.py +2 -0
  286. agentpool/ui/base.py +89 -0
  287. agentpool/ui/mock_provider.py +81 -0
  288. agentpool/ui/stdlib_provider.py +150 -0
  289. agentpool/utils/__init__.py +44 -0
  290. agentpool/utils/baseregistry.py +185 -0
  291. agentpool/utils/count_tokens.py +62 -0
  292. agentpool/utils/dag.py +184 -0
  293. agentpool/utils/importing.py +206 -0
  294. agentpool/utils/inspection.py +334 -0
  295. agentpool/utils/model_capabilities.py +25 -0
  296. agentpool/utils/network.py +28 -0
  297. agentpool/utils/now.py +22 -0
  298. agentpool/utils/parse_time.py +87 -0
  299. agentpool/utils/result_utils.py +35 -0
  300. agentpool/utils/signatures.py +305 -0
  301. agentpool/utils/streams.py +112 -0
  302. agentpool/utils/tasks.py +186 -0
  303. agentpool/vfs_registry.py +250 -0
  304. agentpool-2.1.9.dist-info/METADATA +336 -0
  305. agentpool-2.1.9.dist-info/RECORD +474 -0
  306. agentpool-2.1.9.dist-info/WHEEL +4 -0
  307. agentpool-2.1.9.dist-info/entry_points.txt +14 -0
  308. agentpool-2.1.9.dist-info/licenses/LICENSE +22 -0
  309. agentpool_cli/__init__.py +34 -0
  310. agentpool_cli/__main__.py +66 -0
  311. agentpool_cli/agent.py +175 -0
  312. agentpool_cli/cli_types.py +23 -0
  313. agentpool_cli/common.py +163 -0
  314. agentpool_cli/create.py +175 -0
  315. agentpool_cli/history.py +217 -0
  316. agentpool_cli/log.py +78 -0
  317. agentpool_cli/py.typed +0 -0
  318. agentpool_cli/run.py +84 -0
  319. agentpool_cli/serve_acp.py +177 -0
  320. agentpool_cli/serve_api.py +69 -0
  321. agentpool_cli/serve_mcp.py +74 -0
  322. agentpool_cli/serve_vercel.py +233 -0
  323. agentpool_cli/store.py +171 -0
  324. agentpool_cli/task.py +84 -0
  325. agentpool_cli/utils.py +104 -0
  326. agentpool_cli/watch.py +54 -0
  327. agentpool_commands/__init__.py +180 -0
  328. agentpool_commands/agents.py +199 -0
  329. agentpool_commands/base.py +45 -0
  330. agentpool_commands/commands.py +58 -0
  331. agentpool_commands/completers.py +110 -0
  332. agentpool_commands/connections.py +175 -0
  333. agentpool_commands/markdown_utils.py +31 -0
  334. agentpool_commands/models.py +62 -0
  335. agentpool_commands/prompts.py +78 -0
  336. agentpool_commands/py.typed +0 -0
  337. agentpool_commands/read.py +77 -0
  338. agentpool_commands/resources.py +210 -0
  339. agentpool_commands/session.py +48 -0
  340. agentpool_commands/tools.py +269 -0
  341. agentpool_commands/utils.py +189 -0
  342. agentpool_commands/workers.py +163 -0
  343. agentpool_config/__init__.py +53 -0
  344. agentpool_config/builtin_tools.py +265 -0
  345. agentpool_config/commands.py +237 -0
  346. agentpool_config/conditions.py +301 -0
  347. agentpool_config/converters.py +30 -0
  348. agentpool_config/durable.py +331 -0
  349. agentpool_config/event_handlers.py +600 -0
  350. agentpool_config/events.py +153 -0
  351. agentpool_config/forward_targets.py +251 -0
  352. agentpool_config/hook_conditions.py +331 -0
  353. agentpool_config/hooks.py +241 -0
  354. agentpool_config/jinja.py +206 -0
  355. agentpool_config/knowledge.py +41 -0
  356. agentpool_config/loaders.py +350 -0
  357. agentpool_config/mcp_server.py +243 -0
  358. agentpool_config/nodes.py +202 -0
  359. agentpool_config/observability.py +191 -0
  360. agentpool_config/output_types.py +55 -0
  361. agentpool_config/pool_server.py +267 -0
  362. agentpool_config/prompt_hubs.py +105 -0
  363. agentpool_config/prompts.py +185 -0
  364. agentpool_config/py.typed +0 -0
  365. agentpool_config/resources.py +33 -0
  366. agentpool_config/session.py +119 -0
  367. agentpool_config/skills.py +17 -0
  368. agentpool_config/storage.py +288 -0
  369. agentpool_config/system_prompts.py +190 -0
  370. agentpool_config/task.py +162 -0
  371. agentpool_config/teams.py +52 -0
  372. agentpool_config/tools.py +112 -0
  373. agentpool_config/toolsets.py +1033 -0
  374. agentpool_config/workers.py +86 -0
  375. agentpool_prompts/__init__.py +1 -0
  376. agentpool_prompts/braintrust_hub.py +235 -0
  377. agentpool_prompts/fabric.py +75 -0
  378. agentpool_prompts/langfuse_hub.py +79 -0
  379. agentpool_prompts/promptlayer_provider.py +59 -0
  380. agentpool_prompts/py.typed +0 -0
  381. agentpool_server/__init__.py +9 -0
  382. agentpool_server/a2a_server/__init__.py +5 -0
  383. agentpool_server/a2a_server/a2a_types.py +41 -0
  384. agentpool_server/a2a_server/server.py +190 -0
  385. agentpool_server/a2a_server/storage.py +81 -0
  386. agentpool_server/acp_server/__init__.py +22 -0
  387. agentpool_server/acp_server/acp_agent.py +786 -0
  388. agentpool_server/acp_server/acp_tools.py +43 -0
  389. agentpool_server/acp_server/commands/__init__.py +18 -0
  390. agentpool_server/acp_server/commands/acp_commands.py +594 -0
  391. agentpool_server/acp_server/commands/debug_commands.py +376 -0
  392. agentpool_server/acp_server/commands/docs_commands/__init__.py +39 -0
  393. agentpool_server/acp_server/commands/docs_commands/fetch_repo.py +169 -0
  394. agentpool_server/acp_server/commands/docs_commands/get_schema.py +176 -0
  395. agentpool_server/acp_server/commands/docs_commands/get_source.py +110 -0
  396. agentpool_server/acp_server/commands/docs_commands/git_diff.py +111 -0
  397. agentpool_server/acp_server/commands/docs_commands/helpers.py +33 -0
  398. agentpool_server/acp_server/commands/docs_commands/url_to_markdown.py +90 -0
  399. agentpool_server/acp_server/commands/spawn.py +210 -0
  400. agentpool_server/acp_server/converters.py +235 -0
  401. agentpool_server/acp_server/input_provider.py +338 -0
  402. agentpool_server/acp_server/server.py +288 -0
  403. agentpool_server/acp_server/session.py +969 -0
  404. agentpool_server/acp_server/session_manager.py +313 -0
  405. agentpool_server/acp_server/syntax_detection.py +250 -0
  406. agentpool_server/acp_server/zed_tools.md +90 -0
  407. agentpool_server/aggregating_server.py +309 -0
  408. agentpool_server/agui_server/__init__.py +11 -0
  409. agentpool_server/agui_server/server.py +128 -0
  410. agentpool_server/base.py +189 -0
  411. agentpool_server/http_server.py +164 -0
  412. agentpool_server/mcp_server/__init__.py +6 -0
  413. agentpool_server/mcp_server/server.py +314 -0
  414. agentpool_server/mcp_server/zed_wrapper.py +110 -0
  415. agentpool_server/openai_api_server/__init__.py +5 -0
  416. agentpool_server/openai_api_server/completions/__init__.py +1 -0
  417. agentpool_server/openai_api_server/completions/helpers.py +81 -0
  418. agentpool_server/openai_api_server/completions/models.py +98 -0
  419. agentpool_server/openai_api_server/responses/__init__.py +1 -0
  420. agentpool_server/openai_api_server/responses/helpers.py +74 -0
  421. agentpool_server/openai_api_server/responses/models.py +96 -0
  422. agentpool_server/openai_api_server/server.py +242 -0
  423. agentpool_server/py.typed +0 -0
  424. agentpool_storage/__init__.py +9 -0
  425. agentpool_storage/base.py +310 -0
  426. agentpool_storage/file_provider.py +378 -0
  427. agentpool_storage/formatters.py +129 -0
  428. agentpool_storage/memory_provider.py +396 -0
  429. agentpool_storage/models.py +108 -0
  430. agentpool_storage/py.typed +0 -0
  431. agentpool_storage/session_store.py +262 -0
  432. agentpool_storage/sql_provider/__init__.py +21 -0
  433. agentpool_storage/sql_provider/cli.py +146 -0
  434. agentpool_storage/sql_provider/models.py +249 -0
  435. agentpool_storage/sql_provider/queries.py +15 -0
  436. agentpool_storage/sql_provider/sql_provider.py +444 -0
  437. agentpool_storage/sql_provider/utils.py +234 -0
  438. agentpool_storage/text_log_provider.py +275 -0
  439. agentpool_toolsets/__init__.py +15 -0
  440. agentpool_toolsets/builtin/__init__.py +33 -0
  441. agentpool_toolsets/builtin/agent_management.py +239 -0
  442. agentpool_toolsets/builtin/chain.py +288 -0
  443. agentpool_toolsets/builtin/code.py +398 -0
  444. agentpool_toolsets/builtin/debug.py +291 -0
  445. agentpool_toolsets/builtin/execution_environment.py +381 -0
  446. agentpool_toolsets/builtin/file_edit/__init__.py +11 -0
  447. agentpool_toolsets/builtin/file_edit/file_edit.py +747 -0
  448. agentpool_toolsets/builtin/file_edit/fuzzy_matcher/__init__.py +5 -0
  449. agentpool_toolsets/builtin/file_edit/fuzzy_matcher/example_usage.py +311 -0
  450. agentpool_toolsets/builtin/file_edit/fuzzy_matcher/streaming_fuzzy_matcher.py +443 -0
  451. agentpool_toolsets/builtin/history.py +36 -0
  452. agentpool_toolsets/builtin/integration.py +85 -0
  453. agentpool_toolsets/builtin/skills.py +77 -0
  454. agentpool_toolsets/builtin/subagent_tools.py +324 -0
  455. agentpool_toolsets/builtin/tool_management.py +90 -0
  456. agentpool_toolsets/builtin/user_interaction.py +52 -0
  457. agentpool_toolsets/builtin/workers.py +128 -0
  458. agentpool_toolsets/composio_toolset.py +96 -0
  459. agentpool_toolsets/config_creation.py +192 -0
  460. agentpool_toolsets/entry_points.py +47 -0
  461. agentpool_toolsets/fsspec_toolset/__init__.py +7 -0
  462. agentpool_toolsets/fsspec_toolset/diagnostics.py +115 -0
  463. agentpool_toolsets/fsspec_toolset/grep.py +450 -0
  464. agentpool_toolsets/fsspec_toolset/helpers.py +631 -0
  465. agentpool_toolsets/fsspec_toolset/streaming_diff_parser.py +249 -0
  466. agentpool_toolsets/fsspec_toolset/toolset.py +1384 -0
  467. agentpool_toolsets/mcp_run_toolset.py +61 -0
  468. agentpool_toolsets/notifications.py +146 -0
  469. agentpool_toolsets/openapi.py +118 -0
  470. agentpool_toolsets/py.typed +0 -0
  471. agentpool_toolsets/search_toolset.py +202 -0
  472. agentpool_toolsets/semantic_memory_toolset.py +536 -0
  473. agentpool_toolsets/streaming_tools.py +265 -0
  474. agentpool_toolsets/vfs_toolset.py +124 -0
acp/task/debug.py ADDED
@@ -0,0 +1,197 @@
1
+ """Debugging extensions for ACP task system."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import asdict, dataclass
6
+ from datetime import datetime
7
+ import json
8
+ import logging
9
+ from pathlib import Path
10
+ from typing import TYPE_CHECKING, Any, Literal
11
+
12
+ from acp.task.state import InMemoryMessageStateStore
13
+
14
+
15
+ if TYPE_CHECKING:
16
+ import asyncio
17
+
18
+ from acp.task.state import IncomingMessage
19
+
20
+
21
+ __all__ = ["DebugEntry", "DebuggingMessageStateStore"]
22
+
23
+
24
+ @dataclass
25
+ class DebugEntry:
26
+ """Structured debug entry for ACP message tracking."""
27
+
28
+ timestamp: str
29
+ direction: Literal["outgoing", "incoming"]
30
+ event: Literal["register", "resolve", "reject", "begin", "complete", "fail"]
31
+ request_id: int | None
32
+ method: str
33
+ params: Any = None
34
+ result: Any = None
35
+ error: Any = None
36
+ status: str | None = None
37
+ duration_ms: float | None = None
38
+
39
+
40
+ class DebuggingMessageStateStore(InMemoryMessageStateStore):
41
+ """Enhanced message state store with structured debugging output.
42
+
43
+ Provides much richer debugging information than raw JSON logging:
44
+ - Request/response correlation
45
+ - Timing information
46
+ - Status tracking
47
+ - Structured data output
48
+ - Error details
49
+ """
50
+
51
+ def __init__(self, debug_file: str | Path | None = None) -> None:
52
+ super().__init__()
53
+ self._debug_file = Path(debug_file) if debug_file else None
54
+ self._request_start_times: dict[int, datetime] = {}
55
+
56
+ def register_outgoing(self, request_id: int, method: str) -> asyncio.Future[Any]:
57
+ """Register outgoing request with debug logging."""
58
+ future = super().register_outgoing(request_id, method)
59
+
60
+ # Track start time for duration calculation
61
+ self._request_start_times[request_id] = datetime.now()
62
+ entry = DebugEntry(
63
+ timestamp=datetime.now().isoformat(),
64
+ direction="outgoing",
65
+ event="register",
66
+ request_id=request_id,
67
+ method=method,
68
+ )
69
+ self._log_debug(entry)
70
+
71
+ return future
72
+
73
+ def resolve_outgoing(self, request_id: int, result: Any) -> None:
74
+ """Resolve outgoing request with debug logging."""
75
+ duration = self._calculate_duration(request_id)
76
+ super().resolve_outgoing(request_id, result)
77
+ entry = DebugEntry(
78
+ timestamp=datetime.now().isoformat(),
79
+ direction="outgoing",
80
+ event="resolve",
81
+ request_id=request_id,
82
+ method=self._get_method_for_request(request_id),
83
+ result=result,
84
+ duration_ms=duration,
85
+ )
86
+ self._log_debug(entry)
87
+ self._cleanup_request_timing(request_id)
88
+
89
+ def reject_outgoing(self, request_id: int, error: Any) -> None:
90
+ """Reject outgoing request with debug logging."""
91
+ duration = self._calculate_duration(request_id)
92
+ super().reject_outgoing(request_id, error)
93
+ entry = DebugEntry(
94
+ timestamp=datetime.now().isoformat(),
95
+ direction="outgoing",
96
+ event="reject",
97
+ request_id=request_id,
98
+ method=self._get_method_for_request(request_id),
99
+ error=str(error),
100
+ duration_ms=duration,
101
+ )
102
+ self._log_debug(entry)
103
+ self._cleanup_request_timing(request_id)
104
+
105
+ def reject_all_outgoing(self, error: Any) -> None:
106
+ """Reject all outgoing requests with debug logging."""
107
+ # Log for each pending request
108
+ for request_id in list(self._outgoing.keys()):
109
+ duration = self._calculate_duration(request_id)
110
+ entry = DebugEntry(
111
+ timestamp=datetime.now().isoformat(),
112
+ direction="outgoing",
113
+ event="reject",
114
+ request_id=request_id,
115
+ method=self._get_method_for_request(request_id),
116
+ error=f"Connection error: {error}",
117
+ duration_ms=duration,
118
+ )
119
+ self._log_debug(entry)
120
+
121
+ super().reject_all_outgoing(error)
122
+ self._request_start_times.clear()
123
+
124
+ def begin_incoming(self, method: str, params: Any) -> IncomingMessage:
125
+ """Begin processing incoming request with debug logging."""
126
+ record = super().begin_incoming(method, params)
127
+ entry = DebugEntry(
128
+ timestamp=datetime.now().isoformat(),
129
+ direction="incoming",
130
+ event="begin",
131
+ request_id=None,
132
+ method=method,
133
+ params=params,
134
+ status="pending",
135
+ )
136
+ self._log_debug(entry)
137
+ return record
138
+
139
+ def complete_incoming(self, record: IncomingMessage, result: Any) -> None:
140
+ """Complete incoming request with debug logging."""
141
+ super().complete_incoming(record, result)
142
+ entry = DebugEntry(
143
+ timestamp=datetime.now().isoformat(),
144
+ direction="incoming",
145
+ event="complete",
146
+ request_id=None,
147
+ method=record.method,
148
+ result=result,
149
+ status="completed",
150
+ )
151
+ self._log_debug(entry)
152
+
153
+ def fail_incoming(self, record: IncomingMessage, error: Any) -> None:
154
+ """Fail incoming request with debug logging."""
155
+ super().fail_incoming(record, error)
156
+ entry = DebugEntry(
157
+ timestamp=datetime.now().isoformat(),
158
+ direction="incoming",
159
+ event="fail",
160
+ request_id=None,
161
+ method=record.method,
162
+ error=str(error),
163
+ status="failed",
164
+ )
165
+ self._log_debug(entry)
166
+
167
+ def _log_debug(self, entry: DebugEntry) -> None:
168
+ """Write debug entry to file if configured."""
169
+ if not self._debug_file:
170
+ return
171
+
172
+ try:
173
+ # Convert to dict and filter out None values for cleaner output
174
+ data = {k: v for k, v in asdict(entry).items() if v is not None}
175
+ # Write as JSONL (one JSON object per line)
176
+ with self._debug_file.open("a", encoding="utf-8") as f:
177
+ f.write(json.dumps(data, separators=(",", ":")) + "\n")
178
+
179
+ except Exception:
180
+ # Don't let debug logging break the connection
181
+ logging.exception("Failed to write debug entry")
182
+
183
+ def _calculate_duration(self, request_id: int) -> float | None:
184
+ """Calculate request duration in milliseconds."""
185
+ start_time = self._request_start_times.get(request_id)
186
+ if start_time:
187
+ return (datetime.now() - start_time).total_seconds() * 1000
188
+ return None
189
+
190
+ def _cleanup_request_timing(self, request_id: int) -> None:
191
+ """Clean up timing tracking for completed request."""
192
+ self._request_start_times.pop(request_id, None)
193
+
194
+ def _get_method_for_request(self, request_id: int) -> str:
195
+ """Get method name for outgoing request."""
196
+ record = self._outgoing.get(request_id)
197
+ return record.method if record else "unknown"
acp/task/dispatcher.py ADDED
@@ -0,0 +1,93 @@
1
+ """Message dispatcher for ACP tasks."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ from collections.abc import Awaitable, Callable
7
+ from contextlib import suppress
8
+ from typing import TYPE_CHECKING, Any, Protocol
9
+
10
+ from acp.task import RpcTaskKind
11
+
12
+
13
+ if TYPE_CHECKING:
14
+ from acp.task.queue import MessageQueue
15
+ from acp.task.state import MessageStateStore
16
+ from acp.task.supervisor import TaskSupervisor
17
+
18
+
19
+ RequestRunner = Callable[[dict[str, Any]], Awaitable[Any]]
20
+ NotificationRunner = Callable[[dict[str, Any]], Awaitable[None]]
21
+
22
+
23
+ class MessageDispatcher(Protocol):
24
+ """Protocol for message dispatchers."""
25
+
26
+ def start(self) -> None: ...
27
+
28
+ async def stop(self) -> None: ...
29
+
30
+
31
+ class DefaultMessageDispatcher(MessageDispatcher):
32
+ """Background worker that consumes RPC tasks from a broker."""
33
+
34
+ def __init__(
35
+ self,
36
+ *,
37
+ queue: MessageQueue,
38
+ supervisor: TaskSupervisor,
39
+ store: MessageStateStore,
40
+ request_runner: RequestRunner,
41
+ notification_runner: NotificationRunner,
42
+ ) -> None:
43
+ self._queue = queue
44
+ self._supervisor = supervisor
45
+ self._store = store
46
+ self._request_runner = request_runner
47
+ self._notification_runner = notification_runner
48
+ self._task: asyncio.Task[None] | None = None
49
+
50
+ def start(self) -> None:
51
+ if self._task is not None:
52
+ raise RuntimeError("dispatcher already started")
53
+ self._task = self._supervisor.create(self._run(), name="acp.Dispatcher.loop")
54
+
55
+ async def _run(self) -> None:
56
+ try:
57
+ async for task in self._queue:
58
+ try:
59
+ if task.kind is RpcTaskKind.REQUEST:
60
+ await self._dispatch_request(task.message)
61
+ else:
62
+ await self._dispatch_notification(task.message)
63
+ finally:
64
+ self._queue.task_done()
65
+ except asyncio.CancelledError:
66
+ return
67
+
68
+ async def stop(self) -> None:
69
+ await self._queue.close()
70
+ if self._task is not None:
71
+ with suppress(asyncio.CancelledError):
72
+ await self._task
73
+ self._task = None
74
+
75
+ async def _dispatch_request(self, msg: dict[str, Any]) -> None:
76
+ record = self._store.begin_incoming(msg.get("method", ""), msg.get("params"))
77
+
78
+ async def runner() -> None:
79
+ try:
80
+ result = await self._request_runner(msg)
81
+ except Exception as exc:
82
+ self._store.fail_incoming(record, exc)
83
+ raise
84
+ else:
85
+ self._store.complete_incoming(record, result)
86
+
87
+ self._supervisor.create(runner(), name="acp.Dispatcher.request")
88
+
89
+ async def _dispatch_notification(self, message: dict[str, Any]) -> None:
90
+ async def runner() -> None:
91
+ await self._notification_runner(message)
92
+
93
+ self._supervisor.create(runner(), name="acp.Dispatcher.notification")
acp/task/queue.py ADDED
@@ -0,0 +1,69 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ from contextlib import suppress
5
+ from typing import TYPE_CHECKING, Protocol
6
+
7
+
8
+ if TYPE_CHECKING:
9
+ from collections.abc import AsyncIterator
10
+
11
+ from acp.task import RpcTask
12
+
13
+
14
+ class MessageQueue(Protocol):
15
+ """Protocol for message queues used in RPC task dispatch."""
16
+
17
+ async def publish(self, task: RpcTask) -> None: ...
18
+
19
+ async def close(self) -> None: ...
20
+
21
+ def task_done(self) -> None: ...
22
+
23
+ async def join(self) -> None: ...
24
+
25
+ def __aiter__(self) -> AsyncIterator[RpcTask]: ...
26
+
27
+
28
+ class InMemoryMessageQueue:
29
+ """Simple in-memory broker for RPC task dispatch."""
30
+
31
+ def __init__(self, *, maxsize: int = 0) -> None:
32
+ self._queue: asyncio.Queue[RpcTask | None] = asyncio.Queue(maxsize=maxsize)
33
+ self._closed = False
34
+
35
+ async def publish(self, task: RpcTask) -> None:
36
+ if self._closed:
37
+ raise RuntimeError("mssage queue already closed")
38
+ await self._queue.put(task)
39
+
40
+ async def close(self) -> None:
41
+ if self._closed:
42
+ return
43
+ self._closed = True
44
+ await self._queue.put(None)
45
+
46
+ async def join(self) -> None:
47
+ await self._queue.join()
48
+
49
+ def task_done(self) -> None:
50
+ with suppress(ValueError):
51
+ self._queue.task_done()
52
+
53
+ def __aiter__(self) -> AsyncIterator[RpcTask]:
54
+ return _QueueIterator(self)
55
+
56
+
57
+ class _QueueIterator:
58
+ def __init__(self, queue: InMemoryMessageQueue) -> None:
59
+ self._queue = queue
60
+
61
+ def __aiter__(self) -> _QueueIterator:
62
+ return self
63
+
64
+ async def __anext__(self) -> RpcTask:
65
+ item = await self._queue._queue.get()
66
+ if item is None:
67
+ self._queue.task_done()
68
+ raise StopAsyncIteration
69
+ return item
acp/task/sender.py ADDED
@@ -0,0 +1,82 @@
1
+ """Sender class for sending messages to a remote peer."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ from collections.abc import Callable
7
+ import contextlib
8
+ from dataclasses import dataclass
9
+ import json
10
+ import logging
11
+ from typing import Any
12
+
13
+ import anyio
14
+ from anyio.abc import ByteSendStream
15
+
16
+ from acp.task.supervisor import TaskSupervisor
17
+
18
+
19
+ __all__ = ["MessageSender", "SenderFactory"]
20
+
21
+
22
+ SenderFactory = Callable[[ByteSendStream, TaskSupervisor], "MessageSender"]
23
+
24
+
25
+ @dataclass(slots=True)
26
+ class _PendingSend:
27
+ payload: bytes
28
+ future: asyncio.Future[None]
29
+
30
+
31
+ class MessageSender:
32
+ """Async message sender that queues and transmits JSON-RPC messages."""
33
+
34
+ def __init__(
35
+ self,
36
+ writer: ByteSendStream,
37
+ supervisor: TaskSupervisor,
38
+ ) -> None:
39
+ self._writer = writer
40
+ self._queue: asyncio.Queue[_PendingSend | None] = asyncio.Queue()
41
+ self._closed = False
42
+ self._task = supervisor.create(
43
+ self._loop(), name="acp.Sender.loop", on_error=self._on_error
44
+ )
45
+
46
+ async def send(self, payload: dict[str, Any]) -> None:
47
+ data = (json.dumps(payload, separators=(",", ":")) + "\n").encode("utf-8")
48
+ future: asyncio.Future[None] = asyncio.get_running_loop().create_future()
49
+ await self._queue.put(_PendingSend(data, future))
50
+ await future
51
+
52
+ async def close(self) -> None:
53
+ if self._closed:
54
+ return
55
+ self._closed = True
56
+ await self._queue.put(None)
57
+ if self._task is not None:
58
+ with contextlib.suppress(asyncio.CancelledError):
59
+ await self._task
60
+
61
+ async def _loop(self) -> None:
62
+ try:
63
+ while True:
64
+ item = await self._queue.get()
65
+ if item is None:
66
+ return
67
+ try:
68
+ await self._writer.send(item.payload)
69
+ except Exception as exc:
70
+ if not item.future.done():
71
+ item.future.set_exception(exc)
72
+ raise
73
+ else:
74
+ if not item.future.done():
75
+ item.future.set_result(None)
76
+ except asyncio.CancelledError:
77
+ return
78
+ except anyio.ClosedResourceError:
79
+ return
80
+
81
+ def _on_error(self, task: asyncio.Task[Any], exc: BaseException) -> None:
82
+ logging.exception("Send loop failed", exc_info=exc)
acp/task/state.py ADDED
@@ -0,0 +1,87 @@
1
+ """Message State Store."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ from dataclasses import dataclass
7
+ from typing import Any, Protocol
8
+
9
+
10
+ @dataclass(slots=True)
11
+ class OutgoingMessage:
12
+ """Represents an outgoing message with its request ID, method, and future."""
13
+
14
+ request_id: int
15
+ method: str
16
+ future: asyncio.Future[Any]
17
+
18
+
19
+ @dataclass(slots=True)
20
+ class IncomingMessage:
21
+ """Represents an incoming message with its status, result, and error."""
22
+
23
+ method: str
24
+ params: Any
25
+ status: str = "pending"
26
+ result: Any = None
27
+ error: Any = None
28
+
29
+
30
+ class MessageStateStore(Protocol):
31
+ """Protocol for managing message states."""
32
+
33
+ def register_outgoing(self, request_id: int, method: str) -> asyncio.Future[Any]: ...
34
+
35
+ def resolve_outgoing(self, request_id: int, result: Any) -> None: ...
36
+
37
+ def reject_outgoing(self, request_id: int, error: Any) -> None: ...
38
+
39
+ def reject_all_outgoing(self, error: Any) -> None: ...
40
+
41
+ def begin_incoming(self, method: str, params: Any) -> IncomingMessage: ...
42
+
43
+ def complete_incoming(self, record: IncomingMessage, result: Any) -> None: ...
44
+
45
+ def fail_incoming(self, record: IncomingMessage, error: Any) -> None: ...
46
+
47
+
48
+ class InMemoryMessageStateStore(MessageStateStore):
49
+ """In-memory implementation of MessageStateStore."""
50
+
51
+ def __init__(self) -> None:
52
+ self._outgoing: dict[int, OutgoingMessage] = {}
53
+ self._incoming: list[IncomingMessage] = []
54
+
55
+ def register_outgoing(self, request_id: int, method: str) -> asyncio.Future[Any]:
56
+ future: asyncio.Future[Any] = asyncio.get_running_loop().create_future()
57
+ self._outgoing[request_id] = OutgoingMessage(request_id, method, future)
58
+ return future
59
+
60
+ def resolve_outgoing(self, request_id: int, result: Any) -> None:
61
+ record = self._outgoing.pop(request_id, None)
62
+ if record and not record.future.done():
63
+ record.future.set_result(result)
64
+
65
+ def reject_outgoing(self, request_id: int, error: Any) -> None:
66
+ record = self._outgoing.pop(request_id, None)
67
+ if record and not record.future.done():
68
+ record.future.set_exception(error)
69
+
70
+ def reject_all_outgoing(self, error: Any) -> None:
71
+ for record in self._outgoing.values():
72
+ if not record.future.done():
73
+ record.future.set_exception(error)
74
+ self._outgoing.clear()
75
+
76
+ def begin_incoming(self, method: str, params: Any) -> IncomingMessage:
77
+ record = IncomingMessage(method=method, params=params)
78
+ self._incoming.append(record)
79
+ return record
80
+
81
+ def complete_incoming(self, record: IncomingMessage, result: Any) -> None:
82
+ record.status = "completed"
83
+ record.result = result
84
+
85
+ def fail_incoming(self, record: IncomingMessage, error: Any) -> None:
86
+ record.status = "failed"
87
+ record.error = error
acp/task/supervisor.py ADDED
@@ -0,0 +1,93 @@
1
+ """Task Supervisor."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ from collections.abc import Callable
7
+ from contextlib import suppress
8
+ from typing import TYPE_CHECKING, Any
9
+
10
+ from agentpool import log
11
+
12
+
13
+ if TYPE_CHECKING:
14
+ from collections.abc import Coroutine
15
+
16
+
17
+ __all__ = ["TaskSupervisor"]
18
+
19
+ logger = log.get_logger(__name__)
20
+ ErrorHandler = Callable[[asyncio.Task[Any], BaseException], None]
21
+
22
+
23
+ class TaskSupervisor:
24
+ """Track background tasks and provide graceful shutdown semantics.
25
+
26
+ Inspired by fasta2a's task manager, this supervisor keeps a registry of
27
+ asyncio tasks created for request handling so they can be cancelled and
28
+ awaited reliably when the connection closes.
29
+ """
30
+
31
+ def __init__(self, *, source: str) -> None:
32
+ self._source = source
33
+ self._tasks: set[asyncio.Task[Any]] = set()
34
+ self._closed = False
35
+ self._error_handlers: list[ErrorHandler] = []
36
+
37
+ def add_error_handler(self, handler: ErrorHandler) -> None:
38
+ self._error_handlers.append(handler)
39
+
40
+ def create(
41
+ self,
42
+ coroutine: Coroutine[Any, Any, Any],
43
+ *,
44
+ name: str | None = None,
45
+ on_error: ErrorHandler | None = None,
46
+ ) -> asyncio.Task[Any]:
47
+ if self._closed:
48
+ msg = f"TaskSupervisor for {self._source} already closed"
49
+ raise RuntimeError(msg)
50
+ task = asyncio.create_task(coroutine, name=name)
51
+ self._tasks.add(task)
52
+ task.add_done_callback(lambda t: self._on_done(t, on_error))
53
+ return task
54
+
55
+ def _on_done(self, task: asyncio.Task[Any], on_error: ErrorHandler | None) -> None:
56
+ self._tasks.discard(task)
57
+ if task.cancelled():
58
+ return
59
+ try:
60
+ task.result()
61
+ except Exception as exc:
62
+ handled = False
63
+ if on_error is not None:
64
+ try:
65
+ on_error(task, exc)
66
+ handled = True
67
+ except Exception:
68
+ logger.exception(
69
+ "Error in task-specific error handler",
70
+ source=self._source,
71
+ )
72
+ if not handled:
73
+ for handler in self._error_handlers:
74
+ try:
75
+ handler(task, exc)
76
+ handled = True
77
+ except Exception:
78
+ msg = "Error in supervisor error handler"
79
+ logger.exception(msg, source=self._source)
80
+ if not handled:
81
+ logger.exception("Unhandled error in task", source=self._source)
82
+
83
+ async def shutdown(self) -> None:
84
+ self._closed = True
85
+ if not self._tasks:
86
+ return
87
+ tasks = list(self._tasks)
88
+ for task in tasks:
89
+ task.cancel()
90
+ for task in tasks:
91
+ with suppress(asyncio.CancelledError):
92
+ await task
93
+ self._tasks.clear()
acp/terminal_handle.py ADDED
@@ -0,0 +1,30 @@
1
+ """Terminal handle implementation. NOTE: not integrated yet."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+
8
+ if TYPE_CHECKING:
9
+ from acp.acp_requests import ACPRequests
10
+ from acp.schema import TerminalOutputResponse, WaitForTerminalExitResponse
11
+
12
+
13
+ class TerminalHandle:
14
+ """Handle for a terminal session."""
15
+
16
+ def __init__(self, terminal_id: str, requests: ACPRequests) -> None:
17
+ self.terminal_id = terminal_id
18
+ self._requests = requests
19
+
20
+ async def current_output(self) -> TerminalOutputResponse:
21
+ return await self._requests.terminal_output(self.terminal_id)
22
+
23
+ async def wait_for_exit(self) -> WaitForTerminalExitResponse:
24
+ return await self._requests.wait_for_terminal_exit(self.terminal_id)
25
+
26
+ async def kill(self) -> None:
27
+ return await self._requests.kill_terminal(self.terminal_id)
28
+
29
+ async def release(self) -> None:
30
+ return await self._requests.release_terminal(self.terminal_id)