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
@@ -0,0 +1,24 @@
1
+ """Shared FastAPI dependencies."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Annotated, cast
6
+
7
+ from fastapi import Depends, Request # noqa: TC002
8
+
9
+
10
+ if TYPE_CHECKING:
11
+ from agentpool_server.opencode_server.state import ServerState
12
+
13
+
14
+ def get_state(request: Request) -> ServerState:
15
+ """Get server state from request.
16
+
17
+ The state is stored on app.state.server_state during app creation.
18
+ """
19
+ from agentpool_server.opencode_server.state import ServerState
20
+
21
+ return cast(ServerState, request.app.state.server_state)
22
+
23
+
24
+ StateDep = Annotated["ServerState", Depends(get_state)]
@@ -0,0 +1,269 @@
1
+ """OpenCode-based input provider for agent interactions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ from dataclasses import dataclass, field
7
+ from typing import TYPE_CHECKING, Any
8
+
9
+ from mcp import types
10
+
11
+ from agentpool.log import get_logger
12
+ from agentpool.ui.base import InputProvider
13
+ from agentpool_server.opencode_server.models.events import PermissionRequestEvent
14
+
15
+
16
+ if TYPE_CHECKING:
17
+ from agentpool.agents.context import ConfirmationResult
18
+ from agentpool.messaging import ChatMessage
19
+ from agentpool.messaging.context import NodeContext
20
+ from agentpool.tools.base import Tool
21
+ from agentpool_server.opencode_server.state import ServerState
22
+
23
+ logger = get_logger(__name__)
24
+
25
+ # OpenCode permission responses
26
+ PermissionResponse = str # "once" | "always" | "reject"
27
+
28
+
29
+ @dataclass
30
+ class PendingPermission:
31
+ """A pending permission request awaiting user response."""
32
+
33
+ permission_id: str
34
+ tool_name: str
35
+ args: dict[str, Any]
36
+ future: asyncio.Future[PermissionResponse]
37
+ created_at: float = field(default_factory=lambda: __import__("time").time())
38
+
39
+
40
+ class OpenCodeInputProvider(InputProvider):
41
+ """Input provider that uses OpenCode SSE/REST for user interactions.
42
+
43
+ This provider enables tool confirmation and elicitation requests
44
+ through the OpenCode protocol. When a tool needs confirmation:
45
+ 1. A permission request is created and stored
46
+ 2. An SSE event is broadcast to notify clients
47
+ 3. The provider awaits a response via the REST endpoint
48
+ 4. The client POSTs to /session/{id}/permissions/{permissionID} to respond
49
+ """
50
+
51
+ def __init__(self, state: ServerState, session_id: str) -> None:
52
+ """Initialize OpenCode input provider.
53
+
54
+ Args:
55
+ state: Server state for broadcasting events
56
+ session_id: The session ID for this provider
57
+ """
58
+ self.state = state
59
+ self.session_id = session_id
60
+ self._pending_permissions: dict[str, PendingPermission] = {}
61
+ self._tool_approvals: dict[str, str] = {} # tool_name -> "always" | "reject"
62
+ self._id_counter = 0
63
+
64
+ def _generate_permission_id(self) -> str:
65
+ """Generate a unique permission ID."""
66
+ self._id_counter += 1
67
+ return f"perm_{self._id_counter}_{int(__import__('time').time() * 1000)}"
68
+
69
+ async def get_tool_confirmation(
70
+ self,
71
+ context: NodeContext[Any],
72
+ tool: Tool,
73
+ args: dict[str, Any],
74
+ message_history: list[ChatMessage[Any]] | None = None,
75
+ ) -> ConfirmationResult:
76
+ """Get tool execution confirmation via OpenCode permission request.
77
+
78
+ Creates a pending permission, broadcasts an SSE event, and waits
79
+ for the client to respond via POST /session/{id}/permissions/{permissionID}.
80
+
81
+ Args:
82
+ context: Current node context
83
+ tool: Information about the tool to be executed
84
+ args: Tool arguments that will be passed to the tool
85
+ message_history: Optional conversation history
86
+
87
+ Returns:
88
+ Confirmation result indicating whether to allow, skip, or abort
89
+ """
90
+ try:
91
+ # Check if we have a standing approval/rejection for this tool
92
+ if tool.name in self._tool_approvals:
93
+ standing_decision = self._tool_approvals[tool.name]
94
+ if standing_decision == "always":
95
+ logger.debug("Auto-allowing tool", tool_name=tool.name, reason="always")
96
+ return "allow"
97
+ if standing_decision == "reject":
98
+ logger.debug("Auto-rejecting tool", tool_name=tool.name, reason="reject")
99
+ return "skip"
100
+
101
+ # Create a pending permission request
102
+ permission_id = self._generate_permission_id()
103
+ future: asyncio.Future[PermissionResponse] = asyncio.get_event_loop().create_future()
104
+
105
+ pending = PendingPermission(
106
+ permission_id=permission_id,
107
+ tool_name=tool.name,
108
+ args=args,
109
+ future=future,
110
+ )
111
+ self._pending_permissions[permission_id] = pending
112
+
113
+ max_preview_args = 3
114
+ args_preview = ", ".join(f"{k}={v!r}" for k, v in list(args.items())[:max_preview_args])
115
+ if len(args) > max_preview_args:
116
+ args_preview += ", ..."
117
+
118
+ # Extract call_id from AgentContext if available (set by ClaudeCodeAgent from streaming)
119
+ # Fall back to a generated ID if not available
120
+ call_id = getattr(context, "tool_call_id", None)
121
+ if call_id is None:
122
+ # Generate a synthetic call_id - won't match TUI tool parts but allows display
123
+ call_id = f"toolu_{permission_id}"
124
+ # TODO: Extract message_id from context when available
125
+
126
+ event = PermissionRequestEvent.create(
127
+ session_id=self.session_id,
128
+ permission_id=permission_id,
129
+ tool_name=tool.name,
130
+ args_preview=args_preview,
131
+ message=f"Tool '{tool.name}' wants to execute with args: {args_preview}",
132
+ call_id=call_id,
133
+ )
134
+
135
+ await self.state.broadcast_event(event)
136
+ logger.info("Permission requested", permission_id=permission_id, tool_name=tool.name)
137
+ # Wait for the client to respond
138
+ try:
139
+ response = await future
140
+ except asyncio.CancelledError:
141
+ logger.warning("Permission request cancelled", permission_id=permission_id)
142
+ return "skip"
143
+ finally:
144
+ # Clean up the pending permission
145
+ self._pending_permissions.pop(permission_id, None)
146
+
147
+ # Map OpenCode response to our confirmation result
148
+ return self._handle_permission_response(response, tool.name)
149
+
150
+ except Exception:
151
+ logger.exception("Failed to get tool confirmation")
152
+ return "abort_run"
153
+
154
+ def _handle_permission_response(
155
+ self, response: PermissionResponse, tool_name: str
156
+ ) -> ConfirmationResult:
157
+ """Handle permission response and update tool approval state."""
158
+ match response:
159
+ case "once":
160
+ return "allow"
161
+ case "always":
162
+ self._tool_approvals[tool_name] = "always"
163
+ logger.info("Tool approval set", tool_name=tool_name, approval="always")
164
+ return "allow"
165
+ case "reject":
166
+ return "skip"
167
+ case _:
168
+ logger.warning("Unknown permission response", response=response)
169
+ return "abort_run"
170
+
171
+ def resolve_permission(self, permission_id: str, response: PermissionResponse) -> bool:
172
+ """Resolve a pending permission request.
173
+
174
+ Called by the REST endpoint when the client responds.
175
+
176
+ Args:
177
+ permission_id: The permission request ID
178
+ response: The client's response ("once", "always", or "reject")
179
+
180
+ Returns:
181
+ True if the permission was found and resolved, False otherwise
182
+ """
183
+ pending = self._pending_permissions.get(permission_id)
184
+ if pending is None:
185
+ logger.warning("Permission not found", permission_id=permission_id)
186
+ return False
187
+
188
+ if pending.future.done():
189
+ logger.warning("Permission already resolved", permission_id=permission_id)
190
+ return False
191
+
192
+ pending.future.set_result(response)
193
+ logger.info(
194
+ "Permission resolved",
195
+ permission_id=permission_id,
196
+ response=response,
197
+ )
198
+ return True
199
+
200
+ def get_pending_permissions(self) -> list[dict[str, Any]]:
201
+ """Get all pending permission requests.
202
+
203
+ Returns:
204
+ List of pending permission info dicts
205
+ """
206
+ return [
207
+ {
208
+ "permission_id": p.permission_id,
209
+ "tool_name": p.tool_name,
210
+ "args": p.args,
211
+ "created_at": p.created_at,
212
+ }
213
+ for p in self._pending_permissions.values()
214
+ ]
215
+
216
+ async def get_elicitation(
217
+ self,
218
+ params: types.ElicitRequestParams,
219
+ ) -> types.ElicitResult | types.ErrorData:
220
+ """Get user response to elicitation request.
221
+
222
+ For now, this returns a basic decline since OpenCode doesn't have
223
+ a full elicitation UI like ACP. Future versions could add support
224
+ for more complex elicitation flows.
225
+
226
+ Args:
227
+ params: MCP elicit request parameters
228
+
229
+ Returns:
230
+ Elicit result with user's response or error data
231
+ """
232
+ # For URL elicitation, we could open the URL
233
+ if isinstance(params, types.ElicitRequestURLParams):
234
+ logger.info(
235
+ "URL elicitation request",
236
+ message=params.message,
237
+ url=params.url,
238
+ )
239
+ # Could potentially open URL in browser here
240
+ return types.ElicitResult(action="decline")
241
+
242
+ # For form elicitation, we don't have UI support yet
243
+ logger.info(
244
+ "Form elicitation request (not supported)",
245
+ message=params.message,
246
+ schema=getattr(params, "requestedSchema", None),
247
+ )
248
+ return types.ElicitResult(action="decline")
249
+
250
+ def clear_tool_approvals(self) -> None:
251
+ """Clear all stored tool approval decisions."""
252
+ approval_count = len(self._tool_approvals)
253
+ self._tool_approvals.clear()
254
+ logger.info("Cleared tool approval decisions", count=approval_count)
255
+
256
+ def cancel_all_pending(self) -> int:
257
+ """Cancel all pending permission requests.
258
+
259
+ Returns:
260
+ Number of permissions cancelled
261
+ """
262
+ count = 0
263
+ for pending in list(self._pending_permissions.values()):
264
+ if not pending.future.done():
265
+ pending.future.cancel()
266
+ count += 1
267
+ self._pending_permissions.clear()
268
+ logger.info("Cancelled all pending permissions", count=count)
269
+ return count
@@ -0,0 +1,228 @@
1
+ """OpenCode API models.
2
+
3
+ All models inherit from OpenCodeBaseModel which provides:
4
+ - populate_by_name=True for camelCase alias support
5
+ - by_alias=True serialization by default
6
+ """
7
+
8
+ from agentpool_server.opencode_server.models.base import OpenCodeBaseModel
9
+ from agentpool_server.opencode_server.models.common import (
10
+ TimeCreated,
11
+ TimeCreatedUpdated,
12
+ )
13
+ from agentpool_server.opencode_server.models.app import (
14
+ App,
15
+ AppTimeInfo,
16
+ HealthResponse,
17
+ PathInfo,
18
+ Project,
19
+ ProjectTime,
20
+ VcsInfo,
21
+ )
22
+ from agentpool_server.opencode_server.models.provider import (
23
+ Model,
24
+ ModelCost,
25
+ ModelLimit,
26
+ Mode,
27
+ ModeModel,
28
+ Provider,
29
+ ProviderListResponse,
30
+ ProvidersResponse,
31
+ )
32
+ from agentpool_server.opencode_server.models.session import (
33
+ Session,
34
+ SessionCreateRequest,
35
+ SessionForkRequest,
36
+ SessionInitRequest,
37
+ SessionRevert,
38
+ SessionShare,
39
+ SessionStatus,
40
+ SessionUpdateRequest,
41
+ SummarizeRequest,
42
+ Todo,
43
+ )
44
+ from agentpool_server.opencode_server.models.message import (
45
+ AssistantMessage,
46
+ CommandRequest,
47
+ FilePartInput,
48
+ MessagePath,
49
+ MessageRequest,
50
+ MessageTime,
51
+ MessageWithParts,
52
+ PartInput,
53
+ ShellRequest,
54
+ TextPartInput,
55
+ Tokens,
56
+ TokensCache,
57
+ UserMessage,
58
+ )
59
+ from agentpool_server.opencode_server.models.parts import (
60
+ FilePart,
61
+ Part,
62
+ StepFinishPart,
63
+ StepStartPart,
64
+ TextPart,
65
+ TimeStart,
66
+ TimeStartEnd,
67
+ TimeStartEndCompacted,
68
+ TimeStartEndOptional,
69
+ ToolPart,
70
+ ToolState,
71
+ ToolStateCompleted,
72
+ ToolStateError,
73
+ ToolStatePending,
74
+ ToolStateRunning,
75
+ )
76
+ from agentpool_server.opencode_server.models.file import (
77
+ FileContent,
78
+ FileNode,
79
+ FileStatus,
80
+ FindMatch,
81
+ Symbol,
82
+ )
83
+ from agentpool_server.opencode_server.models.agent import (
84
+ Agent,
85
+ Command,
86
+ )
87
+ from agentpool_server.opencode_server.models.pty import (
88
+ PtyCreateRequest,
89
+ PtyInfo,
90
+ PtySize,
91
+ PtyUpdateRequest,
92
+ )
93
+ from agentpool_server.opencode_server.models.events import (
94
+ Event,
95
+ MessageUpdatedEvent,
96
+ MessageUpdatedEventProperties,
97
+ PartUpdatedEvent,
98
+ PartUpdatedEventProperties,
99
+ ServerConnectedEvent,
100
+ SessionCompactedEvent,
101
+ SessionCompactedProperties,
102
+ SessionCreatedEvent,
103
+ SessionDeletedEvent,
104
+ SessionDeletedProperties,
105
+ SessionErrorEvent,
106
+ SessionErrorInfo,
107
+ SessionErrorProperties,
108
+ SessionIdleEvent,
109
+ SessionIdleProperties,
110
+ SessionInfoProperties,
111
+ SessionStatusEvent,
112
+ SessionStatusProperties,
113
+ SessionUpdatedEvent,
114
+ )
115
+ from agentpool_server.opencode_server.models.mcp import (
116
+ LogRequest,
117
+ MCPStatus,
118
+ )
119
+ from agentpool_server.opencode_server.models.config import (
120
+ Config,
121
+ )
122
+
123
+ __all__ = [
124
+ # Agent
125
+ "Agent",
126
+ # App
127
+ "App",
128
+ "AppTimeInfo",
129
+ # Message
130
+ "AssistantMessage",
131
+ "Command",
132
+ "CommandRequest",
133
+ # Config
134
+ "Config",
135
+ # Events
136
+ "Event",
137
+ # File
138
+ "FileContent",
139
+ "FileNode",
140
+ # Parts
141
+ "FilePart",
142
+ "FilePartInput",
143
+ "FileStatus",
144
+ "FindMatch",
145
+ "HealthResponse",
146
+ # MCP
147
+ "LogRequest",
148
+ "MCPStatus",
149
+ "MessagePath",
150
+ "MessageRequest",
151
+ "MessageTime",
152
+ "MessageUpdatedEvent",
153
+ "MessageUpdatedEventProperties",
154
+ "MessageWithParts",
155
+ "Mode",
156
+ "ModeModel",
157
+ # Provider
158
+ "Model",
159
+ "ModelCost",
160
+ "ModelLimit",
161
+ # Base
162
+ "OpenCodeBaseModel",
163
+ "Part",
164
+ "PartInput",
165
+ "PartUpdatedEvent",
166
+ "PartUpdatedEventProperties",
167
+ "PathInfo",
168
+ "Project",
169
+ "ProjectTime",
170
+ "Provider",
171
+ "ProviderListResponse",
172
+ "ProvidersResponse",
173
+ # PTY
174
+ "PtyCreateRequest",
175
+ "PtyInfo",
176
+ "PtySize",
177
+ "PtyUpdateRequest",
178
+ "ServerConnectedEvent",
179
+ # Session
180
+ "Session",
181
+ "SessionCompactedEvent",
182
+ "SessionCompactedProperties",
183
+ "SessionCreateRequest",
184
+ "SessionCreatedEvent",
185
+ "SessionDeletedEvent",
186
+ "SessionDeletedProperties",
187
+ "SessionErrorEvent",
188
+ "SessionErrorInfo",
189
+ "SessionErrorProperties",
190
+ "SessionForkRequest",
191
+ "SessionIdleEvent",
192
+ "SessionIdleProperties",
193
+ "SessionInfoProperties",
194
+ "SessionInitRequest",
195
+ "SessionRevert",
196
+ "SessionShare",
197
+ "SessionStatus",
198
+ "SessionStatusEvent",
199
+ "SessionStatusProperties",
200
+ "SessionUpdateRequest",
201
+ "SessionUpdatedEvent",
202
+ "ShellRequest",
203
+ "StepFinishPart",
204
+ "StepStartPart",
205
+ "SummarizeRequest",
206
+ "Symbol",
207
+ "TextPart",
208
+ "TextPartInput",
209
+ # Common
210
+ "TimeCreated",
211
+ "TimeCreatedUpdated",
212
+ # Time types (from parts.py)
213
+ "TimeStart",
214
+ "TimeStartEnd",
215
+ "TimeStartEndCompacted",
216
+ "TimeStartEndOptional",
217
+ "Todo",
218
+ "Tokens",
219
+ "TokensCache",
220
+ "ToolPart",
221
+ "ToolState",
222
+ "ToolStateCompleted",
223
+ "ToolStateError",
224
+ "ToolStatePending",
225
+ "ToolStateRunning",
226
+ "UserMessage",
227
+ "VcsInfo",
228
+ ]
@@ -0,0 +1,53 @@
1
+ """Agent and command models."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Literal
6
+
7
+ from pydantic import Field
8
+
9
+ from agentpool_server.opencode_server.models.base import OpenCodeBaseModel
10
+
11
+
12
+ class AgentPermission(OpenCodeBaseModel):
13
+ """Agent permission settings."""
14
+
15
+ edit: Literal["ask", "allow", "deny"] = "ask"
16
+ bash: dict[str, Literal["ask", "allow", "deny"]] = Field(default_factory=dict)
17
+ skill: dict[str, Literal["ask", "allow", "deny"]] = Field(default_factory=dict)
18
+ webfetch: Literal["ask", "allow", "deny"] | None = None
19
+ doom_loop: Literal["ask", "allow", "deny"] | None = None
20
+ external_directory: Literal["ask", "allow", "deny"] | None = None
21
+
22
+
23
+ class AgentModel(OpenCodeBaseModel):
24
+ """Agent model configuration."""
25
+
26
+ model_id: str
27
+ provider_id: str
28
+
29
+
30
+ class Agent(OpenCodeBaseModel):
31
+ """Agent information matching SDK type."""
32
+
33
+ name: str
34
+ description: str | None = None
35
+ mode: Literal["subagent", "primary", "all"] = "primary"
36
+ native: bool | None = None
37
+ hidden: bool | None = None
38
+ default: bool | None = None
39
+ top_p: float | None = None
40
+ temperature: float | None = None
41
+ color: str | None = None
42
+ permission: AgentPermission = Field(default_factory=AgentPermission)
43
+ model: AgentModel | None = None
44
+ prompt: str | None = None
45
+ tools: dict[str, bool] = Field(default_factory=dict)
46
+ options: dict[str, str] = Field(default_factory=dict)
47
+
48
+
49
+ class Command(OpenCodeBaseModel):
50
+ """Slash command."""
51
+
52
+ name: str
53
+ description: str = ""
@@ -0,0 +1,60 @@
1
+ """App, project, and path related models."""
2
+
3
+ from agentpool_server.opencode_server.models.base import OpenCodeBaseModel
4
+
5
+
6
+ class HealthResponse(OpenCodeBaseModel):
7
+ """Response for /global/health endpoint."""
8
+
9
+ healthy: bool = True
10
+ version: str
11
+
12
+
13
+ class PathInfo(OpenCodeBaseModel):
14
+ """Path information for app/project."""
15
+
16
+ config: str = ""
17
+ cwd: str
18
+ data: str = ""
19
+ root: str
20
+ state: str = ""
21
+
22
+
23
+ class AppTimeInfo(OpenCodeBaseModel):
24
+ """App time information."""
25
+
26
+ initialized: float | None = None
27
+
28
+
29
+ class App(OpenCodeBaseModel):
30
+ """App information response."""
31
+
32
+ git: bool = False
33
+ hostname: str = "localhost"
34
+ path: PathInfo
35
+ time: AppTimeInfo
36
+
37
+
38
+ class ProjectTime(OpenCodeBaseModel):
39
+ """Project time information."""
40
+
41
+ created: int
42
+ initialized: int | None = None
43
+
44
+
45
+ class Project(OpenCodeBaseModel):
46
+ """Project information."""
47
+
48
+ id: str
49
+ worktree: str
50
+ vcs_dir: str | None = None
51
+ vcs: str | None = None # "git" or None
52
+ time: ProjectTime
53
+
54
+
55
+ class VcsInfo(OpenCodeBaseModel):
56
+ """VCS (git) information."""
57
+
58
+ branch: str | None = None
59
+ dirty: bool = False
60
+ commit: str | None = None
@@ -0,0 +1,26 @@
1
+ """Base model for all OpenCode API models."""
2
+
3
+ from pydantic import BaseModel, ConfigDict
4
+ from pydantic.alias_generators import to_camel
5
+
6
+
7
+ def convert(text: str) -> str:
8
+ val = to_camel(text)
9
+ if val.endswith("Id"):
10
+ return val.rstrip("Id") + "ID"
11
+ return val
12
+
13
+
14
+ class OpenCodeBaseModel(BaseModel):
15
+ """Base model with OpenCode-compatible configuration.
16
+
17
+ All OpenCode models should inherit from this to ensure:
18
+ - Fields can be populated by their alias (camelCase) or Python name (snake_case)
19
+ - Serialization uses aliases by default for API compatibility
20
+ """
21
+
22
+ model_config = ConfigDict(
23
+ populate_by_name=True,
24
+ alias_generator=convert,
25
+ use_attribute_docstrings=True,
26
+ )
@@ -0,0 +1,23 @@
1
+ """Common/shared models used across multiple domains."""
2
+
3
+ from agentpool_server.opencode_server.models.base import OpenCodeBaseModel
4
+
5
+
6
+ class TimeCreatedUpdated(OpenCodeBaseModel):
7
+ """Timestamp with created and updated fields (milliseconds)."""
8
+
9
+ created: int
10
+ updated: int
11
+
12
+
13
+ class TimeCreated(OpenCodeBaseModel):
14
+ """Timestamp with created field only (milliseconds)."""
15
+
16
+ created: int
17
+
18
+
19
+ class TimeStartEnd(OpenCodeBaseModel):
20
+ """Timestamp with start and optional end (milliseconds)."""
21
+
22
+ start: int
23
+ end: int | None = None