Skip to content

feat: per-vendor model_name defaults on new chat clients (parity with legacy)#809

Open
cosminacho wants to merge 1 commit intomainfrom
feat/default-model-name
Open

feat: per-vendor model_name defaults on new chat clients (parity with legacy)#809
cosminacho wants to merge 1 commit intomainfrom
feat/default-model-name

Conversation

@cosminacho
Copy link
Copy Markdown
Contributor

@cosminacho cosminacho commented Apr 24, 2026

Summary

The legacy chat classes had per-vendor model_name defaults so callers could instantiate UiPathChat() or UiPathChatBedrock() with no args. The new classes re-exported from uipath_langchain.chat (backed by uipath_langchain_client) don't — model= is a required pydantic field. This PR restores parity where a legacy default existed.

Per-vendor defaults (verified against the git history of the legacy classes)

Class Default Mechanism
UiPathChat, UiPathAzureChatOpenAI, UiPathChatOpenAI UIPATH_MODEL_NAMEgpt-4.1-mini-2025-04-14 field default_factory
UiPathChatGoogleGenerativeAI, UiPathChatVertex gemini-2.5-flash field default_factory
UiPathChatBedrock, UiPathChatAnthropicBedrock anthropic.claude-haiku-4-5-20251001-v1:0 field default_factory
UiPathChatBedrockConverse anthropic.claude-haiku-4-5-20251001-v1:0 thin subclass with a model_validator(mode="before")

Classes with NO default (model= stays required)

Class Reason
UiPathChatAnthropic No legacy equivalent
UiPathChatAnthropicVertex No legacy equivalent
UiPathChatFireworks No legacy equivalent

Only Azure-backed classes ever honored UIPATH_MODEL_NAME; Bedrock and Vertex legacy defaults were hardcoded. Verified in commit 634d9fe feat: add chat models.

Approach

Each existing vendor re-export file is where:

  1. The upstream uipath_langchain_client class is first imported
  2. The legacy model_name default is attached inline
src/uipath_langchain/chat/
    __init__.py       # lazy __getattr__ delegates to the vendor files
    openai.py         # sets default on UiPathChat, UiPathAzureChatOpenAI, UiPathChatOpenAI
    bedrock.py        # sets default on UiPathChatBedrock + UiPathChatAnthropicBedrock; wraps UiPathChatBedrockConverse with a before-validator subclass
    vertex.py         # sets default on UiPathChatGoogleGenerativeAI (+ UiPathChatVertex alias)
    models.py         # re-exports the OpenAI family from openai.py

For classes where it works, the default is attached via pydantic FieldInfo mutation directly on the upstream class: cls.model_fields["model_name"].default_factory = factory; cls.model_rebuild(force=True). Pydantic V2 gives each class its own FieldInfo instance at class creation, so the mutation is scoped to exactly that class and doesn't leak to siblings or parents in uipath_langchain_client.

UiPathChatBedrockConverse gets a thin subclass with a @model_validator(mode="before") because its upstream ChatBedrockConverse.set_disable_streaming reads model / model_id from the raw input dict before field defaults fire.

Properties preserved

  • model=... kwarg still wins over the default.
  • For non-wrapped classes, the re-exported class IS the upstream class (identity preserved).
  • For UiPathChatBedrockConverse, the re-export is a subclass — issubclass check still holds.
  • Tracing span names unchanged.
  • Lazy imports preserved: asking for UiPathChat doesn't load Bedrock/Vertex code.

Bookkeeping

  • pyproject.toml: 0.10.50.10.6
  • uv.lock refreshed

Test plan

  • tests/chat/test_default_model_name.py26 tests exercising the public uipath_langchain.chat API only. For each of the 8 defaulted classes: construct cls() with no model kwarg and assert .model_name. For the 3 non-defaulted classes: assert ValidationError is raised. Plus env-var behavior, identity/alias, and subclass-relationship assertions. All pass.
  • uv run pytest tests/chat/ — 192 passed
  • uv run mypy src/ — clean
  • just lint — clean

Generated with Claude Code

@cosminacho cosminacho changed the title feat: default model_name on new chat clients (parity with legacy) feat: per-vendor model_name defaults on new chat clients (parity with legacy) Apr 24, 2026
Ports the legacy model_name defaults from the pre-migration
UiPathRequestMixin / BedrockModels / GeminiModels over to the new
uipath_langchain_client-backed re-exports so callers can construct
UiPathChat(), UiPathChatBedrock(), UiPathChatVertex() etc. with no args.

Defaults per vendor:
- OpenAI / Azure (UiPathChat, UiPathAzureChatOpenAI, UiPathChatOpenAI):
  UIPATH_MODEL_NAME env var, fallback gpt-4.1-mini-2025-04-14.
- Bedrock (UiPathChatBedrock, UiPathChatAnthropicBedrock,
  UiPathChatBedrockConverse): anthropic.claude-haiku-4-5-20251001-v1:0.
- Vertex (UiPathChatGoogleGenerativeAI, UiPathChatVertex): gemini-2.5-flash.

Classes without a legacy equivalent (UiPathChatAnthropic,
UiPathChatAnthropicVertex, UiPathChatFireworks) keep model= required.

Implementation: defaults are attached inline in the per-vendor re-export
files (chat/openai.py, chat/bedrock.py, chat/vertex.py, chat/models.py).
For most classes this is a one-liner FieldInfo mutation
(cls.model_fields["model_name"].default_factory = factory;
cls.model_rebuild(force=True)) which pydantic V2 scopes per class.

UiPathChatBedrockConverse is the one class where the field-default path
does not suffice — its upstream ChatBedrockConverse.set_disable_streaming
before-validator reads model / model_id from the raw input dict before
field defaults fire — so it gets a thin subclass with our own
@model_validator(mode="before") that injects the default into values.

Version bump 0.10.5 -> 0.10.6.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@cosminacho cosminacho force-pushed the feat/default-model-name branch from d3e73bc to 98ecefa Compare April 24, 2026 14:05
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