Commit Graph

333 Commits

Author SHA1 Message Date
sergioperezcheco a2f6b9699b fix(json-schema): integrate Google object type normalization
Co-authored-by: jkomyno <alberto@composio.dev>
2026-08-10 22:01:09 +02:00
Alberto Schiabel 1af694baee Merge branch 'next' into fix/cross-sdk-json-schema-object-conversion 2026-08-10 21:23:10 +02:00
Alberto Schiabel c625edc0f7 fix(core): reuse fetched schemas for provider execution (#4103)
Reuse fetched raw tool schemas for provider-wrapped execution while preserving modifier isolation, runtime validation, and unknown-slug fallback behavior.

Refresh the Python 3.12.13 mise lock entries required by the Audit freshness gate.

Co-authored-by: breezeFur <voidexl@outlook.com>
2026-08-10 13:34:20 +02:00
sdkrelease[bot] 13cba53b1d Release: update version (#4038)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to next, this PR will
be updated.


# Releases
## @composio/core@0.15.0

### Minor Changes

- 1503786: Replace the loose JSON Schema property type with a recursive,
type-safe definition.

`JSONSchemaProperty` (re-exported from `@composio/core` and reachable
through
`Tool.input_parameters` / `Tool.output_parameters`) is now a concrete
recursive
interface instead of effectively `any`. Runtime behavior is unchanged,
but
  consumer code that indexed into it without narrowing (for example
`schema.properties.foo.type` or `schema.default.someField`) may see new
type
errors: `properties` entries are now possibly `undefined` and `default`
/
`enum` values are `unknown`. Narrow with optional chaining or explicit
type
  guards when upgrading.

### Patch Changes

- 2ac6ad3: Bound the background npm version check so registry outages
cannot leave the request pending indefinitely.
- 5105612: Match sensitive upload path segments using the target
filesystem's actual case sensitivity so case-insensitive mounts cannot
bypass the denylist without over-blocking distinct paths on
case-sensitive mounts.
- 051c8c5: Redact secrets that appear inside JSON payloads in telemetry
error text. The key/value rule required the separator to follow the key
name directly, so a serialized body such as `{"api_key": "..."}` — the
shape error messages usually carry — was sent unredacted.
- e5c9ada: Refresh the OpenAI runtime dependency to version 7.
- ecd0861: Release unread response bodies on the paths the SDK knowingly
abandons: cancel every intermediate redirect body in `ssrfSafeFetch`,
and the response body before throwing on `!response.ok` in both
URL-upload call sites, instead of leaving them for the garbage collector
to reclaim.
- 2a6a051: Remove the unused internal `isNewerVersion` helper.
- Updated dependencies [1503786]
  - @composio/json-schema-to-zod@0.2.2
## @composio/openai@0.11.0

### Minor Changes

- e5c9ada: Add support for OpenAI versions 6 and 7.
## @composio/experimental@0.2.2

### Patch Changes

- 4ceaede: Refresh the TypeBox runtime dependency.
## @composio/json-schema-to-zod@0.2.2

### Patch Changes

- 1503786: Model the parser-supported `min`, `max`, and `example` JSON
Schema extensions in the exported recursive schema type.
## @composio/slim@0.15.0

### Patch Changes

- e5c9ada: Refresh the OpenAI runtime dependency to version 7.
- Updated dependencies [1503786]
  - @composio/json-schema-to-zod@0.2.2

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-07 22:16:46 +05:30
jkomyno 3fef432dc0 fix: fail closed on invalid dynamic schemas 2026-08-07 21:03:08 +05:30
LHMQ878 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.
2026-08-07 19:14:49 +05:30
jkomyno 8d4bb3bf7e chore: merge next into json schema conversion fix 2026-08-07 18:44:34 +05:30
jkomyno 4a89ff112c fix(json-schema): enforce dynamic object contracts 2026-08-07 00:06:55 +05:30
jkomyno 063f03a72f docs(changesets): explain each behavior change with a before and after 2026-08-06 22:50:46 +05:30
jkomyno ac6bbabd31 fix(claude-agent-sdk): register complete tool schemas
The provider registered tools through jsonSchemaToZodShape, which returns only
the per-property map. Root-level constraints -- `additionalProperties`, boolean
or schema-valued, and `patternProperties` -- are structurally unrepresentable in
a raw shape, so they were dropped before the Claude Agent SDK ever saw them:
free-form object arguments lost their content, and an unknown key was silently
stripped from tool input rather than rejected.

Registering the complete object schema fixes both. A tool with no input
parameters keeps its closed root explicitly, since a bare `properties: {}` is
now an open object.

Proven at the real SDK boundary rather than against a mocked `tool()`: the new
suite drives createSdkMcpServer over an in-memory MCP transport and asserts on
the advertised inputSchema and on real tools/call results.
2026-08-06 21:59:12 +05:30
jkomyno cb6fe9bf64 chore(changesets): release the schema conversion fixes as minor bumps
Python's unknown-key rejection changes behavior for the langchain, langgraph,
and crewai providers rather than only fixing a defect, so the release carries a
minor bump across both SDKs instead of a patch.
2026-08-06 21:00:15 +05:30
jkomyno 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.
2026-08-06 20:33:53 +05:30
Alberto Schiabel ecd0861741 fix(core): release unread response bodies (#4078)
This PR:
- follows [Undici's
recommendation](https://github.com/nodejs/undici#garbage-collection) to
consume or cancel unread response bodies instead of leaving
connection-resource cleanup to the garbage collector, which can increase
connection pressure and reduce reuse
- cancels every intermediate redirect body in `ssrfSafeFetch` before
validating and following the next hop
- cancels non-success response bodies in both URL-upload callers before
preserving their existing errors
- adds regression coverage for redirect ordering, redirect-budget
exhaustion, and both caller error paths
- adds a patch changeset for `@composio/core`
- supersedes https://github.com/ComposioHQ/composio/pull/4018 and
credits @pacocartones as co-author

## Verification

- `pnpm --filter @composio/core test ssrfGuard fileUtils
ToolRouterSessionFilesMount` (4 files, 58 tests passed)
- `pnpm --filter @composio/core test` (47 files, 1,049 tests passed)
- `pnpm --filter @composio/core typecheck`
- `pnpm lint:packages` (0 errors; existing warnings only)
- Prettier check on all touched files
- `pnpm validate:changesets`

Co-authored-by: pacocartones <pacocartones@users.noreply.github.com>
2026-08-06 17:52:02 +05:30
Rajarshi Datta 2a6a051bc3 refactor(core): remove unused isNewerVersion helper (#4029)
This PR:

- closes #4028
- removes the unused `isNewerVersion` helper from the internal version
utility
- avoids defining malformed-version behavior for a helper with no
callers or package export
- retains `next`'s tested npm version-check timeout implementation
- adds a patch changeset for `@composio/core`
- refreshes Python 3.12.13 artifact metadata in `mise.lock` after the
upstream build was republished

## Verification

- version utility tests: 2 passed
- core typecheck: passed
- changeset validation: passed
- `mise 2026.5.18 lock --platform
linux-x64,linux-arm64,macos-arm64,macos-x64`: clean

---------

Co-authored-by: jkomyno <alberto@composio.dev>
2026-08-06 09:32:53 +05:30
jkomyno 86cc3cc399 chore: merge next into dependabot remediation 2026-08-05 21:29:53 +05:30
Rajarshi Datta 27fbb464f7 Merge branch 'next' into fix/version-check-fetch-timeout 2026-08-04 11:48:10 +05:30
Alberto Schiabel 1503786358 refactor(core): forbid explicit any and type JSON Schema recursively (#3968)
This PR:

- is refreshed directly onto the current next branch now that #3966 and
#3967 have merged; the PR contains only its intended type-safety work
- enforces no explicit any through the standard .oxlintrc.json, pnpm
lint, and plain oxlint --fix in lint-staged; docs remain covered by
their nested configuration
- replaces the loose JSONSchemaProperty in @composio/core with a
concrete recursive interface, removing explicit any reachable through
Tool.inputParameters and Tool.outputParameters
- includes a minor changeset documenting the type narrowing for
properties, default, and enum consumers
- adds a compile-only public-contract test for recursive schemas,
known-key validation, extension keywords, and Tool reachability
- removes explicit any from FileToolModifier, ts-builders, core and CLI
tests, provider tests, and json-schema-to-zod tests
- keeps TypeScript ESLint-parity rules enabled and closes the
tool-router example lint/typecheck gap
- makes no lockfile changes and no runtime behavior changes

## Context

Final PR from the original #3958 split. The migration foundations are
already on next via #3966 and #3967, so this branch no longer carries a
stacked base commit.
2026-08-03 22:24:57 +05:30
jkomyno 2ac6ad320a fix(core): complete version check timeout guard 2026-08-03 18:53:18 +05:30
jkomyno e5c9adabc8 chore(deps): migrate OpenAI runtime to v7 2026-08-03 17:05:23 +05:30
jkomyno 4ceaede87a chore(deps): refresh runtime support dependencies 2026-08-03 17:05:20 +05:30
Alberto Schiabel 51056129ee fix(core): detect filesystem case sensitivity for uploads (#4036)
This PR:
- fixes #4024
- supersedes #4025 with target-filesystem detection instead of
unconditional case folding
- uses `is-fs-case-sensitive` on the nearest existing directory so mixed
mounts and case-sensitive filesystem configurations are handled
correctly
- preserves exact matching on case-sensitive filesystems and falls back
to conservative case-insensitive matching when detection fails
- keeps Node-only detection behind `#platform` and mirrors its runtime
dependency in `@composio/slim`, preserving the workerd-safe bundle and
Slim import
- adds focused Node, workerd, and matcher regressions plus an
`@composio/core` patch changeset
- verifies 1,044 core tests, five CLI upload tests, the Slim
build/import smoke, typecheck, build, ATTW, publint, lint, formatting,
frozen install, and changeset validation
2026-08-03 16:32:40 +05:30
sdkrelease[bot] fdbd44f9eb Release: update version (#3906)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to next, this PR will
be updated.


# Releases
## @composio/core@0.14.1

### Patch Changes

- 577a3d4: Replace the backtracking leading/trailing-slash-trim regexes
in the Cloudflare Workers/Edge platform path helpers with index-walk
loops, closing a polynomial-time regular expression denial-of-service
(CodeQL js/polynomial-redos) on long runs of slash characters. Output is
unchanged for every input.
- 503b50a: Refresh runtime dependencies across the TypeScript SDK
packages.
- 2f63fe5: Guard Tool Router session URL uploads against SSRF,
revalidate redirect targets, and enforce a streamed 100 MiB response
limit across TypeScript URL upload paths.
## @composio/experimental@0.2.1

### Patch Changes

- 503b50a: Refresh runtime dependencies across the TypeScript SDK
packages.
## @composio/mastra@0.10.3

### Patch Changes

- 503b50a: Refresh runtime dependencies across the TypeScript SDK
packages.
## @composio/slim@0.14.1

### Patch Changes

- 503b50a: Refresh runtime dependencies across the TypeScript SDK
packages.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-30 16:25:33 +05:30
Saransh Rana 577a3d4013 security: fix 3 CodeQL alerts (2026-07-22) (#3909)
## Summary

Automated weekly CodeQL remediation run for 2026-07-22. Closes three
`js/polynomial-redos` code scanning alerts (all severity high) in the
Cloudflare Workers / Edge platform shim.

`ts/packages/core/src/platform/workerd.ts` implements the `Platform`
interface for edge runtimes, where Node's `path` module is unavailable,
so path joining and basename extraction were done with regexes. Three of
those regexes (`/\/+$/` twice, `/^\/+|\/+$/g` once) backtrack
quadratically on long runs of `/`, so a path segment made of many
slashes turns a trim into a hang. They are replaced with index-walk
helpers that scan character codes, which is linear and allocates nothing
when the string is already trimmed.

Output is unchanged for every input. Equivalence was verified
exhaustively over all 137,257 strings of length 6 or less drawn from
`{'/', 'a', '\n', '\r', '.', ' ', '\\'}`, plus 300k randomized
multi-segment `joinPath` compositions and a Unicode surrogate spot
check, with zero mismatches against the original regexes. The `\n` and
`\r` cases matter because JavaScript `$` without the `m` flag anchors to
end of input only, so `/\/+$/` must not trim `"a/\n"`; the index walk
agrees.

All 15 open alerts on `next` were triaged. 3 are fixed here, 12 are
skipped with a recommended disposition for a human to action. Details
below.

## Changes

- `ts/packages/core/src/platform/workerd.ts`: add module private
`trimTrailingSlashes` and `trimSurroundingSlashes`, use them in
`joinPath` and `basename`. No export surface change, no `Platform`
interface change, no other platform implementation touched.
- `ts/packages/core/test/platform/workerd.test.ts`: new behavior pinning
test file.
- `.changeset/fix-workerd-slash-trim-redos.md`: patch bump for
`@composio/core`.

## Type of change

- [x] Bug fix
- [ ] New feature
- [ ] Refactor/Chore
- [ ] Documentation
- [ ] Breaking change

## Fixed

| Alert | Rule | Severity | File | Fix | Test that proves it |
|---|---|---|---|---|---|
|
[#55](https://github.com/ComposioHQ/composio/security/code-scanning/55)
| `js/polynomial-redos` | High |
`ts/packages/core/src/platform/workerd.ts:21` | `joinPath` first
segment: `/\/+$/` replaced with `trimTrailingSlashes` | `joinPath
matches the pre-fix regex implementation for single segments` |
|
[#56](https://github.com/ComposioHQ/composio/security/code-scanning/56)
| `js/polynomial-redos` | High |
`ts/packages/core/src/platform/workerd.ts:23` | `joinPath` later
segments: `/^\/+\|\/+$/g` replaced with `trimSurroundingSlashes` |
`joinPath matches the pre-fix regex implementation for every segment
pair` |
|
[#57](https://github.com/ComposioHQ/composio/security/code-scanning/57)
| `js/polynomial-redos` | High |
`ts/packages/core/src/platform/workerd.ts:43` | `basename`: `/\/+$/`
replaced with `trimTrailingSlashes` | `basename matches the pre-fix
regex implementation for every input` |

On test design: the equivalence tests compare the new implementation
against a copy of the pre-fix regex logic, so they pin behavior but pass
in both states by construction. The test that is actually red before the
fix and green after is `rejects the backtracking slash regexes at the
source level`, which asserts the two vulnerable patterns are absent from
`workerd.ts`. That is what would catch a silent revert to the regex
form. A timing based "pathological input completes within N ms" test was
deliberately not written, because it is flaky in CI.

## Skipped

Twelve alerts were read and deliberately not fixed. None were dismissed
via the API; that decision is yours.

### Test only code, recommend `dismiss: used in tests`


**[#47](https://github.com/ComposioHQ/composio/security/code-scanning/47)**
`py/incomplete-url-substring-sanitization`, High,
`python/tests/test_files.py:2518`. The flagged line is `assert
"example.com" in sanitized`, a pytest assertion checking that a logging
redaction helper preserved the host. It is not a URL authorization
check.

```
gh api -X PATCH /repos/ComposioHQ/composio/code-scanning/alerts/47 \
  -f state=dismissed -f dismissed_reason="used in tests" \
  -f dismissed_comment="Substring check is a pytest assertion on a log-redaction helper, not an authorization check. codeql-autofix 2026-07-22, PR #3909"
```


**[#54](https://github.com/ComposioHQ/composio/security/code-scanning/54)**
`js/incomplete-sanitization`, High,
`ts/packages/core/test/models/verifyWebhook.integration.test.ts:339`.
`fixture.payload.replace('{', '{ ')` deliberately corrupts a payload so
the test can assert webhook verification fails on whitespace change. It
is the opposite of a sanitizer.

```
gh api -X PATCH /repos/ComposioHQ/composio/code-scanning/alerts/54 \
  -f state=dismissed -f dismissed_reason="used in tests" \
  -f dismissed_comment="Deliberate payload corruption in a negative webhook-verification test, not a sanitizer. codeql-autofix 2026-07-22, PR #3909"
```

### False positive, recommend `dismiss: false positive`


**[#105](https://github.com/ComposioHQ/composio/security/code-scanning/105)**
and
**[#106](https://github.com/ComposioHQ/composio/security/code-scanning/106)**
`js/prototype-polluting-assignment`, Medium,
`ts/packages/core/src/utils/jsonSchema.ts:255-256`.

The flagged statements are `delete out.$defs` and `delete
out.definitions`. Both use hardcoded literal keys, never attacker
controlled. `out` can never alias `Object.prototype`: every return path
in `walk()` constructs a fresh object via `Object.fromEntries` or object
spread, except the primitive passthrough at line 197, which cannot
return `Object.prototype` because the top level call is seeded with a
value already checked by `isPlainObject`. Two upstream guards further
block the flow CodeQL believes exists: `cloneChildren` filters
`POLLUTING_KEYS` (`__proto__`, `constructor`, `prototype`) at line 171,
and `tryStep` gates property access with
`Object.prototype.hasOwnProperty.call` at line 91. CodeQL cannot see
through that guard because it is wrapped in a tagged union return.

```
gh api -X PATCH /repos/ComposioHQ/composio/code-scanning/alerts/105 \
  -f state=dismissed -f dismissed_reason="false positive" \
  -f dismissed_comment="delete uses a literal key and out is always a freshly constructed object; POLLUTING_KEYS filter and hasOwnProperty guard block the modeled flow. codeql-autofix 2026-07-22, PR #3909"
```

```
gh api -X PATCH /repos/ComposioHQ/composio/code-scanning/alerts/106 \
  -f state=dismissed -f dismissed_reason="false positive" \
  -f dismissed_comment="Same flow as alert 105, on delete out.definitions. codeql-autofix 2026-07-22, PR #3909"
```

### Needs a decision, recommend `keep open`

These are not obviously wrong, but the correct fix changes generated or
rendered output, which is a product decision rather than an automated
one. They are left open on purpose.

| Alert | Rule | File | Why it needs a human |
|---|---|---|---|
|
[#48](https://github.com/ComposioHQ/composio/security/code-scanning/48)
| `js/incomplete-sanitization` |
`docs/app/llms.mdx/[[...slug]]/route.ts:626` | The only runtime site in
this group. Escapes `\|` for a markdown table cell without escaping
backslash first, so a description containing `\|` can break out of the
cell. Impact is table formatting in an LLM facing docs endpoint, not
injection into a code sink. Fixing it changes rendered docs output, and
this file is outside the `@composio/core` test baseline used for this
run. |
|
[#49](https://github.com/ComposioHQ/composio/security/code-scanning/49)
| `js/incomplete-sanitization` |
`docs/scripts/generate-meta-tools.ts:176` | Escapes `"` into YAML
frontmatter without escaping backslash first. Build time, first party
tool metadata. Backslash first escaping changes generated docs. |
|
[#50](https://github.com/ComposioHQ/composio/security/code-scanning/50)
| `js/incomplete-sanitization` |
`ts/packages/core/scripts/generate-docs.ts:1008` | `escapeTextForMdx`,
same class. Build time only. |
|
[#51](https://github.com/ComposioHQ/composio/security/code-scanning/51)
| `js/incomplete-sanitization` |
`ts/packages/core/scripts/generate-docs.ts:1008` | Second instance on
the same chain as #50. |
|
[#88](https://github.com/ComposioHQ/composio/security/code-scanning/88)
| `js/incomplete-sanitization` |
`docs/scripts/generate-meta-tools.ts:134` | Markdown table escaping of
`\|` over first party metadata. |
|
[#89](https://github.com/ComposioHQ/composio/security/code-scanning/89)
| `js/incomplete-sanitization` |
`docs/scripts/generate-meta-tools.ts:136` | Same as #88 on the fallback
description branch. |
|
[#90](https://github.com/ComposioHQ/composio/security/code-scanning/90)
| `js/incomplete-multi-character-sanitization` |
`docs/agent/lib/docs.ts:232` | `toCleanMarkdown` strips JSX and HTML
tags in a single pass, so `<<div>div>` leaves `<div>`. It cleans MDX for
LLM context and its output is never rendered as HTML, so it is not a
security sanitizer. Duplicated verbatim in #92. |
|
[#92](https://github.com/ComposioHQ/composio/security/code-scanning/92)
| `js/incomplete-multi-character-sanitization` |
`docs/scripts/build-agent-index.ts:155` | Verbatim duplicate of the
`toCleanMarkdown` helper in #90. If one is addressed, both should be,
ideally by extracting the shared helper. |

## Scanning config recommendations

Six of the twelve skips (#49, #50, #51, #88, #89, #92) share one root
cause: CodeQL scans build and docs generation scripts, and flags string
escaping over first party metadata that never crosses a trust boundary
at runtime.

This repo uses CodeQL **default setup** (`analysis_key` is
`dynamic/github-code-scanning/codeql:analyze`, and there is no committed
CodeQL workflow), so `paths-ignore` is not available. The two options
are to migrate to advanced setup with a committed workflow so
`paths-ignore` can exclude these directories, or to bulk dismiss the
alerts individually.

**Recommendation: do neither blindly, and do not add `paths-ignore` for
`**/scripts/**`.** These are real findings in real code, just low
priority ones over trusted input. Excluding the directory would also
blind the scanner to genuine future vulnerabilities in build tooling,
which is where supply chain problems tend to live. The better path is a
single follow up PR that fixes the escaping properly, escaping backslash
before the other characters, with the generated output diff reviewed as
part of that PR. If the team decides the churn is not worth it,
dismissing each as `won't fix` with that justification is the honest
alternative, and it keeps future scanning intact.

## How Has This Been Tested?

```
pnpm --filter "@composio/core^..." run build   # build workspace deps once
pnpm --filter @composio/core run test
pnpm --filter @composio/core run typecheck
```

- Pre-fix baseline on clean `next` at `2f63fe540`: **44 test files, 1034
tests, 0 failures.**
- On this branch: **45 test files, 1040 tests, 0 failures.** That is the
baseline plus this PR's 6 new tests.
- Typecheck: clean.
- There were no pre-existing failures, so nothing here is masking one.

Toolchain note for reproduction: the workspace `preinstall` hook
requires `mise`, and `@composio/json-schema-to-zod` must be built before
the `@composio/core` suite will resolve its imports. Without that build,
9 test files fail with `Failed to resolve entry for package
"@composio/json-schema-to-zod"`, which is an environment artifact and
not a real failure.

## Remaining backlog

- Fixable alerts beyond the 15 alert fix cap: **0**. All 15 open alerts
on `next` were triaged in this run.
- Untriaged alerts beyond the 50 alert triage bound: **0**. The bound
was not reached.
- Open alerts remaining after this PR merges: **12**, all listed above
with a recommended disposition. Four of them have ready to run dismissal
commands, which would permanently shrink every future run's fetch.

## Post-fix security scan

`composio-security:security-diff-scan` was run on this PR's diff as the
final gate, because a remediation can introduce its own bug and CodeQL
will not re-run until CI does.

**Verdict: clean. Zero reportable findings.**

Scope: merge-base `2f63fe540` to head `558d730e6`, all three changed
files. Every deep-review row has a completion receipt, so coverage is
complete rather than sampled. Discovery emitted no technically plausible
candidates, so validation and attack-path analysis were skipped under
the scan's documented zero-candidate rule.

Checks that were run and came back negative:

- The fix removes the denial-of-service primitive rather than relocating
it. No regex remains on the trimming paths, and all three loops strictly
progress toward their bound, so there is no unbounded-work or
infinite-loop path.
- Surrogate-pair safety. `charCodeAt` compares UTF-16 code units, and
`/` is U+002F, which can never appear as either half of a surrogate
pair. No astral-plane input can make the index walk disagree with the
regex it replaced.
- No security control changed. `joinPath` feeds `resolvePath`, which
`sensitiveFileUploadPaths.ts:39` consumes for its upload denylist. That
unchanged consumer was inspected as a negative control: byte-identical
output means it cannot observe a difference, and it independently
re-splits on slash runs at line 48 anyway.
- No new allocation or memory amplification. Both helpers return the
input unchanged when nothing needs trimming, so the fix allocates
strictly less than the `.replace()` calls it replaced.
- The new test file reproduces the two pre-fix regex literals as
reference implementations. They are applied only to a literal `CASES`
array, so there is no taint source, and `test/` is absent from this
package's `files` allowlist, so they are never published to SDK
consumers.

No new critical or high finding was introduced by this diff, so no
commit needed reverting and no alert was reclassified.

## 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 documented behavior changed)
- [x] I added tests or explain why not applicable
- [x] I added a changeset if this change affects published packages

## Additional context

Generated by the `codeql-autofix` skill. The bot never dismisses,
closes, or modifies alerts, and never merges or enables auto merge.
Alerts close only because merged code no longer contains the flaw.

---------

Co-authored-by: Saransh <saranshrana@Saranshs-MacBook-Pro.local>
Co-authored-by: jkomyno <alberto@composio.dev>
2026-07-28 13:26:41 +05:30
Alberto Schiabel 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`.
2026-07-27 17:57:29 +05:30
Shrey Singla 2f63fe5407 fix(core): secure Tool Router session URL uploads (#3900)
## Summary

- route Tool Router session URL uploads through the SDK's SSRF-safe
fetch path
- validate every redirect target and reject destinations that resolve to
non-public network addresses
- stream URL response bodies with a 100 MiB limit instead of buffering
unbounded responses
- fail closed for URL uploads on edge runtimes where DNS validation is
unavailable
- apply the bounded response reader to the existing core URL-upload path
as well
- add a patch changeset for `@composio/core`

## Root cause

Tool Router session file uploads fetched string URL inputs directly and
buffered the entire response. That bypassed the SSRF checks already used
by other SDK upload paths and allowed an untrusted URL to target
internal network resources or return an unbounded response body.

## Impact

Node.js and Bun URL uploads now validate resolved addresses before
connecting and revalidate redirect hops. Cloudflare Workers and other
edge runtimes reject URL inputs with a typed error; callers can fetch
trusted content themselves and pass a `File` or `ArrayBuffer` instead.

## Validation

- focused SSRF and file upload tests: 59 passed
- full `@composio/core` suite: 1,034 passed
- TypeScript checks with both tsgo and tsc
- ESLint and Prettier
- package build, ATTW, and publint
- changeset validation
- Cloudflare Workers live E2E: 5 passed
- live Node Tool Router upload/list/download/delete flow
- live Node Tool Router HTTPS URL upload and cleanup

<!-- codesmith:footer -->
---
<a
href="https://app.blacksmith.sh/ComposioHQ/codesmith/composio/pr/3900"><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=1787224599&installation_model_id=428187&pr_number=3900&repository=ComposioHQ%2Fcomposio&return_to=https%3A%2F%2Fgithub.com%2FComposioHQ%2Fcomposio%2Fpull%2F3900&signature=ef519ac58a7945667565c1c143983f353b8947c988079d76c04afa9ab3b111d1"><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 -->
2026-07-22 14:51:39 +05:30
Alberto Schiabel 9498679c26 fix(release): guard and document CLI releases (#3895)
This PR:
- removes the stale `@composio/cli` changeset that wedges
`changesets/action` and preserves its release note in the CLI changelog
- adds `validate:changesets` before the TypeScript release action and
covers ignored-package changesets in the release regression suite
- makes the guard read changeset files directly so it also works in
shallow and detached CI checkouts
- refreshes `mise.lock` after the pinned Python standalone artifacts
moved to the 20260718 build
- adds the repo-local `cli-release` skill with beta, stable-promotion,
verification, and failure-recovery procedures
- replaces the contradictory "stable via changeset" contributor guidance
with the tested-beta promotion path
- extends skill taxonomy, routing probes, and PR path filters so the
guard cannot silently drift

## Regression coverage

The validator test creates a changeset fixture outside a Git repository,
verifies that an ignored CLI package is rejected, then verifies that a
normal package changeset passes. This reproduces the shallow-checkout
failure without relying on a local `next` ref.

## Verification

- `pnpm validate:agent-skills`
- `pnpm validate:skill-routing`
- `pnpm validate:changesets`
- `pnpm test:release-workflow`
- `pnpm lint`
- `pnpm install --frozen-lockfile`
- all 24 TypeScript package test tasks
- skill-creator `quick_validate.py`
- Prettier check
- `git diff --check`
- manual beta release
[`@composio/cli@0.2.33-beta.294`](https://github.com/ComposioHQ/composio/releases/tag/%40composio/cli%400.2.33-beta.294):
33/33 release and installation jobs passed
2026-07-20 23:17:03 +04:00
xHai 8467efdfb9 fix(cli): whoami respects the org selected via orgs switch (#3832)
## Summary

`composio whoami` reports the wrong organization after `composio orgs
switch`.
It always shows the API key's home org, ignoring the switched-to org,
even
though `composio orgs list` correctly reflects the selection.

**Root cause:** `whoami` resolves session info via
`getSessionInfoByUserApiKey`,
which sent only `x-user-api-key` and omitted `x-org-id`. Without that
header the
backend falls back to the API key's home org. Consumer commands
(`search`,
`execute`, …) already forward the selected org via
`resolveCommandProject`, so
only `whoami` was affected — a display bug, not an API bug.

**Verification that the backend honors the header** (direct calls to
`GET /api/v3/auth/session/info`):

| `x-org-id` | returned project/org |
|---|---|
| org A | org A |
| org B | org B |
| (omitted) | API key's home org |

## Changes

- `getSessionInfoByUserApiKey` accepts an optional `orgId` and forwards
it as
`x-org-id` when present (login-time callers pass none, so their behavior
is
  unchanged).
- `whoami` passes the selected global org (`ctx.data.orgId`).
- Unit tests asserting the header is sent when an org is selected and
omitted
  otherwise.

## Type of change
- [x] Bug fix

## How Has This Been Tested?

- New unit tests: `test/src/services/composio-clients.test.ts` (2
cases).
- Existing `whoami.cmd.test.ts` still passes (5 tests total green).
- Manual end-to-end with a real UAK against two orgs: a binary built
from this
  branch reports the switched org correctly (`orgs switch` → `whoami`),
  whereas the released 0.2.31 binary always reported the home org.

## 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 docs affected)
- [x] I added tests or explain why not applicable
- [x] I added a changeset if this change affects published packages
2026-07-17 00:11:33 +04:00
Alberto Schiabel ac7ca020da fix(release): drop stale changeset for ignored @composio/cli (#3861)
This PR:

- unblocks #3820 — the `0.14.0` release train (including
`@composio/experimental@0.2.0` with the `./eve` export) is versioned on
`next` but was never published to npm
- deletes `.changeset/cli-file-upload-denylist.md`: it targets
`@composio/cli`, which is in the changesets `ignore` list (since #3676),
so `changeset version` never consumes it
- the leftover changeset makes `changesets/action` pick version-PR mode
over publish mode on every push to `next`, then fail with `No commits
between next and changeset-release/next` because the versioning no-ops —
see the [failed
run](https://github.com/ComposioHQ/composio/actions/runs/29449907252/job/87469539026);
the publish step never executes
- ports the security note from the deleted changeset into the `0.3.0`
section of `ts/packages/cli/CHANGELOG.md` — the fix commit (fc17c37bf,
#3763) is part of the `0.3.0` tree, and `@composio/cli@0.3.0` has no
tag/release yet

## Context

Once this merges, the next `TS SDK Release` run on `next` will find no
pending changesets, take the publish path (`pnpm changeset:release`),
and push the pending versions to npm.

Follow-up worth considering (not in this PR): a CI check that rejects
changesets referencing packages in the `ignore` list, since any such
changeset permanently wedges the release train.
2026-07-16 16:54:58 +04:00
sdkrelease[bot] 26f3c626e9 Release: update version (#3717)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to next, this PR will
be updated.


# Releases
## @composio/core@0.14.0

### Minor Changes

- fc17c37: Export the sensitive-file-upload denylist guard from the
package root so downstream packages share one implementation:
`assertSafeFileUploadPath`, `isBlockedSensitiveFileUploadPath`, and
`BUILTIN_FILE_UPLOAD_PATH_DENY_SEGMENTS`. The guard now routes its
filesystem access through the internal `#platform` abstraction (adding a
`realpathSync` platform method), so it is edge/workerd-safe and the
module carries no static `node:*` imports. Behavior on Node/Bun is
unchanged.
- 20a4711: `triggers.create` now resolves the connection from `user_id`
on the backend instead of client-side.

- The SDK no longer makes an extra `connectedAccounts.list()` call. When
`connectedAccountId` is omitted, the backend resolves the first active
connection for the user and the trigger's toolkit (ordered by most
recently created), matching tool execution.
- **Behavior change:** `create` no longer throws
`ComposioConnectedAccountNotFoundError` for a missing or invalid
connection. That case now surfaces as the backend error from the upsert
call. `ComposioTriggerTypeNotFoundError` (invalid slug) and
`ValidationError` (including empty `userId`) are still thrown
client-side.
- **Requires a backend that resolves the trigger connection from
`user_id` on upsert**
([ComposioHQ/platform#10932](https://github.com/ComposioHQ/platform/pull/10932)).
Self-hosted deployments must be on a version that includes it.

### Patch Changes

- 7125576: Normalize duplicate JSON Schema `required` entries before
provider tool schemas are emitted.
- 58bc93b: Refresh dependency ranges and lockfiles across the workspace.
- 4c3a321: Disable client retries on `tools.execute` and
`tools.proxyExecute`. These are non-idempotent writes, so a silent retry
after a read timeout could duplicate the side effect (e.g. send the same
email more than once). Both now route through a sibling client built
with `maxRetries: 0`; reads keep the default retry behaviour.
- b07fcad: Add an eve provider: `EveProvider` makes `session.tools()`
return eve-native `defineTool`s, `defineComposioTools` is the
replay-safe `step.started` resolver, and `(ctx, next)` hooks can
rewrite, deny, or transform Tool Router meta-tool calls.

Preserve successful local-tool results when the remote half of a mixed
`COMPOSIO_MULTI_EXECUTE_TOOL` batch fails at the transport layer, so
callers can see which side effects already completed before retrying.

- fa933a6: Fix the `homepage` links in these packages' `package.json`.
They pointed at `github.com/ComposioHQ/composio/tree/main/...`, but the
default branch is `next` and no `main` branch exists, so every link
404'd on npm and in editor tooltips. They now point at `tree/next/...`.
- 2ef40ce: Treat local file paths that begin with `http` as paths
instead of URLs, ensuring that upload allowlist and sensitive-file
denylist checks still run.
- e78ed31: Execute every parallel tool call in
`OpenAIProvider.handleToolCalls`. It previously only ran the first tool
call in each assistant message, so parallel tool calls (on by default)
dropped the rest and left their `tool_call_id`s unanswered, failing the
next request.

The calls are run sequentially, in the order the model returned them —
here "parallel" means the model issued several calls in one turn, not
that they execute concurrently — so each `tool_call_id` is answered
exactly once and the tool messages come back in a deterministic order.

Only the first choice is handled. Tool results are fed back into a
single assistant turn, so with `n > 1` iterating over every choice would
run each tool call once per choice and orphan the `tool_call_id`s from
the alternative completions.

- a0f37a7: Close two secret/SSRF exposure surfaces in the TypeScript
SDK:

- **SSRF guard on URL file inputs.** `composio.files.upload(url)` and
automatic file upload during tool execution previously did a raw
`fetch()` on user-supplied URLs with no guard. They now resolve the host
and refuse private, loopback, link-local (incl. the `169.254.169.254`
cloud-metadata endpoint), CGNAT, and reserved addresses, reject
non-`http(s)` schemes, and follow redirects manually so each hop is
re-validated (blocking a public URL that redirects into internal space).
Blocked requests throw `ComposioBlockedInternalUrlError`. Node-only;
behaviour for public URLs is unchanged.
- **Telemetry redaction.** Error telemetry previously shipped
`error.message` / `error.stack` verbatim. They are now passed through a
redactor that strips URL query strings, `Authorization` bearer/basic
credentials, and secret-like `key=value` pairs (API keys, tokens, client
secrets, passwords) before transport.

- 820abb9: Resolve toolkit version pins case-insensitively. Version maps
are keyed by normalized (lowercase) slugs, but `getToolkitVersion`
previously looked them up with the raw slug, so a pin configured under a
different casing (e.g. `{ GitHub: '20250101_00' }` or
`COMPOSIO_TOOLKIT_VERSION_GITHUB`) could silently fall back to
`'latest'`. Normalization is now centralized in a single
`normalizeToolkitSlug` helper used symmetrically on both the write
(map-building) and read (lookup) paths, so the two sides can no longer
drift. This mirrors the equivalent fix in the Python SDK.
- Updated dependencies [58bc93b]
- Updated dependencies [fa933a6]
  - @composio/json-schema-to-zod@0.2.1
## @composio/experimental@0.2.0

### Minor Changes

- b07fcad: Add an eve provider: `EveProvider` makes `session.tools()`
return eve-native `defineTool`s, `defineComposioTools` is the
replay-safe `step.started` resolver, and `(ctx, next)` hooks can
rewrite, deny, or transform Tool Router meta-tool calls.

Preserve successful local-tool results when the remote half of a mixed
`COMPOSIO_MULTI_EXECUTE_TOOL` batch fails at the transport layer, so
callers can see which side effects already completed before retrying.

### Patch Changes

- 58bc93b: Refresh dependency ranges and lockfiles across the workspace.
- fa933a6: Fix the `homepage` links in these packages' `package.json`.
They pointed at `github.com/ComposioHQ/composio/tree/main/...`, but the
default branch is `next` and no `main` branch exists, so every link
404'd on npm and in editor tooltips. They now point at `tree/next/...`.
## @composio/json-schema-to-zod@0.2.1

### Patch Changes

- 58bc93b: Refresh dependency ranges and lockfiles across the workspace.
- fa933a6: Fix the `homepage` links in these packages' `package.json`.
They pointed at `github.com/ComposioHQ/composio/tree/main/...`, but the
default branch is `next` and no `main` branch exists, so every link
404'd on npm and in editor tooltips. They now point at `tree/next/...`.
## @composio/anthropic@0.10.1

### Patch Changes

- 7125576: Normalize duplicate JSON Schema `required` entries before
provider tool schemas are emitted.
- 58bc93b: Refresh dependency ranges and lockfiles across the workspace.
- fa933a6: Fix the `homepage` links in these packages' `package.json`.
They pointed at `github.com/ComposioHQ/composio/tree/main/...`, but the
default branch is `next` and no `main` branch exists, so every link
404'd on npm and in editor tooltips. They now point at `tree/next/...`.
## @composio/claude-agent-sdk@0.10.1

### Patch Changes

- 58bc93b: Refresh dependency ranges and lockfiles across the workspace.
- fa933a6: Fix the `homepage` links in these packages' `package.json`.
They pointed at `github.com/ComposioHQ/composio/tree/main/...`, but the
default branch is `next` and no `main` branch exists, so every link
404'd on npm and in editor tooltips. They now point at `tree/next/...`.
## @composio/cloudflare@0.10.1

### Patch Changes

- 7125576: Normalize duplicate JSON Schema `required` entries before
provider tool schemas are emitted.
- fa933a6: Fix the `homepage` links in these packages' `package.json`.
They pointed at `github.com/ComposioHQ/composio/tree/main/...`, but the
default branch is `next` and no `main` branch exists, so every link
404'd on npm and in editor tooltips. They now point at `tree/next/...`.
## @composio/google@0.10.1

### Patch Changes

- 7125576: Normalize duplicate JSON Schema `required` entries before
provider tool schemas are emitted.
- fa933a6: Fix the `homepage` links in these packages' `package.json`.
They pointed at `github.com/ComposioHQ/composio/tree/main/...`, but the
default branch is `next` and no `main` branch exists, so every link
404'd on npm and in editor tooltips. They now point at `tree/next/...`.
## @composio/langchain@0.10.1

### Patch Changes

- 58bc93b: Refresh dependency ranges and lockfiles across the workspace.
- fa933a6: Fix the `homepage` links in these packages' `package.json`.
They pointed at `github.com/ComposioHQ/composio/tree/main/...`, but the
default branch is `next` and no `main` branch exists, so every link
404'd on npm and in editor tooltips. They now point at `tree/next/...`.
## @composio/llamaindex@0.10.1

### Patch Changes

- fa933a6: Fix the `homepage` links in these packages' `package.json`.
They pointed at `github.com/ComposioHQ/composio/tree/main/...`, but the
default branch is `next` and no `main` branch exists, so every link
404'd on npm and in editor tooltips. They now point at `tree/next/...`.
## @composio/mastra@0.10.2

### Patch Changes

- 58bc93b: Refresh dependency ranges and lockfiles across the workspace.
- fa933a6: Fix the `homepage` links in these packages' `package.json`.
They pointed at `github.com/ComposioHQ/composio/tree/main/...`, but the
default branch is `next` and no `main` branch exists, so every link
404'd on npm and in editor tooltips. They now point at `tree/next/...`.
## @composio/openai@0.10.1

### Patch Changes

- 7125576: Normalize duplicate JSON Schema `required` entries before
provider tool schemas are emitted.
- fa933a6: Fix the `homepage` links in these packages' `package.json`.
They pointed at `github.com/ComposioHQ/composio/tree/main/...`, but the
default branch is `next` and no `main` branch exists, so every link
404'd on npm and in editor tooltips. They now point at `tree/next/...`.
## @composio/openai-agents@0.10.1

### Patch Changes

- 7125576: Normalize duplicate JSON Schema `required` entries before
provider tool schemas are emitted.
- 58bc93b: Refresh dependency ranges and lockfiles across the workspace.
- fa933a6: Fix the `homepage` links in these packages' `package.json`.
They pointed at `github.com/ComposioHQ/composio/tree/main/...`, but the
default branch is `next` and no `main` branch exists, so every link
404'd on npm and in editor tooltips. They now point at `tree/next/...`.
## @composio/vercel@0.11.1

### Patch Changes

- fa933a6: Fix the `homepage` links in these packages' `package.json`.
They pointed at `github.com/ComposioHQ/composio/tree/main/...`, but the
default branch is `next` and no `main` branch exists, so every link
404'd on npm and in editor tooltips. They now point at `tree/next/...`.
## @composio/slim@0.14.0

### Patch Changes

- 58bc93b: Refresh dependency ranges and lockfiles across the workspace.
- fa933a6: Fix the `homepage` links in these packages' `package.json`.
They pointed at `github.com/ComposioHQ/composio/tree/main/...`, but the
default branch is `next` and no `main` branch exists, so every link
404'd on npm and in editor tooltips. They now point at `tree/next/...`.
- Updated dependencies [58bc93b]
- Updated dependencies [fa933a6]
  - @composio/json-schema-to-zod@0.2.1
## @composio/cli-keyring@0.2.1

### Patch Changes

- 58bc93b: Refresh dependency ranges and lockfiles across the workspace.
## @composio/ts-builders@0.2.1

### Patch Changes

- 58bc93b: Refresh dependency ranges and lockfiles across the workspace.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-16 00:52:07 +04:00
Alberto Schiabel 2ef40ce6da docs: document TypeScript 0.14.0 release (#3849)
This PR:
- documents TypeScript `@composio/core` `0.14.0`, prepared in
https://github.com/ComposioHQ/composio/pull/3717
- calls out trigger behavior changes, provider compatibility,
file-upload security, telemetry redaction, and tool-execution
reliability
- adds the missing `@composio/core` patch Changeset for the local-path
fix merged in https://github.com/ComposioHQ/composio/pull/3766
- leaves the Python `0.18.0` changelog with
https://github.com/ComposioHQ/composio/pull/3825 so the release and docs
PRs do not add the same file
- keeps the TypeScript candidate release in the canonical docs changelog
before publishing

After this PR merges into `next`, the Changesets release PR must
regenerate before publishing.

## Validation

- `pnpm test:release-workflow`
- `pnpm changeset status --since=origin/next`
- `bun run test`
- `bun run lint:links`
- `bun run types:check`
- `bun run build`
- `pnpm exec prettier --check
docs/content/changelog/07-15-26-typescript-sdk-014.mdx
.changeset/http-prefixed-local-paths.md`

`bun run lint` remains red on 23 existing React and Next.js errors
outside these files.
2026-07-16 00:23:41 +04:00
Alberto Schiabel fbcf08136d revert(core): defer v1 session alias removal (#3826)
This PR:
- reverts https://github.com/ComposioHQ/composio/pull/3780
- restores the TypeScript `composio.create()` and `composio.use()`
session aliases, with their runtime and type-test coverage
- restores the prior deprecation state for
`BaseProvider.wrapMcpServerResponse`
- removes the pre-v1 breaking-change changeset so the release PR no
longer advertises this removal

The v1 API-freeze change should be recreated later as a draft PR and
kept out of the merge queue until v1 is ready.
2026-07-14 01:01:18 +04:00
jkomyno d5c86d3d6b fix(release): keep core pre-v1 2026-07-13 20:10:55 +04:00
Anas Khan fa933a6f9b fix(ts): point published package homepage links at the next branch (#3821)
```markdown
The `homepage` field in every published TypeScript package points at
`https://github.com/ComposioHQ/composio/tree/main/ts/packages/<pkg>#readme`. The
repository's default branch is `next` and there is no `main` branch, and GitHub
does not redirect `tree/<branch>` paths to the default branch when that branch
does not exist. As a result each of these homepage links returns a 404 wherever
it is surfaced (the package page on npmjs.com, editor/IntelliSense hovers, and
`npm view <pkg> homepage`).

This repoints each `homepage` to `tree/next/...` so the links resolve. The
`repository.url` (plain `.git` URL) and `bugs.url` fields were already correct
and are left untouched.

The metadata was originally added in #3611; this only corrects the branch in the
`homepage` URLs.

Fixes #

## Changes
- Update the `homepage` field from `tree/main/...` to `tree/next/...` in the 14
  published packages that carry one: `@composio/core`, `@composio/slim`,
  `@composio/experimental`, `@composio/json-schema-to-zod`, and the providers
  `@composio/anthropic`, `@composio/claude-agent-sdk`, `@composio/cloudflare`,
  `@composio/google`, `@composio/langchain`, `@composio/llamaindex`,
  `@composio/mastra`, `@composio/openai`, `@composio/openai-agents`,
  `@composio/vercel`.
- Add a Changeset (patch) covering those 14 published packages.

## Type of change
- [x] Bug fix
- [ ] New feature
- [ ] Refactor/Chore
- [ ] Documentation
- [ ] Breaking change

## How Has This Been Tested?
Metadata-only change, so there is no unit test to add. Verified with:

- Confirmed the target branch: `git ls-remote --symref origin HEAD` reports
  `refs/heads/next`, and `git ls-remote --heads origin main` is empty (no `main`).
- Confirmed the links resolve: `https://github.com/ComposioHQ/composio/tree/main/ts/packages/core`
  returns HTTP 404 while `.../tree/next/ts/packages/core` returns HTTP 200
  (same for the provider packages).
- All 14 edited `package.json` files still parse as valid JSON.
- `pnpm exec prettier --check` on the 14 `package.json` files and the changeset:
  all pass.
- `pnpm changeset status --since=origin/next` lists exactly these 14 packages
  bumping at `patch` (no missing or extra packages), so the changeset CI check is
  satisfied.

Environment: node 26, pnpm 10.28.0.

## 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
- [ ] I updated documentation as needed
- [x] I added tests or explain why not applicable
- [x] I added a changeset if this change affects published packages

## Additional context
The `homepage` URLs pin an explicit branch (`tree/<branch>`), so they will break
again if the default branch is ever renamed. If you would prefer a
branch-agnostic form (for example dropping the `tree/<branch>` segment so the URL
tracks the default branch, or linking to the published README), I am happy to
switch to that instead; I went with the smallest correct fix of pointing at the
actual default branch.
```

Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com>
2026-07-13 20:06:43 +04:00
Alberto Schiabel 71255765a5 fix(schema): normalize duplicate required entries (#3812)
## Summary

- Normalize duplicate JSON Schema `required` entries at the shared
`ToolSchema` ingress boundary.
- Reapply normalization immediately before direct providers emit vendor
schemas (Anthropic, OpenAI, OpenAI Responses, Google, Cloudflare, and
OpenAI Agents).
- Preserve literal `const`/`default`/`enum`/`examples` values, tolerate
aliasing safely, and fail predictably on pathological nesting.
- Document the provider-boundary rule in
`ts/packages/providers/AGENTS.md`.

Co-authored-by: @MatinGathani

## Verification

- `pnpm changeset status`
- `pnpm --filter @composio/core build`
- Focused core and affected-provider Vitest suites (1,151 tests)
- `pnpm typecheck`
- `pnpm lint` (passes with 71 pre-existing warnings)

---------

Co-authored-by: MatinGathani <70268627+matingathani@users.noreply.github.com>
2026-07-13 15:03:38 +04:00
Alberto Schiabel 0de52639c4 feat(core)!: remove bare session aliases; freeze MCP SPI (#3780)
## What and why

This makes the intended v1 API cleanup real rather than postponing it to
v2:

- Remove the TypeScript root aliases `composio.create(...)` and
`composio.use(...)`. Session creation and reuse now live only at
`composio.sessions.create(...)` and `composio.sessions.use(...)`. This
is a deliberate breaking change, reflected by a major changeset.
- Retain `BaseProvider.wrapMcpServerResponse` as the stable v1 provider
SPI. Its earlier deprecation pointed to a method that was never
introduced.

The scope is intentionally narrow: it does **not** remove unrelated
deprecated APIs, and Python keeps its supported `Composio.create/use`
API. The TypeScript docs, examples, providers, runtime fixtures,
generated SDK reference, and API-reference indexes now use the
namespaced TypeScript API. Historical changelog examples are left as
history.

## Verification

- `pnpm typecheck`
- `pnpm --filter @composio/core test -- --run test/core/session.test.ts`
(42 files, 1,018 tests)
- `pnpm exec eslint ts/packages/core/src/composio.ts`
- `pnpm --filter @composio/core generate:docs`
- `cd docs && bun run generate:api-index`
- `cd docs && bun run types:check`
- `git diff --check` and targeted scans for removed TypeScript aliases

I also attempted the affected Node and Cloudflare runtime E2E suites.
They cannot initialize in this checkout without `COMPOSIO_API_KEY` (and,
for Cloudflare, `COMPOSIO_BASE_URL` and `OPENAI_API_KEY`); they did not
report a product assertion failure.
2026-07-13 13:22:55 +04:00
Alberto Schiabel a0f37a7f77 fix(core): SSRF guard on URL file inputs + telemetry secret redaction (#3779)
## What & why

Two v1 non-negotiable gates from the [SDK road to
v1](https://github.com/ComposioHQ/composio) plan are currently red. Both
are self-contained and closed here.

### ① SSRF guard on URL file inputs — `@composio/core`
`composio.files.upload(url)` and automatic file upload during tool
execution did a **raw `fetch()`** on user-supplied URLs
(`readFileContentFromURL`, `fileUtils.node.ts`) with no guard. Because
URL inputs deliberately bypass the local-path allowlist, a caller — or
an LLM-produced tool argument — could point the SDK at internal
infrastructure (`http://169.254.169.254/…` cloud metadata, RFC1918
hosts) or a public URL that 3xx-redirects into internal space.

New `ssrfGuard.node.ts`:
- resolves the host and refuses **private, loopback, link-local (incl.
`169.254.169.254`), CGNAT, TEST-NET, benchmarking, multicast, and
reserved** ranges (IPv4 + IPv6, incl. IPv4-mapped / NAT64);
- validates the **resolved address**, not the hostname string, so
decimal/octal/hex IP obfuscation doesn't slip through;
- rejects non-`http(s)` schemes;
- follows redirects **manually** so every hop is re-validated;
- blocked requests throw the new `ComposioBlockedInternalUrlError`.

Behaviour for legitimate public URLs is unchanged. Node-only path. Known
residual (documented in-file): a DNS-rebinding TOCTOU window between our
lookup and `fetch`'s connect — closing it fully needs connect-time IP
pinning (a custom dispatcher), out of scope here.

### ② Telemetry secret redaction — `@composio/core`
Error telemetry shipped `error.message` / `error.stack` **verbatim** to
`telemetry.composio.dev` with zero redaction. New `redact.ts` runs at
the single chokepoint (`prepareAndSendErrorTelemetry`) and strips URL
query strings, `Authorization` bearer/basic credentials, and secret-like
`key=value` pairs (API keys, tokens, client secrets, passwords) before
transport.

## Tests
- `ssrfGuard.test.ts` — IP classification (v4/v6, mapped, CGNAT,
metadata), scheme rejection, resolve-to-internal, "any resolved address
internal" pinning bypass, redirect-into-internal, redirect budget.
- `redact.test.ts` — URL query, bearer/basic, key/value secrets, quote
preservation, benign text untouched.
- Updated `fileUtils.test.ts` to mock DNS (hermetic) and expect
`redirect: 'manual'`.
- `tsc --noEmit` clean; lint clean.

## Notes
- `patch` changeset included.
- Adds `ComposioBlockedInternalUrlError` to the public error exports.
2026-07-10 19:35:10 +04:00
Alberto Schiabel b07fcada3f feat(experimental): add Eve provider and iMessage example (#3800)
This PR:

- supersedes https://github.com/ComposioHQ/composio/pull/3642 and
credits @shamsharoon for the original Eve provider and iMessage work
- rebases the integration onto the current `next` branch and resolves
its lockfile conflicts
- publishes an isolated `@composio/experimental/eve` entry with the
correct Eve 0.12+ peer contract
- adds recoverable per-session discovery, native Eve context
propagation, and durable approval policies for direct and batched side
effects
- centralizes circular-safe auth-link extraction across Eve and Pi and
replaces dense conditional expressions with named control flow
- hardens the iMessage example against `osascript` option injection,
unsafe trigger scoping, and third-party prompt injection
- preserves completed local-tool results when a mixed local/remote batch
loses its remote transport
- consolidates the example documentation onto shared components,
documents direct model-provider credentials, and clarifies that the
browsable source is not yet a standalone fixture
- verifies the change with 999 core tests, 32 experimental tests,
package builds/typechecks, packed peer-isolation smokes, and a
production docs build

---------

Co-authored-by: shams haroon <144290365+shamsharoon@users.noreply.github.com>
Co-authored-by: shams haroon <shamsharoon7@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: shams haroon <shams@composio.dev>
2026-07-10 16:57:11 +04:00
Alberto Schiabel 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
2026-07-07 00:30:40 +04:00
Alberto Schiabel 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.
2026-07-06 15:30:06 +04:00
Alberto Schiabel 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.
2026-07-06 14:33:55 +04:00
Alberto Schiabel 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>
2026-07-02 13:27:49 +04:00
Alberto Schiabel 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
2026-07-02 11:40:47 +04:00
Anshu Garg 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>
2026-07-02 01:05:07 +04:00
Alberto Schiabel 4c3a321550 fix(core): disable retries on non-idempotent tools.execute/proxyExecute (#3716)
This PR:

- Closes https://github.com/ComposioHQ/composio/issues/3586
- disables client retries on `tools.execute` and `tools.proxyExecute` —
the two non-idempotent writes — so a request that succeeds server-side
but times out client-side is no longer silently replayed (the cause of
duplicate `GMAIL_SEND_EMAIL` sends)
- routes both through a sibling client built with `withOptions({
maxRetries: 0 })`; reads keep the client's default retries (`maxRetries:
2`)
- caches that sibling per `Tools` instance (`clientWithoutRetries`)
since `withOptions` constructs a fresh client and execute/proxy is the
hottest path; mirrors the Python SDK's `client.without_retries`
- adds regression tests asserting both paths route through `maxRetries:
0` and that the sibling is built once across multiple executes

## Context

The original hang on attachments larger than ~25 KB was a backend defect
and has already been fixed server-side. The remaining gap was a
cross-SDK parity one: the Python SDK already disabled retries on these
non-idempotent writes, but `@composio/core` still inherited the client
default of 2 retries (3 attempts total), with no public knob to turn
them off. This is the TypeScript parity port — scoped to exactly
`tools.execute` / `tools.proxy`, leaving `toolRouter.session.execute`
and all reads on their default retry behaviour, matching Python.
2026-06-30 21:53:46 +04:00
sdkrelease[bot] 156a1eb7b2 Release: update version (#3686)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to next, this PR will
be updated.


# Releases
## @composio/vercel@0.11.0

### Minor Changes

- 9ffc696: Add AI SDK 7 support to `@composio/vercel`. The `ai` peer
dependency range is now `^6.0.0 || ^7.0.0` (AI SDK 5 is no longer
supported; both v6 and v7 are covered by e2e compatibility tests).
## @composio/core@0.13.1

### Patch Changes

- 605a726: Add Tool Router session deletion APIs.
## @composio/mastra@0.10.1

### Patch Changes

- cddd66c: Update the supported `@mastra/core` peer dependency range.
## @composio/slim@0.13.1

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-27 00:49:27 +04:00
Alberto Schiabel cddd66c3ce chore(ts): bump Hono, Mastra, and Chrome deps (#3691)
This PR:
- bumps `hono`, `@mastra/core`, and `chrome-devtools-mcp` to their
current latest published versions
- routes the remaining Cloudflare Tool Router Hono consumer through the
workspace catalog
- updates the `@composio/mastra` `@mastra/core` peer range and adds a
patch changeset
- fixes `check-peer-deps` to resolve `semver` through the normal package
dependency
2026-06-26 20:45:25 +04:00
Alberto Schiabel 9ffc696a99 feat(vercel): support AI SDK v7 (#3683)
This PR:

- widens the `ai` peer dependency of `@composio/vercel` to `^6.0.0 ||
^7.0.0`, adding AI SDK v7 support and dropping the previously-untested
v5 arm
- adds Docker-based Node e2e compatibility suites for AI SDK v6 and v7
under `ts/e2e-tests/runtimes/node/vercel-ai-sdk-v{6,7}`, auto-discovered
by the existing e2e matrix (so PR CI exercises them)
- each installs the packed `@composio/vercel` tarball, typechecks the
provider against the target `ai` major, and asserts runtime tool
wrapping/execution (object inputs, JSON-string normalization via
`normalizeToolArguments`, `ToolSet` shape)
- the v7 suite additionally exercises v7's `ToolExecutionOptions` passed
to `tool.execute`
- ships a `minor` changeset (the peer-range narrowing removes a
previously-supported major)
- breaking:
- `ai@5` is no longer an accepted peer of `@composio/vercel`; v5
consumers should stay on the prior minor
2026-06-26 14:08:09 +04:00
Abir Taheer 605a7263ab Add tool router session deletion (#3679)
## Summary
Explain the motivation and context for this change. Link to any related
issues.

Fixes #

## Changes
- 
- 

## Type of change
- [ ] Bug fix
- [ ] New feature
- [ ] Refactor/Chore
- [ ] Documentation
- [ ] Breaking change

## How Has This Been Tested?
Describe the tests you ran and instructions so reviewers can reproduce.
Include any relevant config/versions.

## Screenshots (if applicable)

## Checklist
- [ ] I have read the Code of Conduct and this PR adheres to it
- [ ] I ran linters/tests locally and they passed
- [ ] I updated documentation as needed
- [ ] I added tests or explain why not applicable
- [ ] I added a changeset if this change affects published packages

## Additional context

---------

Co-authored-by: jkomyno <alberto@composio.dev>
2026-06-26 12:38:28 +04:00
sdkrelease[bot] d102ab03ca Release: update version (#3676)
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to next, this PR will
be updated.


# Releases
## @composio/core@0.13.0

### Minor Changes

- d17a268: Add the first-class `composio.sessions.create()` API while
keeping `composio.create()` as an alias, expose the experimental
shared-connection ACL patch helper as `connectedAccounts.updateAcl()`
while keeping `experimental.updateAcl()` as an alias, and include SDK
docs/source in the published package.

**MCP is now opt-in.** Sessions return native tools by default; the
hosted MCP endpoint is only surfaced on the type when you create the
session with `{ mcp: true }`. The default `create()` / `use()` now
return `SessionWithoutMcp` (the runtime object is unchanged —
`session.mcp` still exists at runtime — but it is no longer in the
type).

Migration: read `session.mcp` only after creating with `{ mcp: true }`.

- d17a268: Surface the resolved workbench config on Tool Router
sessions.

- `Session.workbench` is now populated from the API response (on
create/retrieve/attach/update). It exposes the resolved workbench
config, e.g. `session.workbench?.enable` (defaults to `true`
server-side).

This lets callers create a session with the remote workbench disabled
(`workbench: { enable: false }`) and detect that state — the foundation
for running code in a sandbox you own via the experimental
`@composio/experimental/workbench` helpers.

### Patch Changes

- d17a268: Prefer `sandbox` for session code-execution configuration
while continuing to accept the existing `workbench` alias.
- d17a268: Add `triggers.parse()` to parse and optionally verify
incoming webhook requests.
- d17a268: Add `triggers.setWebhookSubscription()` to create or update
the project webhook subscription from the TypeScript SDK.
## @composio/experimental@0.1.0

### Minor Changes

- d17a268: Add the experimental BYO local workbench helpers on the new
`@composio/experimental/workbench` subpath.

These let you run a Composio Tool Router session in a sandbox you own
instead of Composio's hosted remote sandbox:

- `experimental_createLocalWorkbenchSession(composio, session)` takes a
caller-created session and returns `{ helperSource, env }`. It throws
unless the session was created with `workbench: { enable: false }` (a
local sandbox and the remote workbench cannot both run for one session).
- `experimental_createWorkbenchEnv(options)` builds the environment
variables the in-sandbox helper needs to reach Composio.
- `experimental_createPythonWorkbenchHelperSource(options)` returns the
Python helper source.

The local workbench assumes code runs in the developer's sandbox and
exposes Apollo-parity Python helpers for `run_composio_tool`,
`invoke_llm`, `web_search`, and `proxy_execute`.

> **Security caveat:** the helper authenticates with the developer's
full _project_ API key, injected into the sandbox env as
`COMPOSIO_API_KEY`. Any code or tool output running in the sandbox can
read and exfiltrate it — treat the sandbox as your security boundary and
rotate the key. A session-scoped `x-session-access-key` (so the
long-lived project key never enters the sandbox) is the planned
follow-up.

- d17a268: Add an experimental package with a Pi coding-agent provider,
static Composio tool wrapping, and dynamic Tool Router session helpers.

### Patch Changes

- d17a268: Add `proxy_execute` to the experimental local workbench
helper. The in-sandbox helper from
`experimental_createLocalWorkbenchSession`
(`@composio/experimental/workbench`) now exposes `proxy_execute(method,
endpoint, toolkit, query_params=None, body=None, headers=None)`
alongside `run_composio_tool`, `invoke_llm`, and `web_search`, so a
local sandbox can make authenticated direct API calls to a connected
toolkit when no pre-built tool exists. It posts to the public
`…/session/{id}/proxy_execute` route with the session's project API key,
and always returns a `(data, error)` tuple.
## @composio/slim@0.13.0

### Minor Changes

- d17a268: Add a slim Composio core package that mirrors the built
`@composio/core` runtime and types without publishing the packaged
`docs/` or `src/` trees.
## @composio/cli@0.3.1

### Patch Changes

- Updated dependencies [d17a268]
- Updated dependencies [d17a268]
- Updated dependencies [d17a268]
- Updated dependencies [d17a268]
- Updated dependencies [d17a268]
  - @composio/core@0.13.0
  - @composio/cli-local-tools@0.1.1
## @composio/cli-local-tools@0.1.1

### Patch Changes

- Updated dependencies [d17a268]
- Updated dependencies [d17a268]
- Updated dependencies [d17a268]
- Updated dependencies [d17a268]
- Updated dependencies [d17a268]
  - @composio/core@0.13.0

Co-authored-by: Rahul Tarak <cryogenicplanet@gmail.com>
2026-06-25 18:54:17 -07:00
Rahul Tarak 97e40b7071 fix(release): register slim+experimental in root workspaces; fix slim to core version
The changeset release on `next` aborted with "Found changeset add-slim-package
for package @composio/slim which is not in the workspace", blocking the Version
Packages PR and all publishes.

Root cause: changesets' package discovery (@manypkg/get-packages) reads the
root package.json `workspaces` field, which was stale — missing
`ts/packages/slim` and `ts/packages/experimental` (both present in
pnpm-workspace.yaml, so pnpm saw them but changesets did not).

- package.json: add ts/packages/experimental and ts/packages/slim to workspaces
- .changeset/config.json: fix @composio/slim to @composio/core so slim always
  ships the same version as core (slim mirrors the built core runtime)

Verified `changeset version` now resolves: core 0.13.0, slim 0.13.0,
experimental 0.1.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 18:40:30 -07:00