Skip to content

Conversation

@markpollack
Copy link
Member

This commit addresses issues with OpenAI streaming responses where finish_reason is an empty string ("") instead of null, which caused Jackson deserialization failures and inconsistent metadata formatting.

Changes:

  • Configure Jackson coercion in ModelOptionsUtils to handle empty string to enum conversion (empty string -> null)
  • Fix getFinishReasonJson() method in OpenAiChatModel to return uppercase enum names for backward compatibility
  • Fix null pointer exceptions in streaming processing by ensuring getFinishReasonJson() returns empty string instead of null
  • Maintain finish_reason metadata as uppercase enum names ("STOP", "LENGTH") to preserve backward compatibility
  • Add comprehensive test suite covering all edge cases
  • Update streaming tests to expect correct uppercase finish reason values

Key fixes:

  1. Empty string finish_reason now deserializes correctly without errors
  2. Finish reason metadata maintains backward compatibility (uppercase enum names)
  3. No more NullPointerException in streaming Map.of() calls
  4. Proper handling of null, empty string, and valid finish_reason values

Jackson coercion configuration in ModelOptionsUtils now converts empty strings to null for ALL enum deserialization across Spring AI. Analysis shows this change is safe and beneficial for other providers:

  • Anthropic, Ollama use String fields (unaffected by enum coercion)
  • ZhiPuAI, MiniMax, MistralAI, DeepSeek use enum fields but have no documented empty string issues
  • Coercion improves robustness by gracefully handling malformed responses
  • No breaking changes expected for existing provider implementations

Testing:

  • Added OpenAiStreamingFinishReasonTests with 6 comprehensive test cases
  • Fixed existing metadata tests to maintain backward compatibility
  • All tests pass, covering JSON deserialization and streaming scenarios
  • Validates both error handling and correct behavior
  • Added tests for changes to ModelOptionsUtils using enum coersion

This ensures robust handling of OpenAI's empty string finish_reason edge case while maintaining backward compatibility and improving overall system resilience for malformed API responses.

Auto-cherry-pick to 1.0.x
Fixes #1358

Thank you for taking time to contribute this pull request!
You might have already read the contributor guide, but as a reminder, please make sure to:

  • Add a Signed-off-by line to each commit (git commit -s) per the DCO
  • Rebase your changes on the latest main branch and squash your commits
  • Add/Update unit tests as needed
  • Run a build and make sure all tests pass prior to submission

For more details, please check the contributor guide.
Thank you upfront!

This commit addresses issues with OpenAI streaming responses where
finish_reason is an empty string ("") instead of null, which caused
Jackson deserialization failures and inconsistent metadata formatting.

Changes:
- Configure Jackson coercion in ModelOptionsUtils to handle empty
  string to enum conversion (empty string -> null)
- Fix getFinishReasonJson() method in OpenAiChatModel to return
  uppercase enum names for backward compatibility
- Fix null pointer exceptions in streaming processing by ensuring
  getFinishReasonJson() returns empty string instead of null
- Maintain finish_reason metadata as uppercase enum names
  ("STOP", "LENGTH") to preserve backward compatibility
- Add comprehensive test suite covering all edge cases
- Update streaming tests to expect correct uppercase finish reason values

Key fixes:
1. Empty string finish_reason now deserializes correctly without errors
2. Finish reason metadata maintains backward compatibility (uppercase enum names)
3. No more NullPointerException in streaming Map.of() calls
4. Proper handling of null, empty string, and valid finish_reason values

Jackson coercion configuration in ModelOptionsUtils now converts empty
strings to null for ALL enum deserialization across Spring AI. Analysis
shows this change is safe and beneficial for other providers:
- Anthropic, Ollama use String fields (unaffected by enum coercion)
- ZhiPuAI, MiniMax, MistralAI, DeepSeek use enum fields but have no
  documented empty string issues
- Coercion improves robustness by gracefully handling malformed responses
- No breaking changes expected for existing provider implementations

Testing:
- Added OpenAiStreamingFinishReasonTests with 6 comprehensive test cases
- Fixed existing metadata tests to maintain backward compatibility
- All tests pass, covering JSON deserialization and streaming scenarios
- Validates both error handling and correct behavior
- Added tests for changes to ModelOptionsUtils using enum coersion

This ensures robust handling of OpenAI's empty string finish_reason edge
case while maintaining backward compatibility and improving overall
system resilience for malformed API responses.

Auto-cherry-pick to 1.0.x
Fixes #1358

Signed-off-by: Mark Pollack <[email protected]>
@sobychacko sobychacko added the bug Something isn't working label Aug 13, 2025
@sobychacko sobychacko added this to the 1.1.0.M1 milestone Aug 13, 2025
@sobychacko sobychacko merged commit 653918d into main Aug 13, 2025
2 checks passed
spring-builds pushed a commit that referenced this pull request Aug 13, 2025
…4132)

This commit addresses issues with OpenAI streaming responses where
finish_reason is an empty string ("") instead of null, which caused
Jackson deserialization failures and inconsistent metadata formatting.

Changes:
- Configure Jackson coercion in ModelOptionsUtils to handle empty
  string to enum conversion (empty string -> null)
- Fix getFinishReasonJson() method in OpenAiChatModel to return
  uppercase enum names for backward compatibility
- Fix null pointer exceptions in streaming processing by ensuring
  getFinishReasonJson() returns empty string instead of null
- Maintain finish_reason metadata as uppercase enum names
  ("STOP", "LENGTH") to preserve backward compatibility
- Add comprehensive test suite covering all edge cases
- Update streaming tests to expect correct uppercase finish reason values

Key fixes:
1. Empty string finish_reason now deserializes correctly without errors
2. Finish reason metadata maintains backward compatibility (uppercase enum names)
3. No more NullPointerException in streaming Map.of() calls
4. Proper handling of null, empty string, and valid finish_reason values

Jackson coercion configuration in ModelOptionsUtils now converts empty
strings to null for ALL enum deserialization across Spring AI. Analysis
shows this change is safe and beneficial for other providers:
- Anthropic, Ollama use String fields (unaffected by enum coercion)
- ZhiPuAI, MiniMax, MistralAI, DeepSeek use enum fields but have no
  documented empty string issues
- Coercion improves robustness by gracefully handling malformed responses
- No breaking changes expected for existing provider implementations

Testing:
- Added OpenAiStreamingFinishReasonTests with 6 comprehensive test cases
- Fixed existing metadata tests to maintain backward compatibility
- All tests pass, covering JSON deserialization and streaming scenarios
- Validates both error handling and correct behavior
- Added tests for changes to ModelOptionsUtils using enum coersion

This ensures robust handling of OpenAI's empty string finish_reason edge
case while maintaining backward compatibility and improving overall
system resilience for malformed API responses.

Fixes #1358

Signed-off-by: Mark Pollack <[email protected]>
(cherry picked from commit 653918d)
scionaltera pushed a commit to scionaltera/spring-ai that referenced this pull request Sep 3, 2025
…pring-projects#4132)

This commit addresses issues with OpenAI streaming responses where
finish_reason is an empty string ("") instead of null, which caused
Jackson deserialization failures and inconsistent metadata formatting.

Changes:
- Configure Jackson coercion in ModelOptionsUtils to handle empty
  string to enum conversion (empty string -> null)
- Fix getFinishReasonJson() method in OpenAiChatModel to return
  uppercase enum names for backward compatibility
- Fix null pointer exceptions in streaming processing by ensuring
  getFinishReasonJson() returns empty string instead of null
- Maintain finish_reason metadata as uppercase enum names
  ("STOP", "LENGTH") to preserve backward compatibility
- Add comprehensive test suite covering all edge cases
- Update streaming tests to expect correct uppercase finish reason values

Key fixes:
1. Empty string finish_reason now deserializes correctly without errors
2. Finish reason metadata maintains backward compatibility (uppercase enum names)
3. No more NullPointerException in streaming Map.of() calls
4. Proper handling of null, empty string, and valid finish_reason values

Jackson coercion configuration in ModelOptionsUtils now converts empty
strings to null for ALL enum deserialization across Spring AI. Analysis
shows this change is safe and beneficial for other providers:
- Anthropic, Ollama use String fields (unaffected by enum coercion)
- ZhiPuAI, MiniMax, MistralAI, DeepSeek use enum fields but have no
  documented empty string issues
- Coercion improves robustness by gracefully handling malformed responses
- No breaking changes expected for existing provider implementations

Testing:
- Added OpenAiStreamingFinishReasonTests with 6 comprehensive test cases
- Fixed existing metadata tests to maintain backward compatibility
- All tests pass, covering JSON deserialization and streaming scenarios
- Validates both error handling and correct behavior
- Added tests for changes to ModelOptionsUtils using enum coersion

This ensures robust handling of OpenAI's empty string finish_reason edge
case while maintaining backward compatibility and improving overall
system resilience for malformed API responses.

Auto-cherry-pick to 1.0.x
Fixes spring-projects#1358

Signed-off-by: Mark Pollack <[email protected]>
chedim pushed a commit to couchbaselabs/spring-ai that referenced this pull request Sep 19, 2025
…pring-projects#4132)

This commit addresses issues with OpenAI streaming responses where
finish_reason is an empty string ("") instead of null, which caused
Jackson deserialization failures and inconsistent metadata formatting.

Changes:
- Configure Jackson coercion in ModelOptionsUtils to handle empty
  string to enum conversion (empty string -> null)
- Fix getFinishReasonJson() method in OpenAiChatModel to return
  uppercase enum names for backward compatibility
- Fix null pointer exceptions in streaming processing by ensuring
  getFinishReasonJson() returns empty string instead of null
- Maintain finish_reason metadata as uppercase enum names
  ("STOP", "LENGTH") to preserve backward compatibility
- Add comprehensive test suite covering all edge cases
- Update streaming tests to expect correct uppercase finish reason values

Key fixes:
1. Empty string finish_reason now deserializes correctly without errors
2. Finish reason metadata maintains backward compatibility (uppercase enum names)
3. No more NullPointerException in streaming Map.of() calls
4. Proper handling of null, empty string, and valid finish_reason values

Jackson coercion configuration in ModelOptionsUtils now converts empty
strings to null for ALL enum deserialization across Spring AI. Analysis
shows this change is safe and beneficial for other providers:
- Anthropic, Ollama use String fields (unaffected by enum coercion)
- ZhiPuAI, MiniMax, MistralAI, DeepSeek use enum fields but have no
  documented empty string issues
- Coercion improves robustness by gracefully handling malformed responses
- No breaking changes expected for existing provider implementations

Testing:
- Added OpenAiStreamingFinishReasonTests with 6 comprehensive test cases
- Fixed existing metadata tests to maintain backward compatibility
- All tests pass, covering JSON deserialization and streaming scenarios
- Validates both error handling and correct behavior
- Added tests for changes to ModelOptionsUtils using enum coersion

This ensures robust handling of OpenAI's empty string finish_reason edge
case while maintaining backward compatibility and improving overall
system resilience for malformed API responses.

Auto-cherry-pick to 1.0.x
Fixes spring-projects#1358

Signed-off-by: Mark Pollack <[email protected]>
@markpollack markpollack deleted the gh-1358 branch September 26, 2025 13:36
Willam2004 pushed a commit to Willam2004/spring-ai that referenced this pull request Oct 11, 2025
…pring-projects#4132)

This commit addresses issues with OpenAI streaming responses where
finish_reason is an empty string ("") instead of null, which caused
Jackson deserialization failures and inconsistent metadata formatting.

Changes:
- Configure Jackson coercion in ModelOptionsUtils to handle empty
  string to enum conversion (empty string -> null)
- Fix getFinishReasonJson() method in OpenAiChatModel to return
  uppercase enum names for backward compatibility
- Fix null pointer exceptions in streaming processing by ensuring
  getFinishReasonJson() returns empty string instead of null
- Maintain finish_reason metadata as uppercase enum names
  ("STOP", "LENGTH") to preserve backward compatibility
- Add comprehensive test suite covering all edge cases
- Update streaming tests to expect correct uppercase finish reason values

Key fixes:
1. Empty string finish_reason now deserializes correctly without errors
2. Finish reason metadata maintains backward compatibility (uppercase enum names)
3. No more NullPointerException in streaming Map.of() calls
4. Proper handling of null, empty string, and valid finish_reason values

Jackson coercion configuration in ModelOptionsUtils now converts empty
strings to null for ALL enum deserialization across Spring AI. Analysis
shows this change is safe and beneficial for other providers:
- Anthropic, Ollama use String fields (unaffected by enum coercion)
- ZhiPuAI, MiniMax, MistralAI, DeepSeek use enum fields but have no
  documented empty string issues
- Coercion improves robustness by gracefully handling malformed responses
- No breaking changes expected for existing provider implementations

Testing:
- Added OpenAiStreamingFinishReasonTests with 6 comprehensive test cases
- Fixed existing metadata tests to maintain backward compatibility
- All tests pass, covering JSON deserialization and streaming scenarios
- Validates both error handling and correct behavior
- Added tests for changes to ModelOptionsUtils using enum coersion

This ensures robust handling of OpenAI's empty string finish_reason edge
case while maintaining backward compatibility and improving overall
system resilience for malformed API responses.

Auto-cherry-pick to 1.0.x
Fixes spring-projects#1358

Signed-off-by: Mark Pollack <[email protected]>
Signed-off-by: 家娃 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

openai stream Validation issues

3 participants