Bind chat agent sessions to individual devices

This commit is contained in:
showtan001
2026-08-30 21:48:39 +08:00
parent fdaca7539b
commit 697e54427b
3 changed files with 37 additions and 4 deletions
@@ -40,12 +40,13 @@ class ConversationAgent:
self.event_logger = event_logger
self._client: Any | None = None
def chat(self, messages: list[dict[str, Any]]) -> ChatResult:
def chat(self, messages: list[dict[str, Any]], *, tools: dict[str, Callable[..., Any]] | None = None) -> ChatResult:
if self.config.provider not in {"openai", "openai_compatible"}:
raise RuntimeError(
"conversation chat currently requires an OpenAI-compatible provider"
)
client = self._get_client()
active_tools = tools or self.tools
history: list[dict[str, Any]] = [
{
"role": "system",
@@ -88,7 +89,7 @@ class ConversationAgent:
arguments = decoded_arguments
arguments.pop("purpose", None)
arguments.pop("expected_outcome", None)
result = self.tools[name](**arguments)
result = active_tools[name](**arguments)
except Exception as exc:
result = {"ok": False, "error": str(exc)}
calls += 1
@@ -103,6 +104,14 @@ class ConversationAgent:
)
raise RuntimeError("conversation exceeded the maximum tool-call rounds")
def chat_for_device(self, device_id: str, messages: list[dict[str, Any]]) -> ChatResult:
"""Run a conversation bound to exactly one device."""
device_tools = {
name: _bind_device(tool, device_id, name=name)
for name, tool in original_tools.items()
}
return self.chat(messages, tools=device_tools)
def _log(self, event: dict[str, Any]) -> None:
if self.event_logger is not None:
try:
@@ -192,3 +201,16 @@ def _normalize_message(message: dict[str, Any]) -> dict[str, Any]:
blocks.append({"type": "image_url", "image_url": {"url": f"data:{mime};base64,{image}"}})
return {"role": role, "content": blocks}
raise ValueError("message content must be text, image blocks, or image_base64")
def _bind_device(tool: Callable[..., Any], device_id: str, *, name: str) -> Callable[..., Any]:
def bound(**arguments: Any) -> Any:
if name == "list_devices":
return tool(**arguments)
requested = arguments.get("device_id")
if requested is not None and requested != device_id:
raise ValueError(f"conversation is bound to device {device_id}")
arguments["device_id"] = device_id
return tool(**arguments)
return bound