- run_task_brief_research() runner with brief-specific tool set and max_steps=12 - New agents: client_agent (list_clients, get_client) and relations_agent (query_relations) - search_associative tool wrapping MemoryMiddleware semantic search - BRIEF_RESEARCH_TOOLS constant: read-only task/project/note/timeline + memory + client/relations - canvas block extraction in output_formatter (splits visible text from <canvas> draft) - device_ws.py: task_brief_research request type; emits canvas_draft mutation on stream_end - Stage 2 briefMode: briefing_context injected into floating system prompt when present - briefingContext kwarg wired through compile_prompt call chain Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
53 lines
1.5 KiB
Python
53 lines
1.5 KiB
Python
"""Client agent — read-only tools for the clients table."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from typing import Any
|
|
|
|
from langchain_core.tools import tool
|
|
|
|
from app.core.ws_context import execute_on_client
|
|
|
|
|
|
@tool
|
|
async def list_clients(search: str = "", limit: int = 20) -> str:
|
|
"""List clients, optionally filtered by a name/email substring search.
|
|
|
|
search: optional substring to match against client name or email.
|
|
limit: max rows to return (default 20).
|
|
"""
|
|
filters: dict[str, Any] = {"limit": limit}
|
|
if search:
|
|
filters["search"] = search
|
|
|
|
result = await execute_on_client(action="select", table="clients", filters=filters)
|
|
rows = result.get("rows", [])
|
|
if not rows:
|
|
return "No clients found."
|
|
lines = [
|
|
f"- {r.get('name', '?')} (id: {r.get('id')}, email: {r.get('email', '')}, "
|
|
f"company: {r.get('company', '')})"
|
|
for r in rows
|
|
]
|
|
return f"Found {len(rows)} client(s):\n" + "\n".join(lines)
|
|
|
|
|
|
@tool
|
|
async def get_client(id: str) -> str:
|
|
"""Get full details for one client by UUID.
|
|
|
|
id: the client's UUID.
|
|
"""
|
|
if not id:
|
|
return "Client id is required."
|
|
|
|
result = await execute_on_client(action="get", table="clients", data={"id": id})
|
|
row = result.get("row") or result.get("rows", [None])[0] if result else None
|
|
if not row:
|
|
return f"Client '{id}' not found."
|
|
return f"Client details:\n{json.dumps(row, ensure_ascii=False, indent=2)}"
|
|
|
|
|
|
CLIENT_TOOLS: list[Any] = [list_clients, get_client]
|