Skip to content

fix(composio): drop blank optional tool arguments before Composio execution - #14895

Open
andifilhohub wants to merge 1 commit into
langflow-ai:release-1.12.0from
andifilhohub:fix/composio-gmail-tool-empty-optional-fields
Open

fix(composio): drop blank optional tool arguments before Composio execution#14895
andifilhohub wants to merge 1 commit into
langflow-ai:release-1.12.0from
andifilhohub:fix/composio-gmail-tool-empty-optional-fields

Conversation

@andifilhohub

@andifilhohub andifilhohub commented Sep 1, 2026

Copy link
Copy Markdown
Member

Summary

Fixes #14715.

When a Composio action (e.g. Gmail) is used as a Tool by an agent, drafting/sending an email fails with "Tool input validation error" from Composio, even though the same action run directly from the component works fine.

Root cause

  • ComposioBaseComponent.execute_action (src/lfx/src/lfx/base/composio/composio_base.py), used when the component runs directly, already skips optional arguments that are None, empty strings/lists, or equal to the schema default before calling the Composio API.
  • The agent Tool-calling path (SafeLangchainProvider.wrap_toolcomposio_langchain's LangchainProvider.wrap_tool) has no equivalent filtering: it forwards the LLM's raw tool-call arguments to Composio's execute API unchanged.

Tool-calling models routinely populate every property they see in a tool's JSON schema, including optional ones, with empty placeholders. For Gmail's consolidated attachment field this produces {"name": "", "data": ""} even when no attachment was requested. Composio's backend rejects that blank value with "Tool input validation error", which matches the exact payload and error reported in the issue. This divergence between the two execution paths explains why the bug only reproduces "as a Tool."

Fix

SafeLangchainProvider.wrap_tool (src/lfx/src/lfx/base/composio/safe_provider.py) now wraps execute_tool to strip blank optional arguments (recursively, so a nested object like attachment whose leaf values are all blank is dropped too) before delegating to Composio, mirroring execute_action's existing behavior. Required fields are always forwarded untouched, so a genuinely missing required value still reaches Composio's own validation and error reporting.

This is a minimal, surgical change scoped to one file's tool-wrapping logic; no schema-building, UI, or direct-execution code paths were touched.

Test plan

  • Added TestIsBlankValue, TestDropBlankOptionalArguments, and TestSafeLangchainProviderDropsBlankOptionalArguments (the latter reproduces the exact GMAIL_CREATE_EMAIL_DRAFT payload from the issue through the real SafeLangchainProvider.wrap_tool wiring) in src/bundles/lfx-bundles/tests/test_composio_components.py.
  • uv run pytest src/bundles/lfx-bundles/tests/test_composio_components.py -q → 30 passed.
  • uv run pytest src/bundles/lfx-bundles/tests/ -q (full bundle suite) → 192 passed, 29 skipped, no regressions.
  • uv run ruff check / uv run pre-commit run --files ... → clean.

Summary by CodeRabbit

  • Bug Fixes

    • Improved tool execution by removing empty placeholder values from optional arguments.
    • Preserved required fields and valid non-empty values when processing tool calls.
    • Improved consistency between direct component runs and wrapped tool execution.
  • Tests

    • Added coverage for blank-value detection, optional-argument filtering, and end-to-end tool execution behavior.

…cution

Gmail (and other Composio) actions used as an agent Tool go through
SafeLangchainProvider.wrap_tool -> composio_langchain's wrap_tool, which
forwards the LLM's raw tool-call arguments straight to Composio's execute
API. Tool-calling models routinely populate every property they see in a
schema, including optional ones, with empty placeholders - e.g. Gmail's
consolidated "attachment" field as {"name": "", "data": ""} when no
attachment was requested. Composio's backend then rejects the blank value
with "Tool input validation error".

The direct component-run path (ComposioBaseComponent.execute_action) already
drops blank/default optional values before calling the API, but that logic
never ran for the agent Tool-calling path, causing the divergence: running
the Gmail action directly worked, using it as a Tool did not - exactly what
issue langflow-ai#14715 reports.

Wrap execute_tool in SafeLangchainProvider.wrap_tool to strip blank optional
arguments (recursively, for nested objects) before delegating, mirroring
execute_action's existing behavior. Required fields are always forwarded
untouched so a genuinely missing required value still reaches Composio's own
validation.

Fixes langflow-ai#14715
@github-actions github-actions Bot added the bug Something isn't working label Sep 1, 2026
@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: 2c35dfca-96fa-4342-a3bb-d621c6fde536

📥 Commits

Reviewing files that changed from the base of the PR and between 435c0c9 and f0fa5e6.

📒 Files selected for processing (2)
  • src/bundles/lfx-bundles/tests/test_composio_components.py
  • src/lfx/src/lfx/base/composio/safe_provider.py

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


Walkthrough

SafeLangchainProvider now removes blank optional arguments from Composio tool calls while preserving required fields. New tests cover recursive blank detection, filtering behavior, and Gmail draft execution.

Changes

Composio blank argument filtering

Layer / File(s) Summary
Filtering and tool wiring
src/lfx/src/lfx/base/composio/safe_provider.py
Adds recursive blank-value detection and removes blank optional arguments before execute_tool runs. Required blank fields remain unchanged.
Filtering and provider regression tests
src/bundles/lfx-bundles/tests/test_composio_components.py
Tests blank detection, argument filtering, non-dict inputs, Gmail draft payloads, and required blank fields.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to f0fa5

The PR removes blank optional arguments from agent-driven Composio calls while preserving required inputs, aligning behavior with direct execution and preventing the reported validation failures. No actionable merge-blocking risk remains beyond normal checks and review.

Suggested reviewers: erichare

Sequence Diagram(s)

sequenceDiagram
  participant LangchainProvider
  participant SafeLangchainProvider
  participant ComposioExecutor
  LangchainProvider->>SafeLangchainProvider: wrap_tool with execute_tool
  SafeLangchainProvider->>SafeLangchainProvider: remove blank optional arguments
  SafeLangchainProvider->>ComposioExecutor: execute filtered arguments
Loading
🚥 Pre-merge checks | ✅ 8 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.05% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 19 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (8 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: removing blank optional tool arguments before Composio execution.
Linked Issues check ✅ Passed The PR satisfies issue #14715 by filtering blank optional arguments, including nested Gmail attachment fields, before tool execution while preserving required arguments. Tests cover the reported regre…
Out of Scope Changes check ✅ Passed The changes are limited to the Composio tool-wrapping path and related tests. They directly support issue #14715 and contain no unrelated code changes.
Test Coverage For New Implementations ✅ Passed PASS: The PR adds 180 lines to the existing backend test file src/bundles/lfx-bundles/tests/test_composio_components.py. The tests cover _is_blank_value, _drop_blank_optional_arguments, optional…
Test Quality And Coverage ✅ Passed Tests provide strong coverage for the new filtering behavior. The added pytest cases cover blank and non-blank scalar, collection, and nested-dictionary values; optional-field removal; preservation of…
Test File Naming And Structure ✅ Passed The changed backend test file is named test_composio_components.py and is in the configured bundle test path. It uses pytest classes, @pytest.mark.unit, parametrization, assertions, and local mock…
Excessive Mock Usage Warning ✅ Passed PASS. The added tests do not introduce excessive mocks. They use real _is_blank_value, _drop_blank_optional_arguments, and SafeLangchainProvider.wrap_tool behavior. The fake_execute_tool callb…
Full details: Linked Issues check

Explanation

The PR satisfies issue #14715 by filtering blank optional arguments, including nested Gmail attachment fields, before tool execution while preserving required arguments. Tests cover the reported regression and helper behavior.

Full details: Test Coverage For New Implementations

Explanation

PASS: The PR adds 180 lines to the existing backend test file src/bundles/lfx-bundles/tests/test_composio_components.py. The tests cover _is_blank_value, _drop_blank_optional_arguments, optional versus required fields, non-dict inputs, and the actual SafeLangchainProvider.wrap_tool path with the issue #14715 Gmail payload. The test file follows the test_*.py convention, and the repository test configuration includes src/bundles/*/tests. The regression tests verify the new behavior rather than acting as placeholders.

Full details: Test Quality And Coverage

Explanation

Tests provide strong coverage for the new filtering behavior. The added pytest cases cover blank and non-blank scalar, collection, and nested-dictionary values; optional-field removal; preservation of required blank fields; non-dictionary inputs; and preservation of non-blank optional fields. Two regression tests exercise the real SafeLangchainProvider.wrap_tool path with the issue #14715 Gmail payload and assert the exact arguments sent to the executor. The tests use the project’s pytest and unit marker patterns. Async and API-endpoint checks are not applicable to this synchronous wrapper change.

Full details: Test File Naming And Structure

Explanation

The changed backend test file is named test_composio_components.py and is in the configured bundle test path. It uses pytest classes, @pytest.mark.unit, parametrization, assertions, and local mocks. Test names clearly describe the behavior under test. The tests are logically grouped by blank-value detection, argument filtering, and provider wiring. They cover positive cases, negative cases, required blank fields, non-dict inputs, nested blank objects, and the reported Gmail payload. No integration test was added, so integration-directory marking is not applicable. The tests use no external state, so setup or teardown fixtures are not required.

Full details: Excessive Mock Usage Warning

Explanation

PASS. The added tests do not introduce excessive mocks. They use real _is_blank_value, _drop_blank_optional_arguments, and SafeLangchainProvider.wrap_tool behavior. The fake_execute_tool callback only replaces the external Composio execution boundary and captures arguments. The existing MagicMock and patch usage predates this pull request and isolates external API calls and environment state.

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant