agentpool 2.1.9__py3-none-any.whl → 2.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. acp/__init__.py +13 -4
  2. acp/acp_requests.py +20 -77
  3. acp/agent/connection.py +8 -0
  4. acp/agent/implementations/debug_server/debug_server.py +6 -2
  5. acp/agent/protocol.py +6 -0
  6. acp/bridge/README.md +15 -2
  7. acp/bridge/__init__.py +3 -2
  8. acp/bridge/__main__.py +60 -19
  9. acp/bridge/ws_server.py +173 -0
  10. acp/bridge/ws_server_cli.py +89 -0
  11. acp/client/connection.py +38 -29
  12. acp/client/implementations/default_client.py +3 -2
  13. acp/client/implementations/headless_client.py +2 -2
  14. acp/connection.py +2 -2
  15. acp/notifications.py +20 -50
  16. acp/schema/__init__.py +2 -0
  17. acp/schema/agent_responses.py +21 -0
  18. acp/schema/client_requests.py +3 -3
  19. acp/schema/session_state.py +63 -29
  20. acp/stdio.py +39 -9
  21. acp/task/supervisor.py +2 -2
  22. acp/transports.py +362 -2
  23. acp/utils.py +17 -4
  24. agentpool/__init__.py +6 -1
  25. agentpool/agents/__init__.py +2 -0
  26. agentpool/agents/acp_agent/acp_agent.py +407 -277
  27. agentpool/agents/acp_agent/acp_converters.py +196 -38
  28. agentpool/agents/acp_agent/client_handler.py +191 -26
  29. agentpool/agents/acp_agent/session_state.py +17 -6
  30. agentpool/agents/agent.py +607 -572
  31. agentpool/agents/agui_agent/__init__.py +0 -2
  32. agentpool/agents/agui_agent/agui_agent.py +176 -110
  33. agentpool/agents/agui_agent/agui_converters.py +0 -131
  34. agentpool/agents/agui_agent/helpers.py +3 -4
  35. agentpool/agents/base_agent.py +632 -17
  36. agentpool/agents/claude_code_agent/FORKING.md +191 -0
  37. agentpool/agents/claude_code_agent/__init__.py +13 -1
  38. agentpool/agents/claude_code_agent/claude_code_agent.py +1058 -291
  39. agentpool/agents/claude_code_agent/converters.py +74 -143
  40. agentpool/agents/claude_code_agent/history.py +474 -0
  41. agentpool/agents/claude_code_agent/models.py +77 -0
  42. agentpool/agents/claude_code_agent/static_info.py +100 -0
  43. agentpool/agents/claude_code_agent/usage.py +242 -0
  44. agentpool/agents/context.py +40 -0
  45. agentpool/agents/events/__init__.py +24 -0
  46. agentpool/agents/events/builtin_handlers.py +67 -1
  47. agentpool/agents/events/event_emitter.py +32 -2
  48. agentpool/agents/events/events.py +104 -3
  49. agentpool/agents/events/infer_info.py +145 -0
  50. agentpool/agents/events/processors.py +254 -0
  51. agentpool/agents/interactions.py +41 -6
  52. agentpool/agents/modes.py +67 -0
  53. agentpool/agents/slashed_agent.py +5 -4
  54. agentpool/agents/tool_call_accumulator.py +213 -0
  55. agentpool/agents/tool_wrapping.py +18 -6
  56. agentpool/common_types.py +56 -21
  57. agentpool/config_resources/__init__.py +38 -1
  58. agentpool/config_resources/acp_assistant.yml +2 -2
  59. agentpool/config_resources/agents.yml +3 -0
  60. agentpool/config_resources/agents_template.yml +1 -0
  61. agentpool/config_resources/claude_code_agent.yml +10 -6
  62. agentpool/config_resources/external_acp_agents.yml +2 -1
  63. agentpool/delegation/base_team.py +4 -30
  64. agentpool/delegation/pool.py +136 -289
  65. agentpool/delegation/team.py +58 -57
  66. agentpool/delegation/teamrun.py +51 -55
  67. agentpool/diagnostics/__init__.py +53 -0
  68. agentpool/diagnostics/lsp_manager.py +1593 -0
  69. agentpool/diagnostics/lsp_proxy.py +41 -0
  70. agentpool/diagnostics/lsp_proxy_script.py +229 -0
  71. agentpool/diagnostics/models.py +398 -0
  72. agentpool/functional/run.py +10 -4
  73. agentpool/mcp_server/__init__.py +0 -2
  74. agentpool/mcp_server/client.py +76 -32
  75. agentpool/mcp_server/conversions.py +54 -13
  76. agentpool/mcp_server/manager.py +34 -54
  77. agentpool/mcp_server/registries/official_registry_client.py +35 -1
  78. agentpool/mcp_server/tool_bridge.py +186 -139
  79. agentpool/messaging/__init__.py +0 -2
  80. agentpool/messaging/compaction.py +72 -197
  81. agentpool/messaging/connection_manager.py +11 -10
  82. agentpool/messaging/event_manager.py +5 -5
  83. agentpool/messaging/message_container.py +6 -30
  84. agentpool/messaging/message_history.py +99 -8
  85. agentpool/messaging/messagenode.py +52 -14
  86. agentpool/messaging/messages.py +54 -35
  87. agentpool/messaging/processing.py +12 -22
  88. agentpool/models/__init__.py +1 -1
  89. agentpool/models/acp_agents/base.py +6 -24
  90. agentpool/models/acp_agents/mcp_capable.py +126 -157
  91. agentpool/models/acp_agents/non_mcp.py +129 -95
  92. agentpool/models/agents.py +98 -76
  93. agentpool/models/agui_agents.py +1 -1
  94. agentpool/models/claude_code_agents.py +144 -19
  95. agentpool/models/file_parsing.py +0 -1
  96. agentpool/models/manifest.py +113 -50
  97. agentpool/prompts/conversion_manager.py +1 -1
  98. agentpool/prompts/prompts.py +5 -2
  99. agentpool/repomap.py +1 -1
  100. agentpool/resource_providers/__init__.py +11 -1
  101. agentpool/resource_providers/aggregating.py +56 -5
  102. agentpool/resource_providers/base.py +70 -4
  103. agentpool/resource_providers/codemode/code_executor.py +72 -5
  104. agentpool/resource_providers/codemode/helpers.py +2 -2
  105. agentpool/resource_providers/codemode/provider.py +64 -12
  106. agentpool/resource_providers/codemode/remote_mcp_execution.py +2 -2
  107. agentpool/resource_providers/codemode/remote_provider.py +9 -12
  108. agentpool/resource_providers/filtering.py +3 -1
  109. agentpool/resource_providers/mcp_provider.py +89 -12
  110. agentpool/resource_providers/plan_provider.py +228 -46
  111. agentpool/resource_providers/pool.py +7 -3
  112. agentpool/resource_providers/resource_info.py +111 -0
  113. agentpool/resource_providers/static.py +4 -2
  114. agentpool/sessions/__init__.py +4 -1
  115. agentpool/sessions/manager.py +33 -5
  116. agentpool/sessions/models.py +59 -6
  117. agentpool/sessions/protocol.py +28 -0
  118. agentpool/sessions/session.py +11 -55
  119. agentpool/skills/registry.py +13 -8
  120. agentpool/storage/manager.py +572 -49
  121. agentpool/talk/registry.py +4 -4
  122. agentpool/talk/talk.py +9 -10
  123. agentpool/testing.py +538 -20
  124. agentpool/tool_impls/__init__.py +6 -0
  125. agentpool/tool_impls/agent_cli/__init__.py +42 -0
  126. agentpool/tool_impls/agent_cli/tool.py +95 -0
  127. agentpool/tool_impls/bash/__init__.py +64 -0
  128. agentpool/tool_impls/bash/helpers.py +35 -0
  129. agentpool/tool_impls/bash/tool.py +171 -0
  130. agentpool/tool_impls/delete_path/__init__.py +70 -0
  131. agentpool/tool_impls/delete_path/tool.py +142 -0
  132. agentpool/tool_impls/download_file/__init__.py +80 -0
  133. agentpool/tool_impls/download_file/tool.py +183 -0
  134. agentpool/tool_impls/execute_code/__init__.py +55 -0
  135. agentpool/tool_impls/execute_code/tool.py +163 -0
  136. agentpool/tool_impls/grep/__init__.py +80 -0
  137. agentpool/tool_impls/grep/tool.py +200 -0
  138. agentpool/tool_impls/list_directory/__init__.py +73 -0
  139. agentpool/tool_impls/list_directory/tool.py +197 -0
  140. agentpool/tool_impls/question/__init__.py +42 -0
  141. agentpool/tool_impls/question/tool.py +127 -0
  142. agentpool/tool_impls/read/__init__.py +104 -0
  143. agentpool/tool_impls/read/tool.py +305 -0
  144. agentpool/tools/__init__.py +2 -1
  145. agentpool/tools/base.py +114 -34
  146. agentpool/tools/manager.py +57 -1
  147. agentpool/ui/base.py +2 -2
  148. agentpool/ui/mock_provider.py +2 -2
  149. agentpool/ui/stdlib_provider.py +2 -2
  150. agentpool/utils/file_watcher.py +269 -0
  151. agentpool/utils/identifiers.py +121 -0
  152. agentpool/utils/pydantic_ai_helpers.py +46 -0
  153. agentpool/utils/streams.py +616 -2
  154. agentpool/utils/subprocess_utils.py +155 -0
  155. agentpool/utils/token_breakdown.py +461 -0
  156. agentpool/vfs_registry.py +7 -2
  157. {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/METADATA +41 -27
  158. agentpool-2.5.0.dist-info/RECORD +579 -0
  159. {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/WHEEL +1 -1
  160. agentpool_cli/__main__.py +24 -0
  161. agentpool_cli/create.py +1 -1
  162. agentpool_cli/serve_acp.py +100 -21
  163. agentpool_cli/serve_agui.py +87 -0
  164. agentpool_cli/serve_opencode.py +119 -0
  165. agentpool_cli/ui.py +557 -0
  166. agentpool_commands/__init__.py +42 -5
  167. agentpool_commands/agents.py +75 -2
  168. agentpool_commands/history.py +62 -0
  169. agentpool_commands/mcp.py +176 -0
  170. agentpool_commands/models.py +56 -3
  171. agentpool_commands/pool.py +260 -0
  172. agentpool_commands/session.py +1 -1
  173. agentpool_commands/text_sharing/__init__.py +119 -0
  174. agentpool_commands/text_sharing/base.py +123 -0
  175. agentpool_commands/text_sharing/github_gist.py +80 -0
  176. agentpool_commands/text_sharing/opencode.py +462 -0
  177. agentpool_commands/text_sharing/paste_rs.py +59 -0
  178. agentpool_commands/text_sharing/pastebin.py +116 -0
  179. agentpool_commands/text_sharing/shittycodingagent.py +112 -0
  180. agentpool_commands/tools.py +57 -0
  181. agentpool_commands/utils.py +80 -30
  182. agentpool_config/__init__.py +30 -2
  183. agentpool_config/agentpool_tools.py +498 -0
  184. agentpool_config/builtin_tools.py +77 -22
  185. agentpool_config/commands.py +24 -1
  186. agentpool_config/compaction.py +258 -0
  187. agentpool_config/converters.py +1 -1
  188. agentpool_config/event_handlers.py +42 -0
  189. agentpool_config/events.py +1 -1
  190. agentpool_config/forward_targets.py +1 -4
  191. agentpool_config/jinja.py +3 -3
  192. agentpool_config/mcp_server.py +132 -6
  193. agentpool_config/nodes.py +1 -1
  194. agentpool_config/observability.py +44 -0
  195. agentpool_config/session.py +0 -3
  196. agentpool_config/storage.py +82 -38
  197. agentpool_config/task.py +3 -3
  198. agentpool_config/tools.py +11 -22
  199. agentpool_config/toolsets.py +109 -233
  200. agentpool_server/a2a_server/agent_worker.py +307 -0
  201. agentpool_server/a2a_server/server.py +23 -18
  202. agentpool_server/acp_server/acp_agent.py +234 -181
  203. agentpool_server/acp_server/commands/acp_commands.py +151 -156
  204. agentpool_server/acp_server/commands/docs_commands/fetch_repo.py +18 -17
  205. agentpool_server/acp_server/event_converter.py +651 -0
  206. agentpool_server/acp_server/input_provider.py +53 -10
  207. agentpool_server/acp_server/server.py +24 -90
  208. agentpool_server/acp_server/session.py +173 -331
  209. agentpool_server/acp_server/session_manager.py +8 -34
  210. agentpool_server/agui_server/server.py +3 -1
  211. agentpool_server/mcp_server/server.py +5 -2
  212. agentpool_server/opencode_server/.rules +95 -0
  213. agentpool_server/opencode_server/ENDPOINTS.md +401 -0
  214. agentpool_server/opencode_server/OPENCODE_UI_TOOLS_COMPLETE.md +202 -0
  215. agentpool_server/opencode_server/__init__.py +19 -0
  216. agentpool_server/opencode_server/command_validation.py +172 -0
  217. agentpool_server/opencode_server/converters.py +975 -0
  218. agentpool_server/opencode_server/dependencies.py +24 -0
  219. agentpool_server/opencode_server/input_provider.py +421 -0
  220. agentpool_server/opencode_server/models/__init__.py +250 -0
  221. agentpool_server/opencode_server/models/agent.py +53 -0
  222. agentpool_server/opencode_server/models/app.py +72 -0
  223. agentpool_server/opencode_server/models/base.py +26 -0
  224. agentpool_server/opencode_server/models/common.py +23 -0
  225. agentpool_server/opencode_server/models/config.py +37 -0
  226. agentpool_server/opencode_server/models/events.py +821 -0
  227. agentpool_server/opencode_server/models/file.py +88 -0
  228. agentpool_server/opencode_server/models/mcp.py +44 -0
  229. agentpool_server/opencode_server/models/message.py +179 -0
  230. agentpool_server/opencode_server/models/parts.py +323 -0
  231. agentpool_server/opencode_server/models/provider.py +81 -0
  232. agentpool_server/opencode_server/models/pty.py +43 -0
  233. agentpool_server/opencode_server/models/question.py +56 -0
  234. agentpool_server/opencode_server/models/session.py +111 -0
  235. agentpool_server/opencode_server/routes/__init__.py +29 -0
  236. agentpool_server/opencode_server/routes/agent_routes.py +473 -0
  237. agentpool_server/opencode_server/routes/app_routes.py +202 -0
  238. agentpool_server/opencode_server/routes/config_routes.py +302 -0
  239. agentpool_server/opencode_server/routes/file_routes.py +571 -0
  240. agentpool_server/opencode_server/routes/global_routes.py +94 -0
  241. agentpool_server/opencode_server/routes/lsp_routes.py +319 -0
  242. agentpool_server/opencode_server/routes/message_routes.py +761 -0
  243. agentpool_server/opencode_server/routes/permission_routes.py +63 -0
  244. agentpool_server/opencode_server/routes/pty_routes.py +300 -0
  245. agentpool_server/opencode_server/routes/question_routes.py +128 -0
  246. agentpool_server/opencode_server/routes/session_routes.py +1276 -0
  247. agentpool_server/opencode_server/routes/tui_routes.py +139 -0
  248. agentpool_server/opencode_server/server.py +475 -0
  249. agentpool_server/opencode_server/state.py +151 -0
  250. agentpool_server/opencode_server/time_utils.py +8 -0
  251. agentpool_storage/__init__.py +12 -0
  252. agentpool_storage/base.py +184 -2
  253. agentpool_storage/claude_provider/ARCHITECTURE.md +433 -0
  254. agentpool_storage/claude_provider/__init__.py +42 -0
  255. agentpool_storage/claude_provider/provider.py +1089 -0
  256. agentpool_storage/file_provider.py +278 -15
  257. agentpool_storage/memory_provider.py +193 -12
  258. agentpool_storage/models.py +3 -0
  259. agentpool_storage/opencode_provider/ARCHITECTURE.md +386 -0
  260. agentpool_storage/opencode_provider/__init__.py +16 -0
  261. agentpool_storage/opencode_provider/helpers.py +414 -0
  262. agentpool_storage/opencode_provider/provider.py +895 -0
  263. agentpool_storage/project_store.py +325 -0
  264. agentpool_storage/session_store.py +26 -6
  265. agentpool_storage/sql_provider/__init__.py +4 -2
  266. agentpool_storage/sql_provider/models.py +48 -0
  267. agentpool_storage/sql_provider/sql_provider.py +269 -3
  268. agentpool_storage/sql_provider/utils.py +12 -13
  269. agentpool_storage/zed_provider/__init__.py +16 -0
  270. agentpool_storage/zed_provider/helpers.py +281 -0
  271. agentpool_storage/zed_provider/models.py +130 -0
  272. agentpool_storage/zed_provider/provider.py +442 -0
  273. agentpool_storage/zed_provider.py +803 -0
  274. agentpool_toolsets/__init__.py +0 -2
  275. agentpool_toolsets/builtin/__init__.py +2 -12
  276. agentpool_toolsets/builtin/code.py +96 -57
  277. agentpool_toolsets/builtin/debug.py +118 -48
  278. agentpool_toolsets/builtin/execution_environment.py +115 -230
  279. agentpool_toolsets/builtin/file_edit/file_edit.py +115 -7
  280. agentpool_toolsets/builtin/skills.py +9 -4
  281. agentpool_toolsets/builtin/subagent_tools.py +64 -51
  282. agentpool_toolsets/builtin/workers.py +4 -2
  283. agentpool_toolsets/composio_toolset.py +2 -2
  284. agentpool_toolsets/entry_points.py +3 -1
  285. agentpool_toolsets/fsspec_toolset/__init__.py +13 -1
  286. agentpool_toolsets/fsspec_toolset/diagnostics.py +860 -73
  287. agentpool_toolsets/fsspec_toolset/grep.py +99 -7
  288. agentpool_toolsets/fsspec_toolset/helpers.py +3 -2
  289. agentpool_toolsets/fsspec_toolset/image_utils.py +161 -0
  290. agentpool_toolsets/fsspec_toolset/toolset.py +500 -95
  291. agentpool_toolsets/mcp_discovery/__init__.py +5 -0
  292. agentpool_toolsets/mcp_discovery/data/mcp_servers.parquet +0 -0
  293. agentpool_toolsets/mcp_discovery/toolset.py +511 -0
  294. agentpool_toolsets/mcp_run_toolset.py +87 -12
  295. agentpool_toolsets/notifications.py +33 -33
  296. agentpool_toolsets/openapi.py +3 -1
  297. agentpool_toolsets/search_toolset.py +3 -1
  298. agentpool-2.1.9.dist-info/RECORD +0 -474
  299. agentpool_config/resources.py +0 -33
  300. agentpool_server/acp_server/acp_tools.py +0 -43
  301. agentpool_server/acp_server/commands/spawn.py +0 -210
  302. agentpool_storage/text_log_provider.py +0 -275
  303. agentpool_toolsets/builtin/agent_management.py +0 -239
  304. agentpool_toolsets/builtin/chain.py +0 -288
  305. agentpool_toolsets/builtin/history.py +0 -36
  306. agentpool_toolsets/builtin/integration.py +0 -85
  307. agentpool_toolsets/builtin/tool_management.py +0 -90
  308. agentpool_toolsets/builtin/user_interaction.py +0 -52
  309. agentpool_toolsets/semantic_memory_toolset.py +0 -536
  310. {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/entry_points.txt +0 -0
  311. {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,112 @@
1
+ """ShittyCodingAgent.ai text sharing provider.
2
+
3
+ Creates a GitHub Gist and returns a preview URL via shittycodingagent.ai.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ import os
9
+ from typing import TYPE_CHECKING, Any
10
+
11
+ from agentpool_commands.text_sharing.base import ShareResult, TextSharer
12
+
13
+
14
+ if TYPE_CHECKING:
15
+ from agentpool_commands.text_sharing.base import Visibility
16
+
17
+
18
+ PREVIEW_BASE_URL = "https://shittycodingagent.ai/session"
19
+
20
+
21
+ class ShittyCodingAgentSharer(TextSharer):
22
+ """Share text via GitHub Gists with shittycodingagent.ai preview URL.
23
+
24
+ Creates a secret (unlisted) GitHub Gist and returns a URL in the format:
25
+ https://shittycodingagent.ai/session?{gist_id}
26
+ """
27
+
28
+ def __init__(self, token: str | None = None) -> None:
29
+ """Initialize the ShittyCodingAgent sharer.
30
+
31
+ Args:
32
+ token: GitHub personal access token. If not provided,
33
+ reads from GITHUB_TOKEN environment variable.
34
+ """
35
+ self._token = token or os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN")
36
+ if not self._token:
37
+ msg = "GitHub token required. Set GITHUB_TOKEN/GH_TOKEN or pass token parameter."
38
+ raise ValueError(msg)
39
+
40
+ @property
41
+ def name(self) -> str:
42
+ """Name of the sharing service."""
43
+ return "ShittyCodingAgent.ai"
44
+
45
+ async def share(
46
+ self,
47
+ content: str,
48
+ *,
49
+ title: str | None = None,
50
+ syntax: str | None = None,
51
+ visibility: Visibility = "unlisted",
52
+ expires_in: int | None = None,
53
+ ) -> ShareResult:
54
+ """Share content via GitHub Gist with shittycodingagent.ai preview.
55
+
56
+ Args:
57
+ content: The text content to share
58
+ title: Filename for the gist (defaults to "session.html")
59
+ syntax: File extension hint (e.g. "html")
60
+ visibility: Always creates unlisted gist (visibility param ignored)
61
+ expires_in: Ignored (gists don't expire)
62
+
63
+ Returns:
64
+ ShareResult with shittycodingagent.ai preview URL
65
+ """
66
+ import anyenv
67
+
68
+ # Default to session.html for the typical use case
69
+ filename = title or f"session.{syntax or 'html'}"
70
+
71
+ # Always create as unlisted (secret) gist
72
+ payload: dict[str, Any] = {
73
+ "files": {filename: {"content": content}},
74
+ "public": False,
75
+ }
76
+ headers = {
77
+ "Authorization": f"Bearer {self._token}",
78
+ "Accept": "application/vnd.github+json",
79
+ "X-GitHub-Api-Version": "2022-11-28",
80
+ }
81
+ url = "https://api.github.com/gists"
82
+ response: dict[str, Any] = await anyenv.post_json(url, payload, headers=headers)
83
+
84
+ gist_id = response["id"]
85
+ raw_url = response["files"][filename]["raw_url"]
86
+
87
+ # Build the shittycodingagent.ai preview URL
88
+ preview_url = f"{PREVIEW_BASE_URL}?{gist_id}"
89
+
90
+ return ShareResult(
91
+ url=preview_url,
92
+ raw_url=raw_url,
93
+ delete_url=None,
94
+ id=gist_id,
95
+ )
96
+
97
+
98
+ if __name__ == "__main__":
99
+ import asyncio
100
+
101
+ async def main() -> None:
102
+ """Example usage of the ShittyCodingAgentSharer class."""
103
+ sharer = ShittyCodingAgentSharer()
104
+ result = await sharer.share(
105
+ "<html><body><h1>Test Session</h1></body></html>",
106
+ title="session.html",
107
+ )
108
+ print(f"Preview URL: {result.url}")
109
+ print(f"Raw: {result.raw_url}")
110
+ print(f"Gist ID: {result.id}")
111
+
112
+ asyncio.run(main())
@@ -264,6 +264,63 @@ class RegisterToolCommand(NodeCommand):
264
264
  raise CommandError(msg) from e
265
265
 
266
266
 
267
+ class RegisterCodeToolCommand(NodeCommand):
268
+ """Register a new tool from Python code.
269
+
270
+ The code should define a function that will become the tool.
271
+ The function name becomes the tool name unless overridden.
272
+
273
+ Options:
274
+ --name tool_name Custom name for the tool
275
+ --description "text" Custom description
276
+
277
+ Examples:
278
+ /register-code-tool "def greet(name: str) -> str: return f'Hello {name}'"
279
+ /register-code-tool "def add(a: int, b: int) -> int: return a + b" --name sum
280
+ """
281
+
282
+ name = "register-code-tool"
283
+ category = "tools"
284
+
285
+ @classmethod
286
+ def supports_node(cls, node: MessageNode[Any, Any]) -> bool:
287
+ from agentpool import Agent
288
+
289
+ return isinstance(node, Agent)
290
+
291
+ async def execute_command(
292
+ self,
293
+ ctx: CommandContext[AgentContext],
294
+ code: str,
295
+ *,
296
+ name: str | None = None,
297
+ description: str | None = None,
298
+ ) -> None:
299
+ """Register a new tool from code string.
300
+
301
+ Args:
302
+ ctx: Command context
303
+ code: Python code defining a function
304
+ name: Optional custom name for the tool
305
+ description: Optional custom description
306
+ """
307
+ from agentpool.tools.base import Tool
308
+
309
+ try:
310
+ tool_obj = Tool.from_code(code, name=name, description=description)
311
+ tool_obj.enabled = True
312
+ tool_obj.source = "dynamic"
313
+
314
+ registered = ctx.context.agent.tools.register_tool(tool_obj)
315
+ await ctx.print(
316
+ f"**Tool registered:** `{registered.name}`"
317
+ f" - {registered.description or '*No description*'}"
318
+ )
319
+ except Exception as e:
320
+ msg = f"Failed to register code tool: {e}"
321
+ raise CommandError(msg) from e
322
+
323
+
267
324
  async def get_tool_names(ctx: CompletionContext[AgentContext]) -> list[str]:
268
325
  manager = ctx.command_context.context.agent.tools
269
326
  return list({t.name for t in await manager.get_tools()})
@@ -3,25 +3,31 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import importlib.util
6
+ from typing import TYPE_CHECKING, Literal
6
7
  import webbrowser
7
8
 
8
- from anyenv.text_sharing import TextSharerStr, Visibility # noqa: TC002
9
9
  from slashed import CommandContext, CommandError # noqa: TC002
10
10
 
11
11
  from agentpool.messaging.context import NodeContext # noqa: TC001
12
12
  from agentpool_commands.base import NodeCommand
13
13
 
14
14
 
15
+ if TYPE_CHECKING:
16
+ from agentpool_commands.text_sharing import TextSharerStr, Visibility
17
+
18
+
19
+ LogLevel = Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
20
+
21
+
15
22
  class CopyClipboardCommand(NodeCommand):
16
23
  """Copy messages from conversation history to system clipboard.
17
24
 
18
25
  Allows copying a configurable number of messages with options for:
19
26
  - Number of messages to include
20
- - Including/excluding system messages
21
27
  - Token limit for context size
22
28
  - Custom format templates
23
29
 
24
- Requires clipman package to be installed.
30
+ Requires copykitten package to be installed.
25
31
  """
26
32
 
27
33
  name = "copy-clipboard"
@@ -32,7 +38,6 @@ class CopyClipboardCommand(NodeCommand):
32
38
  ctx: CommandContext[NodeContext],
33
39
  *,
34
40
  num_messages: int = 1,
35
- include_system: bool = False,
36
41
  max_tokens: int | None = None,
37
42
  format_template: str | None = None,
38
43
  ) -> None:
@@ -41,19 +46,17 @@ class CopyClipboardCommand(NodeCommand):
41
46
  Args:
42
47
  ctx: Command context
43
48
  num_messages: Number of messages to copy (default: 1)
44
- include_system: Include system messages
45
49
  max_tokens: Only include messages up to token limit
46
50
  format_template: Custom format template
47
51
  """
48
52
  try:
49
- import clipman # type: ignore[import-untyped]
53
+ import copykitten
50
54
  except ImportError as e:
51
- msg = "clipman package required for clipboard operations"
55
+ msg = "copykitten package required for clipboard operations"
52
56
  raise CommandError(msg) from e
53
57
 
54
58
  content = await ctx.context.agent.conversation.format_history(
55
59
  num_messages=num_messages,
56
- include_system=include_system,
57
60
  max_tokens=max_tokens,
58
61
  format_template=format_template,
59
62
  )
@@ -63,8 +66,7 @@ class CopyClipboardCommand(NodeCommand):
63
66
  return
64
67
 
65
68
  try:
66
- clipman.init()
67
- clipman.copy(content)
69
+ copykitten.copy(content)
68
70
  await ctx.print("📋 **Messages copied to clipboard**")
69
71
  except Exception as e:
70
72
  msg = f"Failed to copy to clipboard: {e}"
@@ -72,8 +74,8 @@ class CopyClipboardCommand(NodeCommand):
72
74
 
73
75
  @classmethod
74
76
  def condition(cls) -> bool:
75
- """Check if clipman is available."""
76
- return importlib.util.find_spec("clipman") is not None
77
+ """Check if copykitten is available."""
78
+ return importlib.util.find_spec("copykitten") is not None
77
79
 
78
80
 
79
81
  class EditAgentFileCommand(NodeCommand):
@@ -130,8 +132,7 @@ class ShareHistoryCommand(NodeCommand):
130
132
  ctx: CommandContext[NodeContext],
131
133
  *,
132
134
  provider: TextSharerStr = "paste_rs",
133
- num_messages: int = 1,
134
- include_system: bool = False,
135
+ num_messages: int | None = None,
135
136
  max_tokens: int | None = None,
136
137
  format_template: str | None = None,
137
138
  title: str | None = None,
@@ -143,32 +144,39 @@ class ShareHistoryCommand(NodeCommand):
143
144
  Args:
144
145
  ctx: Command context
145
146
  provider: Text sharing provider to use
146
- num_messages: Number of messages from history to share (ignored if custom_content)
147
- include_system: Include system messages in history
147
+ num_messages: Number of messages from history to share (None = all messages)
148
148
  max_tokens: Token limit for conversation history
149
149
  format_template: Custom format template for history
150
150
  title: Title/filename for the shared content
151
151
  syntax: Syntax highlighting (e.g., "python", "markdown")
152
152
  visibility: Visibility level
153
153
  """
154
- from anyenv.text_sharing import get_sharer
154
+ from agentpool_commands.text_sharing import get_sharer
155
155
 
156
- content = await ctx.context.agent.conversation.format_history(
157
- num_messages=num_messages,
158
- include_system=include_system,
159
- max_tokens=max_tokens,
160
- format_template=format_template,
161
- )
156
+ conversation = ctx.context.agent.conversation
162
157
 
163
- if not content.strip():
158
+ # Check if there's content to share
159
+ messages_to_check = (
160
+ conversation.chat_messages[-num_messages:]
161
+ if num_messages
162
+ else conversation.chat_messages
163
+ )
164
+ if not messages_to_check:
164
165
  await ctx.print("ℹ️ **No content to share**") # noqa: RUF001
165
166
  return
166
167
 
167
168
  try:
168
169
  # Get the appropriate sharer
169
170
  sharer = get_sharer(provider)
170
- # Share the content
171
- result = await sharer.share(content, title=title, syntax=syntax, visibility=visibility)
171
+
172
+ # Use structured sharing for providers that support it (OpenCode)
173
+ # Otherwise fall back to plain text sharing
174
+ result = await sharer.share_conversation(
175
+ conversation,
176
+ title=title,
177
+ visibility=visibility,
178
+ num_messages=num_messages,
179
+ )
172
180
  # Format success message
173
181
  provider_name = sharer.name
174
182
  msg_parts = [f"🔗 **Content shared via {provider_name}:**", f"• URL: {result.url}"]
@@ -183,7 +191,49 @@ class ShareHistoryCommand(NodeCommand):
183
191
  msg = f"Failed to share content via {provider}: {e}"
184
192
  raise CommandError(msg) from e
185
193
 
186
- @classmethod
187
- def condition(cls) -> bool:
188
- """Check if anyenv text_sharing is available."""
189
- return importlib.util.find_spec("anyenv.text_sharing") is not None
194
+
195
+ class GetLogsCommand(NodeCommand):
196
+ """Get recent log entries from memory.
197
+
198
+ Shows captured log entries with filtering options:
199
+ - Filter by minimum log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
200
+ - Filter by logger name substring
201
+ - Limit number of entries returned
202
+
203
+ Logs are shown newest first.
204
+ """
205
+
206
+ name = "get-logs"
207
+ category = "debug"
208
+
209
+ async def execute_command(
210
+ self,
211
+ ctx: CommandContext[NodeContext],
212
+ *,
213
+ level: LogLevel = "INFO",
214
+ logger_filter: str | None = None,
215
+ limit: int | str = 50,
216
+ ) -> None:
217
+ """Get recent log entries.
218
+
219
+ Args:
220
+ ctx: Command context
221
+ level: Minimum log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
222
+ logger_filter: Only show logs from loggers containing this string
223
+ limit: Maximum number of log entries to return
224
+ """
225
+ from agentpool_toolsets.builtin.debug import get_memory_handler
226
+
227
+ # Convert limit to int (slashed passes args as strings)
228
+ limit_int = int(limit) if isinstance(limit, str) else limit
229
+
230
+ handler = get_memory_handler()
231
+ records = handler.get_records(level=level, logger_filter=logger_filter, limit=limit_int)
232
+
233
+ if not records:
234
+ await ctx.print("No log entries found matching criteria")
235
+ return
236
+
237
+ await ctx.print(f"## 📋 {len(records)} Log Entries (newest first)\n")
238
+ for record in records:
239
+ await ctx.print(record.message)
@@ -2,7 +2,14 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from agentpool_config.resources import ResourceInfo
5
+
6
+ from typing import Annotated
7
+ from pydantic import Field
8
+
9
+ from agentpool_config.tools import ImportToolConfig, BaseToolConfig
10
+ from agentpool_config.agentpool_tools import AgentpoolToolConfig
11
+ from agentpool_config.builtin_tools import BuiltinToolConfig
12
+
6
13
  from agentpool_config.forward_targets import ForwardingTarget
7
14
  from agentpool_config.session import SessionQuery
8
15
  from agentpool_config.teams import TeamConfig
@@ -28,11 +35,30 @@ from agentpool_config.hooks import (
28
35
  HooksConfig,
29
36
  PromptHookConfig,
30
37
  )
38
+ from agentpool_config.toolsets import ToolsetConfig
31
39
 
40
+
41
+ ToolConfig = Annotated[
42
+ ImportToolConfig | AgentpoolToolConfig,
43
+ Field(discriminator="type"),
44
+ ]
45
+
46
+ NativeAgentToolConfig = Annotated[
47
+ ToolConfig | BuiltinToolConfig,
48
+ Field(discriminator="type"),
49
+ ]
50
+
51
+ # Unified type for all tool configurations (single tools + toolsets)
52
+ AnyToolConfig = Annotated[
53
+ NativeAgentToolConfig | ToolsetConfig,
54
+ Field(discriminator="type"),
55
+ ]
32
56
  __all__ = [
57
+ "AnyToolConfig",
33
58
  "BaseEventHandlerConfig",
34
59
  "BaseHookConfig",
35
60
  "BaseMCPServerConfig",
61
+ "BaseToolConfig",
36
62
  "CallableHookConfig",
37
63
  "CallbackEventHandlerConfig",
38
64
  "CommandHookConfig",
@@ -41,13 +67,15 @@ __all__ = [
41
67
  "HookConfig",
42
68
  "HooksConfig",
43
69
  "MCPServerConfig",
70
+ "NativeAgentToolConfig",
44
71
  "PromptHookConfig",
45
- "ResourceInfo",
46
72
  "SSEMCPServerConfig",
47
73
  "SessionQuery",
48
74
  "StdioMCPServerConfig",
49
75
  "StdoutEventHandlerConfig",
50
76
  "StreamableHTTPMCPServerConfig",
51
77
  "TeamConfig",
78
+ "ToolConfig",
79
+ "ToolsetConfig",
52
80
  "resolve_handler_configs",
53
81
  ]