Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/kimi_cli/acp/kaos.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
from kaos.local import local_kaos
from kaos.path import KaosPath

from kimi_cli.acp.terminal import TerminalHandle

_DEFAULT_TERMINAL_OUTPUT_LIMIT = 50_000
_DEFAULT_POLL_INTERVAL = 0.2
_TRUNCATION_NOTICE = "[acp output truncated]\n"
Expand Down Expand Up @@ -46,7 +48,7 @@ class ACPProcess:

def __init__(
self,
terminal: acp.TerminalHandle,
terminal: TerminalHandle,
*,
poll_interval: float = _DEFAULT_POLL_INTERVAL,
) -> None:
Expand Down
59 changes: 59 additions & 0 deletions src/kimi_cli/acp/terminal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""Adapter for ACP terminal operations.

The ``acp.TerminalHandle`` convenience class was removed in
agent-client-protocol >= 0.8.0. This module provides a lightweight
replacement that wraps the raw ``acp.Client`` terminal methods behind
the same interface that ``tools.py`` and ``kaos.py`` expect.
"""

from __future__ import annotations

from dataclasses import dataclass

import acp
import acp.schema


@dataclass(slots=True)
class TerminalHandle:
"""Thin wrapper exposing terminal operations on an ``acp.Client``."""

id: str
_client: acp.Client
_session_id: str

async def wait_for_exit(self) -> acp.schema.WaitForTerminalExitResponse:
return await self._client.wait_for_terminal_exit(
session_id=self._session_id, terminal_id=self.id
)

async def current_output(self) -> acp.schema.TerminalOutputResponse:
return await self._client.terminal_output(
session_id=self._session_id, terminal_id=self.id
)

async def kill(self) -> None:
await self._client.kill_terminal(
session_id=self._session_id, terminal_id=self.id
)

async def release(self) -> None:
await self._client.release_terminal(
session_id=self._session_id, terminal_id=self.id
)


async def create_terminal(
client: acp.Client,
*,
command: str,
session_id: str,
output_byte_limit: int | None = None,
) -> TerminalHandle:
"""Create a terminal and return a :class:`TerminalHandle`."""
resp = await client.create_terminal(
command=command,
session_id=session_id,
output_byte_limit=output_byte_limit,
)
return TerminalHandle(id=resp.terminal_id, _client=client, _session_id=session_id)
11 changes: 4 additions & 7 deletions src/kimi_cli/acp/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from kaos.local import local_kaos
from kosong.tooling import CallableTool2, ToolReturnValue

from kimi_cli.acp.terminal import TerminalHandle, create_terminal
from kimi_cli.soul.agent import Runtime
from kimi_cli.soul.approval import Approval
from kimi_cli.soul.toolset import KimiToolset
Expand Down Expand Up @@ -80,23 +81,19 @@ async def __call__(self, params: ShellParams) -> ToolReturnValue:

timeout_seconds = float(params.timeout)
timeout_label = f"{timeout_seconds:g}s"
terminal: acp.TerminalHandle | None = None
terminal: TerminalHandle | None = None
exit_status: (
acp.schema.WaitForTerminalExitResponse | acp.schema.TerminalExitStatus | None
) = None
timed_out = False

try:
term = await self._acp_conn.create_terminal(
terminal = await create_terminal(
self._acp_conn,
command=params.command,
session_id=self._acp_session_id,
output_byte_limit=builder.max_chars,
)
# FIXME: update ACP sdk for the fix
assert isinstance(term, acp.TerminalHandle), (
"Expected TerminalHandle from create_terminal"
)
terminal = term

acp_tool_call_id = get_current_acp_tool_call_id_or_none()
assert acp_tool_call_id, "Expected to have an ACP tool call ID in context"
Expand Down
Loading