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,419 @@
1
+ """Storage manager for handling multiple providers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ from typing import TYPE_CHECKING, Any, Self
7
+
8
+ from anyenv import method_spawner
9
+ from pydantic_ai import Agent
10
+
11
+ from agentpool.log import get_logger
12
+ from agentpool.storage.serialization import serialize_messages
13
+ from agentpool.utils.tasks import TaskManager
14
+ from agentpool_config.storage import (
15
+ FileStorageConfig,
16
+ MemoryStorageConfig,
17
+ SQLStorageConfig,
18
+ TextLogConfig,
19
+ )
20
+
21
+
22
+ if TYPE_CHECKING:
23
+ from collections.abc import Sequence
24
+ from datetime import datetime
25
+ from types import TracebackType
26
+
27
+ from agentpool.common_types import JsonValue
28
+ from agentpool.messaging import ChatMessage
29
+ from agentpool_config.session import SessionQuery
30
+ from agentpool_config.storage import BaseStorageProviderConfig, StorageConfig
31
+ from agentpool_storage.base import StorageProvider
32
+
33
+ logger = get_logger(__name__)
34
+
35
+
36
+ class StorageManager:
37
+ """Manages multiple storage providers.
38
+
39
+ Handles:
40
+ - Provider initialization and cleanup
41
+ - Message distribution to providers
42
+ - History loading from capable providers
43
+ - Global logging filters
44
+ """
45
+
46
+ def __init__(self, config: StorageConfig) -> None:
47
+ """Initialize storage manager.
48
+
49
+ Args:
50
+ config: Storage configuration including providers and filters
51
+ """
52
+ self.config = config
53
+ self.task_manager = TaskManager()
54
+ self.providers = [self._create_provider(cfg) for cfg in self.config.effective_providers]
55
+
56
+ async def __aenter__(self) -> Self:
57
+ """Initialize all providers."""
58
+ for provider in self.providers:
59
+ await provider.__aenter__()
60
+ return self
61
+
62
+ async def __aexit__(
63
+ self,
64
+ exc_type: type[BaseException] | None,
65
+ exc_val: BaseException | None,
66
+ exc_tb: TracebackType | None,
67
+ ) -> None:
68
+ """Clean up all providers."""
69
+ errors = []
70
+ for provider in self.providers:
71
+ try:
72
+ await provider.__aexit__(exc_type, exc_val, exc_tb)
73
+ except Exception as e:
74
+ errors.append(e)
75
+ logger.exception("Error cleaning up provider", provider=provider)
76
+
77
+ await self.task_manager.cleanup_tasks()
78
+
79
+ if errors:
80
+ msg = "Provider cleanup errors"
81
+ raise ExceptionGroup(msg, errors)
82
+
83
+ def cleanup(self) -> None:
84
+ """Clean up all providers."""
85
+ for provider in self.providers:
86
+ try:
87
+ provider.cleanup()
88
+ except Exception:
89
+ logger.exception("Error cleaning up provider", provider=provider)
90
+ self.providers.clear()
91
+
92
+ def _create_provider(self, config: BaseStorageProviderConfig) -> StorageProvider:
93
+ """Create provider instance from configuration."""
94
+ # Extract common settings from BaseStorageProviderConfig
95
+ match self.config.filter_mode:
96
+ case "and" if self.config.agents and config.agents:
97
+ logged_agents: set[str] | None = self.config.agents & config.agents
98
+ case "and":
99
+ # If either is None, use the other; if both None, use None (log all)
100
+ if self.config.agents is None and config.agents is None:
101
+ logged_agents = None
102
+ else:
103
+ logged_agents = self.config.agents or config.agents or set()
104
+ case "override":
105
+ logged_agents = config.agents if config.agents is not None else self.config.agents
106
+
107
+ provider_config = config.model_copy(
108
+ update={
109
+ "log_messages": config.log_messages and self.config.log_messages,
110
+ "log_conversations": config.log_conversations and self.config.log_conversations,
111
+ "log_commands": config.log_commands and self.config.log_commands,
112
+ "log_context": config.log_context and self.config.log_context,
113
+ "agents": logged_agents,
114
+ }
115
+ )
116
+
117
+ match provider_config:
118
+ case SQLStorageConfig() as config:
119
+ from agentpool_storage.sql_provider import SQLModelProvider
120
+
121
+ return SQLModelProvider(provider_config)
122
+ case FileStorageConfig():
123
+ from agentpool_storage.file_provider import FileProvider
124
+
125
+ return FileProvider(provider_config)
126
+ case TextLogConfig():
127
+ from agentpool_storage.text_log_provider import TextLogProvider
128
+
129
+ return TextLogProvider(provider_config)
130
+
131
+ case MemoryStorageConfig():
132
+ from agentpool_storage.memory_provider import MemoryStorageProvider
133
+
134
+ return MemoryStorageProvider(provider_config)
135
+ case _:
136
+ msg = f"Unknown provider type: {provider_config}"
137
+ raise ValueError(msg)
138
+
139
+ def get_history_provider(self, preferred: str | None = None) -> StorageProvider:
140
+ """Get provider for loading history.
141
+
142
+ Args:
143
+ preferred: Optional preferred provider name
144
+
145
+ Returns:
146
+ First capable provider based on priority:
147
+ 1. Preferred provider if specified and capable
148
+ 2. Default provider if specified and capable
149
+ 3. First capable provider
150
+ 4. Raises error if no capable provider found
151
+ """
152
+
153
+ # Function to find capable provider by name
154
+ def find_provider(name: str) -> StorageProvider | None:
155
+ for p in self.providers:
156
+ if (
157
+ not getattr(p, "write_only", False)
158
+ and p.can_load_history
159
+ and p.__class__.__name__.lower() == name.lower()
160
+ ):
161
+ return p
162
+ return None
163
+
164
+ # Try preferred provider
165
+ if preferred and (provider := find_provider(preferred)):
166
+ return provider
167
+
168
+ # Try default provider
169
+ if self.config.default_provider:
170
+ if provider := find_provider(self.config.default_provider):
171
+ return provider
172
+ msg = "Default provider not found or not capable of loading history"
173
+ logger.warning(msg, provider=self.config.default_provider)
174
+
175
+ # Find first capable provider
176
+ for provider in self.providers:
177
+ if not getattr(provider, "write_only", False) and provider.can_load_history:
178
+ return provider
179
+
180
+ msg = "No capable provider found for loading history"
181
+ raise RuntimeError(msg)
182
+
183
+ @method_spawner
184
+ async def filter_messages(
185
+ self,
186
+ query: SessionQuery,
187
+ preferred_provider: str | None = None,
188
+ ) -> list[ChatMessage[str]]:
189
+ """Get messages matching query.
190
+
191
+ Args:
192
+ query: Filter criteria
193
+ preferred_provider: Optional preferred provider to use
194
+ """
195
+ provider = self.get_history_provider(preferred_provider)
196
+ return await provider.filter_messages(query)
197
+
198
+ @method_spawner
199
+ async def log_message(self, message: ChatMessage[Any]) -> None:
200
+ """Log message to all providers."""
201
+ if not self.config.log_messages:
202
+ return
203
+
204
+ for provider in self.providers:
205
+ if provider.should_log_agent(message.name or "no name"):
206
+ await provider.log_message(
207
+ conversation_id=message.conversation_id or "",
208
+ message_id=message.message_id,
209
+ content=str(message.content),
210
+ role=message.role,
211
+ name=message.name,
212
+ cost_info=message.cost_info,
213
+ model=message.model_name,
214
+ response_time=message.response_time,
215
+ forwarded_from=message.forwarded_from,
216
+ provider_name=message.provider_name,
217
+ provider_response_id=message.provider_response_id,
218
+ messages=serialize_messages(message.messages),
219
+ finish_reason=message.finish_reason,
220
+ )
221
+
222
+ @method_spawner
223
+ async def log_conversation(
224
+ self,
225
+ *,
226
+ conversation_id: str,
227
+ node_name: str,
228
+ start_time: datetime | None = None,
229
+ ) -> None:
230
+ """Log conversation to all providers."""
231
+ if not self.config.log_conversations:
232
+ return
233
+
234
+ for provider in self.providers:
235
+ await provider.log_conversation(
236
+ conversation_id=conversation_id,
237
+ node_name=node_name,
238
+ start_time=start_time,
239
+ )
240
+
241
+ @method_spawner
242
+ async def log_command(
243
+ self,
244
+ *,
245
+ agent_name: str,
246
+ session_id: str,
247
+ command: str,
248
+ context_type: type | None = None,
249
+ metadata: dict[str, JsonValue] | None = None,
250
+ ) -> None:
251
+ """Log command to all providers."""
252
+ if not self.config.log_commands:
253
+ return
254
+
255
+ for provider in self.providers:
256
+ await provider.log_command(
257
+ agent_name=agent_name,
258
+ session_id=session_id,
259
+ command=command,
260
+ context_type=context_type,
261
+ metadata=metadata,
262
+ )
263
+
264
+ @method_spawner
265
+ async def log_context_message(
266
+ self,
267
+ *,
268
+ conversation_id: str,
269
+ content: str,
270
+ role: str,
271
+ name: str | None = None,
272
+ model: str | None = None,
273
+ ) -> None:
274
+ """Log context message to all providers."""
275
+ for provider in self.providers:
276
+ await provider.log_context_message(
277
+ conversation_id=conversation_id,
278
+ content=content,
279
+ role=role,
280
+ name=name,
281
+ model=model,
282
+ )
283
+
284
+ @method_spawner
285
+ async def reset(
286
+ self,
287
+ *,
288
+ agent_name: str | None = None,
289
+ hard: bool = False,
290
+ ) -> tuple[int, int]:
291
+ """Reset storage in all providers concurrently."""
292
+
293
+ async def reset_provider(provider: StorageProvider) -> tuple[int, int]:
294
+ try:
295
+ return await provider.reset(agent_name=agent_name, hard=hard)
296
+ except Exception:
297
+ cls_name = provider.__class__.__name__
298
+ logger.exception("Error resetting provider", provider=cls_name)
299
+ return (0, 0)
300
+
301
+ results = await asyncio.gather(*(reset_provider(provider) for provider in self.providers))
302
+ # Return the counts from the last provider (maintaining existing behavior)
303
+ return results[-1] if results else (0, 0)
304
+
305
+ @method_spawner
306
+ async def get_conversation_counts(
307
+ self,
308
+ *,
309
+ agent_name: str | None = None,
310
+ ) -> tuple[int, int]:
311
+ """Get counts from primary provider."""
312
+ provider = self.get_history_provider()
313
+ return await provider.get_conversation_counts(agent_name=agent_name)
314
+
315
+ @method_spawner
316
+ async def get_commands(
317
+ self,
318
+ agent_name: str,
319
+ session_id: str,
320
+ *,
321
+ limit: int | None = None,
322
+ current_session_only: bool = False,
323
+ preferred_provider: str | None = None,
324
+ ) -> list[str]:
325
+ """Get command history."""
326
+ if not self.config.log_commands:
327
+ return []
328
+
329
+ provider = self.get_history_provider(preferred_provider)
330
+ return await provider.get_commands(
331
+ agent_name=agent_name,
332
+ session_id=session_id,
333
+ limit=limit,
334
+ current_session_only=current_session_only,
335
+ )
336
+
337
+ async def update_conversation_title(
338
+ self,
339
+ conversation_id: str,
340
+ title: str,
341
+ ) -> None:
342
+ """Update conversation title in all providers.
343
+
344
+ Args:
345
+ conversation_id: ID of the conversation to update
346
+ title: New title for the conversation
347
+ """
348
+ for provider in self.providers:
349
+ await provider.update_conversation_title(conversation_id, title)
350
+
351
+ async def get_conversation_title(
352
+ self,
353
+ conversation_id: str,
354
+ ) -> str | None:
355
+ """Get the title of a conversation.
356
+
357
+ Args:
358
+ conversation_id: ID of the conversation
359
+
360
+ Returns:
361
+ The conversation title, or None if not set.
362
+ """
363
+ provider = self.get_history_provider()
364
+ return await provider.get_conversation_title(conversation_id)
365
+
366
+ async def generate_conversation_title(
367
+ self,
368
+ conversation_id: str,
369
+ messages: Sequence[ChatMessage[Any]],
370
+ ) -> str | None:
371
+ """Generate and store a title for a conversation.
372
+
373
+ Uses the configured title generation model to create a short,
374
+ descriptive title based on the conversation content.
375
+
376
+ Args:
377
+ conversation_id: ID of the conversation to title
378
+ messages: Messages to use for title generation
379
+
380
+ Returns:
381
+ The generated title, or None if title generation is disabled.
382
+ """
383
+ if not self.config.title_generation_model:
384
+ return None
385
+
386
+ # Check if title already exists
387
+ existing = await self.get_conversation_title(conversation_id)
388
+ if existing:
389
+ return existing
390
+
391
+ # Format messages for the prompt
392
+ formatted = "\n".join(
393
+ f"{msg.role}: {msg.content[:500]}"
394
+ for msg in messages[:4] # Limit context
395
+ )
396
+
397
+ try:
398
+ agent: Agent[None, str] = Agent(
399
+ model=self.config.title_generation_model,
400
+ instructions=self.config.title_generation_prompt,
401
+ )
402
+ result = await agent.run(formatted)
403
+ title = result.output.strip().strip("\"'") # Remove quotes if present
404
+
405
+ # Store the title
406
+ await self.update_conversation_title(conversation_id, title)
407
+ logger.debug(
408
+ "Generated conversation title",
409
+ conversation_id=conversation_id,
410
+ title=title,
411
+ )
412
+ except Exception:
413
+ logger.exception(
414
+ "Failed to generate conversation title",
415
+ conversation_id=conversation_id,
416
+ )
417
+ return None
418
+ else:
419
+ return title
@@ -0,0 +1,136 @@
1
+ """Serialization utilities."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ from pydantic import ConfigDict, TypeAdapter
8
+
9
+ from agentpool.log import get_logger
10
+
11
+
12
+ if TYPE_CHECKING:
13
+ from collections.abc import Sequence
14
+
15
+ from pydantic_ai import ModelMessage, ModelRequestPart, ModelResponsePart
16
+
17
+
18
+ logger = get_logger(__name__)
19
+
20
+ # Type adapter for serializing ModelResponsePart sequences
21
+ parts_adapter = TypeAdapter(
22
+ list,
23
+ config=ConfigDict(ser_json_bytes="base64", val_json_bytes="base64"),
24
+ )
25
+
26
+ # Type adapter for serializing ModelMessage sequences
27
+ messages_adapter = TypeAdapter(
28
+ list,
29
+ config=ConfigDict(ser_json_bytes="base64", val_json_bytes="base64"),
30
+ )
31
+
32
+
33
+ def deserialize_parts(parts_json: str | None) -> Sequence[ModelResponsePart]:
34
+ """Deserialize pydantic-ai message parts from JSON string.
35
+
36
+ Args:
37
+ parts_json: JSON string representation of parts or None if empty
38
+
39
+ Returns:
40
+ Sequence of ModelResponsePart objects, empty if deserialization fails
41
+ """
42
+ if not parts_json:
43
+ return []
44
+
45
+ try:
46
+ # Deserialize using pydantic's JSON deserialization
47
+ return parts_adapter.validate_json(parts_json.encode())
48
+ except Exception as e: # noqa: BLE001
49
+ logger.warning("Failed to deserialize message parts", error=e)
50
+ return [] # Return empty list on failure
51
+
52
+
53
+ def serialize_parts(parts: Sequence[ModelResponsePart | ModelRequestPart]) -> str | None:
54
+ """Serialize pydantic-ai message parts from ChatMessage.
55
+
56
+ Args:
57
+ parts: Sequence of ModelResponsePart from ChatMessage.parts
58
+
59
+ Returns:
60
+ JSON string representation of parts or None if empty
61
+ """
62
+ if not parts:
63
+ return None
64
+
65
+ try:
66
+ # Convert parts to serializable format
67
+ serializable_parts = []
68
+ for part in parts:
69
+ # Handle RetryPromptPart context serialization issues
70
+ from pydantic_ai import RetryPromptPart
71
+
72
+ if isinstance(part, RetryPromptPart) and isinstance(part.content, list):
73
+ for content in part.content:
74
+ if isinstance(content, dict) and "ctx" in content:
75
+ content["ctx"] = {k: str(v) for k, v in content["ctx"].items()}
76
+ serializable_parts.append(part)
77
+
78
+ # Serialize using pydantic's JSON serialization
79
+ return parts_adapter.dump_json(serializable_parts).decode()
80
+ except Exception as e: # noqa: BLE001
81
+ logger.warning("Failed to serialize message parts", error=e)
82
+ return str(parts) # Fallback to string representation
83
+
84
+
85
+ def deserialize_messages(messages_json: str | None) -> list[ModelMessage]:
86
+ """Deserialize pydantic-ai ModelMessage list from JSON string.
87
+
88
+ Args:
89
+ messages_json: JSON string representation of messages or None if empty
90
+
91
+ Returns:
92
+ List of ModelMessage objects, empty if deserialization fails
93
+ """
94
+ if not messages_json:
95
+ return []
96
+
97
+ try:
98
+ # Deserialize using pydantic's JSON deserialization
99
+ return messages_adapter.validate_json(messages_json.encode())
100
+ except Exception as e: # noqa: BLE001
101
+ logger.warning("Failed to deserialize model messages", error=e)
102
+ return [] # Return empty list on failure
103
+
104
+
105
+ def serialize_messages(messages: Sequence[ModelMessage]) -> str | None:
106
+ """Serialize pydantic-ai ModelMessage list to JSON string.
107
+
108
+ Args:
109
+ messages: Sequence of ModelMessage objects from ChatMessage.messages
110
+
111
+ Returns:
112
+ JSON string representation of messages or None if empty
113
+ """
114
+ if not messages:
115
+ return None
116
+
117
+ try:
118
+ # Convert messages to serializable format
119
+ serializable_messages = []
120
+ for message in messages:
121
+ # Handle RetryPromptPart context serialization issues
122
+ from pydantic_ai import ModelRequest, RetryPromptPart
123
+
124
+ if isinstance(message, ModelRequest):
125
+ for part in message.parts:
126
+ if isinstance(part, RetryPromptPart) and isinstance(part.content, list):
127
+ for content in part.content:
128
+ if isinstance(content, dict) and "ctx" in content:
129
+ content["ctx"] = {k: str(v) for k, v in content["ctx"].items()}
130
+ serializable_messages.append(message)
131
+
132
+ # Serialize using pydantic's JSON serialization
133
+ return messages_adapter.dump_json(serializable_messages).decode()
134
+ except Exception as e: # noqa: BLE001
135
+ logger.warning("Failed to serialize model messages", error=e)
136
+ return str(messages) # Fallback to string representation
@@ -0,0 +1,13 @@
1
+ """Talk classes."""
2
+
3
+ from agentpool.talk.stats import TalkStats, AggregatedTalkStats
4
+ from agentpool.talk.talk import Talk, TeamTalk
5
+ from agentpool.talk.registry import ConnectionRegistry
6
+
7
+ __all__ = [
8
+ "AggregatedTalkStats",
9
+ "ConnectionRegistry",
10
+ "Talk",
11
+ "TalkStats",
12
+ "TeamTalk",
13
+ ]
@@ -0,0 +1,128 @@
1
+ """Manages message flow between agents/groups."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from typing import TYPE_CHECKING, Any, Literal
7
+
8
+ from psygnal import Signal
9
+
10
+ from agentpool.log import get_logger
11
+ from agentpool.talk.talk import Talk
12
+ from agentpool.utils.baseregistry import AgentPoolError, BaseRegistry
13
+
14
+
15
+ if TYPE_CHECKING:
16
+ from agentpool import MessageNode
17
+ from agentpool.messaging import ChatMessage
18
+ from agentpool.talk.stats import TalkStats
19
+ from agentpool_config.conditions import ConnectionCondition
20
+
21
+
22
+ logger = get_logger(__name__)
23
+
24
+
25
+ class ConnectionRegistryError(AgentPoolError):
26
+ """Errors related to connection registration."""
27
+
28
+
29
+ @dataclass(frozen=True)
30
+ class EventContext[TMessageContent]:
31
+ """Base context for all condition/event operations."""
32
+
33
+ message: ChatMessage[TMessageContent]
34
+ """The message being processed."""
35
+
36
+ target: MessageNode[Any, Any]
37
+ """The target node this message is being sent to."""
38
+
39
+ stats: TalkStats
40
+ """Statistics for the current connection."""
41
+
42
+ registry: ConnectionRegistry | None
43
+ """Registry of all named connections."""
44
+
45
+ talk: Talk
46
+ """The Talk instance handling this message flow."""
47
+
48
+
49
+ @dataclass(frozen=True)
50
+ class TriggerContext[TMessageContent](EventContext[TMessageContent]):
51
+ """Context for trigger events, extending base context with event information."""
52
+
53
+ event_type: Literal["condition_met", "message_processed", "disconnected"]
54
+ """Type of event that triggered this call."""
55
+
56
+ condition: ConnectionCondition
57
+ """The condition that was triggered (if event_type is condition_met)."""
58
+
59
+
60
+ class ConnectionRegistry(BaseRegistry[str, Talk]):
61
+ """Registry for managing named connections.
62
+
63
+ Allows looking up Talk instances by their name. Only named
64
+ connections get registered.
65
+ """
66
+
67
+ message_flow = Signal(Talk.ConnectionProcessed)
68
+
69
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
70
+ """Initialize registry and connect event handlers."""
71
+ super().__init__(*args, **kwargs)
72
+ # Connect handlers to EventedDict events
73
+ self._items.events.added.connect(self._on_talk_added)
74
+ self._items.events.removed.connect(self._on_talk_removed)
75
+ self._items.events.changed.connect(self._on_talk_changed)
76
+
77
+ def _on_talk_added(self, name: str, talk: Talk) -> None:
78
+ """Handle new talk being added to registry."""
79
+ talk.connection_processed.connect(self._handle_message_flow)
80
+ logger.debug("Connected signal for talk", name=name)
81
+
82
+ def _on_talk_removed(self, name: str, talk: Talk) -> None:
83
+ """Handle talk being removed from registry."""
84
+ talk.connection_processed.disconnect(self._handle_message_flow)
85
+ logger.debug("Disconnected signal for talk", name=name)
86
+
87
+ def _on_talk_changed(self, name: str, old_talk: Talk, new_talk: Talk) -> None:
88
+ """Handle talk being replaced in registry."""
89
+ old_talk.connection_processed.disconnect(self._handle_message_flow)
90
+ new_talk.connection_processed.connect(self._handle_message_flow)
91
+ logger.debug("Reconnected signal for talk", name=name)
92
+
93
+ def _handle_message_flow(self, event: Talk.ConnectionProcessed) -> None:
94
+ """Forward message flow to global stream."""
95
+ self.message_flow.emit(event)
96
+
97
+ @property
98
+ def _error_class(self) -> type[ConnectionRegistryError]:
99
+ return ConnectionRegistryError
100
+
101
+ def _validate_item(self, item: Any) -> Talk:
102
+ """Ensure only Talk instances can be registered."""
103
+ if not isinstance(item, Talk):
104
+ msg = f"Expected Talk instance, got {type(item)}"
105
+ raise self._error_class(msg)
106
+
107
+ return item
108
+
109
+ def register_auto(self, talk: Talk[Any], base_name: str | None = None) -> str:
110
+ """Register talk with auto-generated unique name.
111
+
112
+ Args:
113
+ talk: Talk instance to register
114
+ base_name: Optional base name to use (defaults to talk.name)
115
+
116
+ Returns:
117
+ The actual name used for registration
118
+ """
119
+ base = base_name or talk.name
120
+ counter = 1
121
+ name = base
122
+
123
+ while name in self:
124
+ name = f"{base}_{counter}"
125
+ counter += 1
126
+ talk.name = name
127
+ self.register(name, talk)
128
+ return name