Skip to content

feat(core): add isFinalStep flag to onStepFinish hook [Closes #1368]#1370

Closed
nneelabh02 wants to merge 5 commits into
VoltAgent:mainfrom
nneelabh02:feat/onstepfinish-isfinalstep-1368
Closed

feat(core): add isFinalStep flag to onStepFinish hook [Closes #1368]#1370
nneelabh02 wants to merge 5 commits into
VoltAgent:mainfrom
nneelabh02:feat/onstepfinish-isfinalstep-1368

Conversation

@nneelabh02

@nneelabh02 nneelabh02 commented Jul 3, 2026

Copy link
Copy Markdown

This PR implements the isFinalStep logic within the core execution loop for onStepFinish, as discussed in #1368.

It correctly determines if a step is the final one by calculating window sizes on a per-step basis, avoiding the previous approach of waiting for onEnd. This allows the user to accurately know if the current step is the final one, preventing mid-task context overflows.

Justification for modifying onStepFinish instead of onEnd:
The original issue (#1368) requested exposing lastStepUsage in the onEnd hook. However, as discussed with the maintainers, window size calculations must happen per-step to effectively prevent mid-task context overflows. Waiting until onEnd is too late. Therefore, we decided to leave onEnd untouched and instead add an isFinalStep flag to the onStepFinish hook. This fully addresses the underlying use case of #1368 while adopting a more robust architecture.

Resolves #1368

Summary by CodeRabbit

  • New Features

    • Added a new flag to the step-finish hook so it can indicate when a step is the final one.
    • Final-step detection now works more reliably across multi-step and single-step flows.
  • Bug Fixes

    • Fixed step completion handling so hook callbacks now receive accurate final-step status during text generation and streaming.

@changeset-bot

changeset-bot Bot commented Jul 3, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a6437b5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@voltagent/core Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b0d9989e-92a1-485e-941e-d6c92bd1dd13

📥 Commits

Reviewing files that changed from the base of the PR and between 6ad7fe9 and a6437b5.

📒 Files selected for processing (2)
  • .changeset/add-is-final-step-flag.md
  • packages/core/src/agent/hooks/index.ts
✅ Files skipped from review due to trivial changes (1)
  • .changeset/add-is-final-step-flag.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/core/src/agent/hooks/index.ts

📝 Walkthrough

Walkthrough

This change adds an isFinalStep flag to onStepFinish, threads stop criteria through generateText and streamText, computes the final-step state in the step handler, updates tests, and adds a changeset entry.

Changes

isFinalStep Hook Flag

Layer / File(s) Summary
Hook contract update
packages/core/src/agent/hooks/index.ts
Adds an optional isFinalStep boolean property to OnStepFinishHookArgs.
createStepHandler isFinalStep computation and wiring
packages/core/src/agent/agent.ts
Creates an effective stop predicate in generateText and streamText, passes it into createStepHandler, and derives isFinalStep before calling onStepFinish.
Test coverage for isFinalStep
packages/core/src/agent/agent.spec.ts
Updates the step-count mock and replaces the onStepFinish test with direct hook invocation checks for multi-step and single-step flows.
Changeset entry
.changeset/add-is-final-step-flag.md
Adds a changeset file declaring a minor @voltagent/core release and documenting the hook update.

Estimated code review effort: 2 (Simple) | ~12 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Agent
  participant AISDK
  participant createStepHandler
  participant onStepFinish
  Agent->>AISDK: generateText / streamText with stopWhen
  AISDK->>createStepHandler: onStepFinish(event)
  createStepHandler->>createStepHandler: await stopWhen(event)
  createStepHandler->>onStepFinish: hook args with isFinalStep
Loading

Suggested reviewers: omeraplak

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR adds isFinalStep on onStepFinish, but #1368 requires exposing lastStepUsage in onEnd, so the direct requirement is not met. Implement lastStepUsage in the onEnd hook as requested, or update the linked issue if the scope changed.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly names the main change: adding an isFinalStep flag to onStepFinish.
Description check ✅ Passed It explains the change, rationale, and issue linkage, with only checklist/template details omitted.
Out of Scope Changes check ✅ Passed The changes stay within the hook, agent, test, and changeset scope and don't show unrelated additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cubic-dev-ai cubic-dev-ai Bot 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.

1 issue found across 3 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/core/src/agent/hooks/index.ts

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/agent/agent.ts`:
- Around line 7454-7470: The `isFinalStep` logic in `agent.ts` is still inferred
from `hasToolCalls` and `maxSteps`, so `hooks.onStepFinish` can receive
`isFinalStep: false` even when a custom `stopWhen` has already resolved the
loop. Update the step-finalization logic around the `event`,
`conversationSteps`, and `hooks.onStepFinish` flow to use the actual resolved
stop condition from the loop decision, and pass that result into `isFinalStep`
instead of deriving it only from tool calls or step count.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9e077160-5927-4e7d-9099-0ffd1a2aacfa

📥 Commits

Reviewing files that changed from the base of the PR and between 9a241f0 and 0379204.

📒 Files selected for processing (3)
  • packages/core/src/agent/agent.spec.ts
  • packages/core/src/agent/agent.ts
  • packages/core/src/agent/hooks/index.ts

Comment thread packages/core/src/agent/agent.ts
@nneelabh02
nneelabh02 force-pushed the feat/onstepfinish-isfinalstep-1368 branch from b136b6f to 7b3216d Compare July 3, 2026 06:54

@coderabbitai coderabbitai Bot 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/core/src/agent/agent.ts (1)

7458-7469: 🎯 Functional Correctness | 🔴 Critical | 🏗️ Heavy lift

stopWhen is invoked with the wrong argument shape.

AI SDK's StopCondition predicate signature expects { steps: StepResult[] }, but the code at line 7462 calls await stopWhen(event) passing only the current single StepResult. Built-in conditions like stepCountIs(n) and hasToolCall(...) destructure the full steps array to make decisions—they cannot work correctly without it. Custom stop conditions that inspect step history will also fail.

The codebase already accumulates steps in oc.systemContext.get("conversationSteps"); this array (plus the current step) should be passed as the required { steps: [...] } object.

🐛 Proposed fix
-      const isStopped = await stopWhen(event);
+      const priorSteps = (oc.systemContext.get("conversationSteps") as StepResult<ToolSet>[]) ?? [];
+      const isStopped = await stopWhen({ steps: [...priorSteps, event] });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/agent/agent.ts` around lines 7458 - 7469, The stop
condition call in agent.ts is passing the current StepResult directly, but
stopWhen expects the AI SDK StopCondition shape with a steps array. Update the
final-step logic around the stopWhen invocation to build and pass { steps: [...]
} using the accumulated conversationSteps from oc.systemContext plus the current
event, so built-in conditions like stepCountIs and hasToolCall and any custom
history-based predicates can evaluate correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/core/src/agent/agent.ts`:
- Around line 7458-7469: The stop condition call in agent.ts is passing the
current StepResult directly, but stopWhen expects the AI SDK StopCondition shape
with a steps array. Update the final-step logic around the stopWhen invocation
to build and pass { steps: [...] } using the accumulated conversationSteps from
oc.systemContext plus the current event, so built-in conditions like stepCountIs
and hasToolCall and any custom history-based predicates can evaluate correctly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 64a541e4-062e-43d7-b0ab-b71f53fc6b37

📥 Commits

Reviewing files that changed from the base of the PR and between 7b3216d and 6ad7fe9.

📒 Files selected for processing (2)
  • packages/core/src/agent/agent.spec.ts
  • packages/core/src/agent/agent.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/core/src/agent/agent.spec.ts

@nneelabh02

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nneelabh02

Copy link
Copy Markdown
Author

@Diluka please check this PR, thank you :)

@omeraplak omeraplak closed this Jul 8, 2026
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.

Feature: Expose lastStepUsage in onEnd hook for context window calculation

2 participants