Skip to content

fix(client): give each graph() run its own run id - #132

Merged
cursor[bot] merged 5 commits into
fix/native-graph-span-identityfrom
fix/graph-run-id-per-run-clean
Oct 15, 2026
Merged

cursor[bot] merged 5 commits into
fix/native-graph-span-identityfrom
fix/graph-run-id-per-run-clean

Conversation

@apucacao

@apucacao apucacao commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Running the same graph() twice for the same context reported both runs under one run id, so separate runs looked like one in the $ld:ai:graph:* events.

graph() caches the built graph per context so it doesn't re-evaluate every node's flag on each call. The run id was created in that build, so it was cached too. Each run now gets a fresh id. Every graph event within a run still shares it, and the flag evaluations stay cached.

Builds on #121. In JS the same fix is part of launchdarkly/js-ai-sdk#101.

Testing

  • New test in test_graph_stream.py, for both invoke and stream: two runs on one graph() instance and context get different ids, and all graph events in a run (node, handoff, success) share one. It fails on main.
  • Client, openai-agents, claude-agents and langchain-agents suites pass. mypy and ruff are clean.

Note

Overview
Fixes duplicate runId when reusing a cached graph() build: separate invoke/stream calls on the same instance and context no longer look like one run in $ld:ai:graph:* analytics and OTel.

Each run now mints a fresh runId at execution time (merged into track data from the cached build) and passes it into routing via _run_track_data in route/stream opts. Handoff success/failure events emitted from the cached graph definition read that per-run payload instead of the build-time id. Graph caching per context is unchanged.

Adds TestGraphRunId for both invoke and stream: two runs get distinct ids, and all graph events plus the launchdarkly.graph span share one id per run.

Reviewed by Cursor Bugbot for commit a5e9ad3. Bugbot is set up for automated code reviews on this repo. Configure here.

graph() caches the built graph per context so repeated runs skip
re-evaluating every node's flag. The build also created the graph's
track data, run id included, so every run for the same context
reported the same runId on its $ld:ai:graph:* events.

Each run now copies the cached track data with a fresh runId and passes
it to route and stream_route through their opts, so the node, handoff
and graph-level events of one run share one id and the next run gets
another. The flag evaluations stay cached.
@apucacao

apucacao commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

@apucacao
apucacao changed the base branch from main to fix/native-graph-span-identity October 9, 2026 15:58
@apucacao
apucacao added this pull request to stack #151 October 9, 2026 15:58
@apucacao

apucacao commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

@apucacao

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Each run's launchdarkly.graph span must carry the runId of that run's
graph-level events, for both invoke and stream, and the two runs' spans
must carry different ids.
@apucacao

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

@apucacao

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit a5e9ad3. Configure here.

@jeffdupont jeffdupont left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified this fixes the run-id blocker on #121.

  • Each invoke and stream now mints a fresh runId after the cache lookup (graph.py:945, :1182). The span attribute and all 8 handoff events read it, so Bugbot's #121 finding (graph.py:944) is covered too.
  • TestGraphRunId fails on #121's graph.py (both modes) and passes here. Full client suite: 1533 passed, 1 skipped.

I'll approve once this is out of draft. Simplest path: merge this into fix/native-graph-span-identity so #121 lands with it, then I approve #121.

@apucacao
apucacao marked this pull request as ready for review October 14, 2026 18:00

@jeffdupont jeffdupont left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of draft, head unchanged since my verification (a5e9ad3), CI green. Merge into fix/native-graph-span-identity and I'll approve #121.

@cursor
cursor Bot merged commit a5e9ad3 into main Oct 15, 2026
7 checks passed
@cursor
cursor Bot deleted the fix/graph-run-id-per-run-clean branch October 15, 2026 18:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants