mirror of
https://github.com/agent0ai/agent-zero.git
synced 2026-07-10 01:18:29 +00:00
Render plain Responses completions
When Responses mode accepts a plain-text final answer, reuse the active generating log item as a finished response entry so the WebUI does not remain on the Calling LLM step. Skip normal tool JSON and existing live response-tool logs, and cover the fallback with focused regression tests.
This commit is contained in:
parent
272a0d8dfa
commit
48087de008
3 changed files with 111 additions and 0 deletions
|
|
@ -15,6 +15,7 @@
|
|||
- Do not flatten nested qualname paths into retired legacy folder names.
|
||||
- Extension functions must match the implicit hook's supplied arguments.
|
||||
- Preserve ordering prefixes where exception handling, watchdog registration, or cleanup depends on them.
|
||||
- Hooks that mirror persisted AI responses into UI logs must reuse existing stream log items and avoid duplicating live response-tool logs.
|
||||
|
||||
## Work Guidance
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
from typing import Any
|
||||
|
||||
from helpers import extract_tools
|
||||
from helpers.extension import Extension
|
||||
|
||||
|
||||
class LogPlainResponses(Extension):
|
||||
def execute(self, data: dict[str, Any] | None = None, **kwargs):
|
||||
if not self.agent or not isinstance(data, dict):
|
||||
return
|
||||
|
||||
call_kwargs = data.get("kwargs")
|
||||
if not isinstance(call_kwargs, dict):
|
||||
call_kwargs = {}
|
||||
|
||||
llm_result = call_kwargs.get("llm_result")
|
||||
if getattr(llm_result, "mode", "") != "responses":
|
||||
return
|
||||
|
||||
message = call_kwargs.get("message")
|
||||
call_args = data.get("args")
|
||||
if message is None and isinstance(call_args, tuple) and len(call_args) > 1:
|
||||
message = call_args[1]
|
||||
if not isinstance(message, str) or not message:
|
||||
return
|
||||
if extract_tools.json_parse_dirty(message) is not None:
|
||||
return
|
||||
|
||||
params = getattr(getattr(self.agent, "loop_data", None), "params_temporary", None)
|
||||
if not isinstance(params, dict) or "log_item_response" in params:
|
||||
return
|
||||
|
||||
log_item = params.get("log_item_generating")
|
||||
if log_item is None:
|
||||
return
|
||||
|
||||
params["log_item_response"] = log_item
|
||||
log_item.update(
|
||||
type="response",
|
||||
heading="",
|
||||
content=message,
|
||||
finished=True,
|
||||
update_progress="none",
|
||||
)
|
||||
66
tests/test_plain_response_logging.py
Normal file
66
tests/test_plain_response_logging.py
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
from types import SimpleNamespace
|
||||
|
||||
from helpers.log import Log
|
||||
from extensions.python._functions.agent.Agent.hist_add_ai_response.end._10_log_plain_responses import (
|
||||
LogPlainResponses,
|
||||
)
|
||||
|
||||
|
||||
def _agent_with_generating_log():
|
||||
log = Log()
|
||||
item = log.log(type="agent", heading="A0: Calling LLM...", id="msg-1")
|
||||
agent = SimpleNamespace(
|
||||
loop_data=SimpleNamespace(params_temporary={"log_item_generating": item})
|
||||
)
|
||||
return agent, item
|
||||
|
||||
|
||||
def test_responses_plain_text_completion_finishes_generating_log_as_response():
|
||||
agent, item = _agent_with_generating_log()
|
||||
data = {
|
||||
"args": (agent, "Plain final answer."),
|
||||
"kwargs": {"id": "msg-1", "llm_result": SimpleNamespace(mode="responses")},
|
||||
}
|
||||
|
||||
LogPlainResponses(agent=agent).execute(data=data)
|
||||
|
||||
assert item.type == "response"
|
||||
assert item.heading == ""
|
||||
assert item.content == "Plain final answer."
|
||||
assert item.update_progress == "none"
|
||||
assert item.kvps["finished"] is True
|
||||
assert agent.loop_data.params_temporary["log_item_response"] is item
|
||||
|
||||
|
||||
def test_responses_tool_json_keeps_generating_log_as_agent_step():
|
||||
agent, item = _agent_with_generating_log()
|
||||
data = {
|
||||
"args": (
|
||||
agent,
|
||||
'{"tool_name":"search_engine","tool_args":{"query":"today news"}}',
|
||||
),
|
||||
"kwargs": {"id": "msg-1", "llm_result": SimpleNamespace(mode="responses")},
|
||||
}
|
||||
|
||||
LogPlainResponses(agent=agent).execute(data=data)
|
||||
|
||||
assert item.type == "agent"
|
||||
assert item.heading == "A0: Calling LLM..."
|
||||
assert item.content == ""
|
||||
assert "log_item_response" not in agent.loop_data.params_temporary
|
||||
|
||||
|
||||
def test_responses_plain_text_completion_does_not_replace_live_response_log():
|
||||
agent, item = _agent_with_generating_log()
|
||||
live_response = Log().log(type="response", content="Already live")
|
||||
agent.loop_data.params_temporary["log_item_response"] = live_response
|
||||
data = {
|
||||
"args": (agent, "Plain final answer."),
|
||||
"kwargs": {"id": "msg-1", "llm_result": SimpleNamespace(mode="responses")},
|
||||
}
|
||||
|
||||
LogPlainResponses(agent=agent).execute(data=data)
|
||||
|
||||
assert item.type == "agent"
|
||||
assert item.content == ""
|
||||
assert agent.loop_data.params_temporary["log_item_response"] is live_response
|
||||
Loading…
Add table
Add a link
Reference in a new issue