Skip to content

feat(agents): add TModel generic for discriminated model types in evolve#43

Merged
zrosenbauer merged 5 commits intomainfrom
feat/agents-evolve-model-generic
Mar 20, 2026
Merged

feat(agents): add TModel generic for discriminated model types in evolve#43
zrosenbauer merged 5 commits intomainfrom
feat/agents-evolve-model-generic

Conversation

@zrosenbauer
Copy link
Member

Summary

  • Adds a 5th generic parameter TModel to AgentConfig and Agent that preserves whether the model was set as a static Model or dynamic Resolver<TInput, Model>
  • Threads TModel through evolve() so the mapper callback receives the correctly narrowed type
  • Enables direct .modelId access in evolve mappers without isFunction() narrowing

Before

const proxied = evolve(base, (config) => {
  // config.model is Resolver<TInput, Model> — always a union
  if (isFunction(config.model)) {
    return { model: proxy('default-model') }
  }
  return { model: proxy(config.model.modelId) }
})

After

// When base agent uses a static model:
const proxied = evolve(base, (config) => {
  // config.model is Model — .modelId works directly
  return { model: proxy(config.model.modelId) }
})

Test plan

  • pnpm typecheck --filter=@funkai/agents passes
  • pnpm test --filter=@funkai/agents — all 624 tests pass, no type errors
  • Default TModel = Resolver<TInput, Model> ensures full backwards compatibility

Add a 5th generic parameter `TModel` to `AgentConfig` and `Agent` that
tracks whether the model was set as a static `Model` or a dynamic
`Resolver<TInput, Model>`. This flows through `evolve()` so the mapper
callback receives the correctly narrowed type — enabling direct access
to `.modelId` without unnecessary `isFunction()` narrowing.

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

vercel bot commented Mar 20, 2026

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
funkai Ignored Ignored Preview Mar 20, 2026 1:17am

Request Review

@changeset-bot
Copy link

changeset-bot bot commented Mar 20, 2026

🦋 Changeset detected

Latest commit: 23481e7

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

@coderabbitai
Copy link

coderabbitai bot commented Mar 20, 2026

📝 Walkthrough

Walkthrough

Adds a new generic parameter TModel to AgentConfig and Agent and threads it through agent creation, evolve(), utilities, flow types, runnable guard, and examples so config.model is typed as the agent's specific resolver type.

Changes

Cohort / File(s) Summary
Changeset
./.changeset/evolve-model-generic.md
Changelog entry documenting the addition of the TModel generic for discriminated model typing.
Core types & factory
packages/agents/src/core/agents/types.ts, packages/agents/src/core/agents/base/agent.ts
Added TModel extends Resolver<TInput, Model> = Resolver<TInput, Model> generic to AgentConfig and Agent; model field becomes TModel; agent() factory signature updated and returned agent includes model: config.model.
Evolution API
packages/agents/src/core/agents/evolve.ts
Extended evolve() overloads with TModel; updated base, override mapper parameter and Partial types, internal getAgentConfig/mergeAgentConfigs typings, and return type to preserve TModel.
Utilities & guards
packages/agents/src/core/agents/base/utils.ts, packages/agents/src/lib/runnable.ts
Expanded Agent arity in buildAITools/buildAgentTools/buildAgentTool and updated isAgent type guard to Agent<any, any, any, any, any> — only type-signature changes.
Flow types
packages/agents/src/core/agents/flow/types.ts
FlowSubAgents updated to accept Agent<any, any, any, any, any> so flow subagent records match new Agent arity.
Examples
examples/realworld-cli/api/agents/analyzer.ts, examples/realworld-cli/api/agents/scanner.ts
Type-only imports expanded to include Agent; factory functions now have explicit : Agent return annotations to satisfy new signature.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding a TModel generic parameter for discriminated model types in the evolve() function.
Description check ✅ Passed The description clearly relates to the changeset, explaining the new TModel generic, its purpose, and how it enables type narrowing in evolve() callbacks with backward compatibility.
Docstring Coverage ✅ Passed Docstring coverage is 87.50% which is sufficient. The required threshold is 80.00%.

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

📝 Coding Plan
  • Generate coding plan for human review comments

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

Copy link

@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: 1

Caution

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

⚠️ Outside diff range comments (3)
packages/agents/src/core/agents/types.ts (1)

498-504: ⚠️ Potential issue | 🟡 Minor

Document the new exported TModel type parameter.

Line 503 and Line 680 add a public generic but the corresponding JSDoc blocks don’t describe TModel. Add @typeParam TModel to both exported API docs to keep generated/public typing docs accurate.

As per coding guidelines: "JSDoc on all exports with @param, @returns, @example" and CLAUDE.md: "any exported types/functions added/modified should have JSDoc."

Also applies to: 675-681

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

In `@packages/agents/src/core/agents/types.ts` around lines 498 - 504, Add a JSDoc
`@typeParam` entry describing the new generic TModel (which is Resolver<TInput,
Model>) to the exported API docs that document AgentConfig and the other
exported type around lines 675-681; update the JSDoc blocks for the exported
AgentConfig<TInput, TOutput, TTools, TSubAgents, TModel> and the other affected
exported type to include a concise `@typeParam` TModel explaining it represents
the model resolver type (Resolver<TInput, Model>) so generated docs and typing
comments remain accurate.
packages/agents/src/core/agents/base/agent.ts (1)

82-92: ⚠️ Potential issue | 🟡 Minor

agent() export docs are missing @typeParam TModel.

Line 89 introduces a new public generic parameter, but the JSDoc block does not describe it. Please add @typeParam TModel to keep exported API docs complete.

As per coding guidelines: "JSDoc on all exports with @param, @returns, @example" and CLAUDE.md: "any exported types/functions added/modified should have JSDoc."

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

In `@packages/agents/src/core/agents/base/agent.ts` around lines 82 - 92, The
exported agent<TInput,...,TModel> function's JSDoc is missing a `@typeParam` for
the new generic TModel; update the docblock for the exported function agent to
include a `@typeParam` TModel describing that TModel is the Resolver<TInput,
Model> type (e.g., "TModel - resolver type used to resolve models for given
TInput"), and ensure the top-level JSDoc for agent includes `@param` entries and
`@returns` per guidelines so the public API docs include the new generic.
packages/agents/src/core/agents/evolve.ts (1)

78-83: ⚠️ Potential issue | 🟡 Minor

Add @typeParam TModel to the exported evolve() JSDoc.

The export now includes a new generic parameter (Line 83) that is not documented in the type-param list.

As per coding guidelines: "JSDoc on all exports with @param, @returns, @example" and CLAUDE.md: "any exported types/functions added/modified should have JSDoc."

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

In `@packages/agents/src/core/agents/evolve.ts` around lines 78 - 83, The JSDoc
for the exported function evolve is missing documentation for the newly added
generic TModel; update the JSDoc block for evolve to include an `@typeParam`
TModel description (e.g., "TModel - resolver type that maps TInput to Model")
and briefly explain its role with references to Resolver and Model so the
signature: evolve<TInput, TOutput, TTools, TSubAgents, TModel extends
Resolver<TInput, Model>> is fully documented; ensure the JSDoc contains
`@param/`@returns as required by project guidelines.
🤖 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/evolve.ts`:
- Around line 86-91: The evolve() overload is type-unsafe because the overrides
union uses Partial<AgentConfig<TInput, TOutput, TTools, TSubAgents>> without
preserving the agent's TModel, letting callers supply a different model shape
while evolve still returns Agent<..., TModel>; fix by changing both overload
variants so the Partial references include TModel (i.e.
Partial<AgentConfig<TInput, TOutput, TTools, TSubAgents, TModel>> and the
function variant returns Partial<AgentConfig<..., TModel>>), ensuring evolve's
parameter type preserves the original TModel and the returned Agent<TInput,
TOutput, TTools, TSubAgents, TModel> remains sound.

---

Outside diff comments:
In `@packages/agents/src/core/agents/base/agent.ts`:
- Around line 82-92: The exported agent<TInput,...,TModel> function's JSDoc is
missing a `@typeParam` for the new generic TModel; update the docblock for the
exported function agent to include a `@typeParam` TModel describing that TModel is
the Resolver<TInput, Model> type (e.g., "TModel - resolver type used to resolve
models for given TInput"), and ensure the top-level JSDoc for agent includes
`@param` entries and `@returns` per guidelines so the public API docs include the
new generic.

In `@packages/agents/src/core/agents/evolve.ts`:
- Around line 78-83: The JSDoc for the exported function evolve is missing
documentation for the newly added generic TModel; update the JSDoc block for
evolve to include an `@typeParam` TModel description (e.g., "TModel - resolver
type that maps TInput to Model") and briefly explain its role with references to
Resolver and Model so the signature: evolve<TInput, TOutput, TTools, TSubAgents,
TModel extends Resolver<TInput, Model>> is fully documented; ensure the JSDoc
contains `@param/`@returns as required by project guidelines.

In `@packages/agents/src/core/agents/types.ts`:
- Around line 498-504: Add a JSDoc `@typeParam` entry describing the new generic
TModel (which is Resolver<TInput, Model>) to the exported API docs that document
AgentConfig and the other exported type around lines 675-681; update the JSDoc
blocks for the exported AgentConfig<TInput, TOutput, TTools, TSubAgents, TModel>
and the other affected exported type to include a concise `@typeParam` TModel
explaining it represents the model resolver type (Resolver<TInput, Model>) so
generated docs and typing comments remain accurate.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9c139dc6-7a96-4c1f-a880-a9c1e972b182

📥 Commits

Reviewing files that changed from the base of the PR and between 3fa83a3 and d50d32d.

📒 Files selected for processing (7)
  • .changeset/evolve-model-generic.md
  • packages/agents/src/core/agents/base/agent.ts
  • packages/agents/src/core/agents/base/utils.ts
  • packages/agents/src/core/agents/evolve.ts
  • packages/agents/src/core/agents/flow/types.ts
  • packages/agents/src/core/agents/types.ts
  • packages/agents/src/lib/runnable.ts

The new TModel generic causes TypeScript to infer LanguageModelV3 from
@ai-sdk/provider in the return type. Without an explicit annotation,
TS2742 fires because the example package doesn't directly depend on
that module. Adding `Agent` return types resolves the portability error.

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

@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 `@examples/realworld-cli/api/agents/analyzer.ts`:
- Line 35: Add an `@example` block to the exported function createAnalyzerAgent's
JSDoc showing typical usage (e.g., creating an analyzer with fsTools and a file
path, then calling analyzer.generate with a prompt and awaiting the result);
update the JSDoc immediately above the exported function createAnalyzerAgent to
include the code example fenced as JavaScript/TypeScript and ensure the existing
`@param` and `@returns` tags remain accurate.

In `@examples/realworld-cli/api/agents/scanner.ts`:
- Line 12: Add a JSDoc `@example` block to the exported createScannerAgent
function's existing JSDoc comment: include a short usage example showing
creating the scanner (e.g., const scanner = createScannerAgent(fsTools)),
calling generate with a prompt (e.g., const result = await scanner.generate({
prompt: "Find test files" })), and closing the code fence; keep the rest of the
JSDoc (`@param` and `@returns`) intact and ensure the example is wrapped in a proper
code fence and placed before the ending */.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4e606bc2-fe17-457c-8e2a-fbc4919507bb

📥 Commits

Reviewing files that changed from the base of the PR and between d50d32d and b16c392.

📒 Files selected for processing (2)
  • examples/realworld-cli/api/agents/analyzer.ts
  • examples/realworld-cli/api/agents/scanner.ts

Resolved review threads:
- evolve.ts: preserve TModel in override Partial types for type soundness
- analyzer.ts: add @example to exported function JSDoc
- scanner.ts: add @example to exported function JSDoc

Co-Authored-By: Claude <noreply@anthropic.com>
…t error

TModel was a phantom generic on Agent — structurally invisible to
TypeScript, so evolve() could not infer concrete model types.
Adds readonly model property to Agent interface and exposes
config.model on the agent factory return value.

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

@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 (3)
packages/agents/src/core/agents/types.ts (2)

483-497: ⚠️ Potential issue | 🟡 Minor

Missing @typeParam TModel in AgentConfig interface JSDoc.

Same documentation gap as the Agent interface—add the new type parameter to the JSDoc block.

📝 Proposed fix
  * `@typeParam` TOutput - Agent output type (default: `string`).
  * `@typeParam` TTools - Record of tools available to this agent.
  * `@typeParam` TSubAgents - Record of subagents available to this agent.
+ * `@typeParam` TModel - Model resolver type (default: `Resolver<TInput, Model>`).
  */
 export interface AgentConfig<
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/agents/src/core/agents/types.ts` around lines 483 - 497, Add the
missing JSDoc `@typeParam` for the model type to the AgentConfig interface
documentation: update the JSDoc block above the AgentConfig interface to include
a new line documenting `@typeParam` TModel - describing the agent/model type
(matching how Agent's JSDoc was updated) so the type parameters list includes
TInput, TOutput, TTools, TSubAgents, and TModel and clarifies its purpose.

663-688: ⚠️ Potential issue | 🟡 Minor

Missing @typeParam TModel in Agent interface JSDoc.

The interface JSDoc documents four type parameters but omits the newly added TModel. Per coding guidelines, exported interfaces should have complete JSDoc.

📝 Proposed fix
  * `@typeParam` TOutput - Agent output type.
  * `@typeParam` TTools - Record of tools.
  * `@typeParam` TSubAgents - Record of subagents.
+ * `@typeParam` TModel - Model resolver type (default: `Resolver<TInput, Model>`).
  */
 export interface Agent<
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/agents/src/core/agents/types.ts` around lines 663 - 688, Update the
Agent interface JSDoc to include the missing `@typeParam` for TModel: add a line
documenting TModel (e.g., "@typeParam TModel - Resolver type for the model used
by the agent") so the comment block covers all generic parameters declared on
the Agent interface (TInput, TOutput, TTools, TSubAgents, TModel) and references
the Resolver/Model relationship described in the interface.
packages/agents/src/core/agents/base/agent.ts (1)

36-56: ⚠️ Potential issue | 🟡 Minor

Missing @typeParam TModel in JSDoc.

The function's JSDoc documents TInput, TOutput, TTools, and TSubAgents but omits the newly added TModel generic. As per coding guidelines, exported functions should have complete JSDoc including all type parameters.

📝 Proposed fix
  * `@typeParam` TTools - Record of tools.
  * `@typeParam` TSubAgents - Record of subagents.
+ * `@typeParam` TModel - Model resolver type (default: `Resolver<TInput, Model>`).
  * `@param` config - Agent configuration including name, model, schemas,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/agents/src/core/agents/base/agent.ts` around lines 36 - 56, Add the
missing `@typeParam` TModel to the function JSDoc for the exported agent factory
(the block describing the generic type parameters for the agent returned by
createAgent / Agent type), e.g. add a line like "@typeParam TModel - Model type
used by the agent (default: unspecified or specific model interface)" and mirror
the style of the existing `@typeParam` entries (include default if applicable);
ensure the new `@typeParam` appears with the other generics (TInput, TOutput,
TTools, TSubAgents) in the top docblock so the JSDoc fully documents all
generics.
🤖 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/base/agent.ts`:
- Around line 36-56: Add the missing `@typeParam` TModel to the function JSDoc for
the exported agent factory (the block describing the generic type parameters for
the agent returned by createAgent / Agent type), e.g. add a line like
"@typeParam TModel - Model type used by the agent (default: unspecified or
specific model interface)" and mirror the style of the existing `@typeParam`
entries (include default if applicable); ensure the new `@typeParam` appears with
the other generics (TInput, TOutput, TTools, TSubAgents) in the top docblock so
the JSDoc fully documents all generics.

In `@packages/agents/src/core/agents/types.ts`:
- Around line 483-497: Add the missing JSDoc `@typeParam` for the model type to
the AgentConfig interface documentation: update the JSDoc block above the
AgentConfig interface to include a new line documenting `@typeParam` TModel -
describing the agent/model type (matching how Agent's JSDoc was updated) so the
type parameters list includes TInput, TOutput, TTools, TSubAgents, and TModel
and clarifies its purpose.
- Around line 663-688: Update the Agent interface JSDoc to include the missing
`@typeParam` for TModel: add a line documenting TModel (e.g., "@typeParam TModel -
Resolver type for the model used by the agent") so the comment block covers all
generic parameters declared on the Agent interface (TInput, TOutput, TTools,
TSubAgents, TModel) and references the Resolver/Model relationship described in
the interface.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: f0ff8a3e-e16c-4581-8b89-f1b932aae066

📥 Commits

Reviewing files that changed from the base of the PR and between a763590 and 23481e7.

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

@zrosenbauer zrosenbauer merged commit eef0bad into main Mar 20, 2026
5 checks passed
@zrosenbauer zrosenbauer deleted the feat/agents-evolve-model-generic branch March 20, 2026 01:21
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.

1 participant