Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, ProviderResponse>?` | Each executed node's own response, keyed by node key. Populated by `graph()`; native runners (`toClaudeAgents()`, `toOpenAIAgents()`, `toLangGraph()`) return `path` only. |

#### `ConfigArgs`

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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();
```
Expand Down
2 changes: 1 addition & 1 deletion packages/claude-agents/src/native-graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ export const toClaudeAgents = (
}

span.end();
return { response: finalOutput, usage: totalUsage };
return { response: finalOutput, usage: totalUsage, path };
});
};

Expand Down
2 changes: 1 addition & 1 deletion packages/client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`) |
11 changes: 9 additions & 2 deletions packages/client/src/__tests__/graph.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 7 additions & 0 deletions packages/client/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, ProviderResponse>;
};

export type InitBaseClientOptions = {
Expand Down
2 changes: 1 addition & 1 deletion packages/langchain-agents/src/native-graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
});
};

Expand Down
2 changes: 1 addition & 1 deletion packages/openai-agents/src/native-graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
});
};

Expand Down
Loading