Skip to content

Restore argument-provision checks to __init__ in common.ai operators - #70628

Open
baha-bouali wants to merge 7 commits into
apache:mainfrom
baha-bouali:fix/restore-common-ai-to-init-
Open

Restore argument-provision checks to __init__ in common.ai operators#70628
baha-bouali wants to merge 7 commits into
apache:mainfrom
baha-bouali:fix/restore-common-ai-to-init-

Conversation

@baha-bouali

Copy link
Copy Markdown

Restores two __init__ argument-provision checks that moved to execute() under the
old validate-operators-init rule, now that #70505 narrowed the rule to allow
field is None / field is not None provision checks back in __init__.

AgentOperator : straight revert of #70338's message_history/enable_hitl_review
check back to __init__, with test_agent.py::test_message_history_with_hitl_review_raises
reverted to assert at construction time (and its unneeded skipif removed).

DocumentLoaderOperator : partial revert. source_path/source_bytes exclusivity is
pure provision and moves back to __init__. The file_type check stays in execute(),
since it backs an assert on the rendered value of file_type (itself a template
field). So, checking it in __init__ would validate the unrendered template string instead.
Tests split to match: the two exclusivity tests revert to constructor-time, the two
file_type tests stay at .execute().

Testing

  • uv run --script scripts/ci/prek/validate_operators_init.py on both files -> clean,
    no exemption entries needed under the narrowed rule.
  • pytest providers/common/ai/tests/unit/common/ai/operators/test_agent.py providers/common/ai/tests/unit/common/ai/operators/test_document_loader.py -> passing.

related: #70503


Was generative AI tooling used to co-author this PR?
  • Yes (please specify the tool below)

Comment on lines +155 to +158
# source_path/source_bytes provision is checked in __init__ (that's just "was an
# argument passed"). file_type is different: it backs the assert below, and since
# file_type is itself a template field, whether it was *actually* supplied is only
# knowable after rendering -- so this one check has to stay here, not in __init__.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The rationale here is inverted -- it repeats the claim #70505 refuted. Provision is not knowable after rendering: with render_template_as_native_obj=True a supplied field renders to None, which is precisely why the rule was narrowed to allow is None back in __init__.

What actually keeps this one in execute() is that it isn't a provision check at all, it's a value check: _parse_bytes needs a real extension string, so it has to see the rendered value. The PR body words it correctly ("checking it in __init__ would validate the unrendered template string instead") -- worth pulling that wording into the comment, since #70503 makes this file a reference others will copy.

# file_type is itself a template field, whether it was *actually* supplied is only
# knowable after rendering -- so this one check has to stay here, not in __init__.
if self.source_bytes is not None and self.file_type is None:
raise ValueError("'file_type' is required when using 'source_bytes' (e.g. '.pdf').")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

file_type keeps a rendered-value guard here, but source_path no longer has one, and the assert self.source_path is not None below was leaning on the check that just moved to __init__.

A supplied source_path that renders to None (the native-obj case #70505 is built around) now falls into the else branch, and _resolve_files(None) raises TypeError: argument of type 'NoneType' is not iterable instead of the previous clear ValueError. Worth keeping a self.source_path is None guard here next to the file_type one.

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 think it is fixed now. I reworded the comment and added back the source_path guard, thanks for catching this! Let me know if something is still wrong

Comment on lines +162 to +163
if self.source_bytes is None and self.source_path is None:
raise ValueError("Provide exactly one of 'source_path' or 'source_bytes'.")

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.

Could you please add a unit test for this case?

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.

Done! I added the unit test right in test_document_loader.py.

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.

3 participants