mirror of
https://github.com/ComposioHQ/composio.git
synced 2026-09-22 11:46:35 +08:00
@composio/cli@0.3.4-beta.351
455 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
8086ef02cb |
fix(examples): align Python and TypeScript examples with current backend (#4107)
## Summary - Repairs runnable TypeScript and Python examples for current backend requirements, including authenticated MCP endpoints, current transports, valid tool identifiers, provider limits, and resource uniqueness. - Replaces placeholder resource IDs with explicit `COMPOSIO_EXAMPLES_*` configuration and makes failed examples exit loudly. - Adds `scripts/examples-provision.mjs` as an idempotent provisioning check for a disposable examples project. ## Scope - This PR no longer changes the Python SDK runtime or generated-client dependency. - Python remains pinned to the published `composio-client==1.43.0` in `pyproject.toml`, `setup.py`, and `uv.lock`. - The owned 2.x client integration is deferred until that client completes its release guarantees and is explicitly published. - The scheduled live workflow and manifest remain deferred until their runner is tracked. ## Verification - `make chk` - `make tst` (`927 passed, 33 skipped`) - Hosted checks rerun against commit `12691aca7`. |
||
|
|
26ec42a38c |
chore(py): prepare 0.19.0 release (#4114)
This PR: - builds on top of https://github.com/ComposioHQ/composio/pull/4094 - bumps `composio` and all 12 provider distributions from `0.18.2` to `0.19.0` - keeps `python/composio/__version__.py` and `uv.lock` aligned with package metadata - documents recursive provider argument-presence preservation in the existing cross-SDK changelog - passes the release-workflow guard, Ruff, mypy, provider type inference, and 1,167 Python tests - builds and validates 26 wheel/sdist artifacts with Twine - must be retargeted to `next` after #4094 merges |
||
|
|
64fbc4ee03 | fix(py): preserve nested provider argument presence | ||
|
|
82e25a603e | Merge branch 'fix/cross-sdk-json-schema-object-conversion' into fix/python-provider-argument-serialization | ||
|
|
1af694baee | Merge branch 'next' into fix/cross-sdk-json-schema-object-conversion | ||
|
|
cec99e7a32 | test(py): run provider serialization coverage in CI | ||
|
|
5bb1e20518 |
fix(py): preserve serialized provider arguments
Co-authored-by: Aditya Chawla <aditya17.mitmpl2023@learner.manipal.edu> |
||
|
|
191d919eef | fix(python): harden dynamic schema validation | ||
|
|
c337e5696e |
chore(sdk): prepare Python 0.18.2 and TypeScript 0.15.0 releases (#4095)
Prepares the next SDK train: Python `composio` `0.18.2` and the TypeScript packages that the pending Changesets will publish (`@composio/core` and `@composio/slim` `0.15.0`, `@composio/openai` `0.11.0`, `@composio/experimental` and `@composio/json-schema-to-zod` `0.2.2`). No CLI release is part of this train. ## What this PR does - bumps Python core and all 13 provider packages to `0.18.2`, including `python/composio/__version__.py` and the root plus per-provider `uv.lock` files - adds `docs/content/changelog/08-07-26-sdk-releases.mdx`, the combined customer-facing changelog for both SDKs - documents `@composio/core` `0.15.0` in that entry so the generated release PR passes the release-workflow guard - leaves the pending Changesets untouched; the generated release PR remains responsible for npm versioning and publication ## Release sequence 1. Merge this PR. 2. Let Changesets regenerate the "Release: update version" PR, wait for it to go green, then merge it. Merging publishes the TypeScript packages. 3. Tag the resulting `next` commit `py@0.18.2` to publish the Python packages to PyPI. ## Notes - The root `uv.lock` diff carries ~28 lines of marker-annotation churn beyond the version bumps. That is the repo-pinned `uv` `0.8.19` normalising markers the committed lockfile had recorded differently; no dependency versions change. - `@composio/mastra` and the TypeScript providers are unchanged: their declared peer ranges still accept `@composio/core` `0.15.0`, so Changesets does not bump them. ## Verification - `pnpm test:release-workflow` — passes (Python package, runtime, and provider versions agree; both SDK versions documented in the changelog) - `uv run pytest tests/` in `python/` — 925 passed, 35 skipped - `uv run --package composio python -c "import composio"` — reports `0.18.2` - `bun test tests/static/` in `docs/` — 195 pass, 1 pre-existing failure (`getLLMText — version pointer`, also fails on a clean tree) - `bun run types:check` in `docs/` — MDX generation and route typegen succeed; the final `tsc` step could not run locally because `typescript-7` is absent from `docs/node_modules` |
||
|
|
3fef432dc0 | fix: fail closed on invalid dynamic schemas | ||
|
|
1f94167595 |
fix(python): walk only schema positions when checking dynamic refs
The dynamic-key reference walker descended into every nested dict, so a $ref-shaped value stored under const, default, enum, or examples was treated as a schema reference and raised while the tool was wrapped. Restrict the walk to Draft 7 schema positions. |
||
|
|
051c8c5357 |
fix(telemetry): redact secrets inside JSON payloads (#4043)
## Summary
Telemetry error text is redacted before it leaves the process, but the
key/value rule only matches when the separator follows the key name
directly:
```
\b(authorization|api[-_]?key|...|pwd)\b(\s*[:=]+\s*)(["']?)([^\s"',}&]+)\3
```
In JSON — and in a Python `dict` repr — the key's own closing quote sits
between the name and the colon, so `{"api_key": "..."}` never matches
and the value is sent verbatim. That is the shape error messages usually
carry: an API error envelope, a rejected request body echoed back, or an
f-string interpolating a config dict. Both SDKs share the pattern and
both are affected.
The fix moves the optional quote into the separator group
(`(["']?\s*[:=]+\s*)`). The key name, separator, and quoting are all
preserved in the output; only the value is replaced.
Measured with `redact_sensitive_text` / `redactSensitiveText` directly,
before and after:
| input | before | after |
|---|---|---|
| `api_key=sk-1` | redacted | redacted |
| `api_key: "sk-1"` | redacted | redacted |
| `x-api-key: sk-live-hdr` | redacted | redacted |
| `{"api_key": "sk-live-abc"}` | **leaks** | `{"api_key": "[REDACTED]"}`
|
| `{"api_key":"sk-live-abc"}` | **leaks** | redacted |
| `{"api_key" : "sk-live-abc"}` | **leaks** | redacted |
| `{"refresh_token":"rt-abc.def-123"}` | **leaks** | redacted |
| `{"x-api-key":"sk-hdr","user":"bob"}` | **leaks** | redacted,
`"user":"bob"` kept |
| `{'client_secret': 'cs-live-abc'}` | **leaks** | redacted |
| `the password field is required` | untouched | untouched |
| `no separator here "api_key" and nothing else` | untouched | untouched
|
The end-to-end path in Python is `composio/core/models/base.py:60-61`,
which passes `str(e)` and `traceback.format_exc()` through the redactor
into the telemetry `error` field. A tool failure whose message
interpolates the rejected request body — `Error executing tool: request
body was rejected: {"toolkit": "GMAIL", "arguments": {"api_key": "...",
...}}` — leaked the customer's key today.
## Changes
- `python/composio/utils/redaction.py`,
`ts/packages/core/src/telemetry/redact.ts`: allow a quote between the
key name and the separator.
- Tests on both sides for JSON, minified JSON, spaced-colon JSON, dict
repr, the realistic serialized-payload shape, key/quote preservation,
and no-false-positive cases.
- Changeset for `@composio/core`.
## Type of change
- [x] Bug fix
## How Has This Been Tested?
Node 24.13.0 / pnpm 11.8.0 / Python 3.10.20 (uv), Windows.
- `uv run pytest tests/test_redaction.py` — 13 passed. With
`redaction.py` reverted and the new tests kept, 9 of them fail; the 4
that still pass are the pre-existing test plus the three
no-false-positive controls.
- `npx vitest run test/telemetry/redact.test.ts` in `ts/packages/core` —
10 passed. With `redact.ts` reverted, the 3 new cases fail.
- Full Python suite: 913 passed, same 4 failures as on `next` unchanged
(3 are `ModuleNotFoundError: composio_langchain` from providers not
installed in my env; 1 is `test_empty_name_safe_fails_at_write_time`,
which expects `IsADirectoryError` but Windows raises `PermissionError`
when opening a directory). Collection 944 → 956, exactly the 12 tests
added.
- Full `@composio/core` vitest: 798 passed / 2 failed, byte-identical to
the unchanged baseline (794 passed / same 2 failed — both Windows
path-and-symlink cases). 11 test files fail to load in both runs because
I installed with `--ignore-scripts`; the repo's `preinstall` hook
doesn't run in my shell.
- `ruff format --check` and `ruff check` clean on the two Python files;
`prettier --write` applied to the two TypeScript files.
## Checklist
- [x] I have read the Code of Conduct and this PR adheres to it
- [x] I ran linters/tests locally and they passed
- [ ] I updated documentation as needed — no user-facing behavior change
to document
- [x] I added tests or explain why not applicable
- [x] I added a changeset if this change affects published packages
## Additional context
This is defence-in-depth, so it stays deliberately narrow: same denylist
of key names, same value character class, no new rules. Bare-prefix
secrets (`sk-...`, `ghp_...`) and PEM blocks are still not matched by
either SDK — worth a separate look, but widening the pattern is a
different risk trade-off than closing a shape the rule already intends
to cover.
|
||
|
|
4f009baa69 | fix(python): resolve nested dynamic refs from document root | ||
|
|
4a89ff112c | fix(json-schema): enforce dynamic object contracts | ||
|
|
bbeacac653 |
fix(python): preserve and police dynamic object content in schema conversion
`json_schema_to_model` and `json_schema_to_pydantic_type` now share one compiled object policy, so provider-facing Pydantic models stop silently discarding valid free-form arguments and stop ignoring `patternProperties` and explicit `additionalProperties` controls. Accepted dynamic keys are written back into `__pydantic_extra__`, which is what `LangchainProvider.wrap_tool` re-reads with `getattr`. Acceptance and rejection are asserted from the shared cross-SDK corpus, so the Python entry points cannot diverge from the TypeScript converters. |
||
|
|
5e57815af1 |
fix(json-schema): accept and preserve dynamic object content across converters
Property-less objects (`{ type: "object" }`, `properties: {}`) were being
collapsed to a strict empty object by the Zod converter and given an implicit
`additionalProperties: false` by the Effect converter, so valid free-form
payloads such as METABASE_POST_API_CARD.dataset_query were rejected at the CLI
boundary. `ToolSchema.parse` separately dropped root `patternProperties` and
rejected a schema-valued root `additionalProperties`.
Dynamic keys are now routed to exactly the schemas that apply to them, and the
shared acceptance contract lives in one checked-in corpus with byte-identical
TypeScript and Python copies.
|
||
|
|
f286ca98ac |
chore(deps): bump the uv group across 2 directories with 1 update (#4052)
Bumps the uv group with 1 update in the / directory: [cryptography](https://github.com/pyca/cryptography). Bumps the uv group with 1 update in the /python/providers/claude_agent_sdk directory: [cryptography](https://github.com/pyca/cryptography). Updates `cryptography` from 49.0.0 to 50.0.0 <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst">cryptography's changelog</a>.</em></p> <blockquote> <p>50.0.0 - 2026-07-31</p> <pre><code> * **SECURITY ISSUE**: :func:`~cryptography.hazmat.primitives.serialization.pkcs7.pkcs7_decrypt_der` and its PEM and S/MIME variants no longer expose distinguishable errors or timing when unwrapping a ``RecipientInfo``'s ``encryptedKey``, which could act as a Bleichenbacher oracle for callers that decrypt untrusted messages. A random key is now substituted on failure, as described in :rfc:`3218`. Credit to **@X1AOxiang** for reporting the issue. **CVE-2026-69247** * Deprecated Diffie-Hellman key exchange over finite fields (FFDH). Everything FFDH is deprecated, including the types in ``cryptography.hazmat.primitives.asymmetric.dh`` and loading FFDH keys or parameters with the key loading APIs. Users should migrate to a more modern key exchange algorithm. * Added ``xof()`` class methods to :class:`~cryptography.hazmat.primitives.hashes.SHAKE128` and :class:`~cryptography.hazmat.primitives.hashes.SHAKE256` for constructing algorithm instances configured for use with :class:`~cryptography.hazmat.primitives.hashes.XOFHash`. * The :mod:`X.509 verification <cryptography.x509.verification>` APIs are now considered stable and are subject to our API stability policy. * Added the :doc:`/cobblestone` recipe, an implementation of the Cobblestone-128 and Cobblestone-256 instantiations of the `C2SP chunked-encryption specification <https://c2sp.org/chunked-encryption>`_ for streaming authenticated encryption of large messages. * Parsing a Signed Certificate Timestamp list now rejects encodings that carry trailing bytes after the list or after an individual SCT, instead of silently ignoring them. * Added support for using :class:`~cryptography.x509.Name` as a field type in the :doc:`/hazmat/asn1/index` module. * Loading a public key or an EC private key now rejects DER where the ``subjectPublicKey`` (or EC ``publicKey``) ``BIT STRING`` declares a non-zero number of unused bits, instead of silently ignoring it. * Parsing a CRL entry's ``InvalidityDate`` extension now rejects a ``GeneralizedTime`` that carries fractional seconds or another non-DER form, matching the strict encoding already required for every other X.509 time field. * :func:`~cryptography.x509.ocsp.load_der_ocsp_request` and :func:`~cryptography.x509.ocsp.load_der_ocsp_response` now reject a request or response whose ``version`` field is not ``v1``, the only version defined by RFC 6960, matching the version validation already performed when loading certificates, CSRs and CRLs. * :class:`~cryptography.hazmat.primitives.hashes.XOFHash` is now supported when building against AWS-LC. * HMAC (and therefore PBKDF2-HMAC) with SHA-3 hashes is now supported when building against AWS-LC. * Diffie-Hellman (:doc:`/hazmat/primitives/asymmetric/dh`) is now supported when building against AWS-LC. </tr></table> </code></pre> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/pyca/cryptography/commit/dcb7050b807b00392fa9fe2eac7cb362fcf355cc"><code>dcb7050</code></a> Prepare for 50.0.0 release (<a href="https://redirect.github.com/pyca/cryptography/issues/15372">#15372</a>)</li> <li><a href="https://github.com/pyca/cryptography/commit/53fccd93413a8d7f07d6d8999681f27b75cffa3f"><code>53fccd9</code></a> Don't leak how PKCS#7 encryptedKey decryption failed (<a href="https://redirect.github.com/pyca/cryptography/issues/15369">#15369</a>)</li> <li><a href="https://github.com/pyca/cryptography/commit/d472f978470fbefa521b86d98b2ecccbbb4d1dd8"><code>d472f97</code></a> Add <code>from __future__ import annotations</code> to all src/ Python files (<a href="https://redirect.github.com/pyca/cryptography/issues/15371">#15371</a>)</li> <li><a href="https://github.com/pyca/cryptography/commit/908773d53829fb1466c6db364b31321c3cd8eb9a"><code>908773d</code></a> Bump downstream dependencies in CI (<a href="https://redirect.github.com/pyca/cryptography/issues/15368">#15368</a>)</li> <li><a href="https://github.com/pyca/cryptography/commit/2cc07cc948948211899bcb0cddd1fddf86e95812"><code>2cc07cc</code></a> Bump BoringSSL, OpenSSL, AWS-LC in CI (<a href="https://redirect.github.com/pyca/cryptography/issues/15367">#15367</a>)</li> <li><a href="https://github.com/pyca/cryptography/commit/c94ede9f040fa44942f7139772603419000acf66"><code>c94ede9</code></a> chore(deps): bump ruff from 0.16.0 to 0.16.1 (<a href="https://redirect.github.com/pyca/cryptography/issues/15366">#15366</a>)</li> <li><a href="https://github.com/pyca/cryptography/commit/67a8308dc9ea4cce6056e0f1438f903c208c3f35"><code>67a8308</code></a> chore(deps): bump virtualenv from 21.7.0 to 21.7.1 (<a href="https://redirect.github.com/pyca/cryptography/issues/15365">#15365</a>)</li> <li><a href="https://github.com/pyca/cryptography/commit/95018ffcdbbc510fd92fc872e3a3e80aa6e58596"><code>95018ff</code></a> Release the GIL in one-shot AEAD encrypt/decrypt (<a href="https://redirect.github.com/pyca/cryptography/issues/15361">#15361</a>)</li> <li><a href="https://github.com/pyca/cryptography/commit/6954733eaf55a0074abf88f06f7242dfca3a5d02"><code>6954733</code></a> Release the GIL during DH and DSA parameter generation (<a href="https://redirect.github.com/pyca/cryptography/issues/15364">#15364</a>)</li> <li><a href="https://github.com/pyca/cryptography/commit/6893b94c33e948f6240082461424cfb5da2dacc6"><code>6893b94</code></a> Import _serialization instead of serialization in x509/extensions (<a href="https://redirect.github.com/pyca/cryptography/issues/15363">#15363</a>)</li> <li>Additional commits viewable in <a href="https://github.com/pyca/cryptography/compare/49.0.0...50.0.0">compare view</a></li> </ul> </details> <br /> Updates `cryptography` from 49.0.0 to 50.0.0 <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst">cryptography's changelog</a>.</em></p> <blockquote> <p>50.0.0 - 2026-07-31</p> <pre><code> * **SECURITY ISSUE**: :func:`~cryptography.hazmat.primitives.serialization.pkcs7.pkcs7_decrypt_der` and its PEM and S/MIME variants no longer expose distinguishable errors or timing when unwrapping a ``RecipientInfo``'s ``encryptedKey``, which could act as a Bleichenbacher oracle for callers that decrypt untrusted messages. A random key is now substituted on failure, as described in :rfc:`3218`. Credit to **@X1AOxiang** for reporting the issue. **CVE-2026-69247** * Deprecated Diffie-Hellman key exchange over finite fields (FFDH). Everything FFDH is deprecated, including the types in ``cryptography.hazmat.primitives.asymmetric.dh`` and loading FFDH keys or parameters with the key loading APIs. Users should migrate to a more modern key exchange algorithm. * Added ``xof()`` class methods to :class:`~cryptography.hazmat.primitives.hashes.SHAKE128` and :class:`~cryptography.hazmat.primitives.hashes.SHAKE256` for constructing algorithm instances configured for use with :class:`~cryptography.hazmat.primitives.hashes.XOFHash`. * The :mod:`X.509 verification <cryptography.x509.verification>` APIs are now considered stable and are subject to our API stability policy. * Added the :doc:`/cobblestone` recipe, an implementation of the Cobblestone-128 and Cobblestone-256 instantiations of the `C2SP chunked-encryption specification <https://c2sp.org/chunked-encryption>`_ for streaming authenticated encryption of large messages. * Parsing a Signed Certificate Timestamp list now rejects encodings that carry trailing bytes after the list or after an individual SCT, instead of silently ignoring them. * Added support for using :class:`~cryptography.x509.Name` as a field type in the :doc:`/hazmat/asn1/index` module. * Loading a public key or an EC private key now rejects DER where the ``subjectPublicKey`` (or EC ``publicKey``) ``BIT STRING`` declares a non-zero number of unused bits, instead of silently ignoring it. * Parsing a CRL entry's ``InvalidityDate`` extension now rejects a ``GeneralizedTime`` that carries fractional seconds or another non-DER form, matching the strict encoding already required for every other X.509 time field. * :func:`~cryptography.x509.ocsp.load_der_ocsp_request` and :func:`~cryptography.x509.ocsp.load_der_ocsp_response` now reject a request or response whose ``version`` field is not ``v1``, the only version defined by RFC 6960, matching the version validation already performed when loading certificates, CSRs and CRLs. * :class:`~cryptography.hazmat.primitives.hashes.XOFHash` is now supported when building against AWS-LC. * HMAC (and therefore PBKDF2-HMAC) with SHA-3 hashes is now supported when building against AWS-LC. * Diffie-Hellman (:doc:`/hazmat/primitives/asymmetric/dh`) is now supported when building against AWS-LC. </tr></table> </code></pre> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/pyca/cryptography/commit/dcb7050b807b00392fa9fe2eac7cb362fcf355cc"><code>dcb7050</code></a> Prepare for 50.0.0 release (<a href="https://redirect.github.com/pyca/cryptography/issues/15372">#15372</a>)</li> <li><a href="https://github.com/pyca/cryptography/commit/53fccd93413a8d7f07d6d8999681f27b75cffa3f"><code>53fccd9</code></a> Don't leak how PKCS#7 encryptedKey decryption failed (<a href="https://redirect.github.com/pyca/cryptography/issues/15369">#15369</a>)</li> <li><a href="https://github.com/pyca/cryptography/commit/d472f978470fbefa521b86d98b2ecccbbb4d1dd8"><code>d472f97</code></a> Add <code>from __future__ import annotations</code> to all src/ Python files (<a href="https://redirect.github.com/pyca/cryptography/issues/15371">#15371</a>)</li> <li><a href="https://github.com/pyca/cryptography/commit/908773d53829fb1466c6db364b31321c3cd8eb9a"><code>908773d</code></a> Bump downstream dependencies in CI (<a href="https://redirect.github.com/pyca/cryptography/issues/15368">#15368</a>)</li> <li><a href="https://github.com/pyca/cryptography/commit/2cc07cc948948211899bcb0cddd1fddf86e95812"><code>2cc07cc</code></a> Bump BoringSSL, OpenSSL, AWS-LC in CI (<a href="https://redirect.github.com/pyca/cryptography/issues/15367">#15367</a>)</li> <li><a href="https://github.com/pyca/cryptography/commit/c94ede9f040fa44942f7139772603419000acf66"><code>c94ede9</code></a> chore(deps): bump ruff from 0.16.0 to 0.16.1 (<a href="https://redirect.github.com/pyca/cryptography/issues/15366">#15366</a>)</li> <li><a href="https://github.com/pyca/cryptography/commit/67a8308dc9ea4cce6056e0f1438f903c208c3f35"><code>67a8308</code></a> chore(deps): bump virtualenv from 21.7.0 to 21.7.1 (<a href="https://redirect.github.com/pyca/cryptography/issues/15365">#15365</a>)</li> <li><a href="https://github.com/pyca/cryptography/commit/95018ffcdbbc510fd92fc872e3a3e80aa6e58596"><code>95018ff</code></a> Release the GIL in one-shot AEAD encrypt/decrypt (<a href="https://redirect.github.com/pyca/cryptography/issues/15361">#15361</a>)</li> <li><a href="https://github.com/pyca/cryptography/commit/6954733eaf55a0074abf88f06f7242dfca3a5d02"><code>6954733</code></a> Release the GIL during DH and DSA parameter generation (<a href="https://redirect.github.com/pyca/cryptography/issues/15364">#15364</a>)</li> <li><a href="https://github.com/pyca/cryptography/commit/6893b94c33e948f6240082461424cfb5da2dacc6"><code>6893b94</code></a> Import _serialization instead of serialization in x509/extensions (<a href="https://redirect.github.com/pyca/cryptography/issues/15363">#15363</a>)</li> <li>Additional commits viewable in <a href="https://github.com/pyca/cryptography/compare/49.0.0...50.0.0">compare view</a></li> </ul> </details> <br /> Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/ComposioHQ/composio/network/alerts). </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
0ae443bece |
chore(sdk): prepare Python 0.18.1 and TypeScript 0.14.1 releases (#3988)
This PR: - prepares Python SDK core and provider packages for `0.18.1`, including runtime and lockfile metadata - adds the canonical combined changelog for Python `0.18.1` and the TypeScript releases tracked by https://github.com/ComposioHQ/composio/pull/3906 - documents `@composio/core` `0.14.1` so the generated release PR passes the release-workflow guard - refreshes `mise.lock` so the TypeScript audit workflow reaches the dependency audit - keeps the pending TypeScript Changesets untouched; the generated release PR remains responsible for npm versioning and publication - validates Python with Ruff/mypy, 944 tests, all 13 package builds, and `twine check` - validates TypeScript/docs with the full 26-task `pnpm test`, high-severity production audit, 100 docs static tests, link checks, docs typecheck, and production build |
||
|
|
a3f6b9c8f2 |
fix(py/triggers): swallow malformed chunked frame instead of tearing down subscription (#3892)
## Problem TriggerSubscription._handle_chunked_events is bound directly as a Pysher channel callback. Pysher channel dispatch has no local exception boundary, so malformed chunk frames reached websocket-client error handling and marked the realtime connection failed. The normal payload parser already skips malformed frames, but the chunked path did not. ## Fix - Validate that each decoded frame is an object with string id/chunk, integer non-boolean index, and boolean final fields. - Contain decoder, validation, and reassembly failures at the callback boundary and log only a bounded frame preview. - Clear partial state only when the frame carries a validated string id, allowing that id to be reused safely. - Preserve the valid chunk reassembly path and fix the Chunked docstring typo. ## Regression coverage Tests cover invalid JSON, non-object frames, missing fields, unhashable ids, wrong field types, unexpected decoder failures, and successful same-id reassembly immediately after a bad frame clears partial state. ## Verification - nox -s tst -- tests/test_triggers.py: 83 passed - make chk: Ruff and mypy passed --------- Signed-off-by: Checo <sergio@checo.cc> Co-authored-by: Checo <sergio@checo.cc> Co-authored-by: jkomyno <alberto@composio.dev> |
||
|
|
2a2d77a764 |
fix(py/triggers): stop() deadlock + subscribe() timeout connection leak (#3890)
Fixes #3858 (both bugs reported there). Bug 1 — TriggerSubscription.stop() deadlocks when called from a trigger callback. pysher's Connection.disconnect runs socket.close() then join(timeout) on the websocket thread, but callbacks execute on that same thread's dispatch path (_handle_event blocks on the callback's future.result()), so joining the thread from within a callback that runs on it deadlocks the whole process and _alive is never cleared, so a main thread parked in wait_forever() never exits. Fix: clear _alive synchronously (so wait_forever unblocks immediately) and run disconnect() on a daemon thread, breaking the reentrancy while still closing the socket. Bug 2 — _SubcriptionBuilder.connect() leaks a websocket thread on timeout. The deadline path raised ComposioSDKTimeoutError without calling pusher.disconnect(), so pysher's run loop kept redialing every reconnect_interval for the life of the process — one leaked thread per timed-out subscribe(), and if a leaked connection later succeeded it would authenticate and subscribe the channel of an abandoned TriggerSubscription, silently consuming events. Fix: wrap the wait loop in try/except so the timeout path tears the connection down before re-raising. Added regression tests (TestTriggerSubscriptionStop and TestSubscriptionBuilderConnectTimeout) that reproduce both failure modes offline with mocked pusher connections; all 73 tests in tests/test_triggers.py pass, ruff check + format clean. --------- Co-authored-by: Alberto Schiabel <jkomyno@users.noreply.github.com> Co-authored-by: jkomyno <alberto.schiabel@gmail.com> |
||
|
|
8cb290be35 |
fix(schema_converter): allOf containing a false member must reject every value (#3921)
### Summary
Preserves JSON Schema boolean-schema semantics throughout the Python
schema converter:
- an unsatisfiable `allOf` now propagates through nested combiners
instead of being dropped;
- impossible array items, object properties, and local definition
references remain rejecting;
- composed impossible schemas use a Pydantic type that rejects every
value, including JSON `null`;
- the existing `json_schema_to_pydantic_type(False) is None`
compatibility behavior remains unchanged.
### Problem
The original fix handled only a literal `false` directly inside one
`allOf`. Recursive filtering still interpreted the same `None` value as
both "discard this union branch" and "the whole schema is impossible."
That widened nested `allOf` schemas to `str`, removed impossible
properties/items/definitions, and allowed JSON `null` because Pydantic
treats a bare `None` annotation as `NoneType`.
### Fix
- Add a private unsatisfiable marker with Pydantic core- and JSON-schema
hooks.
- Drop that marker only from `anyOf`/`oneOf`; propagate it through
`allOf`.
- Preserve rejecting semantics for nested object properties, array
items, and local `$defs`/`definitions` references.
- Emit `{"not": {}}` from the rejecting Pydantic type.
- Correct the related empty-`allOf` and all-false-`anyOf` expectations.
### Testing
- `uv run pytest tests/test_schema_converter.py
tests/test_schema_parser.py -q` - 106 passed
- `uv run pytest -m schema -q` - 71 passed
- `make tst` - 928 passed
- `make chk` - Ruff and mypy passed across core, providers, tests, and
scripts
Regression coverage includes direct and nested `allOf`, JSON `null`,
empty arrays with impossible items, optional and required impossible
properties, local definition references, generated JSON Schema, and
shared model consumers.
### Note
#3876 adds coverage for the same function's `anyOf` handling but does
not change this `allOf` propagation path.
---------
Co-authored-by: jkomyno <alberto@composio.dev>
|
||
|
|
026c104fe8 |
fix(py): validate canonical URL targets (#3962)
This PR: - builds on top of https://github.com/ComposioHQ/composio/pull/3823 - carries forward the Requests canonicalization hardening proposed in https://github.com/ComposioHQ/composio/pull/3810 - resolves and validates the prepared hostname that Requests will actually connect to - blocks backslash parser differentials and rejects malformed ports before DNS resolution - adds focused URL-safety coverage while preserving both existing upload entry points Validation: - `uv run --frozen pytest tests/test_url_safety.py tests/test_files.py tests/test_tool_router_session_files.py -q` (177 passed) - `make chk` |
||
|
|
f016bcebb9 |
fix(mimetypes): make guess() case-insensitive on file extensions (#3899)
guess() in composio/utils/mimetypes.py looked up Path(file).suffix against the lowercase _types table without normalizing case, so uppercase suffixes like .PNG or .PDF resolved to application/octet-stream instead of the correct MIME type. Since guess() feeds the mimetype field on file uploads (core/models/_files.py), uploads from phone cameras, scanners and Windows — where uppercase extensions are common — were getting the wrong content type. The fix is a one-line normalization: Path(file).suffix.lower() before the table lookup. This aligns guess() with its sibling get_extension_from_mime_type, which is already case-insensitive, and with the stdlib mimetypes.guess_type. I updated the existing test that documented the old case-sensitive behavior to assert the case-insensitive result instead. Fixes #3857 <!-- codesmith:footer --> --- <a href="https://app.blacksmith.sh/ComposioHQ/codesmith/composio/pr/3899"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img alt="View with Codesmith" src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a> <a href="https://backend.blacksmith.sh/track/enable-autofix?expires=1787222508&installation_model_id=428187&pr_number=3899&repository=ComposioHQ%2Fcomposio&return_to=https%3A%2F%2Fgithub.com%2FComposioHQ%2Fcomposio%2Fpull%2F3899&signature=51d4b1022aa69bc47f45a7daf2e704db96c5eb2a2f267141010ca769b502a062"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img alt="Autofix with Codesmith" src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a> <sup>Need help on this PR? Tag <code>/codesmith</code> with what you need. Autofix is disabled.</sup> <!-- codesmith:autofix:disabled --> <!-- /codesmith:footer --> Signed-off-by: sergioperezcheco <checo520@outlook.com> Co-authored-by: Alberto Schiabel <jkomyno@users.noreply.github.com> Co-authored-by: jkomyno <alberto@composio.dev> |
||
|
|
d94aa32a41 |
test: add unit tests for the schema_converter boolean-schema filter (#3876)
## Description
`composio.utils.schema_converter._filter_boolean_schemas` pre-processes
JSON
Schemas before handing them to `json-schema-to-pydantic`, which doesn't
support boolean schemas (draft-06+ allows `true`/`false` as schemas). It
replaces `true` with `{}`, drops `false`, and recurses through combiner
arrays (`anyOf`/`allOf`/`oneOf`), `properties`, `items` and `$defs`. It
had no
test coverage.
This adds `python/tests/test_schema_converter.py` covering:
- `True` -> `{}` and `False` -> `None`
- non-schema values passing through unchanged
- lists dropping `False` entries, and an all-`False` list becoming
`None`
- combiner arrays dropping `False` entries, and the whole combiner being
removed when every entry is `False`
- a `False` property being dropped while siblings are kept
- plain keys being preserved
No source changes.
## Verification
`pytest python/tests/test_schema_converter.py` - 9 passed. `ruff check`
/
`ruff format` clean.
Co-authored-by: jkomyno <alberto@composio.dev>
|
||
|
|
80e09ad0f0 |
test: add unit tests for pydantic utils (none_to_omit, parse_pydantic_error) (#3784)
## Description `composio/utils/pydantic.py` had no dedicated test module. This adds `tests/test_pydantic_utils.py` covering: - `none_to_omit` converting `None` to the `omit` sentinel while passing through other values (including falsy `0`/`""`) - `parse_pydantic_error` listing missing fields, reporting type errors with the offending parameter, and handling both together No source changes. ## Verification `pytest tests/test_pydantic_utils.py` - 5 passed. `ruff check` / `ruff format --check` clean. Co-authored-by: Alberto Schiabel <jkomyno@users.noreply.github.com> |
||
|
|
503b50ab02 |
chore(deps): refresh SDK, Python, and CI dependencies (#3955)
This PR: - splits https://github.com/ComposioHQ/composio/pull/3953 in two: this PR carries every dependency and GitHub Actions bump **except** the docs site, which follows in a stacked PR - consolidates and supersedes Dependabot PRs #3915, #3916, and #3934 through #3942 - adopts TypeScript 7.0.2 for primary compilation while retaining the `@typescript/typescript6` API lane that TypeScript-ESLint still requires, following the upstream side-by-side guidance - refreshes Python core and provider dependencies, lockfiles, and the Ruff 0.16 lint configuration - updates every GitHub Action with a verified newer official release, including majors, while retaining immutable commit SHA pins and migrating setup-uv cache pruning - deletes four per-package `eslint.config.mjs` shims: under ESLint 10 the default per-file config lookup re-anchors the root config's globs into each package, so `pnpm lint` stayed green while the CLI's try/catch, `process.env` and node-builtin bans went unenforced - bounds and documents the new `brace-expansion` and `@hono/node-server` security overrides, raising the `@hono/node-server` floor to 2.0.10 to clear GHSA-9mqv-5hh9-4cgg - preserves intentional compatibility fixtures and lanes for AI SDK 6, Zod 3, TypeScript 5.8, Mastra AI SDK 5, and Python provider constraints ## Context The docs site is a separate Bun workspace with its own `bun.lock` and is not a pnpm workspace member, so the two halves share no lockfile and no build. Splitting them keeps the Fumadocs 11 migration (a breaking API change with real refactoring) reviewable on its own, independently of the mechanical version bumps here. The `brace-expansion` override deliberately spans majors: GHSA-mh99-v99m-4gvg (HIGH) is published as a single `<=5.0.7` range with no 1.x or 2.x backport, so narrowing it to the 5.x line puts `brace-expansion` 2.1.2 back under `core>minimatch>brace-expansion` and `pnpm audit --prod --audit-level=high` exits 1. Verified both ways; the trade-off it buys is recorded inline in `pnpm-workspace.yaml`. Verified on this branch standalone: `pnpm install --frozen-lockfile`, `pnpm lint`, `pnpm typecheck`, `pnpm build:packages`, `pnpm test` (963 tests, 26/26 tasks), and `pnpm audit --prod --audit-level=high`. |
||
|
|
facd40258c |
chore(py): prepare 0.18.0 release (#3825)
This PR: - builds on https://github.com/ComposioHQ/composio/pull/3823 and https://github.com/ComposioHQ/composio/pull/3824 - bumps the Python SDK and every provider package from `0.17.1` to `0.18.0` - synchronizes the runtime version and root `uv.lock` - adds the canonical July 16 changelog entry, including URL-upload and telemetry security, trigger connection-resolution behavior, provider schema fixes, and the `pyautogen` to `ag2` migration - strengthens release guards for Python workflow invocation, provider metadata, and current Python and TypeScript changelog coverage - limits provider packaging to directories containing `pyproject.toml` - makes provider cleanup, installation, and builds stop on the first failure - incorporates the merged TypeScript changelog and missing Changeset from https://github.com/ComposioHQ/composio/pull/3849 After merging, create and push the annotated `py@0.18.0` tag from the merged `next` commit. ## Validation - `pnpm test:release-workflow` - `uv lock --check` - `uv run --frozen python -c "import composio; assert composio.__version__ == \"0.18.0\""` - `pnpm exec prettier --check docs/content/changelog/07-16-26-python-sdk-018.mdx test/release-workflow.test.ts` - `cd docs && bun run test` - `cd docs && bun run lint:links` - `cd docs && bun run types:check` - `cd python && make build` - `cd python && uv tool run twine check dist/*` |
||
|
|
3b28dc756e |
fix(py): handle list-valued JSON Schema type in openapi signatures (#3822)
`_type_to_parameter` in `python/composio/utils/openapi.py` assumed a
property's
`type` was a scalar string. JSON Schema Draft 2020-12 and OpenAPI 3.1
can express
a nullable field as a list of types instead, for example
`{"type": ["string", "null"]}`. Passing that list to the scalar
membership check
raised `TypeError: unhashable type: 'list'`, which could break tool
signature
generation in providers such as `google_adk`.
## Changes
- Handle list-valued `type` definitions as unions.
- Re-run every member through `_type_to_parameter` with a copy of the
full
property schema and only `type` replaced. This preserves sibling fields
such
as an array's `items`, so `{"type": ["array", "null"], "items": ...}`
resolves
to `Optional[List[...]]`.
- Preserve scalar error behavior for invalid member types: an unknown
type in a
list raises `InvalidSchemaError` instead of silently becoming `Any`.
- Keep the existing empty-list fallback to `Any`.
- Add regression coverage for nullable arrays and scalar/list
unknown-type
parity alongside the existing list-valued type cases.
## Type of change
- [x] Bug fix
- [ ] New feature
- [ ] Refactor/Chore
- [ ] Documentation
- [ ] Breaking change
## Verification
From `python/`:
- `uv run pytest tests/test_openapi.py -q` — 18 passed.
- `make chk` — Ruff and mypy passed across the Python SDK, providers,
tests,
examples, and scripts.
## Checklist
- [x] I have read the Code of Conduct and this PR adheres to it
- [x] I ran linters/tests locally and they passed
- [ ] I updated documentation as needed (not applicable: internal
helper)
- [x] I added regression tests
- [ ] I added a changeset (not applicable: Python-only change)
---------
Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com>
Signed-off-by: jkomyno <alberto@composio.dev>
Co-authored-by: jkomyno <alberto@composio.dev>
|
||
|
|
cb84856a16 |
fix(openai-agents): preserve array item schemas (#3819)
## Summary
Prevent the Python OpenAI Agents provider from rewriting valid JSON
Schema array item definitions.
- Stop adding `"type": "string"` when an `items` schema has no direct
`type`.
- Preserve item schemas using `anyOf`, `oneOf`, `$ref`, object
constraints, or `{}`.
- Continue removing `examples`, `pattern`, and `default` as before.
- Add regression coverage for each affected schema shape.
## Problem
The provider previously added `"type": "string"` to every array `items`
object without a direct
type declaration.
That changes the meaning of valid JSON Schemas. For example:
```json
{
"anyOf": [
{ "type": "object" },
{ "type": "null" }
]
}
became:
{
"type": "string",
"anyOf": [
{ "type": "object" },
{ "type": "null" }
]
}
Because both constraints apply, valid object and null values become
impossible. This could expose
misleading tool schemas to OpenAI Agents or cause correct tool arguments
to be rejected.
## Testing
- OpenAI Agents provider tests — 6 passed
- OpenAI Agents type-inference tests — 5 passed
- Mypy passed
- Ruff lint and formatting passed
- Schema-preservation smoke test passed
Co-authored-by: GautamSharma99 <gautamsharme99067@gmail.com>
Co-authored-by: Alberto Schiabel <jkomyno@users.noreply.github.com>
|
||
|
|
1ea8ad9b3f |
docs: migrate AutoGen provider examples to ag2's LLMConfig API (#3833)
## Summary
The AutoGen provider examples still used the legacy
`llm_config={"config_list": [...]}` dict form, which ag2 0.14 (the
distribution `composio-autogen` depends on since #3729) only keeps for
backport compatibility and marks deprecated in
`LLMConfig.ensure_config`. The install command also pulled
`autogen-agentchat` (Microsoft's next-gen AutoGen package), which the
provider never imports, while the `ag2` distribution the examples
actually import from was only installed transitively.
Fixes #3831
## Changes
- `docs/content/docs/providers/autogen.mdx`: example migrated to
`LLMConfig({...})`, install line changed to `composio composio_autogen
ag2`, added `ag2` keyword and a one-line note that the provider runs on
the ag2 distribution
- `python/providers/autogen/README.md`: same quickstart and install
fixes
- `python/providers/autogen/autogen_demo.py`: same `LLMConfig` migration
`initiate_chat` is left as is: it isn't deprecated in ag2 0.14, and it's
the flow `register_tools` (caller/executor) is verified against.
## Type of change
- [ ] Bug fix
- [ ] New feature
- [ ] Refactor/Chore
- [x] Documentation
- [ ] Breaking change
## How Has This Been Tested?
- Verified in a fresh venv with the local `composio` +
`composio-autogen` packages and `ag2==0.14.0`: the updated example
constructs both agents, wraps a Composio tool via `AutogenProvider`,
registers it with `register_tools`, and executes it through the
executor's function map
- `uv run nox -s chk` (ruff + mypy): green
- `ruff format --check providers/autogen/`: clean
- Docs: `bun run build` and `bun run lint:links` from `docs/`: green
## Screenshots (if applicable)
## Checklist
- [x] I have read the Code of Conduct and this PR adheres to it
- [x] I ran linters/tests locally and they passed
- [x] I updated documentation as needed
- [ ] I added tests or explain why not applicable
- [x] I added a changeset if this change affects published packages
## Additional context
No changeset added: docs and Python-only change, no published TypeScript
package affected. No tests added: example/docs change with no runtime
code paths; the updated example was exercised manually against ag2 0.14
as described above.
---------
Co-authored-by: Alberto Schiabel <jkomyno@users.noreply.github.com>
Co-authored-by: jkomyno <alberto@composio.dev>
|
||
|
|
c4071feab4 |
fix(py): guard URL uploads and redact telemetry (#3823)
This PR: - ports the TypeScript SDK's public-network guard to Python URL file uploads - rejects non-HTTP(S), private, loopback, link-local, reserved, and mixed DNS targets before a request is made - applies the guard to both `FileUploadable.from_url()` and Tool Router session-file URL uploads - redacts URL queries, Authorization credentials, and secret-like key/value pairs before error telemetry leaves the process - adds focused SSRF and redaction regressions alongside the existing file-upload coverage Validation: - `uv run --frozen pytest tests/test_url_safety.py tests/test_redaction.py tests/test_files.py -q` - `uv run --frozen ruff check …` - `uv run --frozen ruff format --check …` |
||
|
|
3a5e62feb4 |
fix(py): support list-valued schema types in tool signatures (#3815)
This PR: - builds on top of https://github.com/ComposioHQ/composio/pull/3754 - normalizes list-valued JSON Schema `type` fields before scalar type lookups - applies the handling to direct fields and `anyOf`/`oneOf` options - adds regressions for nullable, single, mixed, unknown, and combiner-nested type lists - credits @anxkhn as a Git co-author ## Context JSON Schema Draft 2020-12 and OpenAPI 3.1 allow `type` to be an array. The previous parser passed that list to a dictionary lookup, raising `TypeError: unhashable type: 'list'`. This replacement covers the direct case from #3754 and the same shape nested in a combiner. --------- Co-authored-by: Anas Khan <83116240+anxkhn@users.noreply.github.com> |
||
|
|
edd0bf0479 |
docs: centralize SDK release notes (#3814)
This PR: - Adds public docs changelog entries for the Python and TypeScript SDK releases since May 15, 2026, including the previously unmigrated Python 0.13.1 entry. - Removes the Python-local changelog and replaces it with canonical changelog links from the repository and Python READMEs. - Retargets the Python release guard to the docs changelog, documents its table contract, and covers prior-version plus PEP 440 version parsing. Validation: - pnpm test:release-workflow - docs: bun run test - docs: bun run lint:links - docs: bun run types:check - docs: bun run build - pnpm exec prettier --check test/release-workflow.test.ts docs/agent-guidance/guides/changelog.md docs/content/changelog/*.mdx Review: - ce-code-review completed with correctness, testing, maintainability, project-standards, agent-native, learnings, and adversarial passes. All actionable findings were fixed; final adversarial re-review found no remaining P0-P2 issue. |
||
|
|
d5a37efb85 |
fix(python): handle title-less top-level schemas (#3325)
## Summary Fixes `json_schema_to_model` when a top-level JSON schema omits `title` or sets it to `null`. This is the remaining direct-helper path; anonymous nested objects from #2435 are already handled by `schema_converter.py`. - falls back to `GeneratedModel` only when the title is `None`, preserving intentionally empty string titles - adds regression coverage for missing, `null`, and empty titles, model construction, and required-field validation ## Validation - `ruff format --check python/composio/utils/shared.py python/tests/test_schema_parser.py` - `ruff check python/composio/utils/shared.py python/tests/test_schema_parser.py` - `PYTHONPATH="$PWD/python" /Users/jkomyno/work/composio/composio2/.venv/bin/pytest -q python/tests/test_schema_parser.py` This is a follow-up to #2435; it intentionally does not close that already-resolved issue. Co-authored-by: jkomyno <alberto@composio.dev> Co-authored-by: Alberto Schiabel <jkomyno@users.noreply.github.com> |
||
|
|
a13c883845 |
docs: package-manager picker for install commands (#3802)
## What Two changes to the docs install experience: **1. Package-manager picker on install code blocks.** New `PackageInstall` client component (`docs/components/package-install.tsx`): the code block's copy button opens a dropdown of package managers. Selecting one rewrites the displayed command and copies it to the clipboard. - TypeScript blocks: npm (default, `npm install`) / pnpm / bun / yarn (`<pm> add`) - Python blocks: uv (default, `uv add`) / pip (`pip install`) - The menu is portaled to `document.body` so it isn't clipped by the `Tabs`/`CodeBlock` overflow containers, and closes on outside click, Escape, or real scroll movement. **2. `@composio/slim` callout in the quickstart.** The quickstart TypeScript install blocks carry display-only `#` comment lines noting that `@composio/core` ships its docs and TypeScript source in the package (inspectable to coding agents) and that `@composio/slim` is the smaller install with the same API. Comment lines are rendered muted and are **never copied** — the picker copies only the command. ## Where Converted every plain `npm install` / `pip install` code block under `docs/content` (quickstart, all provider pages, single-toolkit MCP, custom tools, migration guides, standup example, SDK reference indexes). The TS reference index's manual npm/pnpm/yarn/bun tabs collapse into one picker. The two SDK-reference generators (`ts/packages/core/scripts/generate-docs.ts`, `python/scripts/generate-docs.py`) emit the new component so regeneration keeps it. Flagged upgrade commands (`pip install -U/--upgrade`) and the bun-first examples were left as-is. ## Verification - `bun run types:check` — pass - `bun run build` — pass - `eslint` on touched TS files — clean (remaining repo lint errors are pre-existing on `next`) - Visual check via dev server + browser: comment lines render muted below the command, picker opens npm/pnpm/bun/yarn (uv/pip on Python tabs), selecting a manager rewrites the command, and the clipboard receives exactly the command with no comment lines. Docs-only behavior change; no changeset (generator-script edits don't touch published code). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
caef908075 |
docs: refresh README(s) (#3801)
## Summary Rewrites the stale root `README.md` against the current docs (structure modeled on [earendil-works/pi](https://github.com/earendil-works/pi)'s README). - **Quickstarts** now use the session-based API (`composio.create()` → `session.tools()`) that the docs treat as canonical, replacing the legacy `composio.tools.get()` flow - **Positioning** matches the docs welcome page: 1000+ pre-authenticated toolkits, per-user sessions, auth, triggers, and a sandbox - **New sections**: CLI install (curl / Homebrew / npm), sessions-via-MCP note, repository layout, minimum runtime versions - **Provider table** merged with package links; adds the Claude Agent SDK providers (both SDKs) and the experimental Pi provider (`@composio/experimental`); documents the Python `composio-gemini`/`composio-google`/`composio-google-adk` split - **Removed**: Rube section (no longer in docs), cover banner (replaced with theme-adaptive brand logomark from brand.composio.dev), master-branch pointer, internal OpenAPI-pull section, private `@composio/ts-builders` listing Docs-only change — no changeset needed. ## Preview Rendered view: [README.md on this branch](https://github.com/ComposioHQ/composio/blob/docs/refresh-root-readme/README.md) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
15a03c10fb |
ci: add dead-code detection (knip + vulture + orphaned-CI check) (#3787)
## What Adds a **report-only** `Dead Code` CI workflow that surfaces likely-orphaned code on every PR, across all three surfaces — TypeScript, Python, and GitHub Actions. Follow-up to the root `Dockerfile` cleanup (#3783) and the dead-code sweep in #3786: instead of finding this stuff by hand, catch it automatically. | Surface | Tool | Wiring | |---|---|---| | TypeScript | [**knip**](https://knip.dev) | `knip.json`; runs via `pnpm dlx knip@5`. Finds unused files, exports, types, and dependencies. | | Python | [**vulture**](https://github.com/jendrikseipp/vulture) | `dead_code` nox session + `make dead-code`; allowlist at `python/config/vulture_allowlist.py`. Finds unused functions/classes/variables (complements Ruff's F401/F841). | | GitHub Actions | small bash script | `.github/scripts/check-orphan-ci.sh` — flags reusable workflows and composite actions with no callers. | ## Why report-only (not blocking) Every job writes findings to the run's **Step Summary** and **never fails the build**. These tools carry unavoidable false positives on a library monorepo — public API surface, dynamic imports, import-map targets (e.g. core's `#platform`), framework entry points. A red ❌ on false positives would just train everyone to ignore the check. Once a job's config is refined enough that a clean run is the steady state, it can be flipped to blocking. ## Validation (ran each locally) - **knip**: 0 unused *files* after scoping out the e2e-test workspaces (knip crashes traversing `ts/e2e-tests/**` — pre-existing knip bug, filed via `ignoreWorkspaces`) and build/docs artifacts. Export/dep categories surface advisory items. - **vulture**: clean run (report-only); allowlist suppresses the 3 `TYPE_CHECKING` re-exports in `custom_tool.py`; `build/`/`dist/` excluded. Surfaces 4 genuine minor items (`bases`, `desc`×3). - **orphan-CI script**: finds none — the repo has no orphaned CI plumbing today. - **Pinning**: `jk actions check` clean for this workflow; `actions/checkout` is SHA-pinned, the two local composite actions need no pin. Local usage is documented under **Dead code detection** in `CONTRIBUTING.md`. ## Note on scope These cover TS/Python/GHA — they would *not* have caught the root `Dockerfile` itself (an arbitrary root file no tool tracks). That class stays a manual-review concern; the orphan-CI script is the closest analogue for the CI surface. |
||
|
|
3e37f3c7a4 |
test: add unit tests for the mimetypes utility (#3750)
## Summary `composio/utils/mimetypes.py` had no test coverage. This adds a suite for both of its public helpers: **`guess()`** (filename/extension → MIME type): - known extensions resolve correctly (json, html, png, mp4, …) - the lookup table is lower-case, so an upper-case suffix (`photo.PNG`) falls back to the default - unknown / missing extensions return `application/octet-stream` - only the final suffix is used (`archive.tar.gz` == `archive.gz`) - `Path` objects are accepted, not just strings **`get_extension_from_mime_type()`** (MIME type → extension): - direct mappings (`image/png` → `png`, `application/vnd.ms-excel` → `xls`, …) - parameters are stripped (`text/plain; charset=utf-8` → `txt`) and matching is case-insensitive - structured `+suffix` handling: known prefixes win (`application/atom+xml` → `atom`), otherwise the suffix is used (`application/vnd.api+json` → `json`, `application/foo+bar` → `bar`) - subtype fallback (`application/x-custom` → `x-custom`), empty subtype → `txt`, and malformed/empty input → `bin` Tests only — no library code changed. `pytest python/tests/test_mimetypes.py` passes (`32 passed`); `ruff check` / `ruff format --check` are clean. Co-authored-by: Alberto Schiabel <jkomyno@users.noreply.github.com> |
||
|
|
fc17c37bf9 |
fix(cli): enforce sensitive-file upload denylist (GHSA-hp3h-89pf-5q58) (#3763)
This PR: - fixes #3746 / GHSA-hp3h-89pf-5q58 — the CLI's tool file-upload path bypassed the sensitive-file denylist - **root cause:** the denylist was enforced at the *caller* layer, so `@composio/cli`'s duplicate upload path (`readFileFromDisk`) read and uploaded any local path a tool argument pointed at — `~/.ssh/id_rsa`, `~/.aws/credentials`, `.env`, etc. — enabling credential exfiltration via `composio execute` / `composio run` (incl. LLM-driven agents hit by prompt injection) - **unified fix:** one canonical guard, exported from `@composio/core` and enforced at the read primitive in every SDK - `core`: the guard now routes fs/path access through the internal `#platform` abstraction (adds a `realpathSync` method), so it carries **no static `node:*` imports** and is exported from the package root: `assertSafeFileUploadPath`, `isBlockedSensitiveFileUploadPath`, `BUILTIN_FILE_UPLOAD_PATH_DENY_SEGMENTS` - `cli`: `readFileFromDisk` calls the shared `assertSafeFileUploadPath` before `fs.readFile`; URLs and `File` objects are unaffected (matches core) - `python`: already routes all uploads through the guarded `FileUploadable.from_path` — no functional change; adds regression tests for parity - supersedes #3755, which exported the then-node-only guard from core's **main** `index.ts` and would have injected `node:fs` into the shared `dist/index.mjs` (the workerd/edge-light entry), likely breaking Cloudflare Workers / Vercel Edge - changesets: `@composio/core` minor (new public exports), `@composio/cli` patch (security fix) ## Verification - core: full suite passes (997), incl. new root-export + realpath-symlink cases - **edge bundle stays clean**: built `dist/index.mjs` has no static `node:*` imports and reaches the platform only via `#platform` - cli: new regression test drives the real `uploadToolInputFiles → readFileFromDisk → guard` chain — `~/.ssh/id_rsa` and `.env` throw `ComposioSensitiveFilePathBlockedError` before any `createPresignedURL` call; a normal file still uploads - python: `test_files.py` + sensitive-path suite pass (145), incl. 3 new `from_path` guard tests - `tsgo` typecheck + eslint clean for core and cli |
||
|
|
820abb9072 |
fix(sdk): resolve toolkit versions case-insensitively in both SDKs (#3762)
## Summary
Toolkit version maps are keyed by **normalized (lowercase) slugs** on
the *write* side — env vars (`COMPOSIO_TOOLKIT_VERSION_*`) and
user-supplied dicts both get their keys lowercased when the map is
built. But the *lookup* read the map with the **raw slug**. A pin
configured under a different casing (e.g. `{ "GitHub": "20250101_00" }`
or `COMPOSIO_TOOLKIT_VERSION_GITHUB` looked up as `GitHub`) therefore
missed the map and silently fell back to `"latest"`, which
`Tools.execute` then rejects with a version-required error — discarding
the user's explicit pin.
Rather than patch only the read side, this **centralizes the
normalization rule** into a single helper per SDK and routes **both**
the map-building (write) and lookup (read) paths through it, so the two
sides can never drift apart again:
- **Python** — `normalize_toolkit_slug()` in
`python/composio/utils/toolkit_version.py`
- **TypeScript** — `normalizeToolkitSlug()` in
`ts/packages/core/src/utils/toolkitVersion.ts`, imported by
`getToolkitVersionsFromEnv` in `sdk.ts`
Behavior is now identical across the two SDKs. This **supersedes
#3759**, which patched only the Python read side and left TS diverging.
## Backend verification
Confirmed against the backend (staging, **1403 toolkits across 15
pages**): every toolkit `slug` is already lowercase (the mixed-case
`name` field is display-only). So the *primary* execute path — which
resolves via `tool.toolkit.slug` — was never broken in practice. This
change:
- **hardens** the direct-util and mixed-case-config paths (a user
passing `{ "GitHub": "…" }` now resolves as expected), and
- **removes a latent cross-SDK divergence**: the TS suite previously
asserted `getToolkitVersion` was *case-sensitive* (`versions.test.ts`),
locking in the bug for an input the production code path can't actually
produce. That test is flipped to assert case-insensitive resolution.
## Tests
- **Python** (`python/tests/test_toolkit_version.py`): case-insensitive
lookup via `get_toolkit_versions` round-trip, and against a raw
pre-normalized map. `18 passed`.
- **TypeScript** (`ts/packages/core/test/core/versions.test.ts`):
replaced the case-sensitivity assertion with case-insensitive resolution
+ a write→read round-trip of a mixed-case user pin. Full core suite `997
passed`.
- Typecheck (`tsc --noEmit`) clean; `ruff` clean.
## Notes
- Changeset added: `@composio/core` patch.
- No public API change; the fix is behavioral (case-insensitive) plus an
internal shared helper.
|
||
|
|
58bc93b2d9 |
chore(deps): consolidate dependency updates (#3760)
This PR: - consolidates https://github.com/ComposioHQ/composio/pull/3733, https://github.com/ComposioHQ/composio/pull/3735 through https://github.com/ComposioHQ/composio/pull/3744, and https://github.com/ComposioHQ/composio/pull/3752 - refreshes the pnpm workspace dependencies under the existing `minimumReleaseAge` supply-chain gate - keeps latest compatible pins for ESLint 9, AI SDK 6, and Cloudflare workers types 4 where latest majors conflict with the current workspace - keeps zod-v3 runtime fixtures on `zod@3.25.76` while bumping the workspace catalog to zod 4 - bumps Python `composio-client` to `1.42.0` and refreshes `uv.lock` - updates the SHA-pinned Claude and Codex workflow actions from the Dependabot action group - adds a patch changeset for the versioned package manifests touched by dependency updates - verifies the rollup with frozen pnpm/uv locks, peer checks, audit threshold checks, typecheck, lint, builds, TypeScript tests, and Python `nox -s chk` ## Context `pnpm audit --prod --audit-level=moderate` passes. The remaining production audit item is a low `@ai-sdk/provider-utils` advisory through Mastra transitive dependencies; forcing it higher would require leaving the compatible stable Mastra dependency path. |
||
|
|
2e42d75259 |
fix(py): apply skip_default to agentic provider signatures (langchain, langgraph, autogen) (#3730)
## Summary
Agentic providers honor `schema_config={"skip_defaults": True}` for
`args_schema` (defaults stripped, fields become required) but were
**not** applying the same `skip_default` to the function
`__signature__`, so the wrapped tool's signature and `args_schema`
disagreed about which defaulted params were optional. The sibling
`llamaindex` provider already passed it to both.
**Supersedes #3727.** This is the polished version, now that the ag2
migration (#3729) landed and `composio-autogen` imports again — so the
autogen case uses a real import instead of the earlier source-load stub,
and the parity tests run in CI.
## Changes
- **langchain / langgraph** (original commit by @anxkhn): pass
`skip_default=self.skip_default` to
`get_signature_format_from_schema_params`.
- **autogen**: same one-line alignment. autogen builds **only**
`__signature__` (no `args_schema`), so it never had the *mismatch* — but
its signature still ignored `skip_defaults`. Aligned for consistency;
verified on the signature alone.
- **tests**: `TestAgenticSkipDefaultsParity` guards each provider with
`pytest.importorskip`; adds real-import autogen regression tests (no
stub).
- **CI + nox**: install `providers/autogen` in the unit-test job
(`py.test.yml`) and the nox `tst` session so the autogen parity tests
actually run, plus a **hard `import composio_autogen` smoke check** in
CI.
## Why the CI import guard (not just the tests)
The `importorskip`-guarded unit tests **skip** when a provider can't be
imported — which is the correct behavior for optional providers, but
means they'd *silently skip* if autogen broke on a fresh install
(exactly the failure that #3729 just fixed). The extra `python -c
"import composio_autogen"` in the import step is a **hard** check that
fails loudly, so a future dependency breakage can't slip through as a
green build.
`providers/langchain` + `providers/autogen` co-install cleanly
(verified: 59 packages, ag2 0.14.0, no conflict). langgraph continues to
skip in CI — its code path is identical to langchain's, which runs.
## Type of change
- [x] Bug fix
## How Has This Been Tested?
- Base venv (langchain only): langchain parity **passes**, langgraph +
autogen **skip** (no error).
- CI-mirror (langchain + autogen, editable): **4 passed, 2 skipped
(langgraph)** — autogen tests actually run and pass.
- Regression proof, each provider: reverting only the provider line
fails the skip-defaults case with `assert 5 is Parameter.empty`;
restoring passes. Verified for langchain **and** autogen.
- `ruff check`, `ruff format --check`, `mypy`, and full
`tests/test_provider.py` (29 passed, 4 skipped) → clean. `py.test.yml`
parses.
## Checklist
- [x] I ran linters/tests locally and they passed
- [x] I added tests: langchain/langgraph parity + regression, and
autogen parity that runs in CI
- [ ] Changeset: not applicable — Python-only change.
## Credits
Original fix by @anxkhn (#3713 → #3727), preserved as the first commit
and co-authored on the follow-up.
---------
Co-authored-by: Anas Khan <83116240+anxkhn@users.noreply.github.com>
|
||
|
|
5ac2de2431 |
fix(py): migrate composio-autogen off abandoned pyautogen to ag2 (#3729)
## Summary `composio-autogen` fails to import on a fresh install: the provider depended on the abandoned `pyautogen` distribution, whose latest release (`0.10.0`) ships **no top-level `autogen` module**. The pin `pyautogen>=0.2.19,<0.11` resolves straight to it, so `import composio_autogen` raises `ModuleNotFoundError: No module named 'autogen'`. The autogen 0.2 lineage moved to the **`ag2`** distribution (`0.14.x`), which provides the same `autogen` package the provider uses (`ConversableAgent`, `autogen.agentchat.register_function`) alongside `autogen-core`. This swaps the dependency. Closes #3728. ## Changes - `providers/autogen/pyproject.toml` and `providers/autogen/setup.py`: `pyautogen>=0.2.19,<0.11` → `ag2>=0.14,<1.0`. `flaml` and `autogen_core` unchanged. **No provider code changes** — the imports and runtime API are identical across the two distributions. ## Type of change - [x] Bug fix ## How Has This Been Tested? Verified in isolation via `uv run --with ./providers/autogen` (a real fresh install of the provider with its new deps → resolves `ag2 0.14.0`): 1. **Import** — `import composio_autogen` now succeeds (previously `ModuleNotFoundError`). 2. **`wrap_tool`** — returns a real `autogen_core.tools.FunctionTool` with the expected signature. 3. **`register_tools` → `autogen.agentchat.register_function`** — the AG2 runtime path works end to end: - caller (LLM side): `caller.llm_config.tools` advertises the tool, - executor (execution side): the function lands in `executor._function_map`. `flaml==2.6.0` + `autogen-core==0.7.5` resolve cleanly alongside `ag2 0.14` (no conflict). ## Notes / follow-up This class of bug (a provider silently un-importable on fresh install) slipped through because **CI never installs or imports the autogen provider** — the unit-test job only installs `providers/langchain`. Worth a small follow-up: add a fresh-install import smoke test for the agentic providers so this can't recur silently. Left out here to keep this PR to the dependency fix and avoid adding ag2's install weight to the main test matrix. ## Checklist - [x] I ran the migration verification locally (isolation) and it passed - [ ] Changeset: not applicable — Python-only change. |
||
|
|
e78ed312c6 |
fix(core): run all parallel OpenAI tool calls from the first choice (#3726)
This PR: - supersedes https://github.com/ComposioHQ/composio/pull/3712, preserving the original commits by @serhiizghama (kept as author/co-author) - fixes `OpenAIProvider.handleToolCalls` to execute **every** tool call in an assistant message — it previously only read `tool_calls[0]`, so parallel tool calls (on by default) were dropped and their `tool_call_id`s went unanswered, failing the next request with the "must be followed by tool messages responding to each `tool_call_id`" error - limits execution to the **first choice** — with `n > 1` the previous loop ran each tool call once per choice and orphaned the `tool_call_id`s belonging to the alternative completions - aligns the Python SDK (`OpenAIProvider.handle_tool_calls`) with the same first-choice behavior so both SDKs stay in parity - fixes the stale `@composio/openai` test that modeled "multiple tool calls" as separate `n` choices rather than one message's `tool_calls` array - clarifies in the changeset that the calls run **sequentially**, in the order the model returned them (here "parallel" means the model issued several calls in one turn, not concurrent execution), so each `tool_call_id` is answered exactly once and deterministically - adds regression tests (TS + Python): both calls run for parallel tool calls in one message, and only the first choice runs when `n > 1` Full `@composio/core` (996) and `@composio/openai` suites green; Python `handle_tool_calls` tests, Ruff, and mypy clean; `tsc` clean. --------- Co-authored-by: serhiizghama <zmrser@gmail.com> |
||
|
|
a69c3edea3 |
fix(triggers): align create() user_id resolution across SDKs (#3723)
This PR: - builds on top of https://github.com/ComposioHQ/composio/pull/3714 — addresses its code-review findings - restores TS/Python parity on slug validation: Python `create()` now validates the slug up-front and raises a new `TriggerTypeNotFound`, mirroring the TS `ComposioTriggerTypeNotFoundError` - switches both SDKs to the native `user_id` upsert field — TS drops the `& { user_id }` intersection and Python drops the `extra_body` shim (both pinned clients already expose the field) - treats a blank/whitespace `userId` (TS) or `user_id`/`connected_account_id` (Python) as missing instead of forwarding it to the backend - documents the error-contract change (`create()` no longer throws `ComposioConnectedAccountNotFoundError` — that case now surfaces from the backend) in the changeset and `ts/docs/api/triggers.md`, and bumps the changeset from `patch` to `minor` - adds Python tests for the 2FA (both-provided) path, unknown-slug, and blank `userId`; tightens the TS auto-resolve assertion and adds an empty-`userId` case ## ⚠️ Release gating Since #3714, `triggers.create()` (both SDKs) relies on the backend resolving the trigger connection from `user_id` on upsert ([ComposioHQ/platform#10932](https://github.com/ComposioHQ/platform/pull/10932)). There is **no client-side fallback** — reintroducing one would undo #3714's intent, so this is a release-sequencing requirement, not a code change here. - Do not release `@composio/core` or the Python SDK until #10932 is live in all regions. - Self-hosted / on-prem deployments must be on a backend version that includes #10932. ## Review findings addressed | # | Finding | Resolution | |---|---------|------------| | P1-1 | Coupled to unreleased backend, no fallback | Documented dependency in changeset; flagged release-gating above (no fallback by design) | | P2-2 | Cross-SDK parity on slug validation | Kept `getType` in both; added Python `TriggerTypeNotFound` mirroring TS | | P2-3 | `user_id` bridge redundant in both SDKs | TS uses native field directly; Python uses `user_id=` kwarg | | P2-4 | Error-contract change shipped silently | Documented in changeset + docs `Throws` section; `minor` bump | | P2-5 | Python missing 2FA (both-provided) test | Added `test_create_with_user_id_and_connected_account_id` | | P3 6–13 | Cleanups | undefined-assertion, `none_to_omit`, docstring, `parsedBody.data`, redundant `else`, stale comments, blank-string guard | ## Verification - TS: `vitest` 59 passed, `typecheck` clean, `eslint`/`prettier` clean - Python: `pytest tests/test_triggers.py` 69 passed, `nox -s chk` (ruff + mypy) clean |
||
|
|
c660007c71 |
fix(py): handle typeless and empty combiner schemas in openapi signatures (#3710)
### Summary
`function_signature_from_jsonschema` in
`python/composio/utils/openapi.py` builds the `__signature__` for tools
wrapped by the `google_adk` provider
(`providers/google_adk/composio_google_adk/provider.py:66`). It already
falls back to `Any` for a top-level property with no `type`, but the
nested combiner helpers do not, so real combiner shapes crash at wrap
time:
- a `oneOf`/`anyOf` option with no `type` key -> `KeyError: 'type'`
- an empty `oneOf`/`anyOf` list -> `TypeError: Cannot take a Union of no
types`
- an empty `allOf` list -> `KeyError: 'type'` (merges to `{}`)
This extends the existing "default to Any" intent to nested options.
Follow-up to #3708, which fixed the same bug family in `shared.py` and
noted this `openapi.py` case for a separate PR.
Fixes #
### Changes
- `_type_to_parameter`: read `schema.get("type")` instead of
`schema["type"]`; when the type is missing, return `t.Any` (mirrors the
top-level fallback). An unknown *string* type still raises
`InvalidSchemaError`.
- `_handle_composite_type`: return `t.Any` for an empty option list
instead of building an empty `Union`. Empty `allOf` merges to `{}` and
resolves to `Any` via the above.
- New `python/tests/test_openapi.py` (11 tests): this builder had none.
Asserts the five former crashes now resolve to `Any`, and that existing
shapes are unchanged.
### Type of change
- [x] Bug fix
- [ ] New feature
- [ ] Refactor/Chore
- [ ] Documentation
- [ ] Breaking change
### How Has This Been Tested?
From `python/`:
```
uv run pytest tests/test_openapi.py -q # 11 passed
make chk # ruff + mypy -> clean
```
To confirm the tests guard the fix, the five former crashes (typeless
`anyOf`/`oneOf` option, empty `anyOf`/`oneOf`/`allOf`) raise on the
unmodified file and now resolve to `Any`; regressions cover
`anyOf:[str,null]` -> `Optional[str]`, a 4-member union, enum, array,
object, and a typeless property.
### Checklist
- [x] I have read the Code of Conduct and this PR adheres to it
- [x] I ran linters/tests locally and they passed
- [ ] I updated documentation as needed (internal util)
- [x] I added tests (new test_openapi.py)
- [ ] I added a changeset (Python-only, not needed)
Co-authored-by: Alberto Schiabel <jkomyno@users.noreply.github.com>
|
||
|
|
b0ab8eacff |
fix(py): handle 4+ option and typeless anyOf/oneOf unions in tool signatures (#3708)
## Summary
`get_signature_format_from_schema_params` in
`python/composio/utils/shared.py` builds the `__signature__` for the
tool wrappers used by the langchain, langgraph, llamaindex, and autogen
providers. Its `oneOf`/`anyOf` handling hardcoded a ladder for exactly
1, 2, or 3 union members and raised `ValueError("Invalid 'oneOf'
schema")` for any union with four or more options. It also indexed
`PYDANTIC_TYPE_TO_PYTHON_TYPE[ptype.get("type")]` directly, so any
combiner option missing a `type` key produced `None` and raised
`KeyError(None)`.
Both shapes are valid JSON Schema and appear in real tool input schemas,
so a tool with a 4-way union, or a combiner option without an explicit
`type`, makes those four providers raise at tool-wrap time. This
replaces the ladder with a single map + `functools.reduce` path that
mirrors the existing `_build_union_from_options` in
`schema_converter.py`, keeping the 1/2/3-member and nullable `[type,
null]` outputs identical to before.
Fixes #
## Changes
- `python/composio/utils/shared.py`: in
`get_signature_format_from_schema_params`, replace the 1/2/3-member
`oneOf`/`anyOf` ladder (which raised `ValueError` for 4+ members) with a
map-each-option-to-a-Python-type + `functools.reduce` Union build that
supports any member count. Unknown/missing option types map to
`typing.Any` instead of raising `KeyError`. Adds `from functools import
reduce` and removes three now-unnecessary `# type: ignore` comments.
- `python/tests/test_schema_parser.py`: add
`TestGetSignatureFormatFromSchemaParams` (8 cases) covering 4- and
5-member unions, an `anyOf` option missing `type`, an all-typeless
`anyOf`, and regressions for the previously supported single/2/3-member
and nullable `[type, null]` shapes.
## Type of change
- [x] Bug fix
- [ ] New feature
- [ ] Refactor/Chore
- [ ] Documentation
- [ ] Breaking change
## How Has This Been Tested?
From `python/`:
```
uv run pytest tests/test_schema_parser.py::TestGetSignatureFormatFromSchemaParams -v # 8 passed
uv run pytest tests/test_schema_parser.py -q # 75 passed
make chk # ruff + mypy -> clean, no new ignores
```
To confirm the tests guard the fix, the new test class was also run
against the unmodified `shared.py`: 4 of the 8 fail there
(`ValueError`/`KeyError` on the 4+/typeless cases), and all 8 pass with
this change. The nullable `anyOf [type, null]` case still resolves to
`Union[str, Any, NoneType]` (its pre-existing behavior); collapsing
`null` into `Optional` lives in `schema_converter` and is intentionally
left out of this minimal fix, with the test documenting current
behavior.
## Screenshots (if applicable)
N/A
## Checklist
- [x] I have read the Code of Conduct and this PR adheres to it
- [x] I ran linters/tests locally and they passed
- [ ] I updated documentation as needed
- [x] I added tests or explain why not applicable
- [ ] I added a changeset if this change affects published packages
## Additional context
No linked issue: this is a self-identified, reproduced bug in the older
schema->signature path. The fix deliberately mirrors
`schema_converter._build_union_from_options` so the two schema paths
agree on N-ary union handling. The same bug family exists in
`python/composio/utils/openapi.py`
(`function_signature_from_jsonschema`, used by the google_adk provider)
but is kept out of this PR to stay single-purpose; happy to follow up on
it separately.
|
||
|
|
20a4711ee0 |
feat(triggers): resolve connection from user_id server-side in create() (#3714)
## What `triggers.create()` used to make an extra **`connectedAccounts.list()`** call to turn a `user_id` into a `connected_account_id` before calling upsert. The backend now resolves the connection from `user_id` directly (picks the first active connection for the user + the trigger's toolkit, parity with tool execution), so the SDK passes `user_id` straight through and drops the round-trip. - **TS** (`ts/packages/core`): removed the `connectedAccounts.list()` block in `Triggers.create()`. `user_id` was already forwarded to upsert (for 2FA); this just removes the now-redundant lookup. `getType` is kept for an early, clear "trigger type not found" error. `connected_account_id` is passed when the caller pins one. - **Python** (`python/composio`): dropped `_get_connected_account_for_user`; `user_id` is sent via `extra_body` and `connected_account_id` is omitted when not provided. ## Why The SDK only ever holds a `user_id`, so every `triggers.create()` paid an extra API call to find a connection. The backend change (ComposioHQ/platform#10932) makes trigger upsert accept `user_id` and auto-resolve — this PR consumes that. ## Behavior notes - When `connected_account_id` is omitted, the backend picks the first active connection ordered by `created_at desc`. The TS SDK's old `list()[0]` ordering was unspecified — selection is now deterministic and consistent with tool execution. - "No connected account found" / "connected account not found" now surface from the **backend** instead of a client-side pre-check. - When 2FA is enabled and `connected_account_id` is pinned, the backend validates that `user_id` owns it (unchanged; `user_id` was already forwarded). - The `extra_body` / `& { user_id }` bridges are still needed only until `@composio/client` / `composio_client` regenerate with `user_id` on the upsert type (the field is already in the OpenAPI contract). ## Tests - TS: `vitest run test/models/triggers.test.ts` → **58 passed** (create tests rewritten to assert no `connectedAccounts.list()` call + `user_id` forwarded). - Python: `pytest tests/test_triggers.py` → **66 passed** (same). ## Depends on Backend: ComposioHQ/platform#10932 (`feat(apollo): resolve trigger connection from user_id on upsert (PLEN-2580)`). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
03cb181fdb |
chore(deps): roll up dependency bumps (#3711)
This PR: - rolls up https://github.com/ComposioHQ/composio/pull/3695, https://github.com/ComposioHQ/composio/pull/3696, https://github.com/ComposioHQ/composio/pull/3697, and https://github.com/ComposioHQ/composio/pull/3698 into one dependency-bump branch - updates Python dependency metadata for `langchain-openai`, `pyautogen`, and `crewai` - updates npm production dependency metadata for `zod-to-json-schema`, `openai`, and `@modelcontextprotocol/sdk` - refreshes `uv.lock` and `pnpm-lock.yaml` with the repo-pinned package managers - leaves Changesets unchanged because the touched TS package manifests are private/ignored and no published TS SDK package metadata changes - verified with `pnpm install --frozen-lockfile`, `pnpm lint`, `pnpm typecheck`, focused TS builds/tests, clean-worktree `pnpm test:examples`, Python import tests, and Python nox checks - note: local `pnpm build:packages` hit a pre-existing broad-build race around `@composio/slim` rebuilding `@composio/core`; focused dependent builds pass --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
9901e01a80 |
feat(py): add tool router session deletion
Release Python 0.17.1 with Tool Router session deletion support. |