mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-09-09 21:49:37 +00:00
fix(gateway): stamp turn_duration on last AI message only in /messages/page (#4755)
_enrich_thread_message_page inlined its own turn_duration loop that stamped EVERY AI message of a run, re-introducing #4152 on the /messages/page endpoint (the legacy /messages and /history endpoints already route through stamp_turn_duration_on_last_ai after #4163, but that fix missed the page path introduced earlier in #4065). A multi-step turn thus rendered the same run lifetime beside every intermediate AI message, reading as repeated thinking latency. Replace the inline loop with the shared stamp_turn_duration_on_last_ai helper so all three message endpoints agree: the run's wall-clock duration lands on its final visible AI message only.
This commit is contained in:
parent
6bb376abfd
commit
baaf2bad47
@ -1329,9 +1329,14 @@ async def _enrich_thread_message_page(
|
||||
"comment": feedback.get("comment"),
|
||||
}
|
||||
|
||||
content = row.get("content")
|
||||
if isinstance(content, dict) and content.get("type") == "ai" and run_id in run_durations:
|
||||
content.setdefault("additional_kwargs", {})["turn_duration"] = run_durations[run_id]
|
||||
# ``turn_duration`` is the run's wall-clock lifetime, not model thinking
|
||||
# time — stamp it on the run's LAST visible AI message only so the UI does
|
||||
# not repeat the same number on every intermediate AI message of a
|
||||
# multi-step turn (#4152). The legacy ``GET /messages`` and ``/history``
|
||||
# endpoints already use ``stamp_turn_duration_on_last_ai``; the page
|
||||
# endpoint was inlining the equivalent loop but stamping every AI row,
|
||||
# which #4163 fixed for the other paths and missed here.
|
||||
stamp_turn_duration_on_last_ai(data, run_durations)
|
||||
return data
|
||||
|
||||
|
||||
|
||||
@ -443,6 +443,37 @@ def test_thread_page_batch_hydrates_duration_for_old_runs():
|
||||
assert response.json()["data"][0]["content"]["additional_kwargs"]["turn_duration"] == 7
|
||||
|
||||
|
||||
def test_thread_page_stamps_turn_duration_on_last_ai_message_only():
|
||||
# #4152 regression: a run with multiple AI messages (multi-step turn) must
|
||||
# carry turn_duration on the LAST AI message only, not on every one.
|
||||
store = MemoryRunEventStore()
|
||||
|
||||
async def seed():
|
||||
await _put_message(store, "run-multi", "ai", "first-answer")
|
||||
await _put_message(store, "run-multi", "ai", "second-answer")
|
||||
|
||||
asyncio.run(seed())
|
||||
record = RunRecord(
|
||||
run_id="run-multi",
|
||||
thread_id="thread-1",
|
||||
assistant_id=None,
|
||||
status="success",
|
||||
on_disconnect="cancel",
|
||||
created_at="2026-01-01T00:00:00Z",
|
||||
updated_at="2026-01-01T00:00:07Z",
|
||||
)
|
||||
app = _make_app(store, records={"run-multi": record})
|
||||
with TestClient(app) as client:
|
||||
response = client.get("/api/threads/thread-1/messages/page")
|
||||
|
||||
data = response.json()["data"]
|
||||
# Messages are returned newest-first; the last AI message is data[0].
|
||||
first_row = next(row for row in data if row["content"]["id"] == "first-answer")
|
||||
second_row = next(row for row in data if row["content"]["id"] == "second-answer")
|
||||
assert second_row["content"]["additional_kwargs"]["turn_duration"] == 7
|
||||
assert "turn_duration" not in first_row["content"].get("additional_kwargs", {})
|
||||
|
||||
|
||||
def test_thread_page_preserves_tool_and_subagent_wrapper_metadata():
|
||||
store = MemoryRunEventStore()
|
||||
asyncio.run(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user