Skip to content

Conversation

ethanabrooks
Copy link
Contributor

@ethanabrooks ethanabrooks commented Aug 14, 2025

This addresses the following error:

Traceback (most recent call last):
  File ".venv/lib/python3.13/site-packages/opentelemetry/trace/__init__.py", line 589, in use_span
    yield span
  File ".venv/lib/python3.13/site-packages/opentelemetry/sdk/trace/__init__.py", line 1105, in start_as_current_span
    yield span
  File ".venv/lib/python3.13/site-packages/temporalio/contrib/opentelemetry.py", line 295, in execute_activity
    return await super().execute_activity(input)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.13/site-packages/temporalio/worker/_interceptor.py", line 123, in execute_activity
    return await self.next.execute_activity(input)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.13/site-packages/temporalio/worker/_activity.py", line 784, in execute_activity
    return await input.fn(*input.args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "app/temporal/heartbeater.py", line 26, in wrapper
    return await fn(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "app/temporal/activities.py", line 160, in wrapper
    raise ApplicationError(
    ...<3 lines>...
    ) from e
temporalio.exceptions.ApplicationError: ClientError: ClientError: 400 INVALID_ARGUMENT. {'error': {'code': 400, 'message': 'Unable to submit request because it must include at least one parts field, which describes the prompt input. Learn more: https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/gemini', 'status': 'INVALID_ARGUMENT'}}

@ethanabrooks ethanabrooks changed the title add handling for thinking-only requests (currently causes UnexpectedModelBehavior) Handle function calls without text (#3) Aug 14, 2025
@ethanabrooks ethanabrooks changed the title Handle function calls without text (#3) Handle function calls without text Aug 14, 2025
Copy link
Collaborator

@DouweM DouweM left a comment

Choose a reason for hiding this comment

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

@ethanabrooks Can you show me the error you'd get without this? It's odd that Google could generate a model response with only tool calls and no text, that it then wouldn't accept when sent back on a subsequent request.

# If we only have function calls without text, add minimal text to satisfy Google API
if has_function_calls and not has_text_parts:
# Add a minimal text part to make the conversation valid for Google API
parts.append({'text': 'I have completed the function calls above.'})
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does this need text or could be empty?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Could we do this inside _content_model_response based on the ModelResponse's parts rather than parsing the returned ContentDict? We already iterate over all items there, so we can keep track of what we've seen.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated the description to include the full error. Yes your suggestion sounds like a good idea.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does this need text or could be empty?

Gave that a shot, but still got:

google.genai.errors.ClientError: 400 INVALID_ARGUMENT. {'error': {'code': 400, 'message': 'Unable to submit request because it must have a text parameter. Add a text parameter and try again. Learn more: https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/gemini', 'status': 'INVALID_ARGUMENT'}}

Could do something more minimal like 'Function call complete'.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could we do this inside _content_model_response based on the ModelResponse's parts rather than parsing the returned ContentDict? We already iterate over all items there, so we can keep track of what we've seen.

Just pushed a new commit that does this. Might need to iterate on the tests.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This is only a Vertex AI issue right? Could we gate it by checking if self.system so that we don't send unnecessary tokens to the non-Vertex Gemini API?

Does it accept ' '? :) I wonder how strict their check is, and I'd rather not waste any tokens

@DouweM
Copy link
Collaborator

DouweM commented Aug 14, 2025

Unable to submit request because it must include at least one parts field, which describes the prompt input. Learn more: https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/gemini

@ethanabrooks The error is odd, because there is in fact a parts field with the function_call, right?

We already have similar logic for the user role message, but that's only for when parts is actually empty:

# Google GenAI requires at least one part in the message.
if not message_parts:
message_parts = [{'text': ''}]

This looks like a bug on Google's side, but I agree we should work around it.

@DouweM
Copy link
Collaborator

DouweM commented Aug 14, 2025

@ethanabrooks By the way nice to see you using Pydantic AI with Temporal! Is that already using our brand-new integration? I'd love feedback on Slack!

@ethanabrooks
Copy link
Contributor Author

@ethanabrooks By the way nice to see you using Pydantic AI with Temporal! Is that already using our brand-new integration? I'd love feedback on Slack!

We just had a big planning meeting where talked about upgrading to v0.7 and using the new temporal features. Will keep you posted!

@ethanabrooks
Copy link
Contributor Author

ethanabrooks commented Aug 14, 2025

Might need some help with the test-coverage issue. It seems to be referencing lines that I didn't change... Also I get the test-coverage error on main as well.

@ethanabrooks ethanabrooks force-pushed the eb/handle-textless-function-calls branch from 9facb04 to e456ad3 Compare August 14, 2025 21:49
@ethanabrooks ethanabrooks force-pushed the eb/handle-textless-function-calls branch from e456ad3 to 8f38d24 Compare August 14, 2025 21:55
@DouweM
Copy link
Collaborator

DouweM commented Aug 14, 2025

Might need some help with the test-coverage issue. It seems to be referencing lines that I didn't change... Also I get the test-coverage error on main as well.

How strange, line 584 doesn't even have a pragma: no cover :/ I can look into that once the code here is ready

@DouweM
Copy link
Collaborator

DouweM commented Aug 16, 2025

@ethanabrooks Just a heads-up that I'll be out this coming week and will be back the 25th. Assuming this is not urgent I'll review it then. If it is, please ping Kludex! Appreciate the patience :)

@ethanabrooks
Copy link
Contributor Author

@ethanabrooks Just a heads-up that I'll be out this coming week and will be back the 25th. Assuming this is not urgent I'll review it then. If it is, please ping Kludex! Appreciate the patience :)

Not a problem. I'll check again next week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants