agentpool 2.1.9__py3-none-any.whl → 2.2.3__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 (174) hide show
  1. acp/__init__.py +13 -0
  2. acp/bridge/README.md +15 -2
  3. acp/bridge/__init__.py +3 -2
  4. acp/bridge/__main__.py +60 -19
  5. acp/bridge/ws_server.py +173 -0
  6. acp/bridge/ws_server_cli.py +89 -0
  7. acp/notifications.py +2 -1
  8. acp/stdio.py +39 -9
  9. acp/transports.py +362 -2
  10. acp/utils.py +15 -2
  11. agentpool/__init__.py +4 -1
  12. agentpool/agents/__init__.py +2 -0
  13. agentpool/agents/acp_agent/acp_agent.py +203 -88
  14. agentpool/agents/acp_agent/acp_converters.py +46 -21
  15. agentpool/agents/acp_agent/client_handler.py +157 -3
  16. agentpool/agents/acp_agent/session_state.py +4 -1
  17. agentpool/agents/agent.py +314 -107
  18. agentpool/agents/agui_agent/__init__.py +0 -2
  19. agentpool/agents/agui_agent/agui_agent.py +90 -21
  20. agentpool/agents/agui_agent/agui_converters.py +0 -131
  21. agentpool/agents/base_agent.py +163 -1
  22. agentpool/agents/claude_code_agent/claude_code_agent.py +626 -179
  23. agentpool/agents/claude_code_agent/converters.py +71 -3
  24. agentpool/agents/claude_code_agent/history.py +474 -0
  25. agentpool/agents/context.py +40 -0
  26. agentpool/agents/events/__init__.py +2 -0
  27. agentpool/agents/events/builtin_handlers.py +2 -1
  28. agentpool/agents/events/event_emitter.py +29 -2
  29. agentpool/agents/events/events.py +20 -0
  30. agentpool/agents/modes.py +54 -0
  31. agentpool/agents/tool_call_accumulator.py +213 -0
  32. agentpool/common_types.py +21 -0
  33. agentpool/config_resources/__init__.py +38 -1
  34. agentpool/config_resources/claude_code_agent.yml +3 -0
  35. agentpool/delegation/pool.py +37 -29
  36. agentpool/delegation/team.py +1 -0
  37. agentpool/delegation/teamrun.py +1 -0
  38. agentpool/diagnostics/__init__.py +53 -0
  39. agentpool/diagnostics/lsp_manager.py +1593 -0
  40. agentpool/diagnostics/lsp_proxy.py +41 -0
  41. agentpool/diagnostics/lsp_proxy_script.py +229 -0
  42. agentpool/diagnostics/models.py +398 -0
  43. agentpool/mcp_server/__init__.py +0 -2
  44. agentpool/mcp_server/client.py +12 -3
  45. agentpool/mcp_server/manager.py +25 -31
  46. agentpool/mcp_server/registries/official_registry_client.py +25 -0
  47. agentpool/mcp_server/tool_bridge.py +78 -66
  48. agentpool/messaging/__init__.py +0 -2
  49. agentpool/messaging/compaction.py +72 -197
  50. agentpool/messaging/message_history.py +12 -0
  51. agentpool/messaging/messages.py +52 -9
  52. agentpool/messaging/processing.py +3 -1
  53. agentpool/models/acp_agents/base.py +0 -22
  54. agentpool/models/acp_agents/mcp_capable.py +8 -148
  55. agentpool/models/acp_agents/non_mcp.py +129 -72
  56. agentpool/models/agents.py +35 -13
  57. agentpool/models/claude_code_agents.py +33 -2
  58. agentpool/models/manifest.py +43 -0
  59. agentpool/repomap.py +1 -1
  60. agentpool/resource_providers/__init__.py +9 -1
  61. agentpool/resource_providers/aggregating.py +52 -3
  62. agentpool/resource_providers/base.py +57 -1
  63. agentpool/resource_providers/mcp_provider.py +23 -0
  64. agentpool/resource_providers/plan_provider.py +130 -41
  65. agentpool/resource_providers/pool.py +2 -0
  66. agentpool/resource_providers/static.py +2 -0
  67. agentpool/sessions/__init__.py +2 -1
  68. agentpool/sessions/manager.py +31 -2
  69. agentpool/sessions/models.py +50 -0
  70. agentpool/skills/registry.py +13 -8
  71. agentpool/storage/manager.py +217 -1
  72. agentpool/testing.py +537 -19
  73. agentpool/utils/file_watcher.py +269 -0
  74. agentpool/utils/identifiers.py +121 -0
  75. agentpool/utils/pydantic_ai_helpers.py +46 -0
  76. agentpool/utils/streams.py +690 -1
  77. agentpool/utils/subprocess_utils.py +155 -0
  78. agentpool/utils/token_breakdown.py +461 -0
  79. {agentpool-2.1.9.dist-info → agentpool-2.2.3.dist-info}/METADATA +27 -7
  80. {agentpool-2.1.9.dist-info → agentpool-2.2.3.dist-info}/RECORD +170 -112
  81. {agentpool-2.1.9.dist-info → agentpool-2.2.3.dist-info}/WHEEL +1 -1
  82. agentpool_cli/__main__.py +4 -0
  83. agentpool_cli/serve_acp.py +41 -20
  84. agentpool_cli/serve_agui.py +87 -0
  85. agentpool_cli/serve_opencode.py +119 -0
  86. agentpool_commands/__init__.py +30 -0
  87. agentpool_commands/agents.py +74 -1
  88. agentpool_commands/history.py +62 -0
  89. agentpool_commands/mcp.py +176 -0
  90. agentpool_commands/models.py +56 -3
  91. agentpool_commands/tools.py +57 -0
  92. agentpool_commands/utils.py +51 -0
  93. agentpool_config/builtin_tools.py +77 -22
  94. agentpool_config/commands.py +24 -1
  95. agentpool_config/compaction.py +258 -0
  96. agentpool_config/mcp_server.py +131 -1
  97. agentpool_config/storage.py +46 -1
  98. agentpool_config/tools.py +7 -1
  99. agentpool_config/toolsets.py +92 -148
  100. agentpool_server/acp_server/acp_agent.py +134 -150
  101. agentpool_server/acp_server/commands/acp_commands.py +216 -51
  102. agentpool_server/acp_server/commands/docs_commands/fetch_repo.py +10 -10
  103. agentpool_server/acp_server/server.py +23 -79
  104. agentpool_server/acp_server/session.py +181 -19
  105. agentpool_server/opencode_server/.rules +95 -0
  106. agentpool_server/opencode_server/ENDPOINTS.md +362 -0
  107. agentpool_server/opencode_server/__init__.py +27 -0
  108. agentpool_server/opencode_server/command_validation.py +172 -0
  109. agentpool_server/opencode_server/converters.py +869 -0
  110. agentpool_server/opencode_server/dependencies.py +24 -0
  111. agentpool_server/opencode_server/input_provider.py +269 -0
  112. agentpool_server/opencode_server/models/__init__.py +228 -0
  113. agentpool_server/opencode_server/models/agent.py +53 -0
  114. agentpool_server/opencode_server/models/app.py +60 -0
  115. agentpool_server/opencode_server/models/base.py +26 -0
  116. agentpool_server/opencode_server/models/common.py +23 -0
  117. agentpool_server/opencode_server/models/config.py +37 -0
  118. agentpool_server/opencode_server/models/events.py +647 -0
  119. agentpool_server/opencode_server/models/file.py +88 -0
  120. agentpool_server/opencode_server/models/mcp.py +25 -0
  121. agentpool_server/opencode_server/models/message.py +162 -0
  122. agentpool_server/opencode_server/models/parts.py +190 -0
  123. agentpool_server/opencode_server/models/provider.py +81 -0
  124. agentpool_server/opencode_server/models/pty.py +43 -0
  125. agentpool_server/opencode_server/models/session.py +99 -0
  126. agentpool_server/opencode_server/routes/__init__.py +25 -0
  127. agentpool_server/opencode_server/routes/agent_routes.py +442 -0
  128. agentpool_server/opencode_server/routes/app_routes.py +139 -0
  129. agentpool_server/opencode_server/routes/config_routes.py +241 -0
  130. agentpool_server/opencode_server/routes/file_routes.py +392 -0
  131. agentpool_server/opencode_server/routes/global_routes.py +94 -0
  132. agentpool_server/opencode_server/routes/lsp_routes.py +319 -0
  133. agentpool_server/opencode_server/routes/message_routes.py +705 -0
  134. agentpool_server/opencode_server/routes/pty_routes.py +299 -0
  135. agentpool_server/opencode_server/routes/session_routes.py +1205 -0
  136. agentpool_server/opencode_server/routes/tui_routes.py +139 -0
  137. agentpool_server/opencode_server/server.py +430 -0
  138. agentpool_server/opencode_server/state.py +121 -0
  139. agentpool_server/opencode_server/time_utils.py +8 -0
  140. agentpool_storage/__init__.py +16 -0
  141. agentpool_storage/base.py +103 -0
  142. agentpool_storage/claude_provider.py +907 -0
  143. agentpool_storage/file_provider.py +129 -0
  144. agentpool_storage/memory_provider.py +61 -0
  145. agentpool_storage/models.py +3 -0
  146. agentpool_storage/opencode_provider.py +730 -0
  147. agentpool_storage/project_store.py +325 -0
  148. agentpool_storage/session_store.py +6 -0
  149. agentpool_storage/sql_provider/__init__.py +4 -2
  150. agentpool_storage/sql_provider/models.py +48 -0
  151. agentpool_storage/sql_provider/sql_provider.py +134 -1
  152. agentpool_storage/sql_provider/utils.py +10 -1
  153. agentpool_storage/text_log_provider.py +1 -0
  154. agentpool_toolsets/builtin/__init__.py +0 -8
  155. agentpool_toolsets/builtin/code.py +95 -56
  156. agentpool_toolsets/builtin/debug.py +16 -21
  157. agentpool_toolsets/builtin/execution_environment.py +99 -103
  158. agentpool_toolsets/builtin/file_edit/file_edit.py +115 -7
  159. agentpool_toolsets/builtin/skills.py +86 -4
  160. agentpool_toolsets/fsspec_toolset/__init__.py +13 -1
  161. agentpool_toolsets/fsspec_toolset/diagnostics.py +860 -73
  162. agentpool_toolsets/fsspec_toolset/grep.py +74 -2
  163. agentpool_toolsets/fsspec_toolset/image_utils.py +161 -0
  164. agentpool_toolsets/fsspec_toolset/toolset.py +159 -38
  165. agentpool_toolsets/mcp_discovery/__init__.py +5 -0
  166. agentpool_toolsets/mcp_discovery/data/mcp_servers.parquet +0 -0
  167. agentpool_toolsets/mcp_discovery/toolset.py +454 -0
  168. agentpool_toolsets/mcp_run_toolset.py +84 -6
  169. agentpool_toolsets/builtin/agent_management.py +0 -239
  170. agentpool_toolsets/builtin/history.py +0 -36
  171. agentpool_toolsets/builtin/integration.py +0 -85
  172. agentpool_toolsets/builtin/tool_management.py +0 -90
  173. {agentpool-2.1.9.dist-info → agentpool-2.2.3.dist-info}/entry_points.txt +0 -0
  174. {agentpool-2.1.9.dist-info → agentpool-2.2.3.dist-info}/licenses/LICENSE +0 -0
@@ -22,6 +22,7 @@ if TYPE_CHECKING:
22
22
  from pydantic_ai import FinishReason
23
23
  from yamling import FormatType
24
24
 
25
+ from agentpool.sessions.models import ProjectData
25
26
  from agentpool_config.session import SessionQuery
26
27
  from agentpool_config.storage import FileStorageConfig
27
28
 
@@ -46,6 +47,7 @@ class MessageData(TypedDict):
46
47
  provider_response_id: str | None
47
48
  messages: str | None
48
49
  finish_reason: FinishReason | None
50
+ parent_id: str | None
49
51
 
50
52
 
51
53
  class ConversationData(TypedDict):
@@ -68,12 +70,26 @@ class CommandData(TypedDict):
68
70
  metadata: dict[str, JsonValue]
69
71
 
70
72
 
73
+ class ProjectDataDict(TypedDict):
74
+ """Data structure for storing project information."""
75
+
76
+ project_id: str
77
+ worktree: str
78
+ name: str | None
79
+ vcs: str | None
80
+ config_path: str | None
81
+ created_at: str
82
+ last_active: str
83
+ settings: dict[str, JsonValue]
84
+
85
+
71
86
  class StorageData(TypedDict):
72
87
  """Data structure for storing storage information."""
73
88
 
74
89
  messages: list[MessageData]
75
90
  conversations: list[ConversationData]
76
91
  commands: list[CommandData]
92
+ projects: list[ProjectDataDict]
77
93
 
78
94
 
79
95
  class FileProvider(StorageProvider):
@@ -99,6 +115,7 @@ class FileProvider(StorageProvider):
99
115
  "messages": [],
100
116
  "conversations": [],
101
117
  "commands": [],
118
+ "projects": [],
102
119
  }
103
120
  self._load()
104
121
 
@@ -205,6 +222,7 @@ class FileProvider(StorageProvider):
205
222
  provider_response_id: str | None = None,
206
223
  messages: str | None = None,
207
224
  finish_reason: FinishReason | None = None,
225
+ parent_id: str | None = None,
208
226
  ) -> None:
209
227
  """Log a new message."""
210
228
  self._data["messages"].append({
@@ -227,6 +245,7 @@ class FileProvider(StorageProvider):
227
245
  "provider_response_id": provider_response_id,
228
246
  "messages": messages,
229
247
  "finish_reason": finish_reason,
248
+ "parent_id": parent_id,
230
249
  })
231
250
  self._save()
232
251
 
@@ -329,6 +348,7 @@ class FileProvider(StorageProvider):
329
348
  "messages": [],
330
349
  "conversations": [],
331
350
  "commands": [],
351
+ "projects": [],
332
352
  }
333
353
  self._save()
334
354
  return conv_count, msg_count
@@ -376,3 +396,112 @@ class FileProvider(StorageProvider):
376
396
  msg_count = len(self._data["messages"])
377
397
 
378
398
  return conv_count, msg_count
399
+
400
+ async def delete_conversation_messages(
401
+ self,
402
+ conversation_id: str,
403
+ ) -> int:
404
+ """Delete all messages for a conversation."""
405
+ original_count = len(self._data["messages"])
406
+ self._data["messages"] = [
407
+ m for m in self._data["messages"] if m["conversation_id"] != conversation_id
408
+ ]
409
+ deleted = original_count - len(self._data["messages"])
410
+ if deleted > 0:
411
+ self._save()
412
+ return deleted
413
+
414
+ # Project methods
415
+
416
+ def _to_project_data(self, data: ProjectDataDict) -> ProjectData:
417
+ """Convert dict to ProjectData."""
418
+ from datetime import datetime
419
+
420
+ from agentpool.sessions.models import ProjectData
421
+
422
+ return ProjectData(
423
+ project_id=data["project_id"],
424
+ worktree=data["worktree"],
425
+ name=data["name"],
426
+ vcs=data["vcs"],
427
+ config_path=data["config_path"],
428
+ created_at=datetime.fromisoformat(data["created_at"]),
429
+ last_active=datetime.fromisoformat(data["last_active"]),
430
+ settings=data["settings"],
431
+ )
432
+
433
+ def _to_project_dict(self, project: ProjectData) -> ProjectDataDict:
434
+ """Convert ProjectData to dict."""
435
+ return ProjectDataDict(
436
+ project_id=project.project_id,
437
+ worktree=project.worktree,
438
+ name=project.name,
439
+ vcs=project.vcs,
440
+ config_path=project.config_path,
441
+ created_at=project.created_at.isoformat(),
442
+ last_active=project.last_active.isoformat(),
443
+ settings=project.settings,
444
+ )
445
+
446
+ async def save_project(self, project: ProjectData) -> None:
447
+ """Save or update a project."""
448
+ # Remove existing if present
449
+ self._data["projects"] = [
450
+ p for p in self._data.get("projects", []) if p["project_id"] != project.project_id
451
+ ]
452
+ # Add new/updated
453
+ self._data["projects"].append(self._to_project_dict(project))
454
+ self._save()
455
+ logger.debug("Saved project", project_id=project.project_id)
456
+
457
+ async def get_project(self, project_id: str) -> ProjectData | None:
458
+ """Get a project by ID."""
459
+ for p in self._data.get("projects", []):
460
+ if p["project_id"] == project_id:
461
+ return self._to_project_data(p)
462
+ return None
463
+
464
+ async def get_project_by_worktree(self, worktree: str) -> ProjectData | None:
465
+ """Get a project by worktree path."""
466
+ for p in self._data.get("projects", []):
467
+ if p["worktree"] == worktree:
468
+ return self._to_project_data(p)
469
+ return None
470
+
471
+ async def get_project_by_name(self, name: str) -> ProjectData | None:
472
+ """Get a project by friendly name."""
473
+ for p in self._data.get("projects", []):
474
+ if p["name"] == name:
475
+ return self._to_project_data(p)
476
+ return None
477
+
478
+ async def list_projects(self, limit: int | None = None) -> list[ProjectData]:
479
+ """List all projects, ordered by last_active descending."""
480
+ projects = sorted(
481
+ self._data.get("projects", []),
482
+ key=lambda p: p["last_active"],
483
+ reverse=True,
484
+ )
485
+ if limit is not None:
486
+ projects = projects[:limit]
487
+ return [self._to_project_data(p) for p in projects]
488
+
489
+ async def delete_project(self, project_id: str) -> bool:
490
+ """Delete a project."""
491
+ original_count = len(self._data.get("projects", []))
492
+ self._data["projects"] = [
493
+ p for p in self._data.get("projects", []) if p["project_id"] != project_id
494
+ ]
495
+ deleted = original_count > len(self._data["projects"])
496
+ if deleted:
497
+ self._save()
498
+ logger.debug("Deleted project", project_id=project_id)
499
+ return deleted
500
+
501
+ async def touch_project(self, project_id: str) -> None:
502
+ """Update project's last_active timestamp."""
503
+ for p in self._data.get("projects", []):
504
+ if p["project_id"] == project_id:
505
+ p["last_active"] = get_now().isoformat()
506
+ self._save()
507
+ return
@@ -16,6 +16,7 @@ if TYPE_CHECKING:
16
16
  from collections.abc import Sequence
17
17
 
18
18
  from agentpool.common_types import JsonValue
19
+ from agentpool.sessions.models import ProjectData
19
20
  from agentpool_config.session import SessionQuery
20
21
  from agentpool_config.storage import MemoryStorageConfig
21
22
  from agentpool_storage.models import MessageData, QueryFilters, StatsFilters, TokenUsage
@@ -31,12 +32,14 @@ class MemoryStorageProvider(StorageProvider):
31
32
  self.messages: list[dict[str, Any]] = []
32
33
  self.conversations: list[dict[str, Any]] = []
33
34
  self.commands: list[dict[str, Any]] = []
35
+ self.projects: dict[str, ProjectData] = {}
34
36
 
35
37
  def cleanup(self) -> None:
36
38
  """Clear all stored data."""
37
39
  self.messages.clear()
38
40
  self.conversations.clear()
39
41
  self.commands.clear()
42
+ self.projects.clear()
40
43
 
41
44
  async def filter_messages(self, query: SessionQuery) -> list[ChatMessage[str]]:
42
45
  """Filter messages from memory."""
@@ -121,6 +124,7 @@ class MemoryStorageProvider(StorageProvider):
121
124
  provider_response_id: str | None = None,
122
125
  messages: str | None = None,
123
126
  finish_reason: str | None = None,
127
+ parent_id: str | None = None,
124
128
  ) -> None:
125
129
  """Store message in memory."""
126
130
  if next((i for i in self.messages if i["message_id"] == message_id), None):
@@ -394,3 +398,60 @@ class MemoryStorageProvider(StorageProvider):
394
398
  msg_count = len(self.messages)
395
399
 
396
400
  return conv_count, msg_count
401
+
402
+ async def delete_conversation_messages(
403
+ self,
404
+ conversation_id: str,
405
+ ) -> int:
406
+ """Delete all messages for a conversation."""
407
+ original_count = len(self.messages)
408
+ self.messages = [m for m in self.messages if m["conversation_id"] != conversation_id]
409
+ return original_count - len(self.messages)
410
+
411
+ # Project methods
412
+
413
+ async def save_project(self, project: ProjectData) -> None:
414
+ """Save or update a project."""
415
+ self.projects[project.project_id] = project
416
+
417
+ async def get_project(self, project_id: str) -> ProjectData | None:
418
+ """Get a project by ID."""
419
+ return self.projects.get(project_id)
420
+
421
+ async def get_project_by_worktree(self, worktree: str) -> ProjectData | None:
422
+ """Get a project by worktree path."""
423
+ for project in self.projects.values():
424
+ if project.worktree == worktree:
425
+ return project
426
+ return None
427
+
428
+ async def get_project_by_name(self, name: str) -> ProjectData | None:
429
+ """Get a project by friendly name."""
430
+ for project in self.projects.values():
431
+ if project.name == name:
432
+ return project
433
+ return None
434
+
435
+ async def list_projects(self, limit: int | None = None) -> list[ProjectData]:
436
+ """List all projects, ordered by last_active descending."""
437
+ projects = sorted(
438
+ self.projects.values(),
439
+ key=lambda p: p.last_active,
440
+ reverse=True,
441
+ )
442
+ if limit is not None:
443
+ projects = projects[:limit]
444
+ return list(projects)
445
+
446
+ async def delete_project(self, project_id: str) -> bool:
447
+ """Delete a project."""
448
+ if project_id in self.projects:
449
+ del self.projects[project_id]
450
+ return True
451
+ return False
452
+
453
+ async def touch_project(self, project_id: str) -> None:
454
+ """Update project's last_active timestamp."""
455
+ if project_id in self.projects:
456
+ project = self.projects[project_id]
457
+ self.projects[project_id] = project.touch()
@@ -36,6 +36,9 @@ class MessageData(TypedDict):
36
36
  timestamp: str
37
37
  """When the message was sent (ISO format)"""
38
38
 
39
+ parent_id: str | None
40
+ """ID of the parent message for tree-structured conversations."""
41
+
39
42
  model: str | None
40
43
  """Name of the model that generated this message"""
41
44