Skip to content

Support OpenAI and Anthropic message processors - #9809

Open
lumincui wants to merge 4 commits into
modelscope:mainfrom
lumincui:agent/provider-message-processors
Open

Support OpenAI and Anthropic message processors#9809
lumincui wants to merge 4 commits into
modelscope:mainfrom
lumincui:agent/provider-message-processors

Conversation

@lumincui

@lumincui lumincui commented Jul 28, 2026

Copy link
Copy Markdown

What changed

  • normalize OpenAI assistant.tool_calls into SWIFT tool_call messages
  • normalize Anthropic tool_use and tool_result content blocks into SWIFT canonical roles
  • add explicit OpenAIMessagesPreprocessor and AnthropicMessagesPreprocessor classes
  • auto-detect provider tool-call formats in MessagesPreprocessor
  • document both accepted formats in English and Chinese

Why

MessagesPreprocessor._check_messages keeps only role, content, loss, and loss_scale. OpenAI-style tool calls stored in assistant.tool_calls were therefore silently removed during dataset preprocessing even though templates can encode tool calls. This can produce training examples that retain assistant narration but lose the actual tool-call targets.

Anthropic tool-use traces similarly need their content blocks expanded into SWIFT's canonical assistant, tool_call, and tool_response roles before template encoding.

Impact

OpenAI and Anthropic agent traces can now be passed through the normal dataset preprocessing path without an external conversion script. Parallel OpenAI tool calls, string or object arguments, Anthropic text/tool interleaving, nested text tool results, and loss metadata are covered.

The regression test also decodes supervised labels and asserts that the tool name is present, rather than only checking that template encoding succeeds.

Validation

  • pre-commit run --all-files
  • python -m unittest tests.general.test_data_preprocess.TestProviderMessagesPreprocess tests.general.test_data_preprocess.TestRejectedMessagesPreprocess tests.general.test_data_preprocess.TestDataPreprocess.test_tool_message

Related to #8327 and #9084.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@lumincui

lumincui commented Jul 28, 2026

Copy link
Copy Markdown
Author

Thanks @ezeli and @HGY19854338008 for raising #8327 and #9084 and providing concrete OpenAI tool-call examples — they were very helpful when shaping this change.

This PR adds normalization for OpenAI assistant.tool_calls and Anthropic tool-use content blocks while continuing to use the existing MessagesPreprocessor pipeline. @ezeli and @HGY19854338008, if you have time, it would be great if you could check whether the OpenAI behavior matches what you had in mind.

@Jintao-Huang @hjh0119 @tastelikefeet, when convenient, we would also appreciate your guidance on whether MessagesPreprocessor is the right integration point for these provider formats. Happy to adjust the design based on your feedback. Thank you!

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

Comment thread swift/dataset/preprocessor/core.py
Comment thread swift/dataset/preprocessor/core.py
@tastelikefeet

Copy link
Copy Markdown
Collaborator

Thanks! I will check this code asap

new_messages.append({
'role': 'tool_response',
'content': cls._anthropic_block_content(block.get('content', '')),
**message_metadata,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about the multi-modal blocks?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for catching this. The previous implementation only handled text and tool blocks, so Anthropic image blocks could be silently dropped.

I addressed this in 526c412:

  • base64 and URL image sources are converted to ms-swift's canonical <image> placeholders plus the top-level images field, preserving their original order;
  • the same conversion works for both regular message content and multimodal tool_result content;
  • unsupported image source/content block types now raise a clear error instead of being silently discarded;
  • auto-detection also recognizes Anthropic image blocks without requiring a tool block.

The regression test covers a mixed text -> base64 image -> tool_use -> URL image tool_result -> text conversation, verifies the canonical messages and ordered images values, checks StdTemplateInputs compatibility, and loads the base64 image through ms-swift's existing load_image path. Thank you for the helpful review!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a follow-up, I also added symmetric regression coverage for OpenAI Chat Completions multimodal messages in 54b24c99. No additional OpenAI processor conversion was needed because the existing StdTemplateInputs.remove_messages_media path already extracts image_url blocks into <image> placeholders and the top-level images field. The new test verifies base64 and URL images in order, real base64 decoding, and that assistant text can coexist with normalized tool_calls. The focused 9-test suite and all pre-commit hooks pass. Responses API input_text/input_image blocks use a separate schema and are documented as outside this Chat Completions example. Thank you again for prompting the multimodal coverage!


OpenAI tool-call format:
```jsonl
{"messages": [{"role": "user", "content": "How is the weather?"}, {"role": "assistant", "content": null, "tool_calls": [{"type": "function", "function": {"name": "get_weather", "arguments": "{\"city\":\"Beijing\"}"}}]}, {"role": "tool", "content": "Sunny"}]}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An example of multi-modal messages is needed

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks — I added matching Anthropic multimodal tool-use examples to both the English and Chinese custom-dataset documentation in 526c412.

The example includes a base64 image in a normal user message and a URL image inside tool_result, and explains that they are converted to <image> placeholders and the top-level images field in their original order.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have now added matching OpenAI Chat Completions multimodal examples to both the English and Chinese documentation in 54b24c99. The example covers base64 and URL image_url blocks together with an assistant tool_calls entry, and documents their conversion to ordered <image> placeholders plus the top-level images field. It also clarifies that Responses API input_text/input_image blocks use a different schema. Thanks again for the helpful suggestion!

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.

3 participants