Skip to content

refactor(api): replace provider if-else chains in simple_chat with a ChatStreamer#542

Closed
GdoongMathew wants to merge 7 commits into
AsyncFuncAI:mainfrom
GdoongMathew:refactor/chat_streamer
Closed

refactor(api): replace provider if-else chains in simple_chat with a ChatStreamer#542
GdoongMathew wants to merge 7 commits into
AsyncFuncAI:mainfrom
GdoongMathew:refactor/chat_streamer

Conversation

@GdoongMathew

Copy link
Copy Markdown
Contributor

Summary

Extracts provider-specific streaming into a ChatStreamer hierarchy.

Changes

  • New api/chat.py: abstract ChatStreamer + one subclass per provider (Ollama,
    OpenRouter, OpenAI, Azure, Bedrock, DashScope, Google). Subclasses self-register via
    __init_subclass__; ChatStreamer.create(...) returns the right one. Adding a provider
    = adding a class. Each exposes respond_stream(prompt) -> AsyncIterator[str].
  • simple_chat.py: reduced to prompt()/simplified_prompt() builders plus
    stream_and_fallback(), which retries once with the context-free prompt on token-limit
    errors. Streamers now propagate exceptions, so the fallback works for all providers.

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

Copy link
Copy Markdown
Contributor

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 refactors the chat completion streaming logic by extracting provider-specific implementations from api/simple_chat.py into a clean, registry-based ChatStreamer class hierarchy in api/chat.py. This significantly simplifies the main API endpoint and centralizes the streaming logic. The review feedback highlights a case-sensitivity bug in the token limit error detection helper, as well as multiple potential KeyError risks across the new streamer classes when directly accessing optional configuration keys like temperature, top_p, top_k, and num_ctx from model_config.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread api/simple_chat.py Outdated
Comment on lines 340 to 344
def _is_token_limit_error(exc: Exception) -> bool:
error_message = str(exc)
return any(
k in error_message for k in ("maximum context length", "token limit", "too many tokens")
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

The case-sensitive check in _is_token_limit_error will fail to detect token limit errors if the exception message contains any capital letters (e.g., 'Token limit exceeded' or 'Token Limit Exceeded'). Convert the error message to lowercase before performing the substring checks to ensure the fallback mechanism is reliably triggered.

Suggested change
def _is_token_limit_error(exc: Exception) -> bool:
error_message = str(exc)
return any(
k in error_message for k in ("maximum context length", "token limit", "too many tokens")
)
def _is_token_limit_error(exc: Exception) -> bool:
error_message = str(exc).lower()
return any(
k in error_message for k in ("maximum context length", "token limit", "too many tokens")
)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed

Comment thread api/chat.py
Comment on lines +60 to +68
self.model_kwargs = {
"model": model,
"stream": True,
"options": {
"temperature": model_config["temperature"],
"top_p": model_config["top_p"],
"num_ctx": model_config["num_ctx"]
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Directly accessing keys like temperature, top_p, and num_ctx from model_config can raise a KeyError if they are not defined in the configuration file. It is safer to dynamically build the options dictionary only with the keys that are actually present in model_config.

Suggested change
self.model_kwargs = {
"model": model,
"stream": True,
"options": {
"temperature": model_config["temperature"],
"top_p": model_config["top_p"],
"num_ctx": model_config["num_ctx"]
}
}
options = {}
for key in ("temperature", "top_p", "num_ctx"):
if key in model_config:
options[key] = model_config[key]
self.model_kwargs = {
"model": model,
"stream": True,
"options": options
}

Comment thread api/chat.py
Comment on lines +105 to +111
self.model_kwargs = {
"model": model,
"stream": True,
"temperature": model_config["temperature"]
}
if "top_k" in model_config:
self.model_kwargs["top_k"] = model_config["top_k"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Directly accessing model_config["temperature"] can raise a KeyError if it is not defined in the configuration. Use a safe dictionary check or fallback to ensure robustness.

Suggested change
self.model_kwargs = {
"model": model,
"stream": True,
"temperature": model_config["temperature"]
}
if "top_k" in model_config:
self.model_kwargs["top_k"] = model_config["top_k"]
self.model_kwargs = {
"model": model,
"stream": True,
}
if "temperature" in model_config:
self.model_kwargs["temperature"] = model_config["temperature"]
if "top_k" in model_config:
self.model_kwargs["top_k"] = model_config["top_k"]

Comment thread api/chat.py
Comment on lines +136 to +143
self.model_kwargs = {
"model": model,
"stream": True,
"temperature": model_config["temperature"]
}
# Only add top_p if it exists in the model config
if "top_p" in model_config:
self.model_kwargs["top_p"] = model_config["top_p"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Directly accessing model_config["temperature"] can raise a KeyError if it is not defined in the configuration. Use a safe dictionary check or fallback to ensure robustness.

Suggested change
self.model_kwargs = {
"model": model,
"stream": True,
"temperature": model_config["temperature"]
}
# Only add top_p if it exists in the model config
if "top_p" in model_config:
self.model_kwargs["top_p"] = model_config["top_p"]
self.model_kwargs = {
"model": model,
"stream": True,
}
if "temperature" in model_config:
self.model_kwargs["temperature"] = model_config["temperature"]
if "top_p" in model_config:
self.model_kwargs["top_p"] = model_config["top_p"]

Comment thread api/chat.py
Comment on lines +172 to +177
self.model_kwargs = {
"model": model,
"stream": True,
"temperature": model_config["temperature"],
"top_p": model_config["top_p"]
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Directly accessing model_config["temperature"] and model_config["top_p"] can raise a KeyError if they are not defined in the configuration. Use safe dictionary checks to ensure robustness.

Suggested change
self.model_kwargs = {
"model": model,
"stream": True,
"temperature": model_config["temperature"],
"top_p": model_config["top_p"]
}
self.model_kwargs = {
"model": model,
"stream": True,
}
if "temperature" in model_config:
self.model_kwargs["temperature"] = model_config["temperature"]
if "top_p" in model_config:
self.model_kwargs["top_p"] = model_config["top_p"]

Comment thread api/chat.py
Comment on lines +209 to +213
self.model_kwargs = {
"model": model,
"temperature": model_config["temperature"],
"top_p": model_config["top_p"]
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Directly accessing model_config["temperature"] and model_config["top_p"] can raise a KeyError if they are not defined in the configuration. Use safe dictionary checks to ensure robustness.

Suggested change
self.model_kwargs = {
"model": model,
"temperature": model_config["temperature"],
"top_p": model_config["top_p"]
}
self.model_kwargs = {
"model": model,
}
if "temperature" in model_config:
self.model_kwargs["temperature"] = model_config["temperature"]
if "top_p" in model_config:
self.model_kwargs["top_p"] = model_config["top_p"]

Comment thread api/chat.py
Comment on lines +237 to +242
self.model_kwargs = {
"model": model,
"stream": True,
"temperature": model_config["temperature"],
"top_p": model_config["top_p"],
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Directly accessing model_config["temperature"] and model_config["top_p"] can raise a KeyError if they are not defined in the configuration. Use safe dictionary checks to ensure robustness.

Suggested change
self.model_kwargs = {
"model": model,
"stream": True,
"temperature": model_config["temperature"],
"top_p": model_config["top_p"],
}
self.model_kwargs = {
"model": model,
"stream": True,
}
if "temperature" in model_config:
self.model_kwargs["temperature"] = model_config["temperature"]
if "top_p" in model_config:
self.model_kwargs["top_p"] = model_config["top_p"]

Comment thread api/chat.py
Comment on lines +266 to +273
self.client = genai.GenerativeModel(
model_name=model,
generation_config=GenerationConfig(
temperature=model_config["temperature"],
top_p=model_config["top_p"],
top_k=model_config["top_k"],
)
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Directly accessing model_config["temperature"], model_config["top_p"], and model_config["top_k"] can raise a KeyError if they are not defined in the configuration. Use safe dictionary checks to build the GenerationConfig to ensure robustness.

Suggested change
self.client = genai.GenerativeModel(
model_name=model,
generation_config=GenerationConfig(
temperature=model_config["temperature"],
top_p=model_config["top_p"],
top_k=model_config["top_k"],
)
)
generation_kwargs = {}
for key in ("temperature", "top_p", "top_k"):
if key in model_config:
generation_kwargs[key] = model_config[key]
self.client = genai.GenerativeModel(
model_name=model,
generation_config=GenerationConfig(**generation_kwargs) if generation_kwargs else None
)

@GdoongMathew
GdoongMathew deleted the refactor/chat_streamer branch July 18, 2026 04:31
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