Skip to content

Commit 83272ed

Browse files
committed
refactor: simplify finish_reason mapping and update type hints
- Replace if/elif chain with dictionary mapping for better maintainability - Add _FINISH_REASON_MAPPING constant with explicit string->enum mappings - Remove Union[FinishReason, str] type - finish_reason is always enum now - Update docstring to clarify all values mapped to enum with OTHER fallback - Update tracing comment for accuracy (defensive fallback only) Addresses Gemini Code Assist bot review feedback: - Dictionary-based mapping improves code clarity - Type hint now accurate (no Union needed since we always map to enum) - Documentation reflects actual behavior (always enum, never string)
1 parent 75484f8 commit 83272ed

3 files changed

Lines changed: 16 additions & 15 deletions

File tree

src/google/adk/models/lite_llm.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@
6464
_NEW_LINE = "\n"
6565
_EXCLUDED_PART_FIELD = {"inline_data": {"data"}}
6666

67+
# Mapping of LiteLLM finish_reason strings to FinishReason enum values
68+
_FINISH_REASON_MAPPING = {
69+
"length": types.FinishReason.MAX_TOKENS,
70+
"stop": types.FinishReason.STOP,
71+
"tool_calls": types.FinishReason.STOP,
72+
"function_call": types.FinishReason.STOP,
73+
"content_filter": types.FinishReason.SAFETY,
74+
}
75+
6776

6877
class ChatCompletionFileUrlObject(TypedDict, total=False):
6978
file_data: str
@@ -508,18 +517,9 @@ def _model_response_to_generate_content_response(
508517
# Map LiteLLM finish_reason strings to FinishReason enum
509518
# This provides type consistency with Gemini native responses and avoids warnings
510519
finish_reason_str = str(finish_reason).lower()
511-
if finish_reason_str == "length":
512-
llm_response.finish_reason = types.FinishReason.MAX_TOKENS
513-
elif finish_reason_str == "stop":
514-
llm_response.finish_reason = types.FinishReason.STOP
515-
elif "tool" in finish_reason_str or "function" in finish_reason_str:
516-
# Handle tool_calls, function_call variants
517-
llm_response.finish_reason = types.FinishReason.STOP
518-
elif finish_reason_str == "content_filter":
519-
llm_response.finish_reason = types.FinishReason.SAFETY
520-
else:
521-
# For unknown reasons, use OTHER
522-
llm_response.finish_reason = types.FinishReason.OTHER
520+
llm_response.finish_reason = _FINISH_REASON_MAPPING.get(
521+
finish_reason_str, types.FinishReason.OTHER
522+
)
523523
if response.get("usage", None):
524524
llm_response.usage_metadata = types.GenerateContentResponseUsageMetadata(
525525
prompt_token_count=response["usage"].get("prompt_tokens", 0),

src/google/adk/models/llm_response.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,11 @@ class LlmResponse(BaseModel):
7878
Only used for streaming mode.
7979
"""
8080

81-
finish_reason: Optional[Union[types.FinishReason, str]] = None
81+
finish_reason: Optional[types.FinishReason] = None
8282
"""The finish reason of the response.
8383
84-
Can be either a types.FinishReason enum (from Gemini) or a string (from LiteLLM).
84+
Always a types.FinishReason enum. LiteLLM string values are mapped to
85+
corresponding enum values (with fallback to OTHER for unknown values).
8586
"""
8687

8788
error_code: Optional[str] = None

src/google/adk/telemetry/tracing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ def trace_call_llm(
284284
if isinstance(llm_response.finish_reason, types.FinishReason):
285285
finish_reason_str = llm_response.finish_reason.name.lower()
286286
else:
287-
# Fallback for string values (should not occur with LiteLLM after enum mapping)
287+
# Defensive fallback for string values (should never occur - all values mapped to enum)
288288
finish_reason_str = str(llm_response.finish_reason).lower()
289289
span.set_attribute(
290290
'gen_ai.response.finish_reasons',

0 commit comments

Comments
 (0)