Build Framework Scenarios for Trueup

Continue building Trueup in this repository. Read README.md, hackathon.md, CHANGELOG.md and src/ first. This session is recorded by Entire and published: work only inside this repository and never mention anything outside it. Do not git commit or push. Memory on this machine is limited: build and run one library at a time.
Task: build the framework scenarios that are listed but marked not_built (rough reference: .ref/run2.py, .ref/fake2.py, .ref/tl.py, .ref/tls.py; rebuild properly, don't copy).
- Fake provider: agent flows (tool call, then the answer after the tool result), parallel tools, loops (the model keeps calling a tool, for max turns), a tool name that doesn't exist, the LLM failing on the second call, and the OpenAI Agents SDK Responses flows including the full streaming event sequence, an error event and a cut. Fixture-test each against the real SDKs.
- Scenarios: LangChain/LangGraph (invoke, stream, stream error, stream cut, refusal, 500, ReAct agent, tool raises, LLM fails on second call, parallel tools, agent streaming, step limit) and OpenAI Agents SDK (agent with tool, tool raises, LLM fails on second call, max turns, unknown tool, streamed run, streamed run with error event, streamed run cut). Each with expected truth the comparer can check.
- Runner: each library's recommended setup for frameworks, with the framework packages installed in its venv (a framework instrumentation silently does nothing if the framework package is missing; add a regression test that fails loudly in that case):
- neatlogs: neatlogs.init(instrumentations=[<framework key per its README>]), export disabled.
- openinference: LangChainInstrumentor, OpenAIAgentsInstrumentor (plus OpenAIInstrumentor for plain SDK use).
- openllmetry: Traceloop.init(exporter=<in-memory>, disable_batch=True). Don't reuse one async client across asyncio.run loops. The run status check uses the top-level span (for the Agents SDK, the "Agent workflow" / trace root).
trueup sweep <lib> --framework langchain|openai-agents|all(default: everything). Re-run all three libraries, one at a time. Add counts per library and per check to hackathon.md as leads (not confirmed bugs). Pay attention to: whether a crashed Agents SDK run shows OK at the top level; whether OpenLLMetry with Traceloop.init and the Agents SDK records twice the real number of LLM calls and tokens in non-streaming runs (and whether streaming is unaffected); whether an unknown-tool error appears anywhere in the trace.- Update CHANGELOG.md. Plain words, no filler.
uv run pytest -qmust pass. Finish with a summary: tests, scenarios run per library, NOT RUN with reasons, leads per library by severity, and the answers to the three questions in item 4.
The 20 framework scenarios are built and all three libraries swept: 51 of 51 scenarios ran for each, none NOT RUN. uv run pytest -q passes (213 tests), and the 18 e2e tests against the real library venvs pass too. Nothing is committed.
One trap I hit. neatlogs with instrumentations=["langchain"] first exported no spans and raised no error. It checks import langchain, and the venv only had langchain-core and langchain-openai, so it logged "Skipped: langchain (not installed)". Every venv now installs langchain. Before a framework scenario runs, the runner checks that the framework imports and that an instrumentor for it is active; if not, the scenario is NOT RUN with the reason. Regression tests cover this offline (tests/test_framework_setup.py) and against the real venvs (tests/test_e2e.py).
What was built
- Fake provider: the agent flows you listed, decided from the request so the fake keeps no state. They're fixture-tested against the real openai SDK, LangChain, LangGraph and the Agents SDK in
tests/test_fake_agents.py. A test also runs all 51 scenarios with no tracing library and checks the expected truth against what really happens. - Two framework behaviours that shaped the expectations:
- LangGraph's
create_react_agentdoesn't raise at the step limit. It answers "Sorry, need more steps", solg-step-limitis a successful run with 3 calls. - langchain-openai raises its own
OpenAIAPIErrorandOpenAIConnectionError.
- LangGraph's
- Runner: each library's recommended framework setup as you specified. Each agent gets its own AsyncOpenAI client, and the Agents SDK's own trace upload to api.openai.com is turned off.
- Comparer:
- Run status now uses the trace root.
- New
toolscheck: each tool that ran has a span, and a tool that raised is marked as an error. - New
error_recordedcheck: a framework error (not a provider error) must show on some span. - The OpenLLMetry adapter no longer counts LangGraph task, tool and workflow spans as LLM calls.
- Sweep:
trueup sweep <lib> --framework all|none|langchain|openai-agents, defaultall.
Leads (not confirmed bugs). Plain-SDK counts are the same as the last sweep (22 / 10 / 14), so the new ones all come from the framework scenarios:
| library | total | high | medium | from framework scenarios |
|---|---|---|---|---|
| neatlogs | 58 | 9 | 49 | 36 (5 high: crashed run shows OK at the root; 31 medium: 27 missing finish reason, 3 failed calls with no exception event, 1 refusal not recorded) |
| openinference | 19 | 7 | 12 | 9 (5 high: crashed run shows OK at the root; 4 medium: 3 failed calls with no exception event, 1 refusal not recorded) |
| openllmetry | 29 | 21 | 8 | 15 (10 high: 5 crashed run shows OK at the root, 5 doubled LLM spans; 5 medium: 3 failed calls with no exception event, 1 refusal not recorded, 1 unknown-tool error on no span) |
The 27 neatlogs finish leads might come from the adapter rather than neatlogs itself. Those spans do carry OpenInference's llm.finish_reason, but not neatlogs.llm.finish_reason, and the adapter reads only the neatlogs keys, as it did in the earlier sweeps. Tool spans were correct in all three libraries, including for the tool that raised. Per-check counts are in hackathon.md.
Your three questions
- Does a crashed Agents SDK run show OK at the top level? Yes, in all three libraries and in all 5 crash scenarios (500 on the second call, max turns, unknown tool, streamed error event, streamed cut).
- Does OpenLLMetry with
Traceloop.initdouble calls and tokens? Yes, in all 5 non-streamed runs, exactly twice: each call gets one span from the Agents SDK instrumentation and another from the OpenAI instrumentation under it. For example,ag-runreally made 2 calls with 36 tokens; the trace shows 4 spans and 72 tokens. Streamed runs are not affected (3 of 3 correct). - Does the unknown-tool error appear anywhere? In neatlogs and OpenInference, only as the status description of the
turnspan (ERROR, no exception event), while the root stays OK. In OpenLLMetry it appears nowhere:no_such_toolshows up only as the tool call in the model's output.
CHANGELOG.md, hackathon.md and the README are updated. I also deleted an empty spans_raw_optimized.log that neatlogs had written to the repo root when I ran a manual check there.