Skip to content

Navigation Menu

Sign in
Sign up

fix(email): make --trace write a real trace on the daemon-relay path - #3346

Draft
github-actions[bot] wants to merge 1 commit into
main from
autofix/issue-3345
Draft

fix(email): make --trace write a real trace on the daemon-relay path #3346
github-actions[bot] wants to merge 1 commit into
main from
autofix/issue-3345

Conversation

@github-actions

@github-actions github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

gaia email --trace was advertised in --help but did nothing — the flag was parsed and then dropped, so you got no trace file, no warning, and no way to capture what the email agent actually did during a run. It now writes a JSON trace of the run into the current directory (email_trace_<timestamp>_<run-id>.json) and prints the path, so anyone benchmarking or debugging the email agent can see the full request, every tool call and result, and the final answer.

Closes #3345

Test plan

  • python -m pytest tests/unit/test_agent_query.py tests/unit/test_email_cli.py -q passes
  • python util/lint.py --all passes
  • With Lemonade running and the Google connector configured: gaia email --trace -q 'summarize my unread emails' prints 📝 trace written to ... and the named file contains the tool calls the run made
  • gaia email -q 'summarize my unread emails' (no --trace) leaves no JSON file behind
  • gaia email --trace -i writes one trace file per turn

⚠️ Needs manual validation — unit tests cover the trace writer against a
stubbed relay, but nothing here exercises a real daemon + email sidecar. A
maintainer should run the three gaia email steps above against a live
Lemonade + Google connector before merging.

🔍 Technical details

Root cause: gaia email -q relays through the daemon via
gaia.daemon.agent_query.run_query() (src/gaia/cli.py:4633), whose signature had no
trace parameter. args.trace came from the shared parent_parser, was never read on
this path, and never reached the request.

What changed:

  • src/gaia/daemon/agent_query.pyrun_query(..., trace=False). There is no
    in-process agent to introspect on the relay path, so the canonical SSE stream is the
    trace: _consume() takes an optional sink and _write_trace() dumps
    {agent_id, run_id, recorded_at, request, terminal_type, final_answer, error_detail, events}
    to ./<agent>_trace_<timestamp>_<run_id>.json. run_id is in the filename so two REPL
    turns in the same second can't collide. The path is echoed on stderr
    (ConsoleRenderer.on_trace_written) and returned as QueryOutcome.trace_path.
  • Traces are written on the failure paths too — Ctrl-C, and a stream that ends without a
    terminal event (the CLI-synthesized error frame is recorded alongside the real
    events). A trace is most useful exactly when the run broke.
  • Per the fail-loudly rule, an unwritable CWD raises a DaemonError naming the path and
    the fix rather than skipping the file.
  • src/gaia/cli.pyhandle_email_command reads args.trace and passes it to
    run_query; _email_interactive takes trace and writes one file per turn.
  • Docs: --trace row added to the email options tables in docs/reference/cli.mdx and
    docs/guides/email.mdx, with a note that a trace contains real email content.

Verified: 4 new tests in tests/unit/test_agent_query.py (file written with the full
event stream, nothing written without the flag, partial capture when the stream has no
terminal event) and 1 in tests/unit/test_email_cli.py (the flag reaches run_query);
37 tests across the email/agent-query suites pass. Also exercised run_query(trace=True)
against a stubbed relay to confirm the file contents. Black + isort clean; pylint's 2
remaining errors are pre-existing and unrelated (PIL.Image.LANCZOS, a try-except-raise
in the UI router).

Only gaia email uses run_query today, so no other CLI surface changes behavior.

gaia email --trace was parsed and dropped: the query path relays through the
daemon, and run_query() had no trace parameter, so the flag silently behaved
like omitting it. The relay path has no in-process agent to introspect, so the
canonical SSE stream is the trace — run_query now records the request plus every
status/token/tool_call/tool_result/final event to
./<agent>_trace_<timestamp>_<run_id>.json, echoes the path on stderr, and
returns it as QueryOutcome.trace_path. Interrupted runs and streams that die
without a terminal event still write what they saw, which is when a trace is
worth most.
Closes #3345 
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@kovtcharov-amd kovtcharov-amd Awaiting requested review from kovtcharov-amd kovtcharov-amd will be requested when the pull request is marked ready for review kovtcharov-amd is a code owner

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

[Bug]: gaia email --trace is a no-op on the daemon-relay query path

0 participants

AltStyle によって変換されたページ (->オリジナル) /