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.
- acp/__init__.py +13 -0
- acp/bridge/README.md +15 -2
- acp/bridge/__init__.py +3 -2
- acp/bridge/__main__.py +60 -19
- acp/bridge/ws_server.py +173 -0
- acp/bridge/ws_server_cli.py +89 -0
- acp/notifications.py +2 -1
- acp/stdio.py +39 -9
- acp/transports.py +362 -2
- acp/utils.py +15 -2
- agentpool/__init__.py +4 -1
- agentpool/agents/__init__.py +2 -0
- agentpool/agents/acp_agent/acp_agent.py +203 -88
- agentpool/agents/acp_agent/acp_converters.py +46 -21
- agentpool/agents/acp_agent/client_handler.py +157 -3
- agentpool/agents/acp_agent/session_state.py +4 -1
- agentpool/agents/agent.py +314 -107
- agentpool/agents/agui_agent/__init__.py +0 -2
- agentpool/agents/agui_agent/agui_agent.py +90 -21
- agentpool/agents/agui_agent/agui_converters.py +0 -131
- agentpool/agents/base_agent.py +163 -1
- agentpool/agents/claude_code_agent/claude_code_agent.py +626 -179
- agentpool/agents/claude_code_agent/converters.py +71 -3
- agentpool/agents/claude_code_agent/history.py +474 -0
- agentpool/agents/context.py +40 -0
- agentpool/agents/events/__init__.py +2 -0
- agentpool/agents/events/builtin_handlers.py +2 -1
- agentpool/agents/events/event_emitter.py +29 -2
- agentpool/agents/events/events.py +20 -0
- agentpool/agents/modes.py +54 -0
- agentpool/agents/tool_call_accumulator.py +213 -0
- agentpool/common_types.py +21 -0
- agentpool/config_resources/__init__.py +38 -1
- agentpool/config_resources/claude_code_agent.yml +3 -0
- agentpool/delegation/pool.py +37 -29
- agentpool/delegation/team.py +1 -0
- agentpool/delegation/teamrun.py +1 -0
- agentpool/diagnostics/__init__.py +53 -0
- agentpool/diagnostics/lsp_manager.py +1593 -0
- agentpool/diagnostics/lsp_proxy.py +41 -0
- agentpool/diagnostics/lsp_proxy_script.py +229 -0
- agentpool/diagnostics/models.py +398 -0
- agentpool/mcp_server/__init__.py +0 -2
- agentpool/mcp_server/client.py +12 -3
- agentpool/mcp_server/manager.py +25 -31
- agentpool/mcp_server/registries/official_registry_client.py +25 -0
- agentpool/mcp_server/tool_bridge.py +78 -66
- agentpool/messaging/__init__.py +0 -2
- agentpool/messaging/compaction.py +72 -197
- agentpool/messaging/message_history.py +12 -0
- agentpool/messaging/messages.py +52 -9
- agentpool/messaging/processing.py +3 -1
- agentpool/models/acp_agents/base.py +0 -22
- agentpool/models/acp_agents/mcp_capable.py +8 -148
- agentpool/models/acp_agents/non_mcp.py +129 -72
- agentpool/models/agents.py +35 -13
- agentpool/models/claude_code_agents.py +33 -2
- agentpool/models/manifest.py +43 -0
- agentpool/repomap.py +1 -1
- agentpool/resource_providers/__init__.py +9 -1
- agentpool/resource_providers/aggregating.py +52 -3
- agentpool/resource_providers/base.py +57 -1
- agentpool/resource_providers/mcp_provider.py +23 -0
- agentpool/resource_providers/plan_provider.py +130 -41
- agentpool/resource_providers/pool.py +2 -0
- agentpool/resource_providers/static.py +2 -0
- agentpool/sessions/__init__.py +2 -1
- agentpool/sessions/manager.py +31 -2
- agentpool/sessions/models.py +50 -0
- agentpool/skills/registry.py +13 -8
- agentpool/storage/manager.py +217 -1
- agentpool/testing.py +537 -19
- agentpool/utils/file_watcher.py +269 -0
- agentpool/utils/identifiers.py +121 -0
- agentpool/utils/pydantic_ai_helpers.py +46 -0
- agentpool/utils/streams.py +690 -1
- agentpool/utils/subprocess_utils.py +155 -0
- agentpool/utils/token_breakdown.py +461 -0
- {agentpool-2.1.9.dist-info → agentpool-2.2.3.dist-info}/METADATA +27 -7
- {agentpool-2.1.9.dist-info → agentpool-2.2.3.dist-info}/RECORD +170 -112
- {agentpool-2.1.9.dist-info → agentpool-2.2.3.dist-info}/WHEEL +1 -1
- agentpool_cli/__main__.py +4 -0
- agentpool_cli/serve_acp.py +41 -20
- agentpool_cli/serve_agui.py +87 -0
- agentpool_cli/serve_opencode.py +119 -0
- agentpool_commands/__init__.py +30 -0
- agentpool_commands/agents.py +74 -1
- agentpool_commands/history.py +62 -0
- agentpool_commands/mcp.py +176 -0
- agentpool_commands/models.py +56 -3
- agentpool_commands/tools.py +57 -0
- agentpool_commands/utils.py +51 -0
- agentpool_config/builtin_tools.py +77 -22
- agentpool_config/commands.py +24 -1
- agentpool_config/compaction.py +258 -0
- agentpool_config/mcp_server.py +131 -1
- agentpool_config/storage.py +46 -1
- agentpool_config/tools.py +7 -1
- agentpool_config/toolsets.py +92 -148
- agentpool_server/acp_server/acp_agent.py +134 -150
- agentpool_server/acp_server/commands/acp_commands.py +216 -51
- agentpool_server/acp_server/commands/docs_commands/fetch_repo.py +10 -10
- agentpool_server/acp_server/server.py +23 -79
- agentpool_server/acp_server/session.py +181 -19
- agentpool_server/opencode_server/.rules +95 -0
- agentpool_server/opencode_server/ENDPOINTS.md +362 -0
- agentpool_server/opencode_server/__init__.py +27 -0
- agentpool_server/opencode_server/command_validation.py +172 -0
- agentpool_server/opencode_server/converters.py +869 -0
- agentpool_server/opencode_server/dependencies.py +24 -0
- agentpool_server/opencode_server/input_provider.py +269 -0
- agentpool_server/opencode_server/models/__init__.py +228 -0
- agentpool_server/opencode_server/models/agent.py +53 -0
- agentpool_server/opencode_server/models/app.py +60 -0
- agentpool_server/opencode_server/models/base.py +26 -0
- agentpool_server/opencode_server/models/common.py +23 -0
- agentpool_server/opencode_server/models/config.py +37 -0
- agentpool_server/opencode_server/models/events.py +647 -0
- agentpool_server/opencode_server/models/file.py +88 -0
- agentpool_server/opencode_server/models/mcp.py +25 -0
- agentpool_server/opencode_server/models/message.py +162 -0
- agentpool_server/opencode_server/models/parts.py +190 -0
- agentpool_server/opencode_server/models/provider.py +81 -0
- agentpool_server/opencode_server/models/pty.py +43 -0
- agentpool_server/opencode_server/models/session.py +99 -0
- agentpool_server/opencode_server/routes/__init__.py +25 -0
- agentpool_server/opencode_server/routes/agent_routes.py +442 -0
- agentpool_server/opencode_server/routes/app_routes.py +139 -0
- agentpool_server/opencode_server/routes/config_routes.py +241 -0
- agentpool_server/opencode_server/routes/file_routes.py +392 -0
- agentpool_server/opencode_server/routes/global_routes.py +94 -0
- agentpool_server/opencode_server/routes/lsp_routes.py +319 -0
- agentpool_server/opencode_server/routes/message_routes.py +705 -0
- agentpool_server/opencode_server/routes/pty_routes.py +299 -0
- agentpool_server/opencode_server/routes/session_routes.py +1205 -0
- agentpool_server/opencode_server/routes/tui_routes.py +139 -0
- agentpool_server/opencode_server/server.py +430 -0
- agentpool_server/opencode_server/state.py +121 -0
- agentpool_server/opencode_server/time_utils.py +8 -0
- agentpool_storage/__init__.py +16 -0
- agentpool_storage/base.py +103 -0
- agentpool_storage/claude_provider.py +907 -0
- agentpool_storage/file_provider.py +129 -0
- agentpool_storage/memory_provider.py +61 -0
- agentpool_storage/models.py +3 -0
- agentpool_storage/opencode_provider.py +730 -0
- agentpool_storage/project_store.py +325 -0
- agentpool_storage/session_store.py +6 -0
- agentpool_storage/sql_provider/__init__.py +4 -2
- agentpool_storage/sql_provider/models.py +48 -0
- agentpool_storage/sql_provider/sql_provider.py +134 -1
- agentpool_storage/sql_provider/utils.py +10 -1
- agentpool_storage/text_log_provider.py +1 -0
- agentpool_toolsets/builtin/__init__.py +0 -8
- agentpool_toolsets/builtin/code.py +95 -56
- agentpool_toolsets/builtin/debug.py +16 -21
- agentpool_toolsets/builtin/execution_environment.py +99 -103
- agentpool_toolsets/builtin/file_edit/file_edit.py +115 -7
- agentpool_toolsets/builtin/skills.py +86 -4
- agentpool_toolsets/fsspec_toolset/__init__.py +13 -1
- agentpool_toolsets/fsspec_toolset/diagnostics.py +860 -73
- agentpool_toolsets/fsspec_toolset/grep.py +74 -2
- agentpool_toolsets/fsspec_toolset/image_utils.py +161 -0
- agentpool_toolsets/fsspec_toolset/toolset.py +159 -38
- agentpool_toolsets/mcp_discovery/__init__.py +5 -0
- agentpool_toolsets/mcp_discovery/data/mcp_servers.parquet +0 -0
- agentpool_toolsets/mcp_discovery/toolset.py +454 -0
- agentpool_toolsets/mcp_run_toolset.py +84 -6
- agentpool_toolsets/builtin/agent_management.py +0 -239
- agentpool_toolsets/builtin/history.py +0 -36
- agentpool_toolsets/builtin/integration.py +0 -85
- agentpool_toolsets/builtin/tool_management.py +0 -90
- {agentpool-2.1.9.dist-info → agentpool-2.2.3.dist-info}/entry_points.txt +0 -0
- {agentpool-2.1.9.dist-info → agentpool-2.2.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
"""PTY (Pseudo-Terminal) routes.
|
|
2
|
+
|
|
3
|
+
Uses the agent's execution environment PTY manager for terminal sessions.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import contextlib
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from typing import TYPE_CHECKING, Any
|
|
12
|
+
|
|
13
|
+
from fastapi import APIRouter, HTTPException, WebSocketDisconnect
|
|
14
|
+
|
|
15
|
+
from agentpool_server.opencode_server.models import PtyInfo
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from exxec.pty_manager import PtyManagerProtocol
|
|
20
|
+
from fastapi import WebSocket
|
|
21
|
+
|
|
22
|
+
from agentpool_server.opencode_server.dependencies import StateDep
|
|
23
|
+
from agentpool_server.opencode_server.models import PtyCreateRequest, PtyUpdateRequest
|
|
24
|
+
from agentpool_server.opencode_server.state import ServerState
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
router = APIRouter(prefix="/pty", tags=["pty"])
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class PtySession:
|
|
32
|
+
"""Active PTY session with WebSocket subscribers."""
|
|
33
|
+
|
|
34
|
+
pty_id: str
|
|
35
|
+
subscribers: set[WebSocket] = field(default_factory=set)
|
|
36
|
+
read_task: asyncio.Task[Any] | None = None
|
|
37
|
+
buffer: str = ""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# Track WebSocket subscribers per PTY session
|
|
41
|
+
_pty_sessions: dict[str, PtySession] = {}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _get_pty_manager(state: StateDep) -> PtyManagerProtocol:
|
|
45
|
+
"""Get PTY manager from agent's execution environment.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
state: Server state with agent
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
PTY manager from the agent's execution environment
|
|
52
|
+
|
|
53
|
+
Raises:
|
|
54
|
+
HTTPException: If PTY is not supported
|
|
55
|
+
"""
|
|
56
|
+
try:
|
|
57
|
+
return state.agent.env.get_pty_manager()
|
|
58
|
+
except NotImplementedError as e:
|
|
59
|
+
raise HTTPException(
|
|
60
|
+
status_code=501, detail="PTY not supported by this execution environment"
|
|
61
|
+
) from e
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _convert_pty_info(info: Any, title: str | None = None) -> PtyInfo:
|
|
65
|
+
"""Convert exxec PtyInfo to OpenCode PtyInfo model.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
info: PtyInfo from exxec
|
|
69
|
+
title: Optional title override
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
OpenCode PtyInfo model
|
|
73
|
+
"""
|
|
74
|
+
return PtyInfo(
|
|
75
|
+
id=info.id,
|
|
76
|
+
title=title or f"Terminal {info.id[-4:]}",
|
|
77
|
+
command=info.command,
|
|
78
|
+
args=info.args,
|
|
79
|
+
cwd=info.cwd or "",
|
|
80
|
+
status=info.status,
|
|
81
|
+
pid=info.pid,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@router.get("")
|
|
86
|
+
async def list_ptys(state: StateDep) -> list[PtyInfo]:
|
|
87
|
+
"""List all PTY sessions."""
|
|
88
|
+
manager = _get_pty_manager(state)
|
|
89
|
+
sessions = await manager.list_sessions()
|
|
90
|
+
return [_convert_pty_info(s) for s in sessions]
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@router.post("")
|
|
94
|
+
async def create_pty(request: PtyCreateRequest, state: StateDep) -> PtyInfo:
|
|
95
|
+
"""Create a new PTY session."""
|
|
96
|
+
from agentpool_server.opencode_server.models.events import PtyCreatedEvent
|
|
97
|
+
|
|
98
|
+
manager = _get_pty_manager(state)
|
|
99
|
+
|
|
100
|
+
# Use working dir from state if not specified
|
|
101
|
+
cwd = request.cwd or state.working_dir
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
info = await manager.create(
|
|
105
|
+
command=request.command,
|
|
106
|
+
args=request.args,
|
|
107
|
+
cwd=cwd,
|
|
108
|
+
env=request.env,
|
|
109
|
+
)
|
|
110
|
+
except Exception as e:
|
|
111
|
+
raise HTTPException(status_code=400, detail=f"Failed to create PTY: {e}") from e
|
|
112
|
+
|
|
113
|
+
pty_id = info.id
|
|
114
|
+
title = request.title or f"Terminal {pty_id[-4:]}"
|
|
115
|
+
|
|
116
|
+
# Create session tracker for WebSocket subscribers
|
|
117
|
+
session = PtySession(pty_id=pty_id)
|
|
118
|
+
_pty_sessions[pty_id] = session
|
|
119
|
+
|
|
120
|
+
# Start background task to read output and distribute to subscribers
|
|
121
|
+
session.read_task = asyncio.create_task(_read_pty_output(manager, pty_id, state))
|
|
122
|
+
|
|
123
|
+
pty_info = _convert_pty_info(info, title=title)
|
|
124
|
+
|
|
125
|
+
# Broadcast PTY created event
|
|
126
|
+
event = PtyCreatedEvent.create(info=pty_info.model_dump(by_alias=True))
|
|
127
|
+
await state.broadcast_event(event)
|
|
128
|
+
|
|
129
|
+
return pty_info
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
async def _read_pty_output(manager: PtyManagerProtocol, pty_id: str, state: ServerState) -> None:
|
|
133
|
+
"""Background task to read PTY output and distribute to subscribers."""
|
|
134
|
+
from agentpool_server.opencode_server.models.events import PtyExitedEvent
|
|
135
|
+
|
|
136
|
+
session = _pty_sessions.get(pty_id)
|
|
137
|
+
if not session:
|
|
138
|
+
return
|
|
139
|
+
|
|
140
|
+
exit_code = 0
|
|
141
|
+
try:
|
|
142
|
+
async for data in manager.stream(pty_id):
|
|
143
|
+
decoded = data.decode("utf-8", errors="replace")
|
|
144
|
+
|
|
145
|
+
if session.subscribers:
|
|
146
|
+
# Send to all connected WebSocket clients
|
|
147
|
+
disconnected: set[WebSocket] = set()
|
|
148
|
+
for ws in session.subscribers:
|
|
149
|
+
try:
|
|
150
|
+
await ws.send_text(decoded)
|
|
151
|
+
except Exception: # noqa: BLE001
|
|
152
|
+
disconnected.add(ws)
|
|
153
|
+
session.subscribers -= disconnected
|
|
154
|
+
else:
|
|
155
|
+
# Buffer output if no subscribers
|
|
156
|
+
session.buffer += decoded
|
|
157
|
+
# Limit buffer size
|
|
158
|
+
if len(session.buffer) > 100000: # noqa: PLR2004
|
|
159
|
+
session.buffer = session.buffer[-50000:]
|
|
160
|
+
|
|
161
|
+
except asyncio.CancelledError:
|
|
162
|
+
return # Don't broadcast exit if cancelled
|
|
163
|
+
except Exception: # noqa: BLE001
|
|
164
|
+
exit_code = -1
|
|
165
|
+
|
|
166
|
+
# Stream ended - process exited, broadcast event
|
|
167
|
+
event = PtyExitedEvent.create(pty_id=pty_id, exit_code=exit_code)
|
|
168
|
+
await state.broadcast_event(event)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
@router.get("/{pty_id}")
|
|
172
|
+
async def get_pty(pty_id: str, state: StateDep) -> PtyInfo:
|
|
173
|
+
"""Get PTY session details."""
|
|
174
|
+
manager = _get_pty_manager(state)
|
|
175
|
+
info = await manager.get_info(pty_id)
|
|
176
|
+
if not info:
|
|
177
|
+
raise HTTPException(status_code=404, detail="PTY session not found")
|
|
178
|
+
return _convert_pty_info(info)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@router.patch("/{pty_id}")
|
|
182
|
+
async def update_pty(pty_id: str, request: PtyUpdateRequest, state: StateDep) -> PtyInfo:
|
|
183
|
+
"""Update PTY session (title, resize)."""
|
|
184
|
+
from exxec.pty_manager import PtySize
|
|
185
|
+
|
|
186
|
+
from agentpool_server.opencode_server.models.events import PtyUpdatedEvent
|
|
187
|
+
|
|
188
|
+
manager = _get_pty_manager(state)
|
|
189
|
+
info = await manager.get_info(pty_id)
|
|
190
|
+
if not info:
|
|
191
|
+
raise HTTPException(status_code=404, detail="PTY session not found")
|
|
192
|
+
|
|
193
|
+
# Handle resize if requested
|
|
194
|
+
if request.size:
|
|
195
|
+
await manager.resize(pty_id, PtySize(rows=request.size.rows, cols=request.size.cols))
|
|
196
|
+
# Refresh info after resize
|
|
197
|
+
info = await manager.get_info(pty_id)
|
|
198
|
+
if not info:
|
|
199
|
+
raise HTTPException(status_code=404, detail="PTY session not found after resize")
|
|
200
|
+
|
|
201
|
+
# Title is handled at the API level, not in the PTY manager
|
|
202
|
+
title = request.title if request.title else f"Terminal {pty_id[-4:]}"
|
|
203
|
+
|
|
204
|
+
pty_info = _convert_pty_info(info, title=title)
|
|
205
|
+
|
|
206
|
+
# Broadcast PTY updated event
|
|
207
|
+
event = PtyUpdatedEvent.create(info=pty_info.model_dump(by_alias=True))
|
|
208
|
+
await state.broadcast_event(event)
|
|
209
|
+
|
|
210
|
+
return pty_info
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
@router.delete("/{pty_id}")
|
|
214
|
+
async def remove_pty(pty_id: str, state: StateDep) -> dict[str, bool]:
|
|
215
|
+
"""Remove/kill PTY session."""
|
|
216
|
+
from agentpool_server.opencode_server.models.events import PtyDeletedEvent
|
|
217
|
+
|
|
218
|
+
manager = _get_pty_manager(state)
|
|
219
|
+
|
|
220
|
+
# Kill the PTY session
|
|
221
|
+
success = await manager.kill(pty_id)
|
|
222
|
+
if not success:
|
|
223
|
+
raise HTTPException(status_code=404, detail="PTY session not found")
|
|
224
|
+
|
|
225
|
+
# Cleanup session tracker
|
|
226
|
+
session = _pty_sessions.pop(pty_id, None)
|
|
227
|
+
if session:
|
|
228
|
+
# Cancel read task
|
|
229
|
+
if session.read_task and not session.read_task.done():
|
|
230
|
+
session.read_task.cancel()
|
|
231
|
+
with contextlib.suppress(asyncio.CancelledError):
|
|
232
|
+
await session.read_task
|
|
233
|
+
|
|
234
|
+
# Close all WebSocket connections
|
|
235
|
+
for ws in session.subscribers:
|
|
236
|
+
with contextlib.suppress(Exception):
|
|
237
|
+
await ws.close()
|
|
238
|
+
|
|
239
|
+
# Broadcast PTY deleted event
|
|
240
|
+
event = PtyDeletedEvent.create(pty_id=pty_id)
|
|
241
|
+
await state.broadcast_event(event)
|
|
242
|
+
|
|
243
|
+
return {"success": True}
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
@router.websocket("/{pty_id}/connect")
|
|
247
|
+
async def connect_pty(websocket: WebSocket, pty_id: str) -> None:
|
|
248
|
+
"""Connect to PTY via WebSocket for interactive terminal."""
|
|
249
|
+
# Get state from websocket's app
|
|
250
|
+
|
|
251
|
+
state: ServerState = websocket.app.state.server_state
|
|
252
|
+
|
|
253
|
+
try:
|
|
254
|
+
manager = _get_pty_manager(state)
|
|
255
|
+
except HTTPException:
|
|
256
|
+
await websocket.close(code=4501, reason="PTY not supported")
|
|
257
|
+
return
|
|
258
|
+
|
|
259
|
+
info = await manager.get_info(pty_id)
|
|
260
|
+
if not info:
|
|
261
|
+
await websocket.close(code=4004, reason="PTY session not found")
|
|
262
|
+
return
|
|
263
|
+
|
|
264
|
+
await websocket.accept()
|
|
265
|
+
|
|
266
|
+
# Get or create session tracker
|
|
267
|
+
if pty_id not in _pty_sessions:
|
|
268
|
+
_pty_sessions[pty_id] = PtySession(pty_id=pty_id)
|
|
269
|
+
session = _pty_sessions[pty_id]
|
|
270
|
+
session.subscribers.add(websocket)
|
|
271
|
+
|
|
272
|
+
# Send buffered output
|
|
273
|
+
if session.buffer:
|
|
274
|
+
try:
|
|
275
|
+
await websocket.send_text(session.buffer)
|
|
276
|
+
session.buffer = ""
|
|
277
|
+
except Exception: # noqa: BLE001
|
|
278
|
+
pass
|
|
279
|
+
|
|
280
|
+
try:
|
|
281
|
+
while True:
|
|
282
|
+
# Receive input from client
|
|
283
|
+
data = await websocket.receive_text()
|
|
284
|
+
|
|
285
|
+
# Write to PTY stdin
|
|
286
|
+
info = await manager.get_info(pty_id)
|
|
287
|
+
if info and info.status == "running":
|
|
288
|
+
try:
|
|
289
|
+
await manager.write(pty_id, data.encode())
|
|
290
|
+
except Exception: # noqa: BLE001
|
|
291
|
+
break
|
|
292
|
+
else:
|
|
293
|
+
break
|
|
294
|
+
except WebSocketDisconnect:
|
|
295
|
+
pass
|
|
296
|
+
except Exception: # noqa: BLE001
|
|
297
|
+
pass
|
|
298
|
+
finally:
|
|
299
|
+
session.subscribers.discard(websocket)
|