Skip to content

feat: add model subpath exports, rename GeminiModel to GoogleModel, and add api field to OpenAIModel#711

Merged
pgrayy merged 1 commit intostrands-agents:mainfrom
pgrayy:agent-tasks/model-subpath-exports-keep-names
Mar 23, 2026
Merged

feat: add model subpath exports, rename GeminiModel to GoogleModel, and add api field to OpenAIModel#711
pgrayy merged 1 commit intostrands-agents:mainfrom
pgrayy:agent-tasks/model-subpath-exports-keep-names

Conversation

@pgrayy
Copy link
Copy Markdown
Member

@pgrayy pgrayy commented Mar 23, 2026

Description

This PR introduces model subpath exports under @strands-agents/sdk/models/*, renames GeminiModel to GoogleModel, and adds a required api field to OpenAIModel. These changes prepare the SDK for 1.0 by establishing stable public API names and an extensible configuration pattern for model providers.

Motivation

With 1.0 approaching this week, we want to lock in model provider naming that:

  1. Keeps names consistent with the Python SDK (BedrockModel, OpenAIModel, AnthropicModel) rather than deviating with implementation-specific names like ConverseModel or ChatModel. The class name should not expose the underlying API being used.
  2. Allows users to switch between APIs (e.g., OpenAI Chat Completions to Responses) through configuration rather than swapping out an entirely different model provider class. This also makes it easier for Strands to dynamically switch APIs based on the model's decision.
  3. Provides clean subpath imports under @strands-agents/sdk/models/* for proper namespacing.

Note, we tried to come up with a new naming convention under #694. This was a contested change though. Also, it would lead to a significant deviation from the Python SDK. We are too close to 1.0 and so opened this PR instead.

Public API Changes

Subpath exports moved under @strands-agents/sdk/models/:

// Before
import { BedrockModel } from "@strands-agents/sdk/bedrock"
import { OpenAIModel } from "@strands-agents/sdk/openai"
import { AnthropicModel } from "@strands-agents/sdk/anthropic"
import { GeminiModel } from "@strands-agents/sdk/gemini"

// After
import { BedrockModel } from "@strands-agents/sdk/models/bedrock"
import { OpenAIModel } from "@strands-agents/sdk/models/openai"
import { AnthropicModel } from "@strands-agents/sdk/models/anthropic"
import { GoogleModel } from "@strands-agents/sdk/models/google"

BedrockModel is still exported top-level from @strands-agents/sdk, so existing top-level imports continue to work.

GeminiModel renamed to GoogleModel to align with the provider (not the product line) and the builtInTools config field replaces geminiTools:

// Before
import { GeminiModel } from "@strands-agents/sdk/gemini"
const model = new GeminiModel({ modelId: "gemini-2.5-flash" })

// After
import { GoogleModel } from "@strands-agents/sdk/models/google"
const model = new GoogleModel({ modelId: "gemini-2.5-flash" })

OpenAIModel now requires an api field that explicitly declares which OpenAI API to use. Currently only 'chat' (Chat Completions) is supported. When Responses API support is added later, api will become optional and default to 'responses', making that a non-breaking change for existing users.

// Before
const model = new OpenAIModel({ modelId: "gpt-4o" })

// After
const model = new OpenAIModel({
  api: "chat",
  modelId: "gpt-4o",
})

Related Issues

N/A

Documentation PR

strands-agents/docs#694

Type of Change

Breaking change

Testing

How have you tested the change?

  • I ran npm run check

All 1632 unit tests pass. Lint, format, and type-check are clean.

Checklist

  • I have read the CONTRIBUTING document
  • I have added any necessary tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

- Add subpath exports under ./models/ (bedrock, openai, anthropic, google)
- Rename GeminiModel to GoogleModel, move src/models/gemini/ to src/models/google/
- Rename geminiTools config field to builtInTools
- Add required api field to OpenAIModelOptions ('chat' for Chat Completions API)
- Keep BedrockModel, OpenAIModel, AnthropicModel names unchanged
@pgrayy pgrayy temporarily deployed to manual-approval March 23, 2026 13:17 — with GitHub Actions Inactive
@github-actions github-actions bot added the strands-running <strands-managed> Whether or not an agent is currently running label Mar 23, 2026
@github-actions
Copy link
Copy Markdown

API Design Question: Nested vs Flat Namespaces

The SDK Decision Records state:

"Public APIs should expose commonly-used functionality through flat, top-level namespaces rather than requiring users to import from deeply nested module paths."

This PR changes model imports from flat paths (@strands-agents/sdk/openai) to nested paths (@strands-agents/sdk/models/openai).

Questions for API review:

  1. Is the /models/ grouping justified given this decision record guidance?
  2. Could we maintain flat paths (e.g., /bedrock, /openai, /google) while still achieving the tree-shaking goals mentioned in the PR description?

The motivation makes sense for consistency with the Python SDK and future extensibility, but I wanted to flag this for explicit consideration during API review since it appears to diverge from the documented pattern.

@github-actions
Copy link
Copy Markdown

API Design Consideration: api Field Default Strategy

The PR description mentions:

"When Responses API support is added later, api will become optional and default to 'responses', making that a non-breaking change for existing users."

This is an interesting pattern but has a subtle implication: new code written after that change (without explicit api) will use 'responses', while existing code with api: 'chat' continues working. This creates two "camps" of code with different defaults.

Alternative to consider: Make api optional now with default 'chat'. When Responses API is added, users who want it would explicitly opt-in with api: 'responses'. This keeps the default stable and follows the "pay for play" principle from the decision records.

This isn't a blocking concern—just a design consideration for the API review discussion.

@github-actions
Copy link
Copy Markdown

Code Review Summary

Assessment: Comment

This PR introduces important API changes for 1.0 readiness. The implementation is clean and well-tested, with comprehensive documentation in the PR description and a linked docs PR.

Review Categories
  • API Design: Raises questions about nested /models/* paths vs the "Prefer Flat Namespaces" decision record, and the api field default strategy—flagged for API review discussion.
  • Code Quality: Minor inconsistency in error message ("Gemini API key" should match GoogleModel rename).
  • Testing: Tests properly updated for all changes; package verification tests confirm subpath exports work.
  • Documentation: PR description is comprehensive with before/after examples; docs PR linked.

Good work preparing this for 1.0! The design questions above are for API review consideration, not blocking concerns.

@github-actions github-actions bot removed the strands-running <strands-managed> Whether or not an agent is currently running label Mar 23, 2026
@pgrayy pgrayy added this pull request to the merge queue Mar 23, 2026
Merged via the queue into strands-agents:main with commit 3043ebb Mar 23, 2026
20 checks passed
@pgrayy pgrayy deleted the agent-tasks/model-subpath-exports-keep-names branch March 23, 2026 15:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants