Skip to content

Conversation

@xingyaoww
Copy link
Collaborator

@xingyaoww xingyaoww commented Nov 19, 2025

Summary

This PR adds force_string_serializer as an argument to the LLM class, similar to the existing native_tool_calling argument. This allows users to explicitly control string serialization behavior when needed while maintaining full backward compatibility through automatic detection.

Changes

1. LLM Class (openhands-sdk/openhands/sdk/llm/llm.py)

  • Added new field: force_string_serializer: bool | None

    • Default: None (auto-detect based on model features)
    • True: Forces string content serializer for all messages
    • False: Allows list content serializer (when other features permit)
  • Updated format_messages_for_llm method: Now checks LLM's force_string_serializer setting first, falling back to model features auto-detection when None

2. Tests (tests/sdk/llm/test_llm.py)

Added two comprehensive test functions:

  • test_llm_force_string_serializer_auto_detect(): Verifies automatic detection based on model
  • test_llm_force_string_serializer_override(): Verifies explicit override behavior (True/False)

Use Cases

1. Force string serialization for custom providers

llm = LLM(
    model="custom-provider/model",
    api_key=SecretStr("key"),
    force_string_serializer=True,  # Override auto-detection
)

2. Enable list serialization with caching

llm = LLM(
    model="deepseek-v3",
    api_key=SecretStr("key"),
    force_string_serializer=False,  # Allow list format
    caching_prompt=True,
)

3. Auto-detection (default behavior)

llm = LLM(
    model="gpt-4o",
    api_key=SecretStr("key"),
    # force_string_serializer=None by default
)

Design Decisions

  • None as default: Maintains backward compatibility and allows automatic detection to work as before
  • Follows native_tool_calling pattern: Consistent with existing boolean control options that affect message formatting
  • Clear use cases: Particularly useful for HuggingFace, Groq, and other custom providers that don't support list content

Backward Compatibility

Fully backward compatible - all existing code continues to work without changes. Default behavior (auto-detection) remains unchanged.

Testing

  • ✅ Added 2 new tests for force_string_serializer
  • ✅ All 421 existing LLM tests pass
  • ✅ Pre-commit hooks pass (ruff format, ruff lint, pycodestyle, pyright)
  • ✅ No breaking changes detected

Related

This feature allows users to override automatic model-based detection when working with:

  • Custom LLM providers
  • Models not yet in the feature detection database
  • Scenarios requiring explicit control over message serialization format

@xingyaoww can click here to continue refining the PR


Agent Server images for this PR

GHCR package: https://github.com/OpenHands/agent-sdk/pkgs/container/agent-server

Variants & Base Images

Variant Architectures Base Image Docs / Tags
java amd64, arm64 eclipse-temurin:17-jdk Link
python amd64, arm64 nikolaik/python-nodejs:python3.12-nodejs22 Link
golang amd64, arm64 golang:1.21-bookworm Link

Pull (multi-arch manifest)

# Each variant is a multi-arch manifest supporting both amd64 and arm64
docker pull ghcr.io/openhands/agent-server:b80db8c-python

Run

docker run -it --rm \
  -p 8000:8000 \
  --name agent-server-b80db8c-python \
  ghcr.io/openhands/agent-server:b80db8c-python

All tags pushed for this build

ghcr.io/openhands/agent-server:b80db8c-golang-amd64
ghcr.io/openhands/agent-server:b80db8c-golang_tag_1.21-bookworm-amd64
ghcr.io/openhands/agent-server:b80db8c-golang-arm64
ghcr.io/openhands/agent-server:b80db8c-golang_tag_1.21-bookworm-arm64
ghcr.io/openhands/agent-server:b80db8c-java-amd64
ghcr.io/openhands/agent-server:b80db8c-eclipse-temurin_tag_17-jdk-amd64
ghcr.io/openhands/agent-server:b80db8c-java-arm64
ghcr.io/openhands/agent-server:b80db8c-eclipse-temurin_tag_17-jdk-arm64
ghcr.io/openhands/agent-server:b80db8c-python-amd64
ghcr.io/openhands/agent-server:b80db8c-nikolaik_s_python-nodejs_tag_python3.12-nodejs22-amd64
ghcr.io/openhands/agent-server:b80db8c-python-arm64
ghcr.io/openhands/agent-server:b80db8c-nikolaik_s_python-nodejs_tag_python3.12-nodejs22-arm64
ghcr.io/openhands/agent-server:b80db8c-golang
ghcr.io/openhands/agent-server:b80db8c-java
ghcr.io/openhands/agent-server:b80db8c-python

About Multi-Architecture Support

  • Each variant tag (e.g., b80db8c-python) is a multi-arch manifest supporting both amd64 and arm64
  • Docker automatically pulls the correct architecture for your platform
  • Individual architecture tags (e.g., b80db8c-python-amd64) are also available if needed

- Add force_string_serializer field to LLM class similar to native_tool_calling
- Default to None for automatic detection based on model features
- Allow explicit override (True/False) when needed for custom providers
- Update format_messages_for_llm to use LLM's force_string_serializer
  if set, otherwise fall back to model features auto-detection
- Add comprehensive tests for auto-detection and override behavior

Co-authored-by: openhands <openhands@all-hands.dev>
@github-actions
Copy link
Contributor

Coverage

Coverage Report •
FileStmtsMissCoverMissing
openhands-sdk/openhands/sdk/llm
   llm.py40915163%332, 336, 343, 347, 351, 355–357, 361–362, 373–374, 376–377, 381, 398, 432, 441, 461, 490, 511, 515, 530, 536–537, 556–557, 567, 592–597, 618–619, 622, 626, 638, 643–646, 653, 656, 664–669, 673–676, 678, 691, 695–697, 699–700, 705–706, 708, 715, 718–723, 821–822, 825–828, 869, 883, 937, 940–942, 945–953, 957–959, 962, 965–967, 974–975, 984, 991–993, 997, 999–1004, 1006–1023, 1026–1030, 1032–1033, 1039–1048, 1061, 1075, 1080
TOTAL12275562154% 

@xingyaoww xingyaoww marked this pull request as ready for review November 19, 2025 22:20
@xingyaoww xingyaoww requested a review from enyst November 19, 2025 22:20
@xingyaoww xingyaoww enabled auto-merge (squash) November 19, 2025 22:24
@xingyaoww xingyaoww merged commit 7fed944 into main Nov 20, 2025
23 checks passed
@xingyaoww xingyaoww deleted the add-force-string-serializer-arg branch November 20, 2025 02:47
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.

4 participants