Skip to content
7 changes: 7 additions & 0 deletions .changeset/step-finish-ai-sdk-passthrough.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@funkai/agents": minor
---

Pass through full AI SDK `StepResult` fields in `onStepFinish` events instead of stripping tool calls/results to summary fields. `StepFinishEvent` is now a superset of the Vercel AI SDK's `StepResult<ToolSet>` — all SDK fields (`text`, `toolCalls`, `toolResults`, `finishReason`, `usage`, `reasoning`, `sources`, `response`, etc.) are passed through unchanged, plus funkai-specific additions (`stepId`, `agentChain`).

**Breaking:** `toolCalls` entries now contain full AI SDK `TypedToolCall` objects (with `input`) instead of `{ toolName, argsTextLength }`. `toolResults` entries now contain full `TypedToolResult` objects (with `output`) instead of `{ toolName, resultTextLength }`. `usage` is now the AI SDK's `LanguageModelUsage` type (with `undefined`-able fields) instead of a simplified `{ inputTokens: number; outputTokens: number; totalTokens: number }`.
29 changes: 18 additions & 11 deletions docs/reference/flow-agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,17 +266,24 @@ interface StepInfo {

## StepFinishEvent

Emitted by `onStepFinish`. Agent tool-loop steps populate the left columns; flow orchestration steps populate the right.

| Field | Type | Present on |
| ------------- | -------------------------------------------------------------------- | ------------------------ |
| `stepId` | `string` | Agent tool-loop steps |
| `toolCalls` | `readonly { toolName: string; argsTextLength: number }[]` | Agent tool-loop steps |
| `toolResults` | `readonly { toolName: string; resultTextLength: number }[]` | Agent tool-loop steps |
| `usage` | `{ inputTokens: number; outputTokens: number; totalTokens: number }` | Agent tool-loop steps |
| `step` | `StepInfo` | Flow orchestration steps |
| `result` | `unknown` | Flow orchestration steps |
| `duration` | `number` | Flow orchestration steps |
Emitted by `onStepFinish`. For agent tool-loop steps, the event is a full superset of the Vercel AI SDK's `StepResult<ToolSet>` — all SDK fields are passed through unchanged, plus funkai-specific additions. Flow orchestration steps populate the flow-specific fields instead.

| Field | Type | Present on | Description |
| ---------------- | --------------------------- | ------------------------ | --------------------------------------------- |
| `stepId` | `string` | Agent tool-loop steps | funkai addition: e.g. `"myAgent:0"` |
| `agentChain` | `AgentChainEntry[]` | Both | funkai addition: agent ancestry chain |
| `stepNumber` | `number` | Agent tool-loop steps | AI SDK: zero-based step index |
| `text` | `string` | Agent tool-loop steps | AI SDK: generated text |
| `toolCalls` | `TypedToolCall<ToolSet>[]` | Agent tool-loop steps | AI SDK: full tool call objects with `input` |
| `toolResults` | `TypedToolResult<ToolSet>[]`| Agent tool-loop steps | AI SDK: full tool result objects with `output` |
| `finishReason` | `FinishReason` | Agent tool-loop steps | AI SDK: why the step ended |
| `usage` | `LanguageModelUsage` | Agent tool-loop steps | AI SDK: token usage |
| `reasoning` | `ReasoningPart[]` | Agent tool-loop steps | AI SDK: reasoning content |
| `sources` | `Source[]` | Agent tool-loop steps | AI SDK: cited sources |
| `response` | `LanguageModelResponseMetadata & { messages }` | Agent tool-loop steps | AI SDK: response metadata |
| `step` | `StepInfo` | Flow orchestration steps | Flow step info (id, index, type) |
| `result` | `unknown` | Flow orchestration steps | Flow step result value |
| `duration` | `number` | Flow orchestration steps | Flow step duration in ms |

## FlowAgentOverrides

Expand Down
8 changes: 4 additions & 4 deletions examples/streaming/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,17 @@ const geographyAgent = agent({
if (toolCalls && toolCalls.length > 0) {
console.log(`\n[step ${stepId}] Tool calls:`);
for (const tc of toolCalls) {
console.log(` → ${tc.toolName} (${tc.argsTextLength} chars args)`);
console.log(` → ${tc.toolName} (input: ${JSON.stringify(tc.input)})`);
}
}
if (toolResults && toolResults.length > 0) {
console.log(`[step ${stepId}] Tool results:`);
for (const tr of toolResults) {
console.log(` ← ${tr.toolName} (${tr.resultTextLength} chars result)`);
console.log(` ← ${tr.toolName} (output: ${JSON.stringify(tr.output)})`);
}
}
if (usage && usage.totalTokens > 0) {
console.log(`[step ${stepId}] Tokens: ${usage.inputTokens} in / ${usage.outputTokens} out`);
if (usage && (usage.totalTokens ?? 0) > 0) {
console.log(`[step ${stepId}] Tokens: ${usage.inputTokens ?? 0} in / ${usage.outputTokens ?? 0} out`);
}
},
});
Expand Down
Loading
Loading