Skip to content

refactor(ChatModel): Standardize Non-blocking Behavior for ChatModelBase Implementations#642

Merged
AlbumenJ merged 1 commit intoagentscope-ai:mainfrom
wuji1428:refactor-chatmodel-block
Jan 26, 2026
Merged

refactor(ChatModel): Standardize Non-blocking Behavior for ChatModelBase Implementations#642
AlbumenJ merged 1 commit intoagentscope-ai:mainfrom
wuji1428:refactor-chatmodel-block

Conversation

@wuji1428
Copy link
Contributor

AgentScope-Java Version

[The version of AgentScope-Java you are working on, e.g. 1.0.7, check your pom.xml dependency version or run mvn dependency:tree | grep agentscope-parent:pom(only mac/linux)]

Description

Add subscribeOn to non-streaming calls to the OpenAIChatModel, DashScopeChatModel, and OllamaChatModel models. This maintains consistent blocking behavior for all non-streaming calls to ChatModel.

Checklist

Please check the following items before code is ready to be reviewed.

  • Code has been formatted with mvn spotless:apply
  • All tests are passing (mvn test)
  • Javadoc comments are complete and follow project conventions
  • Related documentation has been updated (e.g. links, examples, etc.)
  • Code is ready for review

Related Issues

Ref #571

… scheduler to unify processing in chatmodel non-streaming mode.
@wuji1428 wuji1428 requested a review from a team January 23, 2026 02:54
@gemini-code-assist
Copy link

Summary of Changes

Hello @wuji1428, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request refactors the ChatModel implementations to standardize their non-blocking behavior when handling non-streaming requests. By explicitly scheduling these operations on a boundedElastic scheduler, the change ensures that API calls do not block the calling thread, thereby improving application responsiveness and resource management. This aligns the behavior of various chat models, providing a more consistent and predictable reactive programming experience.

Highlights

  • Standardized Non-blocking Behavior: Implemented subscribeOn(Schedulers.boundedElastic()) for non-streaming calls in DashScopeChatModel, OllamaChatModel, and OpenAIChatModel to ensure consistent non-blocking behavior across these ChatModelBase implementations.
  • New Test Coverage: Added a new integration test file, ChatModelNonStreamingBlockingBehaviorTest.java, to explicitly verify that non-streaming calls to DashScopeChatModel, OpenAIChatModel, and OllamaChatModel are indeed non-blocking.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request successfully standardizes the non-blocking behavior for non-streaming calls in DashScopeChatModel, OllamaChatModel, and OpenAIChatModel by using subscribeOn(Schedulers.boundedElastic()). The addition of ChatModelNonStreamingBlockingBehaviorTest is a great step to verify this behavior. My review includes suggestions to improve consistency in exception handling across the models and to enhance the new test file for better robustness and maintainability.

Comment on lines +263 to +265
new RuntimeException(
"DashScope API call failed: " + e.getMessage(),
e));

Choose a reason for hiding this comment

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

medium

For consistency with other models like OpenAIChatModel, it's better to use the more specific ModelException instead of a generic RuntimeException. This provides more structured error information.

Suggested change
new RuntimeException(
"DashScope API call failed: " + e.getMessage(),
e));
new ModelException(
"DashScope API call failed: " + e.getMessage(),
e, modelName, "dashscope"));

Comment on lines +197 to +203
try {
OllamaResponse response = httpClient.chat(request);
return Flux.just(
formatter.parseResponse(response, startTime));
} catch (Exception e) {
return Flux.error(e);
}

Choose a reason for hiding this comment

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

medium

The current exception handling is inconsistent with other models. It just re-throws the exception without logging or adding context. For better diagnostics and consistency, please log the error and wrap it in a ModelException, similar to OpenAIChatModel.

                                        try {
                                            OllamaResponse response = httpClient.chat(request);
                                            return Flux.just(
                                                    formatter.parseResponse(response, startTime));
                                        } catch (Exception e) {
                                            log.error("Ollama API call failed: {}", e.getMessage(), e);
                                            return Flux.error(new ModelException("Ollama API call failed: " + e.getMessage(), e, modelName, "ollama"));
                                        }

Comment on lines +162 to +167
return Flux.error(
new ModelException(
"Failed to call OpenAI API: " + e.getMessage(),
e,
modelName,
"openai"));

Choose a reason for hiding this comment

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

medium

For better diagnostics and consistency with other models like DashScopeChatModel, it's good practice to log the exception before returning the error Flux.

                                    log.error("Failed to call OpenAI API: {}", e.getMessage(), e);
                                    return Flux.error(
                                            new ModelException(
                                                    "Failed to call OpenAI API: " + e.getMessage(),
                                                    e,
                                                    modelName,
                                                    "openai"));

Comment on lines +63 to +66
new MockResponse()
.setResponseCode(200)
.setBody("{\"request_id\":\"test\",\"output\":{\"choices\":[]}}")
.setHeader("Content-Type", "application/json"));

Choose a reason for hiding this comment

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

medium

For consistency with the other tests in this file and to make the test more robust when testing asynchronous behavior, consider adding a body delay to the mock response.

Suggested change
new MockResponse()
.setResponseCode(200)
.setBody("{\"request_id\":\"test\",\"output\":{\"choices\":[]}}")
.setHeader("Content-Type", "application/json"));
new MockResponse()
.setResponseCode(200)
.setBody("{\"request_id\":\"test\",\"output\":{\"choices\":[]}}")
.setHeader("Content-Type", "application/json")
.setBodyDelay(RESPONSE_DELAY_MS, TimeUnit.MILLISECONDS));


DashScopeChatModel model =
DashScopeChatModel.builder().apiKey("test-key").modelName("qwen-max").stream(false)
.baseUrl(mockServer.url("/").toString().replaceAll("/$", ""))

Choose a reason for hiding this comment

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

medium

The base URL construction logic mockServer.url("/").toString().replaceAll("/$", "") is duplicated in all three test methods. To improve maintainability and reduce duplication, consider extracting this logic into a baseUrl field initialized in the setUp() method.

@codecov
Copy link

codecov bot commented Jan 23, 2026

Codecov Report

❌ Patch coverage is 75.86207% with 7 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...a/io/agentscope/core/model/DashScopeChatModel.java 69.23% 4 Missing ⚠️
...java/io/agentscope/core/model/OpenAIChatModel.java 66.66% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

@AlbumenJ AlbumenJ merged commit 7abf10e into agentscope-ai:main Jan 26, 2026
5 checks passed
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.

2 participants