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
@@ -0,0 +1,309 @@
1
+ """AggregatingServer for managing multiple servers with shared pool."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ from contextlib import AsyncExitStack
7
+ from dataclasses import dataclass
8
+ from typing import TYPE_CHECKING, Any, Literal, Self
9
+
10
+ from agentpool.log import get_logger
11
+ from agentpool_server.base import BaseServer
12
+
13
+
14
+ if TYPE_CHECKING:
15
+ from collections.abc import Sequence
16
+ from types import TracebackType
17
+
18
+ from agentpool import AgentPool
19
+
20
+ # Type-safe server status literals
21
+ ServerStatus = Literal["not_initialized", "initialized", "running", "failed", "stopped"]
22
+
23
+
24
+ @dataclass(frozen=True)
25
+ class ServerInfo:
26
+ """Type-safe server information."""
27
+
28
+ name: str
29
+ server_type: type[BaseServer]
30
+ status: ServerStatus
31
+
32
+
33
+ logger = get_logger(__name__)
34
+
35
+
36
+ class AggregatingServer(BaseServer):
37
+ """Server that manages multiple protocol servers sharing one AgentPool.
38
+
39
+ Coordinates multiple server instances (AG-UI, A2A, MCP, etc.) as a single unit.
40
+ All servers share the same AgentPool and are started/stopped together.
41
+
42
+ This is useful when you want to expose the same pool of agents via multiple
43
+ protocols simultaneously (e.g., AG-UI for web clients, A2A for agent-to-agent
44
+ communication).
45
+
46
+ Example:
47
+ ```python
48
+ async with AgentPool(config) as pool:
49
+ servers = [
50
+ AGUIServer(pool, port=8002),
51
+ A2AServer(pool, port=8001),
52
+ ]
53
+ async with AggregatingServer(pool, servers) as agg:
54
+ async with agg.run_context():
55
+ # Both servers running, sharing the same pool
56
+ await asyncio.Event().wait()
57
+ ```
58
+ """
59
+
60
+ def __init__(
61
+ self,
62
+ pool: AgentPool[Any],
63
+ servers: Sequence[BaseServer],
64
+ *,
65
+ name: str | None = None,
66
+ raise_exceptions: bool = False,
67
+ ) -> None:
68
+ """Initialize aggregating server.
69
+
70
+ Args:
71
+ pool: AgentPool to be shared by all servers
72
+ servers: Sequence of servers to aggregate
73
+ name: Server name for logging (auto-generated if None)
74
+ raise_exceptions: Whether to raise exceptions during server start
75
+ """
76
+ if not servers:
77
+ msg = "At least one server must be provided"
78
+ raise ValueError(msg)
79
+
80
+ super().__init__(pool, name=name, raise_exceptions=raise_exceptions)
81
+
82
+ self.servers = list(servers)
83
+ self.exit_stack = AsyncExitStack()
84
+ self._initialized_servers: list[BaseServer] = []
85
+
86
+ async def __aenter__(self) -> Self:
87
+ """Initialize aggregating server and all child servers."""
88
+ await super().__aenter__()
89
+
90
+ self.log.info("Initializing aggregated servers", count=len(self.servers))
91
+
92
+ try:
93
+ for server in self.servers:
94
+ try:
95
+ initialized_server = await self.exit_stack.enter_async_context(server)
96
+ self._initialized_servers.append(initialized_server)
97
+ self.log.info("Initialized server", server_name=server.name)
98
+ except Exception:
99
+ self.log.exception("Failed to initialize server", server_name=server.name)
100
+ if self.raise_exceptions:
101
+ raise
102
+
103
+ if not self._initialized_servers:
104
+ msg = "No servers were successfully initialized"
105
+ raise RuntimeError(msg) # noqa: TRY301
106
+
107
+ self.log.info(
108
+ "All servers initialized",
109
+ successful=len(self._initialized_servers),
110
+ failed=len(self.servers) - len(self._initialized_servers),
111
+ )
112
+
113
+ except Exception:
114
+ await self.exit_stack.aclose()
115
+ raise
116
+
117
+ return self
118
+
119
+ async def __aexit__(
120
+ self,
121
+ exc_type: type[BaseException] | None,
122
+ exc_val: BaseException | None,
123
+ exc_tb: TracebackType | None,
124
+ ) -> None:
125
+ """Cleanup all servers and base server resources."""
126
+ self.log.info("Shutting down aggregated servers")
127
+
128
+ await self.exit_stack.aclose()
129
+ self._initialized_servers.clear()
130
+
131
+ await super().__aexit__(exc_type, exc_val, exc_tb)
132
+
133
+ self.log.info("Aggregated servers shutdown complete")
134
+
135
+ async def _start_async(self) -> None:
136
+ """Start all initialized servers concurrently."""
137
+ if not self._initialized_servers:
138
+ self.log.warning("No initialized servers to start")
139
+ return
140
+
141
+ self.log.info("Starting aggregated servers", count=len(self._initialized_servers))
142
+
143
+ server_tasks: list[tuple[BaseServer, asyncio.Task[None] | None]] = []
144
+
145
+ for server in self._initialized_servers:
146
+ try:
147
+ server.start_background()
148
+ server_tasks.append((server, server._server_task))
149
+ self.log.info("Started server in background", server=server.name)
150
+ except Exception:
151
+ self.log.exception("Failed to start server", server=server.name)
152
+ if self.raise_exceptions:
153
+ for started_server, _ in server_tasks:
154
+ try:
155
+ started_server.stop()
156
+ except Exception:
157
+ self.log.exception(
158
+ "Error stopping server", server_name=started_server.name
159
+ )
160
+ raise
161
+
162
+ if not server_tasks:
163
+ msg = "No servers were successfully started"
164
+ raise RuntimeError(msg)
165
+
166
+ self.log.info(
167
+ "All servers started",
168
+ successful=len(server_tasks),
169
+ failed=len(self._initialized_servers) - len(server_tasks),
170
+ )
171
+
172
+ tasks = [task for _, task in server_tasks if task is not None]
173
+ if tasks:
174
+ await self._wait_for_tasks(tasks, server_tasks)
175
+
176
+ async def _wait_for_tasks(
177
+ self,
178
+ tasks: list[asyncio.Task[None]],
179
+ server_tasks: Sequence[tuple[BaseServer, asyncio.Task[None] | None]],
180
+ ) -> None:
181
+ """Wait for server tasks and handle shutdown."""
182
+ try:
183
+ done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
184
+
185
+ for task in done:
186
+ if task.exception():
187
+ self.log.error("Server task failed", error=task.exception())
188
+ else:
189
+ self.log.info("Server task completed")
190
+
191
+ # Stop all other servers gracefully
192
+ for server, _ in server_tasks:
193
+ try:
194
+ server.stop()
195
+ except Exception:
196
+ self.log.exception("Error stopping server")
197
+
198
+ if pending:
199
+ for task in pending:
200
+ task.cancel()
201
+ await asyncio.gather(*pending, return_exceptions=True)
202
+
203
+ except asyncio.CancelledError:
204
+ for server, _ in server_tasks:
205
+ try:
206
+ server.stop()
207
+ except Exception:
208
+ self.log.exception("Error stopping server during cancellation")
209
+ raise
210
+
211
+ def add_server(self, server: BaseServer) -> None:
212
+ """Add a server to the aggregation.
213
+
214
+ Args:
215
+ server: Server to add
216
+
217
+ Raises:
218
+ RuntimeError: If aggregating server is currently running
219
+ """
220
+ if self.is_running:
221
+ msg = "Cannot add server while aggregating server is running"
222
+ raise RuntimeError(msg)
223
+
224
+ self.servers.append(server)
225
+ self.log.info("Added server to aggregation", server=server.name)
226
+
227
+ def remove_server(self, server: BaseServer) -> None:
228
+ """Remove a server from the aggregation.
229
+
230
+ Args:
231
+ server: Server to remove
232
+
233
+ Raises:
234
+ RuntimeError: If aggregating server is currently running
235
+ ValueError: If server is not in aggregation
236
+ """
237
+ if self.is_running:
238
+ msg = "Cannot remove server while aggregating server is running"
239
+ raise RuntimeError(msg)
240
+
241
+ try:
242
+ self.servers.remove(server)
243
+ self.log.info("Removed server from aggregation", server=server.name)
244
+ except ValueError as e:
245
+ msg = f"Server {server.name} not found in aggregation"
246
+ raise ValueError(msg) from e
247
+
248
+ def get_server(self, name: str) -> BaseServer | None:
249
+ """Get a server by name from the aggregation.
250
+
251
+ Args:
252
+ name: Server name to find
253
+
254
+ Returns:
255
+ Server instance or None if not found
256
+ """
257
+ all_servers = self.servers + self._initialized_servers
258
+ for server in all_servers:
259
+ if server.name == name:
260
+ return server
261
+ return None
262
+
263
+ def list_servers(self) -> list[ServerInfo]:
264
+ """List all servers in the aggregation with their status.
265
+
266
+ Returns:
267
+ List of type-safe ServerInfo objects
268
+ """
269
+ return [
270
+ ServerInfo(
271
+ name=server.name,
272
+ server_type=type(server),
273
+ status=self._get_server_status(server),
274
+ )
275
+ for server in self.servers
276
+ ]
277
+
278
+ def get_server_status(self) -> dict[str, ServerStatus]:
279
+ """Get status of all servers.
280
+
281
+ Returns:
282
+ Dict mapping server names to their type-safe status
283
+ """
284
+ return {server.name: self._get_server_status(server) for server in self.servers}
285
+
286
+ def _get_server_status(self, server: BaseServer) -> ServerStatus:
287
+ """Get type-safe status for a specific server."""
288
+ if server in self._initialized_servers:
289
+ return "running" if server.is_running else "initialized"
290
+ return "not_initialized"
291
+
292
+ @property
293
+ def initialized_server_count(self) -> int:
294
+ """Number of successfully initialized servers."""
295
+ return len(self._initialized_servers)
296
+
297
+ @property
298
+ def running_server_count(self) -> int:
299
+ """Number of currently running servers."""
300
+ return sum(1 for server in self._initialized_servers if server.is_running)
301
+
302
+ def __repr__(self) -> str:
303
+ """String representation of aggregating server."""
304
+ return (
305
+ f"AggregatingServer(name={self.name}, "
306
+ f"servers={len(self.servers)}, "
307
+ f"initialized={len(self._initialized_servers)}, "
308
+ f"running={self.running_server_count})"
309
+ )
@@ -0,0 +1,11 @@
1
+ """AG-UI server module for agentpool.
2
+
3
+ This module provides server implementation for exposing AgentPool agents
4
+ via the AG-UI protocol with each agent on its own route.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from agentpool_server.agui_server.server import AGUIServer
10
+
11
+ __all__ = ["AGUIServer"]
@@ -0,0 +1,128 @@
1
+ """AG-UI server implementation for agentpool pool.
2
+
3
+ This module provides a server that exposes all agents in an AgentPool
4
+ via the AG-UI protocol, with each agent accessible at its own route.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import TYPE_CHECKING
10
+
11
+ from agentpool.log import get_logger
12
+ from agentpool_server.http_server import HTTPServer
13
+
14
+
15
+ if TYPE_CHECKING:
16
+ from starlette.requests import Request
17
+ from starlette.responses import Response
18
+ from starlette.routing import Route
19
+
20
+ from agentpool import AgentPool
21
+
22
+
23
+ logger = get_logger(__name__)
24
+
25
+ DEFAULT_PORT = 8002
26
+
27
+
28
+ class AGUIServer(HTTPServer):
29
+ """AG-UI server for exposing pool agents on separate routes.
30
+
31
+ Provides a unified HTTP server that exposes all agents in the pool via
32
+ the AG-UI protocol. Each agent is accessible at `/{agent_name}` route.
33
+
34
+ Example:
35
+ ```python
36
+ pool = AgentPool(manifest)
37
+
38
+ server = AGUIServer(pool, host="localhost", port=8002)
39
+
40
+ async with server:
41
+ async with server.run_context():
42
+ # Agents accessible at:
43
+ # POST http://localhost:8002/agent1
44
+ # POST http://localhost:8002/agent2
45
+ await do_other_work()
46
+ ```
47
+ """
48
+
49
+ def __init__(
50
+ self,
51
+ pool: AgentPool,
52
+ *,
53
+ name: str | None = None,
54
+ host: str = "localhost",
55
+ port: int = DEFAULT_PORT,
56
+ raise_exceptions: bool = False,
57
+ ) -> None:
58
+ """Initialize AG-UI server.
59
+
60
+ Args:
61
+ pool: AgentPool containing available agents
62
+ name: Optional server name (auto-generated if None)
63
+ host: Host to bind server to
64
+ port: Port to bind server to
65
+ raise_exceptions: Whether to raise exceptions during server start
66
+ """
67
+ super().__init__(pool, name=name, host=host, port=port, raise_exceptions=raise_exceptions)
68
+
69
+ async def get_routes(self) -> list[Route]:
70
+ """Get Starlette routes for AG-UI protocol.
71
+
72
+ Returns:
73
+ List of Route objects for each agent plus root listing endpoint
74
+ """
75
+ from pydantic_ai.ui.ag_ui import AGUIAdapter
76
+ from starlette.routing import Route
77
+
78
+ routes: list[Route] = []
79
+
80
+ # Create route for each agent in the pool
81
+ for agent_name in self.pool.agents:
82
+
83
+ async def agent_handler(request: Request, agent_name: str = agent_name) -> Response:
84
+ """Handle AG-UI requests for a specific agent."""
85
+ from starlette.responses import JSONResponse
86
+
87
+ pool_agent = self.pool.agents.get(agent_name)
88
+ if pool_agent is None:
89
+ msg = f"Agent {agent_name!r} not found"
90
+ return JSONResponse({"error": msg}, status_code=404)
91
+ agentlet = await pool_agent.get_agentlet(None, pool_agent.model_name, str)
92
+ try:
93
+ # Use AGUIAdapter.dispatch_request() which handles the full
94
+ # AG-UI protocol: parsing request, running agent, streaming response
95
+ return await AGUIAdapter.dispatch_request(request, agent=agentlet)
96
+ except Exception as e:
97
+ self.log.exception("Error handling AG-UI request", agent=agent_name)
98
+ return JSONResponse({"error": str(e)}, status_code=500)
99
+
100
+ routes.append(Route(f"/{agent_name}", agent_handler, methods=["POST"]))
101
+ self.log.debug("Registered AG-UI route", agent=agent_name, route=f"/{agent_name}")
102
+
103
+ # Add root endpoint that lists available agents
104
+ async def list_agents(request: Request) -> Response:
105
+ """List all available agents."""
106
+ from starlette.responses import JSONResponse
107
+
108
+ agent_list = [
109
+ {"name": name, "route": f"/{name}", "model": agent.model_name}
110
+ for name, agent in self.pool.agents.items()
111
+ ]
112
+ return JSONResponse({"agents": agent_list, "count": len(agent_list)})
113
+
114
+ routes.append(Route("/", list_agents, methods=["GET"]))
115
+ self.log.info("Created AG-UI routes", agent_count=len(self.pool.agents))
116
+ return routes
117
+
118
+ def get_agent_url(self, agent_name: str) -> str:
119
+ """Get the endpoint URL for a specific agent."""
120
+ return f"{self.base_url}/{agent_name}"
121
+
122
+ def list_agent_routes(self) -> dict[str, str]:
123
+ """List all agent routes.
124
+
125
+ Returns:
126
+ Dictionary mapping agent names to their URLs
127
+ """
128
+ return {name: self.get_agent_url(name) for name in self.pool.agents}
@@ -0,0 +1,189 @@
1
+ """Base server class for AgentPool servers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ from contextlib import asynccontextmanager
7
+ from typing import TYPE_CHECKING, Any, Self
8
+
9
+ from agentpool.log import get_logger
10
+ from agentpool.utils.tasks import TaskManager
11
+
12
+
13
+ if TYPE_CHECKING:
14
+ from collections.abc import AsyncIterator
15
+ from types import TracebackType
16
+
17
+ from agentpool import AgentPool
18
+
19
+ logger = get_logger(__name__)
20
+
21
+
22
+ class BaseServer:
23
+ """Base class for all AgentPool servers.
24
+
25
+ Provides standardized interface for server lifecycle management:
26
+ - async def _start_async() - blocking server execution (implemented by subclasses)
27
+ - def start_background() - non-blocking server start via background task
28
+ - def stop() - stop background server task
29
+ - async with run_context() - automatic server start/stop management
30
+
31
+ Features:
32
+ - Centralized task management via TaskManager
33
+ - Configurable exception handling via raise_exceptions parameter
34
+ - Automatic pool lifecycle management
35
+ - Background task lifecycle management
36
+ """
37
+
38
+ def __init__(
39
+ self,
40
+ pool: AgentPool[Any],
41
+ *,
42
+ name: str | None = None,
43
+ raise_exceptions: bool = False,
44
+ **kwargs: Any,
45
+ ) -> None:
46
+ """Initialize base server with agent pool.
47
+
48
+ Args:
49
+ pool: AgentPool containing available agents
50
+ name: Optional Server name (auto-generated from class name if None)
51
+ raise_exceptions: Whether to raise exceptions during server start
52
+ **kwargs: Additional arguments (for subclass compatibility)
53
+ """
54
+ self.pool = pool
55
+ self.name = name or f"{self.__class__.__name__}-{id(self):x}"
56
+ self.raise_exceptions = raise_exceptions
57
+ self.task_manager = TaskManager()
58
+ self._server_task: asyncio.Task[None] | None = None
59
+ self._shutdown_event = asyncio.Event()
60
+ self.log = logger.bind(server_name=self.name)
61
+
62
+ async def __aenter__(self) -> Self:
63
+ """Enter async context and initialize server resources (pool, etc.)."""
64
+ await self.pool.__aenter__()
65
+ return self
66
+
67
+ async def __aexit__(
68
+ self,
69
+ exc_type: type[BaseException] | None,
70
+ exc_val: BaseException | None,
71
+ exc_tb: TracebackType | None,
72
+ ) -> None:
73
+ """Exit async context and cleanup server resources."""
74
+ # Cleanup any pending tasks
75
+ await self.task_manager.cleanup_tasks()
76
+ # Cleanup pool
77
+ await self.pool.__aexit__(exc_type, exc_val, exc_tb)
78
+
79
+ async def _start_async(self) -> None:
80
+ """Start the server (blocking async - runs until stopped).
81
+
82
+ This method must be implemented by subclasses and should run
83
+ the server until it's stopped or encounters an error.
84
+
85
+ This is the internal implementation that subclasses override.
86
+ The public start() method handles exception management.
87
+ """
88
+ msg = "Subclasses must implement _start_async()"
89
+ raise NotImplementedError(msg)
90
+
91
+ async def start(self) -> None:
92
+ """Start the server (blocking async - runs until stopped).
93
+
94
+ This is the public interface that handles exception management
95
+ based on the raise_exceptions setting. Subclasses should implement
96
+ _start_async() instead of overriding this method.
97
+ """
98
+ try:
99
+ self.log.info("Starting server")
100
+ await self._start_async()
101
+ except Exception as e:
102
+ if self.raise_exceptions:
103
+ raise
104
+ self.log.exception("Server error", exc_info=e)
105
+ finally:
106
+ await self.shutdown()
107
+
108
+ async def shutdown(self) -> None:
109
+ """Shutdown server resources.
110
+
111
+ This method can be overridden by subclasses to add specific
112
+ cleanup logic. The base implementation handles task cleanup.
113
+ """
114
+ try:
115
+ await self.task_manager.cleanup_tasks()
116
+ except Exception:
117
+ self.log.exception("Error during server shutdown")
118
+ finally:
119
+ self._shutdown_event.set()
120
+ self.log.info("Server shutdown complete")
121
+
122
+ def start_background(self) -> None:
123
+ """Start server in background task (non-blocking).
124
+
125
+ Creates a background task that runs start() method.
126
+ Server will run in the background until stop() is called.
127
+ """
128
+ if self._server_task is not None and not self._server_task.done():
129
+ msg = "Server is already running in background"
130
+ raise RuntimeError(msg)
131
+
132
+ self._shutdown_event.clear()
133
+ self._server_task = self.task_manager.create_task(
134
+ self._run_with_shutdown(), name=f"{self.name}-task"
135
+ )
136
+
137
+ async def _run_with_shutdown(self) -> None:
138
+ """Internal wrapper that handles shutdown signaling."""
139
+ try:
140
+ await self.start()
141
+ finally:
142
+ self._shutdown_event.set()
143
+
144
+ def stop(self) -> None:
145
+ """Stop the background server task (non-blocking)."""
146
+ if self._server_task is not None and not self._server_task.done():
147
+ self._server_task.cancel()
148
+
149
+ async def wait_until_stopped(self) -> None:
150
+ """Wait until the server stops (either by stop() or natural completion)."""
151
+ if self._server_task is None:
152
+ return
153
+
154
+ # Wait for either task completion or shutdown event
155
+ await self._shutdown_event.wait()
156
+
157
+ # Ensure task is cleaned up
158
+ if self._server_task and not self._server_task.done():
159
+ self._server_task.cancel()
160
+
161
+ if self._server_task:
162
+ await asyncio.gather(self._server_task, return_exceptions=True)
163
+ self._server_task = None
164
+
165
+ @property
166
+ def is_running(self) -> bool:
167
+ """Check if server is currently running in background."""
168
+ return self._server_task is not None and not self._server_task.done()
169
+
170
+ @asynccontextmanager
171
+ async def run_context(self) -> AsyncIterator[None]:
172
+ """Async context manager for automatic server start/stop.
173
+
174
+ Starts the server in background when entering context,
175
+ automatically stops it when exiting context.
176
+
177
+ Example:
178
+ async with server: # Initialize resources
179
+ async with server.run_context(): # Start server
180
+ # Server is running in background
181
+ await do_other_work()
182
+ # Server automatically stopped
183
+ """
184
+ self.start_background()
185
+ try:
186
+ yield
187
+ finally:
188
+ self.stop()
189
+ await self.wait_until_stopped()