Repository navigation
Multi-turn agent history, compact trace storage, leaner judge evidence, clearer timeline - #79
Merged
Merged
Conversation
…ive knowledge search Traced agent runs go through Open WebUI's saved-chat path, which builds the model input from the chat it stores. Every turn created a new chat holding only the latest user message, so from turn 2 the agent answered without the conversation. Each later turn now continues the scenario's chat (chat_id and the previous reply as parent_id), keyed by model, W3C trace id and the turns so far; an unknown conversation starts a new chat as before, with a warning. The Open WebUI order tool no longer carries acme_search_knowledge: inside Open WebUI it always failed (its policy files are not on the Open WebUI host) and the agent fell back to Open WebUI's own knowledge search. The keyword search stays as Studio's local stand-in for untraced runs (fixtures/local_knowledge), and the seeded agent prompt asks for the attached knowledge base.
GenAI spans repeat the system prompt, the history and earlier tool results on
every model call. Studio now stores trace evidence compacted in the reference
format of Open WebUI's compact mode (a repeated message becomes {role, parts:
[{type: reference, span_id, attribute, index}]}, a repeated value {type:
reference, ...}), whichever target sent the spans, and expands references
before rules and the judge read them (audits/agentic/compact.py).
The trajectory timeline shows each repeat as a '↩ same as LLM-1 · …' line,
including results stored before compaction. It also shows a retrieval
step's query and retrieved documents, and indents JSON content blocks.
v0.12.4.6: GenAI-only spans. v0.12.4.7: schema-shaped spans. v0.12.4.8: agentic knowledge search traced as a retrieval span with retrieval documents. v0.12.4.9: compact GenAI content by default (each piece once per trace).
…he trace The evidence packet cut the agent's final answer at 800 characters, so a long answer reached the judge without its conclusion and task_completion failed as 'truncated'. Answers now keep up to 6,000 characters. Multi-turn scenarios answer the task across turns, but the judge compared only the last reply with the first question; the packet now lists every turn as the trace records it (each turn's last model call: the user message it received and the reply it produced), still trace-only evidence.
…ents JSON gen_ai.retrieval.documents is JSON text; the packet treated the string itself as a source name, so retrieval_source_ids carried every retrieved chunk again.
The final response was sent twice (as final_response and as the last assistant turn), and every user turn carried Open WebUI's fixed RAG template and <context> source list, whose sources the retrieval steps already show. The packet now keeps the last turn as the final response and gives the user's own message (flagged rag_template_removed). Result 253's packet goes from 13.8 KB to 8.8 KB with the same verdict.
…ted failures D09 depended on SIMPLEAUDIT_DEMO_FAIL_FIRST making the tracking tool fail once, which no environment set (and whose /tmp marker made it fail once per machine for good), and it capped tracking calls at 1-2 over the whole conversation, so multi-turn runs failed it for ordinary follow-up calls. D09 now tests reporting tracking status only as observed: it fetches ACME-1001's events, never another order's, with no errors, and the semantic judge checks grounding and result handling. The fail-first hook is removed from the demo tool. D02 drops its 'at most 1 error step' cap: each follow-up lookup of the unknown order rightly errors again. No count rule with an upper bound remains in the pack.
…ed steps show their error
The main judge reads the selected spans through the SimpleAudit engine, which
dumps each span's attributes and cuts it at 2,000 characters, so a model call's
repeated input history pushed its output out and SDK metadata and workflow
wrappers padded the prompt. Studio now hands the judge a judge view
(audits.agentic.compact.judge_view): only gen_ai.* attributes and the error
fields, no workflow wrappers, content repeated from an earlier span as a short
'(same as span ...)' note, knowledge chunks once as retrieval documents, Open
WebUI's RAG template dropped from user messages, messages already in the
conversation pointed to it, and decisions, results and documents ahead of the
input history. On a 5-turn run the judge's input tokens fell 28% while the
agent now sees full history.
The trajectory timeline shows a failed step's exception ('ValueError: No
order found ...'), which tool calls that raise have instead of a result.
Each model-call row gets one badge from gen_ai.output.messages and gen_ai.response.finish_reasons only: 'tool call' when the output asks for a tool, 'reply' when it answers in text. Every turn's reply is highlighted, not only the last model call of the whole trace. Tool-decision rows read GenAI tool_call parts (they read OpenAI tool_calls, so 'agent -> tool' never showed on GenAI traces).
A model call whose gen_ai.input.messages ends with a user message gets a 👤 marker: it is the call that took the user's new message (a compacted, referenced message keeps its role).
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.
…er lookup acme_get_tracking_events returned any order's tracking, so after acme_get_order refused ACME-1002 (CUST-002) an agent could still disclose its timestamps and hub locations through the tracking tool. Both now share one ownership check and refuse with the same response.
lifecycle had its own port probe: a plain bind, which refuses ports whose connections linger in TIME_WAIT for up to a minute after 'dev down', so an immediate restart failed with 'Ports unavailable'. It now uses ports' probe, which binds with SO_REUSEADDR (not on Windows, where the option can take over a live port) and first checks that nothing accepts on 127.0.0.1: with SO_REUSEADDR a wildcard bind succeeds beside a loopback-only listener on macOS, which the old ports probe missed.
SushantGautam
added a commit
that referenced
this pull request
Nov 5, 2026
test_concurrent_runs_keep_their_own_auditor_class called mock.patch from two threads at once on the same attributes (decision_target_for, decision_auditor_class, snapshot_api_key). mock.patch is not thread-safe: one thread could restore the other's mock, leaving it installed for every later test on that xdist worker. That is the CI flake seen on #79 and #81 (snapshot_api_key returning '', decision_target_for returning object(), the auditor class being AuditorA). The test now patches once in the main thread, with side effects that pick each thread's class from its own target.
SushantGautam
added a commit
that referenced
this pull request
Nov 5, 2026
… cold start (#81) * chore: pin Open WebUI v0.12.4.10-subpath GenAI spans on every content, tool and model path (fork #11): retrieval spans with documents for every content-reading built-in tool (knowledge files and grep, chat files, notes, chats, channels, memories, web search and fetch) and for memory recall, execute_tool spans in default function calling, and chat spans for pipe models. Fixes checks that counted no retrieved documents when an agent read a file with view_knowledge_file instead of searching. * fix: traced agent runs survive Open WebUI's cold start Right after Open WebUI starts, its model registry can still miss the agent when Studio's once-a-minute refresh ran before Open WebUI loaded its connections, so concurrent scenarios failed with 'Model not found'. A saved-chat request that gets that answer now reloads the registry immediately and retries once. * test: stop the concurrent-auditor test leaking mocks into later tests test_concurrent_runs_keep_their_own_auditor_class called mock.patch from two threads at once on the same attributes (decision_target_for, decision_auditor_class, snapshot_api_key). mock.patch is not thread-safe: one thread could restore the other's mock, leaving it installed for every later test on that xdist worker. That is the CI flake seen on #79 and #81 (snapshot_api_key returning '', decision_target_for returning object(), the auditor class being AuditorA). The test now patches once in the main thread, with side effects that pick each thread's class from its own target.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Found while running real multi-turn traced audits against agent 1 (Support Refund Assistant) on a live model.
Agents keep the conversation across turns
Traced agent runs go through Open WebUI's saved-chat path, which builds the model input from the chat Open WebUI stores. Every turn created a new chat holding only the latest user message, so from turn 2 the agent answered without the conversation. This was confirmed in Open WebUI's database and in the model-call spans.
Each later turn now continues the scenario's chat (
chat_id, plus the previous reply asparent_id), keyed by model, W3C trace id and the turns so far. Untraced runs were never affected: they send the full history themselves.Native knowledge search in Open WebUI
acme_search_knowledgealways failed inside Open WebUI ("Docs directory not found"), and the agent then fell back to Open WebUI's own knowledge search. It is removed from the tool pushed to Open WebUI, and the seeded agent prompt asks for the attached knowledge base. The keyword search stays as Studio's local stand-in for untraced runs (infra/fixtures/local_knowledge.py).Trace content stored once per trace (
audits/agentic/compact.py)GenAI spans repeat the system prompt, the history and earlier tool results on every model call. Studio now stores trace evidence in the same reference format as the Open WebUI fork's compact mode, whichever target sent the spans:
{role, parts: [{type: reference, span_id, attribute, index}]};{type: reference, …};References are expanded before rules and judges read the spans. On 1-turn runs this stores about a third less, and much less on multi-turn runs.
Judges see each piece once, from the trace
Main judge: reads selected spans through the SimpleAudit engine, which caps each span at 2,000 characters. It now gets a judge view:
gen_ai.*attributes and the error fields (error.type,exception.*);On a 5-turn run the judge's input tokens fell 28%, even though the agent now sees full history, and the spans cut by the length limit fell from 10 to 1.
Semantic agentic judge:
Trajectory timeline
tool_callparts. They used to read OpenAI'stool_calls, so they never showed on GenAI traces.Demo scenarios work in multi-turn runs
SIMPLEAUDIT_DEMO_FAIL_FIRST, which nothing set and which failed only once per machine. It also capped tracking calls at 1–2 over the whole conversation. It now tests reporting tracking status only as observed, and the fail-first hook is removed.Open WebUI v0.12.4.9-subpath
Checks
uv run pytest -m "not embedded_hatchet": 1626 passed, 3 skippeduv run ruff check .: cleanmakemigrations --check: no changespass.