From 8a5193cf872565b2e19b391904ac168d4b7c4e27 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 26 Aug 2026 21:51:14 +0000 Subject: [PATCH] feat: expose graph traversal path and per-node responses in ProviderGraphResponse Co-Authored-By: Paul Loeb --- AGENTS.md | 2 ++ README.md | 2 ++ packages/claude-agents/src/native-graph.ts | 2 +- packages/client/README.md | 2 +- packages/client/src/__tests__/graph.test.ts | 11 +++++++++-- packages/client/src/graph.ts | 2 +- packages/client/src/types.ts | 7 +++++++ packages/langchain-agents/src/native-graph.ts | 2 +- packages/openai-agents/src/native-graph.ts | 2 +- 9 files changed, 25 insertions(+), 7 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 39a6593..391b53e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -243,6 +243,8 @@ The value returned by `graph().invoke()`. | `response` | string | The final text output (from the last node executed). | | `usage` | `{ input, output, total }` | Aggregate token counts across all nodes. | | `judgeResults` | `ProviderResponse['judgeResults']?` | Results from a graph-level judge, if configured. | +| `path` | `string[]` | Node keys in execution order, starting at the root — use this to show which branch the router picked. | +| `nodes` | `Record?` | Each executed node's own response, keyed by node key. Populated by `graph()`; native runners (`toClaudeAgents()`, `toOpenAIAgents()`, `toLangGraph()`) return `path` only. | #### `ConfigArgs` diff --git a/README.md b/README.md index 889db0b..dcf6797 100644 --- a/README.md +++ b/README.md @@ -268,6 +268,8 @@ const result = await graph('support-graph', { console.log(result.response); // final output console.log(result.usage); // aggregate { input, output, total } +console.log(result.path); // node keys in execution order, e.g. ['triage', 'billing'] +console.log(result.nodes); // each node's own response, keyed by node key await shutdown(); ``` diff --git a/packages/claude-agents/src/native-graph.ts b/packages/claude-agents/src/native-graph.ts index 5069d67..f69d421 100644 --- a/packages/claude-agents/src/native-graph.ts +++ b/packages/claude-agents/src/native-graph.ts @@ -313,7 +313,7 @@ export const toClaudeAgents = ( } span.end(); - return { response: finalOutput, usage: totalUsage }; + return { response: finalOutput, usage: totalUsage, path }; }); }; diff --git a/packages/client/README.md b/packages/client/README.md index 628a24b..383c85c 100644 --- a/packages/client/README.md +++ b/packages/client/README.md @@ -255,5 +255,5 @@ All types are re-exported from this package. Handler packages import them from h | `GraphArgs` | Options accepted by `resolveGraph()` — extends `GraphOptions` with a required `context` | | `GraphDefinition` | A resolved agent graph: topology accessors, `runNode`, and the traverse primitives | | `GraphNode` / `GraphEdge` | A node (evaluated agent config + edges) and a directed edge (with handoff data) | -| `ProviderGraphResponse` | The value returned by `graph(...).invoke()`: `{ response, usage, trackData, judgeResults? }` | +| `ProviderGraphResponse` | The value returned by `graph(...).invoke()`: `{ response, usage, path, nodes?, judgeResults? }` | | `GraphTopology` | The parsed graph flag shape (`root` + `edges`) | diff --git a/packages/client/src/__tests__/graph.test.ts b/packages/client/src/__tests__/graph.test.ts index b2e91ef..fa04d9e 100644 --- a/packages/client/src/__tests__/graph.test.ts +++ b/packages/client/src/__tests__/graph.test.ts @@ -210,8 +210,15 @@ describe('graph().invoke()', () => { const result = await graph('graph-flag', { handlers: [handler] }).invoke('hi', mockContext); expect(result.usage.total).toBeGreaterThan(0); expect(result.response).toBeDefined(); - expect((result as any).path).toBeUndefined(); - expect((result as any).nodes).toBeUndefined(); + }); + + it('returns the traversal path and per-node responses', async () => { + setupTwoNodeGraph(); + const handler = makeHandler(); + const result = await graph('graph-flag', { handlers: [handler] }).invoke('hi', mockContext); + expect(result.path).toEqual(['root-node', 'leaf-node']); + expect(Object.keys(result.nodes ?? {})).toEqual(['root-node', 'leaf-node']); + expect(result.nodes?.['leaf-node']?.response).toBe('agent-response'); }); it('tracks $ld:ai:graph:invocation_success on success', async () => { diff --git a/packages/client/src/graph.ts b/packages/client/src/graph.ts index 892f122..b306154 100644 --- a/packages/client/src/graph.ts +++ b/packages/client/src/graph.ts @@ -590,7 +590,7 @@ export const graph = ( span.setStatus({ code: SpanStatusCode.OK }); span.end(); - return { response: finalResponse, usage: totalUsage, judgeResults }; + return { response: finalResponse, usage: totalUsage, judgeResults, path, nodes }; } catch (err) { const elapsed = Date.now() - startTime; getClient().track('$ld:ai:graph:duration:total', context, graphTrackData, elapsed); diff --git a/packages/client/src/types.ts b/packages/client/src/types.ts index bf8455e..4c30ea6 100644 --- a/packages/client/src/types.ts +++ b/packages/client/src/types.ts @@ -528,6 +528,13 @@ export type ProviderGraphResponse = { response: string; usage: TokenUsage; judgeResults?: ProviderResponse['judgeResults']; + /** Node keys in the order they were executed, starting at the root. */ + path: string[]; + /** + * Each executed node's own response, keyed by node key. Populated by + * `graph()`; native runners that delegate traversal to a framework omit it. + */ + nodes?: Record; }; export type InitBaseClientOptions = { diff --git a/packages/langchain-agents/src/native-graph.ts b/packages/langchain-agents/src/native-graph.ts index 149cec9..77dfa81 100644 --- a/packages/langchain-agents/src/native-graph.ts +++ b/packages/langchain-agents/src/native-graph.ts @@ -314,7 +314,7 @@ export const toLangGraph = ( getClient().track('$ld:ai:graph:invocation_success', ldContext, rootTrackData, 1); } - return { response: finalOutput, usage: totalUsage }; + return { response: finalOutput, usage: totalUsage, path }; }); }; diff --git a/packages/openai-agents/src/native-graph.ts b/packages/openai-agents/src/native-graph.ts index f885613..7e84da7 100644 --- a/packages/openai-agents/src/native-graph.ts +++ b/packages/openai-agents/src/native-graph.ts @@ -223,7 +223,7 @@ export const toOpenAIAgents = ( span.setStatus({ code: SpanStatusCode.OK }); span.end(); - return { response: finalOutput, usage: totalUsage }; + return { response: finalOutput, usage: totalUsage, path }; }); };