Skip to content

feat(agents): input parameter parity with Vercel AI SDK#65

Merged
zrosenbauer merged 8 commits intomainfrom
fix/62
Mar 27, 2026
Merged

feat(agents): input parameter parity with Vercel AI SDK#65
zrosenbauer merged 8 commits intomainfrom
fix/62

Conversation

@zrosenbauer
Copy link
Copy Markdown
Member

Summary

Closes #62

  • Add CallSettings to AgentConfig and per-call overrides: temperature, maxOutputTokens, topP, topK, presencePenalty, frequencyPenalty, stopSequences, seed, maxRetries
  • Add granular timeout support — timeout now accepts number | { totalMs?, stepMs?, toolMs?, ... } forwarded to the AI SDK
  • Add telemetry (experimental_telemetry) on both config and per-call overrides
  • Add custom stop conditions (stopWhen) — combined with internal stepCountIs(maxSteps) safety ceiling
  • Add stream-only callbacks: onChunk, onStreamError (AI SDK's onError), onAbort
  • Re-export StopCondition and TelemetrySettings from the public API

All new fields are optional — no breaking changes.

Test plan

  • pnpm typecheck — all 22 tasks pass
  • pnpm build --filter=@funkai/agents — clean build
  • pnpm test --filter=@funkai/agents — 644/644 tests pass, no type errors
  • Manual verification with a real agent using new CallSettings (e.g. temperature, maxOutputTokens)
  • Manual verification of stopWhen with custom stop conditions
  • Manual verification of stream-only callbacks (onChunk, onStreamError, onAbort)

zrosenbauer and others added 2 commits March 25, 2026 18:25
Surface CallSettings (temperature, maxOutputTokens, topP, topK,
presencePenalty, frequencyPenalty, stopSequences, seed, maxRetries),
telemetry (experimental_telemetry), granular timeout objects, custom
stop conditions (stopWhen), and stream-only callbacks (onChunk,
onStreamError, onAbort) on both AgentConfig and per-call overrides.

Closes #62

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 25, 2026

🦋 Changeset detected

Latest commit: 578b809

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

This PR includes changesets to release 1 package
Name Type
@funkai/agents 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

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 25, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
funkai Ready Ready Preview, Comment Mar 27, 2026 7:52pm

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 25, 2026

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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 66599f84-4793-421b-93db-efc4dfe39ac0

📥 Commits

Reviewing files that changed from the base of the PR and between 1623a5d and 578b809.

📒 Files selected for processing (4)
  • packages/agents/src/core/agents/base/agent.ts
  • packages/agents/src/core/agents/flow/steps/factory.ts
  • packages/agents/src/core/types.test-d.ts
  • packages/agents/src/core/types.ts

📝 Walkthrough

Walkthrough

Replaces ad-hoc StepFinishEvent assembly with explicit AI-backed types and factory functions: StepFinishEvent now embeds AIStepResult fields, createAgentStepFinishEvent and createFlowStepFinishEvent were added, call sites in agent and flow step factories now use these factories, and a type-only test plus a changeset were added.

Changes

Cohort / File(s) Summary
Type Definition & Factories
packages/agents/src/core/types.ts
Changed StepFinishEvent from Partial<AIStepResult> & {...} to AIStepResult & {...}; added EMPTY_AI_STEP and exported factory functions createAgentStepFinishEvent(step, extras) and createFlowStepFinishEvent(fields, extras?) to produce fully populated events.
Agent runtime usage
packages/agents/src/core/agents/base/agent.ts
Replaced inline StepFinishEvent object construction with createAgentStepFinishEvent(...) when invoking onStepFinish hooks; import updated accordingly.
Flow step factory
packages/agents/src/core/agents/flow/steps/factory.ts
Replaced manual finish/error event literal assembly with createFlowStepFinishEvent(...) for success and error paths.
Type-level tests
packages/agents/src/core/types.test-d.ts
New Vitest type-check file asserting StepFinishEvent fields/types, ensuring toolCalls/toolResults align with AIStepResult and factories return the expected types.
Changeset / Release note
.changeset/input-param-parity.md
Added changeset documenting a minor bump for @funkai/agents describing input-parameter-parity-related surface additions (CallSettings, telemetry, timeout, stopWhen, stream callbacks).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed Title accurately describes the main change: adding input parameter parity with Vercel AI SDK, which is the primary objective across all modified files.
Description check ✅ Passed Description is directly related to the changeset, detailing CallSettings, timeout handling, telemetry, stop conditions, and stream callbacks—all reflected in the code changes.
Linked Issues check ✅ Passed Pull request meets core acceptance criteria from #62: CallSettings fields added to AgentConfig and overrides [#62], timeout extended for TimeoutConfiguration [#62], stream callbacks exposed [#62], telemetry params forwarded [#62], stopWhen user-configurable [#62], all params forwarded to AI SDK functions [#62], type checks pass [#62], and changeset added [#62].
Out of Scope Changes check ✅ Passed All changes are scoped to #62 objectives: StepFinishEvent refactoring directly supports the AI SDK parity work by centralizing event construction; no unrelated refactoring or new features detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

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/agents/src/core/agents/flow/flow-agent.ts (1)

296-315: ⚠️ Potential issue | 🟡 Minor

Fix nested ternary to comply with no-ternary rule.

Lines 301-303 use a nested ternary expression, which violates the project's no-ternary lint rule (flagged by static analysis). Use if/else blocks instead.

Proposed fix using if/else
 function resolveSignal(params: FlowGenerateParams): AbortSignal {
   const { timeout, signal } = params;

-  // Object timeout — use totalMs for the flow-level signal (stepMs/toolMs
-  // are forwarded to individual agent calls, not handled here)
-  const timeoutMs = typeof timeout === "number"
-    ? timeout
-    : (typeof timeout === "object" && isNotNil(timeout) ? timeout.totalMs : undefined);
+  // Object timeout — use totalMs for the flow-level signal (stepMs/toolMs
+  // are forwarded to individual agent calls, not handled here).
+  let timeoutMs: number | undefined;
+  if (typeof timeout === "number") {
+    timeoutMs = timeout;
+  } else if (typeof timeout === "object" && isNotNil(timeout)) {
+    timeoutMs = timeout.totalMs;
+  }

   if (signal && isNotNil(timeoutMs)) {
     return AbortSignal.any([signal, AbortSignal.timeout(timeoutMs)]);
   }
   if (isNotNil(timeoutMs)) {
     return AbortSignal.timeout(timeoutMs);
   }
   if (signal) {
     return signal;
   }
   return new AbortController().signal;
 }

As per coding guidelines: "No ternaries — use match(), if/else, or early returns."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/agents/src/core/agents/flow/flow-agent.ts` around lines 296 - 315,
The nested ternary in resolveSignal that computes timeoutMs from
FlowGenerateParams (using timeout and isNotNil) violates the no-ternary rule;
replace it with a clear if/else block: declare let timeoutMs: number |
undefined, then if typeof timeout === "number" set timeoutMs = timeout, else if
typeof timeout === "object" && isNotNil(timeout) set timeoutMs =
timeout.totalMs, else leave undefined; keep the rest of resolveSignal logic that
uses signal, AbortSignal.timeout and AbortSignal.any unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/agents/src/core/agents/flow/flow-agent.ts`:
- Around line 296-315: The nested ternary in resolveSignal that computes
timeoutMs from FlowGenerateParams (using timeout and isNotNil) violates the
no-ternary rule; replace it with a clear if/else block: declare let timeoutMs:
number | undefined, then if typeof timeout === "number" set timeoutMs = timeout,
else if typeof timeout === "object" && isNotNil(timeout) set timeoutMs =
timeout.totalMs, else leave undefined; keep the rest of resolveSignal logic that
uses signal, AbortSignal.timeout and AbortSignal.any unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: abd7dcf4-a9f7-4a71-a344-077826049389

📥 Commits

Reviewing files that changed from the base of the PR and between 675aae8 and 4daf688.

📒 Files selected for processing (5)
  • .changeset/input-param-parity.md
  • packages/agents/src/core/agents/base/agent.ts
  • packages/agents/src/core/agents/flow/flow-agent.ts
  • packages/agents/src/core/agents/types.ts
  • packages/agents/src/index.ts

Merge duplicate ai import, replace nested ternary with if/else in
flow-agent resolveSignal, capitalize comment.

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/agents/src/core/agents/base/agent.ts`:
- Around line 814-821: Change the stopWhen types to accept either a single
StopCondition or an array and update buildStopConditions to accept and normalize
both forms: update GenerateParams.stopWhen and AgentGenerateOverrides.stopWhen
to the widened type StopCondition<ToolSet> | StopCondition<ToolSet>[] |
undefined, and change buildStopConditions(maxSteps, userConditions) to accept
userConditions: StopCondition<ToolSet> | StopCondition<ToolSet>[] | undefined;
implement logic so if userConditions is nil return stepCountIs(maxSteps), if
it's an array return [...userConditions, stepCountIs(maxSteps)], and if it's a
single StopCondition return [userConditions, stepCountIs(maxSteps)] so the
stepCountIs is always enforced.

In `@packages/agents/src/core/agents/flow/flow-agent.ts`:
- Around line 299-311: The resolveSignal logic in flow-agent.ts only reads
timeout.totalMs and silently drops stepMs/chunkMs, so update resolveSignal (the
function that extracts timeoutMs) to either narrow the accepted timeout type to
number | { totalMs?: number } or validate the passed object and throw when
unsupported keys (stepMs, chunkMs, etc.) are present; ensure callers like
flowAgent.generate and flowAgent.stream cannot pass nested timeout objects with
stepMs/chunkMs that will be ignored by: 1) adjusting the TypeScript type for the
timeout parameter to remove stepMs/chunkMs, or 2) adding a runtime check inside
resolveSignal that inspects the timeout object and throws a clear error if any
unknown keys (e.g., "stepMs", "chunkMs") are found, otherwise continue to use
totalMs to build the AbortSignal.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: b36fdb41-2291-40c6-a68b-44596649b252

📥 Commits

Reviewing files that changed from the base of the PR and between 4daf688 and 7472f3a.

📒 Files selected for processing (3)
  • packages/agents/src/core/agents/base/agent.ts
  • packages/agents/src/core/agents/flow/flow-agent.ts
  • packages/agents/src/core/agents/types.ts

Address PR review feedback: the AI SDK accepts `StopCondition |
StopCondition[]` for `stopWhen`. Widen the type on AgentGenerateOverrides
and update buildStopConditions() to normalize both forms.

Co-Authored-By: Claude <noreply@anthropic.com>
@zrosenbauer
Copy link
Copy Markdown
Member Author

Re: flow agent timeout object handling — created #67 to track this as a follow-up. The flow agent currently only supports totalMs from timeout objects; stepMs/toolMs/per-tool keys are silently dropped. Will address with either a warning, type narrowing, or runtime validation in a separate PR.

Make toolCalls and toolResults required fields on StepFinishEvent
instead of hiding them behind Partial<AIStepResult>. Add factory
functions (stepFinishEventFromAIStep, stepFinishEventFromFlow) so
event construction is centralized and flow steps stub empty arrays.

Add type tests ensuring StepFinishEvent.toolCalls and toolResults
match the AI SDK's StepResult types.

Closes #66

Co-Authored-By: Claude <noreply@anthropic.com>
Replace `Partial<AIStepResult>` with full `AIStepResult` intersection
so all AI SDK fields are always present. Flow steps get sensible
defaults via EMPTY_AI_STEP constant. Removes redundant toolCalls and
toolResults re-declarations.

Renames factory functions:
- stepFinishEventFromAIStep → createAgentStepFinishEvent
- stepFinishEventFromFlow → createFlowStepFinishEvent

Co-Authored-By: Claude <noreply@anthropic.com>
@zrosenbauer zrosenbauer merged commit a7d1e53 into main Mar 27, 2026
5 checks passed
@zrosenbauer zrosenbauer deleted the fix/62 branch March 27, 2026 19:59
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.

feat(agents): achieve 100% input parameter parity with Vercel AI SDK generateText/streamText

1 participant