refactor: break up chat_agent() into helpers (#542)
Co-authored-by: Kimi Agent <kimi@timmy.local> Co-committed-by: Kimi Agent <kimi@timmy.local>
This commit was merged in pull request #542.
This commit is contained in:
@@ -71,21 +71,20 @@ async def clear_history(request: Request):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/default/chat", response_class=HTMLResponse)
|
def _validate_message(message: str) -> str:
|
||||||
async def chat_agent(request: Request, message: str = Form(...)):
|
"""Strip and validate chat input; raise HTTPException on bad input."""
|
||||||
"""Chat — synchronous response with native Agno tool confirmation."""
|
from fastapi import HTTPException
|
||||||
|
|
||||||
message = message.strip()
|
message = message.strip()
|
||||||
if not message:
|
if not message:
|
||||||
from fastapi import HTTPException
|
|
||||||
|
|
||||||
raise HTTPException(status_code=400, detail="Message cannot be empty")
|
raise HTTPException(status_code=400, detail="Message cannot be empty")
|
||||||
|
|
||||||
if len(message) > MAX_MESSAGE_LENGTH:
|
if len(message) > MAX_MESSAGE_LENGTH:
|
||||||
from fastapi import HTTPException
|
|
||||||
|
|
||||||
raise HTTPException(status_code=422, detail="Message too long")
|
raise HTTPException(status_code=422, detail="Message too long")
|
||||||
|
return message
|
||||||
|
|
||||||
# Record user activity so the thinking engine knows we're not idle
|
|
||||||
|
def _record_user_activity() -> None:
|
||||||
|
"""Notify the thinking engine that the user is active."""
|
||||||
try:
|
try:
|
||||||
from timmy.thinking import thinking_engine
|
from timmy.thinking import thinking_engine
|
||||||
|
|
||||||
@@ -93,6 +92,67 @@ async def chat_agent(request: Request, message: str = Form(...)):
|
|||||||
except Exception:
|
except Exception:
|
||||||
logger.debug("Failed to record user input for thinking engine")
|
logger.debug("Failed to record user input for thinking engine")
|
||||||
|
|
||||||
|
|
||||||
|
def _extract_tool_actions(run_output) -> list[dict]:
|
||||||
|
"""If Agno paused the run for tool confirmation, build approval items."""
|
||||||
|
from timmy.approvals import create_item
|
||||||
|
|
||||||
|
tool_actions: list[dict] = []
|
||||||
|
status = getattr(run_output, "status", None)
|
||||||
|
is_paused = status == "PAUSED" or str(status) == "RunStatus.paused"
|
||||||
|
|
||||||
|
if not (is_paused and getattr(run_output, "active_requirements", None)):
|
||||||
|
return tool_actions
|
||||||
|
|
||||||
|
for req in run_output.active_requirements:
|
||||||
|
if not getattr(req, "needs_confirmation", False):
|
||||||
|
continue
|
||||||
|
te = req.tool_execution
|
||||||
|
tool_name = getattr(te, "tool_name", "unknown")
|
||||||
|
tool_args = getattr(te, "tool_args", {}) or {}
|
||||||
|
|
||||||
|
item = create_item(
|
||||||
|
title=f"Dashboard: {tool_name}",
|
||||||
|
description=format_action_description(tool_name, tool_args),
|
||||||
|
proposed_action=json.dumps({"tool": tool_name, "args": tool_args}),
|
||||||
|
impact=get_impact_level(tool_name),
|
||||||
|
)
|
||||||
|
_pending_runs[item.id] = {
|
||||||
|
"run_output": run_output,
|
||||||
|
"requirement": req,
|
||||||
|
"tool_name": tool_name,
|
||||||
|
"tool_args": tool_args,
|
||||||
|
}
|
||||||
|
tool_actions.append(
|
||||||
|
{
|
||||||
|
"approval_id": item.id,
|
||||||
|
"tool_name": tool_name,
|
||||||
|
"description": format_action_description(tool_name, tool_args),
|
||||||
|
"impact": get_impact_level(tool_name),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return tool_actions
|
||||||
|
|
||||||
|
|
||||||
|
def _log_exchange(
|
||||||
|
message: str, response_text: str | None, error_text: str | None, timestamp: str
|
||||||
|
) -> None:
|
||||||
|
"""Append user message and agent/error reply to the in-memory log."""
|
||||||
|
message_log.append(role="user", content=message, timestamp=timestamp, source="browser")
|
||||||
|
if response_text:
|
||||||
|
message_log.append(
|
||||||
|
role="agent", content=response_text, timestamp=timestamp, source="browser"
|
||||||
|
)
|
||||||
|
elif error_text:
|
||||||
|
message_log.append(role="error", content=error_text, timestamp=timestamp, source="browser")
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/default/chat", response_class=HTMLResponse)
|
||||||
|
async def chat_agent(request: Request, message: str = Form(...)):
|
||||||
|
"""Chat — synchronous response with native Agno tool confirmation."""
|
||||||
|
message = _validate_message(message)
|
||||||
|
_record_user_activity()
|
||||||
|
|
||||||
timestamp = datetime.now().strftime("%H:%M:%S")
|
timestamp = datetime.now().strftime("%H:%M:%S")
|
||||||
response_text = None
|
response_text = None
|
||||||
error_text = None
|
error_text = None
|
||||||
@@ -104,54 +164,15 @@ async def chat_agent(request: Request, message: str = Form(...)):
|
|||||||
error_text = f"Chat error: {exc}"
|
error_text = f"Chat error: {exc}"
|
||||||
run_output = None
|
run_output = None
|
||||||
|
|
||||||
# Check if Agno paused the run for tool confirmation
|
tool_actions: list[dict] = []
|
||||||
tool_actions = []
|
|
||||||
if run_output is not None:
|
if run_output is not None:
|
||||||
status = getattr(run_output, "status", None)
|
tool_actions = _extract_tool_actions(run_output)
|
||||||
is_paused = status == "PAUSED" or str(status) == "RunStatus.paused"
|
|
||||||
|
|
||||||
if is_paused and getattr(run_output, "active_requirements", None):
|
|
||||||
for req in run_output.active_requirements:
|
|
||||||
if getattr(req, "needs_confirmation", False):
|
|
||||||
te = req.tool_execution
|
|
||||||
tool_name = getattr(te, "tool_name", "unknown")
|
|
||||||
tool_args = getattr(te, "tool_args", {}) or {}
|
|
||||||
|
|
||||||
from timmy.approvals import create_item
|
|
||||||
|
|
||||||
item = create_item(
|
|
||||||
title=f"Dashboard: {tool_name}",
|
|
||||||
description=format_action_description(tool_name, tool_args),
|
|
||||||
proposed_action=json.dumps({"tool": tool_name, "args": tool_args}),
|
|
||||||
impact=get_impact_level(tool_name),
|
|
||||||
)
|
|
||||||
_pending_runs[item.id] = {
|
|
||||||
"run_output": run_output,
|
|
||||||
"requirement": req,
|
|
||||||
"tool_name": tool_name,
|
|
||||||
"tool_args": tool_args,
|
|
||||||
}
|
|
||||||
tool_actions.append(
|
|
||||||
{
|
|
||||||
"approval_id": item.id,
|
|
||||||
"tool_name": tool_name,
|
|
||||||
"description": format_action_description(tool_name, tool_args),
|
|
||||||
"impact": get_impact_level(tool_name),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
raw_content = run_output.content if hasattr(run_output, "content") else ""
|
raw_content = run_output.content if hasattr(run_output, "content") else ""
|
||||||
response_text = _clean_response(raw_content or "")
|
response_text = _clean_response(raw_content or "")
|
||||||
if not response_text and not tool_actions:
|
if not response_text and not tool_actions:
|
||||||
response_text = None # let error template show if needed
|
response_text = None
|
||||||
|
|
||||||
message_log.append(role="user", content=message, timestamp=timestamp, source="browser")
|
_log_exchange(message, response_text, error_text, timestamp)
|
||||||
if response_text:
|
|
||||||
message_log.append(
|
|
||||||
role="agent", content=response_text, timestamp=timestamp, source="browser"
|
|
||||||
)
|
|
||||||
elif error_text:
|
|
||||||
message_log.append(role="error", content=error_text, timestamp=timestamp, source="browser")
|
|
||||||
|
|
||||||
return templates.TemplateResponse(
|
return templates.TemplateResponse(
|
||||||
request,
|
request,
|
||||||
|
|||||||
Reference in New Issue
Block a user