feat(telegram): stop generation from the client, questions survive a restart, images reach the model inline, albums become one turn

This commit is contained in:
hh
2026-09-02 02:11:44 +02:00
parent 7a8ee0f200
commit 85b14e2c2f
12 changed files with 452 additions and 76 deletions
+17 -4
View File
@@ -313,7 +313,7 @@ class ClaudeSdkBackend:
if not history or history[-1].get("role") != "user":
msg = "the last message must be a user turn"
raise ValueError(msg)
prompt = _prompt_text(history[-1].get("content"))
prompt = _prompt(history[-1].get("content"))
prior = history[:-1]
key = conversation_id or fingerprint(prior)
spec = _SessionSpec(kind=kind, pinned=pinned, tools=tools)
@@ -404,7 +404,7 @@ class ClaudeSdkBackend:
async def _run_turn(
self,
live: Session,
prompt: str,
prompt: str | list[dict[str, Any]],
turn: _Turn,
observer: Callable[[Any], None] | None = None,
capture: TurnCapture | None = None,
@@ -421,7 +421,7 @@ class ClaudeSdkBackend:
raw: list[Any] = []
next_index = 0
offset = 0
await live.client.query(prompt)
await live.client.query(prompt if isinstance(prompt, str) else _stream(prompt))
async for message in live.client.receive_response():
if observer is not None:
observer(message)
@@ -845,14 +845,27 @@ def _mcp_disallowed(
return out
def _prompt_text(content: Any) -> str:
def _prompt(content: Any) -> str | list[dict[str, Any]]:
"""Plain text when the turn is text only; the block list when images ride along."""
text = text_of(content)
if not text:
msg = "user message has no text content"
raise ValueError(msg)
if isinstance(content, list) and any(
isinstance(b, dict) and b.get("type") != "text" for b in content
):
return [dict(b) for b in content if isinstance(b, dict)]
return text
async def _stream(content: list[dict[str, Any]]) -> AsyncIterator[dict[str, Any]]:
yield {
"type": "user",
"message": {"role": "user", "content": content},
"parent_tool_use_id": None,
}
def synthesize_turn_messages(raw: Iterable[Any]) -> list[dict[str, Any]]:
out: list[dict[str, Any]] = []
for message in raw:
+2 -2
View File
@@ -20,7 +20,7 @@ from typing import TYPE_CHECKING, Any, Protocol
import psutil
if TYPE_CHECKING:
from collections.abc import AsyncIterator, Iterator, Mapping
from collections.abc import AsyncIterable, AsyncIterator, Iterator, Mapping
__all__ = ["DEFAULT_TTL", "Session", "SessionClient", "SessionPool", "cgroup_limit"]
@@ -41,7 +41,7 @@ _RSS_HEADROOM = 0.8
class SessionClient(Protocol):
async def connect(self) -> None: ...
async def query(self, prompt: str) -> None: ...
async def query(self, prompt: str | AsyncIterable[dict[str, Any]]) -> None: ...
def receive_response(self) -> AsyncIterator[Any]: ...
async def interrupt(self) -> None: ...
async def disconnect(self) -> None: ...