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,206 @@
1
+ """Jinja2 environment configuration."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Any, Literal
6
+
7
+ from pydantic import BaseModel, ConfigDict, Field
8
+ from schemez import Schema
9
+
10
+ from agentpool_config.tools import ToolConfig
11
+
12
+
13
+ if TYPE_CHECKING:
14
+ from jinja2 import Template
15
+ from jinjarope import Environment
16
+
17
+ UndefinedBehaviour = Literal["default", "strict", "debug", "chainable", "lax"]
18
+ NewLineType = Literal["\n", "\r\n", "\r"]
19
+
20
+
21
+ class Jinja2EnvironmentConfig(Schema):
22
+ """Configuration for Jinja2 environment.
23
+
24
+ See: https://jinja.palletsprojects.com/en/3.1.x/api/#jinja2.Environment
25
+ """
26
+
27
+ model_config = ConfigDict(json_schema_extra={"title": "Jinja2 Environment Configuration"})
28
+
29
+ block_start_string: str = Field(default="{%", title="Block start string", examples=["{%", "<%"])
30
+ """String denoting the beginning of a block (default: '{%')."""
31
+
32
+ block_end_string: str = Field(default="%}", title="Block end string", examples=["%}", "%>"])
33
+ """String denoting the end of a block (default: '%}')."""
34
+
35
+ variable_start_string: str = Field(
36
+ default="{{",
37
+ title="Variable start string",
38
+ examples=["{{", "${"],
39
+ )
40
+ """String denoting the beginning of a variable (default: '{{')."""
41
+
42
+ variable_end_string: str = Field(
43
+ default="}}",
44
+ title="Variable end string",
45
+ examples=["}}", "}"],
46
+ )
47
+ """String denoting the end of a variable (default: '}}')."""
48
+
49
+ comment_start_string: str = Field(
50
+ default="{#",
51
+ title="Comment start string",
52
+ examples=["{#", "<!--"],
53
+ )
54
+ """String denoting the beginning of a comment (default: '{#')."""
55
+
56
+ comment_end_string: str = Field(
57
+ default="#}",
58
+ title="Comment end string",
59
+ examples=["#}", "-->"],
60
+ )
61
+ """String denoting the end of a comment (default: '#}')."""
62
+
63
+ line_statement_prefix: str | None = Field(
64
+ default=None,
65
+ title="Line statement prefix",
66
+ examples=["#", "%"],
67
+ )
68
+ """Prefix that begins a line-based statement (e.g., '#' for line statements)."""
69
+
70
+ line_comment_prefix: str | None = Field(
71
+ default=None,
72
+ title="Line comment prefix",
73
+ examples=["##", "//"],
74
+ )
75
+ """Prefix that begins a line-based comment."""
76
+
77
+ trim_blocks: bool = Field(default=False, title="Trim blocks")
78
+ """Remove first newline after a block (affects whitespace control)."""
79
+
80
+ lstrip_blocks: bool = Field(default=False, title="Left strip blocks")
81
+ """Remove leading spaces and tabs from the start of a line to a block."""
82
+
83
+ newline_sequence: NewLineType = Field(
84
+ default="\n",
85
+ title="Newline sequence",
86
+ examples=["\n", "\r\n", "\r"],
87
+ )
88
+ """Sequence that starts a newline (default: '\n')."""
89
+
90
+ keep_trailing_newline: bool = Field(default=False, title="Keep trailing newline")
91
+ """Preserve the trailing newline when rendering templates."""
92
+
93
+ extensions: list[str] = Field(
94
+ default_factory=list,
95
+ title="Jinja2 extensions",
96
+ examples=[["jinja2.ext.do", "jinja2.ext.loopcontrols"], ["jinja2.ext.i18n"]],
97
+ )
98
+ """List of Jinja2 extensions to load (e.g., 'jinja2.ext.do')."""
99
+
100
+ undefined: UndefinedBehaviour = Field(
101
+ default="default",
102
+ title="Undefined behavior",
103
+ examples=["strict", "debug", "chainable"],
104
+ )
105
+ """Behavior when accessing undefined variables (default, strict, debug, chainable)."""
106
+
107
+ filters: list[ToolConfig] = Field(default_factory=list, title="Custom filters")
108
+ """Custom filters as list of tool configurations."""
109
+
110
+ tests: list[ToolConfig] = Field(default_factory=list, title="Custom tests")
111
+ """Custom tests as list of tool configurations."""
112
+
113
+ globals: dict[str, BaseModel] = Field(default_factory=dict, title="Global variables")
114
+ """Global variables available to all templates."""
115
+
116
+ def create_environment(self, *, enable_async: bool = False) -> Environment:
117
+ """Create configured Jinja2 environment.
118
+
119
+ Args:
120
+ enable_async: Whether to enable async features
121
+ """
122
+ from jinjarope import Environment
123
+
124
+ return Environment(enable_async=enable_async, **self.create_environment_kwargs())
125
+
126
+ def create_environment_kwargs(self) -> dict[str, Any]:
127
+ """Convert config to Jinja2 environment kwargs.
128
+
129
+ Creates a dictionary of kwargs for jinja2.Environment with proper
130
+ conversion of special values.
131
+
132
+ Returns:
133
+ Dict of kwargs for jinja2.Environment constructor
134
+
135
+ Raises:
136
+ ValueError: If filter or test imports fail
137
+ """
138
+ # Basic config
139
+ kwargs = self.model_dump(exclude={"filters", "tests"})
140
+
141
+ try:
142
+ # Convert filters - use tool name as filter name
143
+ tools = [cfg.get_tool() for cfg in self.filters]
144
+ kwargs["filters"] = {tool.name: tool.callable for tool in tools}
145
+ tools = [cfg.get_tool() for cfg in self.tests]
146
+ kwargs["tests"] = {tool.name: tool.callable for tool in tools}
147
+
148
+ except Exception as exc:
149
+ msg = f"Failed to import Jinja2 filters/tests: {exc}"
150
+ raise ValueError(msg) from exc
151
+
152
+ return kwargs
153
+
154
+
155
+ class Jinja2Template(Schema):
156
+ """Template with environment configuration."""
157
+
158
+ model_config = ConfigDict(json_schema_extra={"title": "Jinja2 Template Configuration"})
159
+
160
+ template: str = Field(
161
+ title="Template string",
162
+ examples=["Hello {{ name }}!", "{% for item in items %}{{ item }}{% endfor %}"],
163
+ )
164
+ """The template string to render."""
165
+
166
+ environment: Jinja2EnvironmentConfig = Field(
167
+ default_factory=Jinja2EnvironmentConfig,
168
+ title="Environment configuration",
169
+ )
170
+ """Environment configuration for this template."""
171
+
172
+ def get_template(self, *, enable_async: bool = False) -> Template:
173
+ """Get compiled Jinja2 template.
174
+
175
+ Args:
176
+ enable_async: Whether to enable async features
177
+
178
+ Returns:
179
+ Compiled template ready for rendering
180
+ """
181
+ env = self.environment.create_environment(enable_async=enable_async)
182
+ return env.from_string(self.template)
183
+
184
+ def render(self, **kwargs: Any) -> str:
185
+ """Render template with provided variables.
186
+
187
+ Args:
188
+ **kwargs: Template variables
189
+
190
+ Returns:
191
+ Rendered template string
192
+ """
193
+ template = self.get_template()
194
+ return template.render(**kwargs)
195
+
196
+ async def render_async(self, **kwargs: Any) -> str:
197
+ """Render template asynchronously.
198
+
199
+ Args:
200
+ **kwargs: Template variables
201
+
202
+ Returns:
203
+ Rendered template string
204
+ """
205
+ template = self.get_template(enable_async=True)
206
+ return await template.render_async(**kwargs)
@@ -0,0 +1,41 @@
1
+ """Knowledge configuration."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pydantic import ConfigDict, Field
6
+ from schemez import Schema
7
+
8
+ from agentpool.prompts.prompts import PromptType
9
+
10
+
11
+ class Knowledge(Schema):
12
+ """Collection of context sources for an agent.
13
+
14
+ Supports both simple paths and rich resource types for content loading,
15
+ plus AgentPool's prompt system for dynamic content generation.
16
+
17
+ Docs: https://phil65.github.io/agentpool/YAML%20Configuration/knowledge_configuration/
18
+ """
19
+
20
+ model_config = ConfigDict(json_schema_extra={"title": "Knowledge Configuration"})
21
+
22
+ paths: list[str] = Field(
23
+ default_factory=list,
24
+ examples=[["docs/readme.md", "https://api.example.com/docs"], ["/data/context.txt"]],
25
+ title="Resource paths",
26
+ )
27
+ """Quick access to files and URLs."""
28
+
29
+ prompts: list[PromptType] = Field(default_factory=list, title="Dynamic prompts")
30
+ """Prompts for dynamic content generation:
31
+ - StaticPrompt: Fixed message templates
32
+ - DynamicPrompt: Python function-based
33
+ - FilePrompt: File-based with template support
34
+ """
35
+
36
+ convert_to_markdown: bool = Field(default=False, title="Convert to markdown")
37
+ """Whether to convert content to markdown when possible."""
38
+
39
+ def get_resources(self) -> list[PromptType | str]:
40
+ """Get all resources."""
41
+ return self.prompts + self.paths
@@ -0,0 +1,350 @@
1
+ """Models for resource information."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Sequence as TypingSequence
6
+ import inspect
7
+ from typing import Annotated, Literal
8
+ import warnings
9
+
10
+ from pydantic import ConfigDict, Field, SecretStr, model_validator
11
+ from schemez import Schema
12
+ from upathtools import to_upath
13
+
14
+ from agentpool.common_types import JsonObject
15
+ from agentpool.utils.importing import import_callable
16
+
17
+
18
+ class BaseResourceLoaderConfig(Schema):
19
+ """Base class for all resource types."""
20
+
21
+ type: str = Field(init=False, title="Resource type")
22
+ """Type identifier for this resource."""
23
+
24
+ description: str = Field(
25
+ default="",
26
+ title="Resource description",
27
+ examples=["Configuration file", "User data", "API response"],
28
+ )
29
+ """Human-readable description of the resource."""
30
+
31
+ uri: str | None = Field(
32
+ default=None,
33
+ title="Resource URI",
34
+ examples=["file:///path/to/file", "https://api.example.com/data"],
35
+ )
36
+ """Canonical URI for this resource, set during registration if unset."""
37
+
38
+ # watch: WatchConfig | None = None
39
+ # """Configuration for file system watching, if supported."""
40
+
41
+ name: str | None = Field(
42
+ default=None,
43
+ exclude=True,
44
+ title="Resource name",
45
+ examples=["config", "user_data", "api_response"],
46
+ )
47
+ """Technical identifier (automatically set from config key during registration)."""
48
+
49
+ model_config = ConfigDict(frozen=True)
50
+
51
+ # @property
52
+ # def supports_watching(self) -> bool:
53
+ # """Whether this resource instance supports watching."""
54
+ # return False
55
+
56
+ # def is_watched(self) -> bool:
57
+ # """Tell if this resource should be watched."""
58
+ # return self.supports_watching and self.watch is not None and self.watch.enabled
59
+
60
+ def is_templated(self) -> bool:
61
+ """Whether this resource supports URI templates."""
62
+ return False # Default: resources are static
63
+
64
+ @property
65
+ def mime_type(self) -> str:
66
+ """Get the MIME type for this resource.
67
+
68
+ This should be overridden by subclasses that can determine
69
+ their MIME type. Default is text/plain.
70
+ """
71
+ return "text/plain"
72
+
73
+
74
+ class PathResourceLoaderConfig(BaseResourceLoaderConfig):
75
+ """Resource loaded from a file or URL."""
76
+
77
+ model_config = ConfigDict(json_schema_extra={"x-doc-title": "Path Resource"})
78
+
79
+ type: Literal["path"] = Field(default="path", init=False, title="Resource type")
80
+ """Discriminator field identifying this as a path-based resource."""
81
+
82
+ path: str = Field(
83
+ title="File path or URL",
84
+ examples=["/path/to/file.txt", "https://example.com/data.json", "config/settings.yml"],
85
+ )
86
+ """Path to the file or URL to load."""
87
+
88
+ watch: WatchConfig | None = Field(default=None, title="Watch configuration")
89
+ """Configuration for watching the file for changes."""
90
+
91
+ def validate_resource(self) -> list[str]:
92
+ """Check if path exists for local files."""
93
+ warnings = []
94
+ path = to_upath(self.path)
95
+ prefixes = ("http://", "https://")
96
+ if not path.exists() and not path.as_uri().startswith(prefixes):
97
+ warnings.append(f"Resource path not found: {path}")
98
+ return warnings
99
+
100
+ @property
101
+ def supports_watching(self) -> bool:
102
+ """Whether this resource instance supports watching."""
103
+ if not to_upath(self.path).exists():
104
+ msg = f"Cannot watch non-existent path: {self.path}"
105
+ warnings.warn(msg, UserWarning, stacklevel=2)
106
+ return False
107
+ return True
108
+
109
+ @model_validator(mode="after")
110
+ def validate_path(self) -> PathResourceLoaderConfig:
111
+ """Validate that the path is not empty."""
112
+ if not self.path:
113
+ msg = "Path cannot be empty"
114
+ raise ValueError(msg)
115
+ return self
116
+
117
+ def is_templated(self) -> bool:
118
+ """Path resources are templated if they contain placeholders."""
119
+ return "{" in str(self.path)
120
+
121
+ @property
122
+ def mime_type(self) -> str:
123
+ """Get MIME type based on file extension."""
124
+ from agentpool.mime_utils import guess_type
125
+
126
+ return guess_type(str(self.path)) or "application/octet-stream"
127
+
128
+
129
+ class TextResourceLoaderConfig(BaseResourceLoaderConfig):
130
+ """Raw text resource."""
131
+
132
+ model_config = ConfigDict(json_schema_extra={"x-doc-title": "Text Resource"})
133
+
134
+ type: Literal["text"] = Field(default="text", init=False, title="Resource type")
135
+ """Discriminator field identifying this as a text-based resource."""
136
+
137
+ content: str = Field(
138
+ title="Text content",
139
+ examples=["Hello World", '{ "key": "value" }', "---\nkey: value"],
140
+ )
141
+ """The actual text content of the resource."""
142
+
143
+ _mime_type: str | None = None # Optional override
144
+
145
+ @model_validator(mode="after")
146
+ def validate_content(self) -> TextResourceLoaderConfig:
147
+ """Validate that the content is not empty."""
148
+ if not self.content:
149
+ msg = "Content cannot be empty"
150
+ raise ValueError(msg)
151
+ return self
152
+
153
+ @property
154
+ def mime_type(self) -> str:
155
+ """Get MIME type, trying to detect JSON/YAML."""
156
+ if self._mime_type:
157
+ return self._mime_type
158
+ # Could add content inspection here
159
+ return "text/plain"
160
+
161
+
162
+ class CLIResourceLoaderConfig(BaseResourceLoaderConfig):
163
+ """Resource from CLI command execution."""
164
+
165
+ model_config = ConfigDict(json_schema_extra={"x-doc-title": "CLI Resource"})
166
+
167
+ type: Literal["cli"] = Field(default="cli", init=False, title="Resource type")
168
+ """Discriminator field identifying this as a CLI-based resource."""
169
+
170
+ command: str | TypingSequence[str] = Field(
171
+ title="Command to execute",
172
+ examples=["ls -la", "git status", ["python", "script.py", "--arg"]],
173
+ )
174
+ """Command to execute (string or sequence of arguments)."""
175
+
176
+ shell: bool = Field(default=False, title="Use shell")
177
+ """Whether to run the command through a shell."""
178
+
179
+ cwd: str | None = Field(
180
+ default=None,
181
+ title="Working directory",
182
+ examples=["/path/to/project", "~/workspace"],
183
+ )
184
+ """Working directory for command execution."""
185
+
186
+ timeout: float | None = Field(
187
+ default=None,
188
+ title="Timeout in seconds",
189
+ examples=[30.0, 60.0, 120.0],
190
+ )
191
+ """Maximum time in seconds to wait for command completion."""
192
+
193
+ @model_validator(mode="after")
194
+ def validate_command(self) -> CLIResourceLoaderConfig:
195
+ """Validate command configuration."""
196
+ if not self.command:
197
+ msg = "Command cannot be empty"
198
+ raise ValueError(msg)
199
+ if (
200
+ isinstance(self.command, list | tuple)
201
+ and not self.shell
202
+ and not all(isinstance(part, str) for part in self.command)
203
+ ):
204
+ msg = "When shell=False, all command parts must be strings"
205
+ raise ValueError(msg)
206
+ return self
207
+
208
+
209
+ class RepositoryResource(BaseResourceLoaderConfig):
210
+ """Git repository content."""
211
+
212
+ model_config = ConfigDict(json_schema_extra={"x-doc-title": "Repository Resource"})
213
+
214
+ type: Literal["repository"] = Field(default="repository", init=False, title="Resource type")
215
+ """Repository resource configuration."""
216
+
217
+ repo_url: str = Field(
218
+ title="Repository URL",
219
+ examples=["https://github.com/user/repo.git", "git@github.com:user/repo.git"],
220
+ )
221
+ """URL of the git repository."""
222
+
223
+ ref: str = Field(
224
+ default="main",
225
+ title="Git reference",
226
+ examples=["main", "develop", "v1.0.0", "abc123def"],
227
+ )
228
+ """Git reference (branch, tag, or commit)."""
229
+
230
+ path: str = Field(
231
+ default="",
232
+ title="Repository path",
233
+ examples=["", "src/", "docs/README.md"],
234
+ )
235
+ """Path within the repository."""
236
+
237
+ sparse_checkout: list[str] | None = Field(
238
+ default=None,
239
+ title="Sparse checkout paths",
240
+ examples=[["src/", "docs/"], ["*.py", "requirements.txt"]],
241
+ )
242
+ """Optional list of paths for sparse checkout."""
243
+
244
+ user: str | None = Field(
245
+ default=None,
246
+ title="Username",
247
+ examples=["github_user", "git_username"],
248
+ )
249
+ """Optional user name for authentication."""
250
+
251
+ password: SecretStr | None = Field(default=None, title="Password")
252
+ """Optional password for authentication."""
253
+
254
+ def validate_resource(self) -> list[str]:
255
+ warnings = []
256
+ if self.user and not self.password:
257
+ warnings.append(f"Repository {self.repo_url} has user but no password")
258
+ return warnings
259
+
260
+
261
+ class SourceResourceLoaderConfig(BaseResourceLoaderConfig):
262
+ """Resource from Python source code."""
263
+
264
+ model_config = ConfigDict(json_schema_extra={"x-doc-title": "Source Resource"})
265
+
266
+ type: Literal["source"] = Field(default="source", init=False, title="Resource type")
267
+ """Source code resource configuration."""
268
+
269
+ import_path: str = Field(
270
+ title="Import path",
271
+ examples=["mypackage.module", "utils.helpers", "app.models.User"],
272
+ )
273
+ """Dotted import path to the Python module or object."""
274
+
275
+ recursive: bool = Field(default=False, title="Include recursively")
276
+ """Whether to include submodules recursively."""
277
+
278
+ include_tests: bool = Field(default=False, title="Include tests")
279
+ """Whether to include test files and directories."""
280
+
281
+ @model_validator(mode="after")
282
+ def validate_import_path(self) -> SourceResourceLoaderConfig:
283
+ """Validate that the import path is properly formatted."""
284
+ if not all(part.isidentifier() for part in self.import_path.split(".")):
285
+ msg = f"Invalid import path: {self.import_path}"
286
+ raise ValueError(msg)
287
+ return self
288
+
289
+
290
+ class CallableResourceLoaderConfig(BaseResourceLoaderConfig):
291
+ """Resource from executing a Python callable."""
292
+
293
+ model_config = ConfigDict(json_schema_extra={"x-doc-title": "Callable Resource"})
294
+
295
+ type: Literal["callable"] = Field(default="callable", init=False, title="Resource type")
296
+ """Callable-based resource configuration."""
297
+
298
+ import_path: str = Field(
299
+ title="Callable import path",
300
+ examples=["mymodule.get_data", "utils.generators.create_content"],
301
+ )
302
+ """Dotted import path to the callable to execute."""
303
+
304
+ keyword_args: JsonObject = Field(default_factory=dict, title="Keyword arguments")
305
+ """Keyword arguments to pass to the callable."""
306
+
307
+ @model_validator(mode="after")
308
+ def validate_import_path(self) -> CallableResourceLoaderConfig:
309
+ """Validate that the import path is properly formatted."""
310
+ if not all(part.isidentifier() for part in self.import_path.split(".")):
311
+ msg = f"Invalid import path: {self.import_path}"
312
+ raise ValueError(msg)
313
+ return self
314
+
315
+ def is_templated(self) -> bool:
316
+ """Callable resources are templated if they take parameters."""
317
+ fn = import_callable(self.import_path)
318
+ sig = inspect.signature(fn)
319
+ return bool(sig.parameters)
320
+
321
+
322
+ Resource = Annotated[
323
+ PathResourceLoaderConfig
324
+ | TextResourceLoaderConfig
325
+ | CLIResourceLoaderConfig
326
+ | SourceResourceLoaderConfig
327
+ | CallableResourceLoaderConfig,
328
+ Field(discriminator="type"),
329
+ ]
330
+
331
+
332
+ class WatchConfig(Schema):
333
+ """Watch configuration for resources."""
334
+
335
+ enabled: bool = Field(default=False, title="Watch enabled")
336
+ """Whether the watch is enabled"""
337
+
338
+ patterns: list[str] | None = Field(
339
+ default=None,
340
+ title="Watch patterns",
341
+ examples=[["*.py", "*.yml"], ["src/**", "!**/__pycache__"]],
342
+ )
343
+ """List of pathspec patterns (.gitignore style)"""
344
+
345
+ ignore_file: str | None = Field(
346
+ default=None,
347
+ title="Ignore file path",
348
+ examples=[".gitignore", ".watchignore"],
349
+ )
350
+ """Path to .gitignore-style file"""