mirror of
https://github.com/ComposioHQ/composio.git
synced 2026-09-22 11:46:35 +08:00
@composio/cli@0.2.32-beta.273
276 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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> |
||
|
|
6a4cb542ae |
fix(core): resolve $ref/$defs so file flags behind a reference aren't dropped (#3566)
## Problem Tools whose parameter schemas express their file fields through a `$ref`/`$defs` indirection lose auto file handling: with `dangerouslyAllowAutoUploadDownloadFiles` enabled, a `file_uploadable` input behind a `$ref` is never staged (the local path is forwarded as-is and the backend rejects it), and the `format: "path"` hint never reaches the model. `GMAIL_GET_ATTACHMENT` is the canonical shape — its parameters nest the file flag two `$ref` hops deep: ``` data → $ref → #/$defs/GetAttachmentResponse → file → $ref → #/$defs/FileDownloadable (file_downloadable: true) ``` This is the TypeScript-SDK counterpart of #3506 (the Python side is handled separately in #3545). Two coupled causes defeat reference resolution: 1. **`$defs` is dropped on parse.** `ParametersSchema` (`src/types/tool.types.ts`) is a strict `z.object` that never declared `$defs`/`definitions`, so `ToolSchema.parse` stripped the root definition block off every tool. Each nested `$ref` was then dangling and unresolvable for *all* downstream consumers — providers that pass `inputParameters` straight to the model (e.g. `OpenAIProvider`) and the file modifier alike. (`JSONSchemaPropertySchema` already accepts both keywords; the root did not.) 2. **The file modifier never dereferences.** `transformProperties`, `schemaHasFileProperty`, and the upload/download hydration recurse `properties`/`anyOf`/`oneOf`/`allOf`/`items` but skip `$ref`, so a flag reachable only through a reference is invisible to the walk. ## Solution - Add `$defs`/`definitions` to `ParametersSchema` so the root definition block survives parsing and `$ref` pointers stay resolvable. - Dereference `inputParameters`/`outputParameters` in `FileToolModifier` (node runtime) before walking, via the existing `dereferenceJsonSchema` helper in `'sentinel'` mode — the same mode `MastraProvider` already uses. Tools that ship a `$ref` without a matching `$defs` target (#3307) degrade to a permissive object instead of throwing, exactly as today. No new dependencies; `dereferenceJsonSchema` already exists and is exercised by the Mastra provider. The edge (`workerd`) modifier is unchanged — its upload/download paths already throw as unsupported. ## Testing - `pnpm typecheck` — clean. - `pnpm test` (core) — 926 passing, including new cases: - `$ref`-indirected `file_uploadable` is marked `format: "path"` by `modifyToolSchema`. - `fileUploadModifier` stages a file whose flag is reachable only via `$ref`/`$defs`. - a `$ref` with no matching `$defs` target degrades gracefully (no throw). - root `$defs` survives `ToolSchema.parse` and nested `$ref` pointers remain intact. - Provider suites unaffected: `mastra` (51), `openai` (29), `vercel` (10), `anthropic` (19) all green. --------- Co-authored-by: jkomyno <alberto@composio.dev> |
||
|
|
4b76dbf70d |
fix(core): remove deprecated auth-config uuid field from V3 responses (#3633)
Replacement for #3528, preserving @lingala-composio's original commit, so CI can run from a same-repository branch. The original PR is from a fork. The TypeScript E2E workflow reads `COMPOSIO_API_KEY`, `COMPOSIO_BASE_URL_STAGING`, `COMPOSIO_USER_API_KEY`, `OPENAI_API_KEY`, and `ANTHROPIC_API_KEY` from repository secrets, and GitHub does not expose those secrets to fork PR workflow runs. That is why #3528's E2E checks failed with empty env values before exercising this SDK change. ## What & Why The Composio platform is removing the deprecated V1/V2 UUID-mirror fields from V3 API responses. The TypeScript SDK read and re-exposed the auth-config `uuid`, which was a deprecated mirror of the canonical nanoid `id`. This stops the SDK from depending on the removed field. ## Changes - Drop `uuid: authConfig.uuid` from `transformAuthConfigRetrieveResponse`. - Remove `uuid` from `AuthConfigRetrieveResponseSchema`. - Update AuthConfigs tests and fixtures to match the new contract. - Keep top-level `expectedInputFields` unchanged; only the deprecated nested bag was removed. ## Verification - `git diff --check origin/next...HEAD` - `pnpm --filter @composio/core test AuthConfigs` --------- Co-authored-by: lingala-composio <rahul.lingala@composio.dev> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
23f9053804 |
chore(ts): clean up dependencies and bump toolchain (#3623)
This PR: - consolidates and bumps TypeScript/npm dependencies across the monorepo, docs, examples, and e2e fixtures — no runtime behavior changes - **cleanup:** remove the unused `ansis` dependency from `@composio/cli` (`picocolors` is the actual color lib), drop the dead `uuid` catalog entry, catalog `dotenv` + `@types/bun` and repoint drifting examples/e2e onto them, and replace `chalk` with `picocolors` in `@composio/core` (smaller, ESM, already used by the CLI) - **TypeScript 6:** bump `typescript` `5.9 → 6.0.3` everywhere (catalog, CLI test fixtures, docs); drop vestigial `declaration`/`outDir` from the provider `tsconfig.json`s to fix the TS 6 `rootDir` regression (`TS6059`); add `ignoreDeprecations: "6.0"` in docs for the `baseUrl` deprecation - **toolchain:** `tsdown 0.18 → 0.22.3`, `vitest` + `@vitest/ui → 4.1.9`, `publint → 0.3.21`, `wrangler → 4.101.0` (each the latest version within the 3-day `minimumReleaseAge` gate) - **Effect + hono:** `effect 3.21.3`, `@effect/cli 0.75.2`, `@effect/platform 0.96.1`, `platform-bun 0.90.0`, `platform-node-shared 0.60.0`, `language-service 0.86.2`, `@effect/vitest 0.29.0`, `hono 4.12.25`; pin the Effect peer cohort (`printer`/`printer-ansi`/`typeclass`/`rpc`/`sql`/`cluster`/`experimental`/`workflow`) as `@composio/cli` devDeps so the auto-installed peers resolve coherently, and bump `@cloudflare/workers-types` to satisfy `wrangler`'s peer - changesets: `@composio/cli` patch (ansis removal) and `@composio/core` patch (chalk → picocolors) - verified: `build`, `typecheck` (tsgo + real `tsc` 6.0.3), and local tests (excluding e2e) all pass |
||
|
|
cbbad15126 |
fix(ts): support Zod 4 custom tool schemas (#3495)
## Summary Stacked on #3494. This PR tightens the SDK's Zod boundary now that the TypeScript packages are moving to the newer Node/toolchain baseline. The main issue was asymmetric Zod support: `@composio/json-schema-to-zod` already supports projects with Zod 3 and Zod 4 by generating schemas through `zod/v3`, but custom tools converted schemas in the opposite direction through `zod-to-json-schema` only. With a bare Zod 4 `z.object(...)`, that path degraded to an empty JSON Schema. ## What changed - Added a shared core helper for Zod schema -> JSON Schema conversion. - Supports both `zod/v3` schemas and Zod 4 schemas via `z.toJSONSchema`. - Converts custom-tool input schemas in Zod 4 input mode, so defaulted fields stay optional in the generated JSON Schema. - Uses the shared helper in both custom-tool entrypoints: `createCustomTool(...)` and legacy `composio.tools.createCustomTool(...)`. - Updates custom-tool types so Zod 4 schemas infer their `execute` input type while keeping the session context parameter required for context-using tools. - Exposes `jsonSchemaToZodShape` through the narrow `@composio/core/utils/json-schema` subpath. - Switches the Claude Agent SDK provider to use that core subpath instead of depending directly on `@composio/json-schema-to-zod` or converting to a full Zod object and casting `.shape` out of it. - Adds patch changesets for `@composio/core` and `@composio/claude-agent-sdk`. ## Review hardening Follow-up fixes from a deeper pass over the new conversion boundary: - **Fixes a Zod 3 regression in the v3/v4 discriminator.** The detector keyed on `_def.type` being defined, but Zod 3 stores the element schema there for `z.array()` / `z.promise()` — so a Zod 3 array/promise `outputParams` was misrouted into `z.toJSONSchema` and crashed with `Cannot read properties of undefined (reading 'def')`. It now discriminates on `_def.type` being a string literal (Zod 4) versus a `ZodType` object (Zod 3), with a regression test. - **Mirrors input/output mode on the Zod 3 path.** The `io` mode was applied to the Zod 4 converter but dropped on the Zod 3 branch; it now maps onto `zod-to-json-schema`'s `pipeStrategy`/`effectStrategy` so `.default()` / `.transform()` / `.pipe()` schemas serialize consistently across both runtimes. Added a v3/v4 input-mode parity test. - **Fails loudly on a missing named definition** instead of returning the wrapper document, which downstream silently degraded into an empty object schema. - **Replaces broad `as never` casts** in the Claude Agent SDK provider with a single concrete `tool()` signature — this sidesteps the SDK's deep-instantiation error while keeping the handler's real argument type. - **Trims now-dead code** from the custom-tool schema types and conversion path. ## Verification - `mise exec -- pnpm --filter @composio/core test` (933 passing) - `mise exec -- pnpm --filter @composio/claude-agent-sdk test -- --runInBand` (17 passing) - `mise exec -- pnpm --filter @composio/core build` (publint + attw clean, emits `@composio/core/utils/json-schema`) - `mise exec -- pnpm --filter @composio/claude-agent-sdk exec tsc --noEmit --skipLibCheck` - `mise exec -- pnpm --filter @composio/claude-agent-sdk build` (publint + attw clean) - `mise exec -- pnpm install --frozen-lockfile` - `git diff --check` Note: `mise exec -- pnpm --filter @composio/core typecheck` still fails on the existing `src/utils/pusher.ts` `ChannelAuthorizationHandler` type mismatch. This PR does not touch that file; the core build and full core unit suite pass. |
||
|
|
025a657597 |
feat(ts): drop CommonJS support (#3494)
This PR moves the TypeScript SDK support floor to the latest Node.js 22 release and uses that as the point where we stop carrying custom CommonJS compatibility machinery. The e2e runtime coverage now exercises the latest Node 22, Node 24, and Node 25 lines, so the SDK is tested against the minimum supported version and the newer runtimes users are likely to adopt next. Because the SDK packages are still on `0.x`, the accompanying changeset uses `minor` bumps while calling out that this is a breaking change inside the existing 0.x line. It also moves pnpm under mise on this Node 22 layer. That belongs here, not in #3493, because the pinned `pnpm@10.28.2` requires Node.js `>=22.13`. Removing Corepack is intentional: Node.js documents that Corepack is no longer distributed starting with Node.js v25, so relying on `corepack enable` would keep a toolchain dependency that is already on the way out of the Node distribution. ## What changed - Pins the local/toolchain Node.js floor to `22.22.3` in `mise.toml`, `mise.lock`, `toolchain-versions.json`, and root `devEngines`. - Pins pnpm in `mise.toml` as `"npm:pnpm" = "10.28.2"` and makes mise the single source of truth for the pnpm version. Removes the root `packageManager` / `devEngines.packageManager` Corepack pin entirely (rather than keeping a second copy of the version that could drift) and removes stale `packageManager` metadata from real TS packages/examples and generators. - Sets `dangerouslyDisablePackageManagerCheck: true` in `turbo.jsonc` so Turbo discovers pnpm from `pnpm-lock.yaml` instead of requiring a `packageManager` field. Without this, Turbo fails workspace resolution (`Could not resolve workspaces -> Missing 'packageManager' field`), which is the only reason the field would otherwise need to stay. - Replaces `corepack enable` in the shared setup action with mise-managed pnpm. The E2E Docker images install bun + pnpm directly from `mise.toml`/`mise.lock` (with `dangerouslyDisablePackageManagerCheck`-style separation: Node/Deno stay on the base image as the test matrix axis and are disabled via `MISE_DISABLE_TOOLS` so mise does not shadow them; the tool binaries are symlinked into `/usr/local/bin`). No `BUN_VERSION`/`PNPM_VERSION` build args are threaded from the host anymore, and bun+pnpm now carry `mise.lock` checksum verification. - Extends the install-time toolchain check to validate pnpm against mise alongside Bun. - Sets the Node E2E matrix and install fallback checks to `22.22.3`, `24.16.0`, and `25.9.0`. - Makes TS package builds ESM-only: `tsdown` now emits `.mjs` / `.d.mts` only and uses the ATTW `esm-only` profile. - Removes explicit `require` / `.cjs` / `.d.cts` package export paths and internal import mappings from the public TS SDK packages. - Marks public TS SDK packages as `type: module` where they were missing it. - Replaces the remaining runtime `require('pusher-js')` with dynamic ESM import. - Deletes the legacy CJS example. - Reintroduces `node/cjs-basic` as a modern Node `require(esm)` interop E2E: it verifies `require('@composio/core')` works through Node's native ESM loader on Node 22, 24, and 25 while resolving to `dist/index.mjs`, not a `.cjs` artifact. - Removes `.cjs` / `.cts` handling from example validation and CLI project-language detection. - Updates provider scaffolding so newly generated providers are ESM-only. - Adds a minor changeset warning that CommonJS callers can only rely on Node's native `require(esm)` interop and that custom CommonJS compatibility machinery is gone. ## Bundled behavior changes Two changes here are technically independent of the CommonJS removal but ride along because they touch the same files and ship in the same release cut. Calling them out explicitly so they are not missed in review: - **`PusherUtils` realtime channel auth (`@composio/core`).** Replacing the runtime `require('pusher-js')` with a dynamic ESM `import()` was done alongside conforming `channelAuthorization` to pusher-js's typed `customHandler(params, callback)` contract. The previous `(authOptions) => Promise` shape did not match pusher-js's actual calling convention — it read `endpoint`/`headers`/`params` off an argument that pusher-js never passes — so this also fixes that latent mismatch. New unit tests (`ts/packages/core/test/utils/pusher.test.ts`) cover the auth request shape (endpoint, `x-api-key` header, JSON `socket_id`/`channel_name` body) and the success / invalid-JSON / network-failure callback paths. - **CLI meta-tool slug list (`@composio/cli`).** Drops `COMPOSIO_UPSERT_RECIPE` and `COMPOSIO_GET_RECIPE` from `META_TOOL_SLUG_LIST` in `tools-executor.ts`; `@composio/client` alpha.74 removed those slugs from the `SessionExecuteMetaParams['slug']` union. The list is declared `satisfies ReadonlyArray<SessionExecuteMetaParams['slug']>`, so this is enforced at compile time (`pnpm typecheck`) — keeping the stale slugs would be a type error — and needs no separate runtime test. ## Verification - Verified latest Node 22/24/25 releases from the official Node dist index: `22.22.3`, `24.16.0`, `25.9.0` (https://nodejs.org/dist/index.json). - Verified Node docs state Corepack is no longer distributed starting with Node.js v25: https://nodejs.org/download/release/v22.22.3/docs/api/corepack.html - `mise exec -- pnpm --version` -> `10.28.2` - `mise exec -- pnpm install --frozen-lockfile` - `mise exec -- bun run ts/scripts/pre-install/check-toolchain.ts` - `mise exec -- pnpm --filter @e2e-tests/utils typecheck` - `mise exec -- pnpm --filter @e2e-tests/node-cjs-basic typecheck` - `mise exec -- pnpm --filter @e2e-tests/node-cjs-basic test:e2e:node` - `mise exec -- pnpm --filter @e2e-tests/node-esm-basic typecheck` - `mise exec -- pnpm --filter @composio/cli typecheck` - `mise exec -- pnpm --filter @composio/cli test -- --runInBand` - `mise exec -- pnpm --filter @composio/core typecheck` - `mise exec -- pnpm --filter @composio/core exec vitest run test/utils/pusher.test.ts` - `mise exec -- pnpm run build:packages` - `mise exec -- turbo run build --dry-run` resolves all workspace packages with no root `packageManager` field (pnpm discovered from `pnpm-lock.yaml`). - `mise exec -- pnpm --filter @composio/cli exec vitest run test/src/services/project-environment-detector.test.ts` - `mise exec -- pnpm exec prettier --check ...` - `docker build -f ts/e2e-tests/_utils/Dockerfile.node --build-arg NODE_VERSION=24.16.0 -t composio-e2e-node:misecheck .` (also `Dockerfile.deno` with `DENO_VERSION=2.6.7 NODE_MAJOR=22`) — both build green; runtime resolves Node/Deno from the base image and pnpm 10.28.2 / bun 1.3.10 from mise. - `docker manifest inspect node:24.16.0-slim` - `docker manifest inspect node:25.9.0-slim` - `bash -n ts/scripts/create-provider.sh && git diff --check` - `ruby -e "require 'yaml'; YAML.load_file('.github/workflows/ts.test-e2e.yml')"` - Tracked example validation in a clean temporary tree: `Validated 21 example packages.` |
||
|
|
5f004ffbfe |
fix(cli): drop recipe meta-tool slugs removed from @composio/client (#3615)
This PR: - cherry-picks the CLI fix from https://github.com/ComposioHQ/composio/pull/3494 so `next` is unblocked independently of that larger ESM-only PR - fixes the `@composio/cli#build` typecheck failure on `next` (`TS2322` in `ts/packages/cli/src/services/tools-executor.ts`) that is currently breaking the **TS SDK Release** workflow - `@composio/client` alpha.74 (https://github.com/ComposioHQ/composio/pull/3609) removed `COMPOSIO_UPSERT_RECIPE` and `COMPOSIO_GET_RECIPE` from `SessionExecuteMetaParams['slug']`, but `META_TOOL_SLUG_LIST` (declared `satisfies ReadonlyArray<SessionExecuteMetaParams['slug']>`) still listed them, so the build no longer type-checked - adds a `@composio/cli` patch changeset Verified locally: `pnpm --filter @composio/cli typecheck` passes. |
||
|
|
a0bef5d986 |
chore(deps): bump composio client SDKs (TS alpha.74, Py 1.41.0) (#3609)
This PR: - bumps the TS catalog `@composio/client` from `0.1.0-alpha.72` to `0.1.0-alpha.74` (published from ComposioHQ/composio-base-ts#84) and refreshes `pnpm-lock.yaml` - bumps the Python `composio-client` pin from `1.39.0` to `1.41.0` (published from ComposioHQ/composio-base-py#69) - adds a patch changeset for `@composio/core` and `@composio/cli` so the client bump actually ships in the next release ## Context Neither client is auto-bumped in this repo — there is no Stainless→consumer bot, and Dependabot does not touch the pnpm `catalog:` pin (TS) or the exact `composio-client==` pin (Py), so these were a manual catch-up. The Python `1.41.0` PyPI publish initially failed with a `403 Forbidden` (stale `PYPI_TOKEN`); it was re-run successfully before this bump, so `1.41.0` is live on PyPI. |
||
|
|
f6df489c0b |
Release: update version (#3429)
> [!WARNING] > ## ⚠️ Breaking change — `@composio/core@0.11.0` (minor bump, pre-1.0) > > The legacy in-memory custom-tools registry **`composio.tools.createCustomTool(...)` has been removed** (changeset `44e5458`). Because `@composio/core` is pre-1.0, this ships as a **minor** bump per semver convention — but it **is breaking**: any code calling `composio.tools.createCustomTool(...)` will fail to compile/run after upgrading. Consumers pinned to `^0.10.0` will **not** auto-upgrade to `0.11.0` and must opt in explicitly. ### Migration: use Tool Router custom tools Custom tools are now standalone factories bound to a **Tool Router session**, instead of being registered into an in-memory registry on the `composio.tools` namespace. **Before (removed):** ```ts // ❌ No longer available in 0.11.0 const tool = composio.tools.createCustomTool({ /* ... */ }); ``` **After — a standalone tool (no auth):** ```ts import { Composio, experimental_createTool } from '@composio/core'; import { z } from 'zod'; const composio = new Composio(); const grep = experimental_createTool('GREP', { name: 'Grep Search', description: 'Search for patterns in files', inputParams: z.object({ pattern: z.string(), path: z.string() }), execute: async (input) => ({ matches: [] }), }); // Bind the custom tool(s) to a Tool Router session const session = await composio.create(userId, { experimental: { customTools: [grep] }, }); ``` **After — a tool that extends a Composio toolkit (inherits that toolkit's auth):** ```ts const getImportantEmails = experimental_createTool('GET_IMPORTANT_EMAILS', { name: 'Get Important Emails', description: 'Fetch high-priority emails', extendsToolkit: 'gmail', inputParams: z.object({ limit: z.number().default(10) }), execute: async (input, ctx) => { // ctx.execute() returns the standard { data, error, logId } shape const result = await ctx.execute('GMAIL_SEARCH', { query: 'is:important' }); return { emails: result.data }; }, }); const session = await composio.create(userId, { experimental: { customTools: [getImportantEmails] }, }); ``` **After — grouping related tools into a custom toolkit:** ```ts import { experimental_createToolkit } from '@composio/core'; const devTools = experimental_createToolkit('DEV_TOOLS', { name: 'Dev Tools', description: 'Local developer utilities', tools: [grep], // tools here must NOT set `extendsToolkit` }); const session = await composio.create(userId, { experimental: { customToolkits: [devTools] }, }); ``` > Notes: > - `experimental_createTool` / `experimental_createToolkit` are also available from the dedicated `@composio/core/experimental` entry point. > - Tool slugs are auto-prefixed with `LOCAL_` when exposed to the agent (e.g. `GREP` → `LOCAL_GREP`; inside a toolkit, `DEV_TOOLS` + `GREP` → `LOCAL_DEV_TOOLS_GREP`). > - These APIs are intentionally namespaced `experimental_*` — they are not yet stable and may change. --- 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.11.0 ### Minor Changes - |
||
|
|
eba6c6d7ef |
fix(release): keep provider peer bumps range-aware (#3582)
This PR: - prevents the open Changesets release PR from promoting provider packages to `1.0.0` when `@composio/core` gets a minor bump that still satisfies their peer range - points Changesets at `next`, matching the active TypeScript release branch and workflow trigger - enables `onlyUpdatePeerDependentsWhenOutOfRange` so peer dependents only major-bump when the new dependency version leaves their declared range - adds a release workflow guard that runs Changesets against a fixture and verifies `@composio/core@0.10.0` -> `0.11.0` keeps `@composio/openai` on `0.9.3` - leaves https://github.com/ComposioHQ/composio/pull/3429 to regenerate after this lands on `next` |
||
|
|
a94715f577 |
feat(sdk): forward user_id on triggers.create for trigger 2FA (#3576)
## What `triggers.create(userId/user_id, ...)` already accepts a user id and uses it to resolve the connected account, but **dropped it** when building the `trigger_instances.upsert` body. With [2FA for triggers](https://linear.app/composio/issue/PLEN-2580) on the backend, 2FA-enabled projects need `user_id` on the upsert to verify the pinned connected account belongs to the caller's user. This forwards `user_id` to upsert in **both SDKs**: - **TS** (`ts/packages/core/src/models/Triggers.ts`): adds `user_id` to the upsert params via a `& { user_id?: string }` bridge. - **Python** (`python/composio/core/models/triggers.py`): forwards `user_id` via the client's supported `extra_body` escape hatch. Both bridges exist only until `@composio/client` / `composio-client` regenerate from the updated OpenAPI spec with a native `user_id` field — drop them then. ## Safety Backends without trigger 2FA ignore the extra field, so this is safe to land ahead of / alongside the backend rollout (hermes PR #10635). ## Tests - TS: upsert-body assertion added. - Python: `tests/test_triggers.py::test_create_with_user_id` asserts `extra_body == {"user_id": ...}`. 49 tests pass. Closes part of PLEN-2580 (SDK follow-up to the agreed approach). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: jkomyno <alberto@composio.dev> |
||
|
|
ce4b213361 |
fix(providers): normalize string tool-call arguments across all providers (TS + Python) (#3514)
## Summary Models — and some MCP transports — occasionally emit tool-call arguments as a **JSON string instead of an object/dict**. The most visible trigger is `COMPOSIO_MULTI_EXECUTE_TOOL` on the Vercel AI SDK, where streaming fails with: > `messages.3.content.1.tool_use.input: Input should be a valid dictionary` Until now only a handful of providers guarded against this, each with its own slightly different inline check, leaving most providers vulnerable and behaviour inconsistent across the SDK. This PR centralizes the coercion into **one helper per language** and routes **every** provider through it, in both the TypeScript and Python SDKs. Closes https://github.com/ComposioHQ/composio/issues/2406 ## What changed **TypeScript** — new `normalizeToolArguments` in `@composio/core` (exported), used by every provider: `vercel`, `cloudflare`, `openai-agents`, `openai` (ChatCompletions + Responses), `anthropic`, `google`, `langchain`, `llamaindex`, `claude-agent-sdk`, `mastra`. **Python** — new `normalize_tool_arguments` in `composio.utils.shared`, used by every provider: `openai`, `openai-responses`, `anthropic`, `google`, `langchain`, `langgraph`, `crewai`, `autogen`, `llamaindex`, `gemini`, `google-adk`, `openai-agents`, `claude-agent-sdk`. Shared semantics (identical in both languages): | Input | Result | | --- | --- | | object / dict | returned unchanged | | JSON string | parsed to object | | empty / whitespace string | `{}` | | `null` / `undefined` / `None` | `{}` | | array, primitive, unparseable string, JSON that isn't an object | **typed error** (`ComposioInvalidToolArgumentsError` / `InvalidParams`) with the original parse error as cause | The typed error replaces the previous grab-bag of behaviours: a raw `SyntaxError`/`JSONDecodeError`, or — worse — silently forwarding a malformed string downstream. ## Why this supersedes the open PRs This consolidates and extends three open PRs that each addressed a slice of the problem inconsistently. Their authors are credited as co-authors on the relevant commits: - **#3489** (LlamaIndex + Claude Agent SDK, TS) — @srijanarya - **#3438** (Anthropic, Google, LangChain, TS) — @aptsalt - **#3437** (Google ADK empty schemas + name fix, Python) — @pragnyanramtha — its empty-`input_parameters` / missing-description handling and the `gemini` → `google_adk` provider-name fix are folded in here. Compared to the three combined, this PR additionally: covers **every** provider in **both** SDKs (not a subset of one), defines a single source of truth instead of per-provider snippets, normalizes empty/`null` payloads to `{}`, and raises an actionable typed error instead of leaking `SyntaxError` or forwarding a bad string. ## Tests - Exhaustive unit tests for both helpers (object passthrough, JSON-string parse, empty/null → `{}`, malformed/non-object → typed error). - Per-provider regression tests across the touched TypeScript providers (string path, malformed-string path, empty-payload path). - Full `@composio/core` + touched-provider TS suites pass; `typecheck` and `lint` clean. Python `ruff` clean and new test green. ## Changeset Patch bump for all affected TypeScript packages (`@composio/core` + the providers). Python follows its own versioning, so no changeset there. --------- Co-authored-by: srijanarya <74669415+srijanarya@users.noreply.github.com> Co-authored-by: Deepak Singh Kandari <deepaksinghkandari07@gmail.com> Co-authored-by: Pragnyan Ramtha <pragnyanramtha@gmail.com> |
||
|
|
56534e2158 |
chore(cli): release 0.2.31 (#3538)
## What Manual version bump for **`@composio/cli` → 0.2.31**, replacing the broken changeset-bot flow. - Bumps `ts/packages/cli/package.json` `0.2.30 → 0.2.31` - Adds the `0.2.31` entry to `ts/packages/cli/CHANGELOG.md` - Consumes (deletes) the 5 CLI changesets it covers: - `composio upgrade <version>` (#3428) - `x-cli-session-id` header (#3430) - refreshed approval fallback page (#3431) - LLM-friendly output (#3450) - fish completion paths (#3162) + 1-hour permission expiry (#3449) - Leaves the `@composio/core` changesets untouched for the bot. ## Why manual The changeset release bot (`ts.release.yml` → `changesets/action`) has been failing on **`HttpError: Bad credentials`** on every run since 2026-06-04 — its `CI_BOT_TOKEN` secret is expired/invalid — so it can no longer regenerate the "Release: update version" PR (#3429, stale since 2026-05-20). `build-cli-binaries.yml` is healthy and independent of that token: on merge to `next` it compares `ts/packages/cli/package.json` against the previous commit, detects the version change, and builds + publishes the stable **`@composio/cli@0.2.31`** GitHub release (cross-platform binaries). The CLI is `"private": true`, so it ships only as the GitHub binary release, not npm — this path fully covers it. ## Validated The pinned-actions binary pipeline was already validated green end-to-end (all 4 platform binaries built + full install-test matrix passed) on a `build-beta` run. Local binary (built from this same source) passed version/whoami/help, LLM-friendly stdout, `upgrade <version>`, and the full Slack + `experimental_subAgent` integration test. ## Follow-up (separate) `CI_BOT_TOKEN` needs refreshing to restore the changeset bot (recommend a GitHub App installation token over a personal PAT to avoid future expiry). Tracked outside this PR. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
df104ec1fa |
chore: CLI 0.2.31 patch release (#3536)
## Changes since `@composio/cli@0.2.30` ### Features - **feat(cli): `composio upgrade <version>`** (#3428) — install a specific stable or beta release (`0.13.1`, `0.13.1-beta.42`, or full tag). No-arg behavior unchanged; `--beta` still controls the latest-prerelease case. - **feat(cli): send `x-cli-session-id` header** (#3430) — attach the per-cwd CLI session id to every client request so tool execution logs can be grouped by CLI session. - **feat(cli): refresh approval fallback page** (#3431) — browser fallback tool-approval prompt restyled in the CLI landing-page visual language and served directly from the loopback callback server; native macOS sidecar remains preferred. ### Fixes - **fix(cli): make output more LLM-friendly** (#3450) — route logger output to stderr, gate human-only notices/prompts on interactive TTYs, keep `composio run` helper/subagent logs off stdout. - **fix(cli): permission allows expire after 1 hour** (#3449) — prompt action relabeled "Allow for 1 hr"; cached allow decisions expire after 1h with stale-entry pruning. - **fix: fish completion install paths** (#3162) — write completions to `~/.config/fish/completions/composio.fish` and sanitize lines that could break parsing. ## Changeset A single patch bump (`@composio/cli` → 0.2.31) aggregated from the pending changesets: - `.changeset/cli-upgrade-version-arg.md` - `.changeset/cli-session-id-header.md` - `.changeset/cli-permission-fallback-design.md` - `.changeset/quiet-llm-friendly-cli.md` - `.changeset/cli-fish-completions-and-permission-expiry.md` (new — covers #3162 and #3449) ## Testing ### Phase 1: CI Types/Lint - N/A for this branch — `ts.typecheck` / `ts.test` / `ts.build` are gated on `paths: ts/**`, and this branch only adds a `.changeset/*.md`. Each underlying CLI PR (#3428/#3430/#3431/#3449/#3450/#3162) already passed CI when merged to `next`. ### Phase 2: Local Binary Test ✅ Built from source (`pnpm turbo build` → `build:binary`) and tested: - `composio version` → `0.2.30` ✅ · `composio whoami` → JSON ✅ · `composio --help` ✅ - `composio run 'console.log(...)'` → clean stdout (LLM-friendly stderr routing confirmed, #3450) ✅ - `composio upgrade` `<version>` arg wired (`normalizeReleaseTag`, #3428) ✅ - `SLACK_SEND_MESSAGE` input validation correctly rejects unknown keys (LLM-friendly errors) ✅ - **Slack integration test** ✅ — `SLACK_FIND_CHANNELS` → `SLACK_SEND_MESSAGE` → `SLACK_FETCH_CONVERSATION_HISTORY` → `experimental_subAgent` (structured output via `z` schema + `result.prompt()`) → summary posted to `#buzz-skill-based-cli-testing`. ### Phase 3: Bundled Binary (CI) ✅ pipeline unblocked The CI binary pipeline was briefly blocked by a new org policy requiring SHA-pinned actions — **already resolved on `next` by #3531** (`chore(ci): pin GitHub Actions to SHAs`). A validation `build-beta` on an identically-pinned branch confirmed the fix: "Resolve Release Metadata" passes and binaries build/test green across platforms. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
44e5458c35 |
feat(core): remove legacy TypeScript custom tools (#3509)
This PR is **part 2 of 3** splitting https://github.com/ComposioHQ/composio/pull/3505 to make the removal of the old 2025 custom tools easier to review. It carries the **TypeScript** slice. - builds on top of https://github.com/ComposioHQ/composio/pull/3508 (stacked — review/merge the Python slice first; this PR's base is `remove-py-custom-tools`) - removes the legacy `composio.tools.createCustomTool(...)` in-memory registry: the plural `CustomTools` model, registry wiring, legacy-only tests/examples/`ts/docs` pages, and stale error/type exports - preserves the 2026 tool-router APIs: `experimental_createTool`, `experimental_createToolkit`, `ToolRouter`, `ToolRouterSession`, and inline custom-tool execution - regenerates the TypeScript SDK reference so raw tool listing no longer describes the removed local registry and points to session-scoped custom tools - adds a `@composio/core` minor changeset ## Notes - The committed SDK reference is **verified self-consistent**: `pnpm --filter @composio/core generate:docs` reproduces it with zero diff. - This slice is a byte-identical subset of #3505 — the three split branches recombine to that PR's exact tree. See #3505 for the original verification logs (`typecheck`, `test`, `lint`, `cf-workers` e2e); CI re-runs per PR. |
||
|
|
b69cef123f |
fix(mastra): tolerate dangling $ref in tool schemas [PLEN-2451] (#3400)
## Summary Closes [PLEN-2451](https://linear.app/composio/issue/PLEN-2451/mastraprovider-dollardefsdollarref-schema-is-dangling-at-the-api). Fixes https://github.com/ComposioHQ/composio/issues/3307. The Composio API ships some tools (e.g. `GMAIL_FETCH_EMAILS`) with `outputParameters` like: ```jsonc { "type": "object", "properties": { "data": { "$ref": "#/$defs/FetchEmailsResponse" }, // ← points into $defs "error": { "type": "string" }, "successful": { "type": "boolean" } }, "required": ["data", "successful"] // ← no `$defs` block anywhere } ``` Since [PLEN-2244](https://linear.app/composio/issue/PLEN-2244) introduced strict `dereferenceJsonSchema`, this caused `composio.tools.get(...)` to throw `JsonSchemaRefResolutionError: Cannot resolve $ref #/$defs/FetchEmailsResponse` upfront via `MastraProvider.wrapTool`, making every Gmail / Slack / Google Calendar tool unusable through the Mastra integration. ### Approach Two-tier fix that keeps the architectural boundary from PLEN-2244 (only the provider that owns the validation contract pre-processes the schema): 1. **`@composio/core`** — add an additive opt-in to `dereferenceJsonSchema`: ```ts dereferenceJsonSchema(schema, { onUnresolved: 'sentinel', // default 'throw' unchanged onReplace: (ref, reason) => { /* observe */ }, }) ``` In `'sentinel'` mode the unresolvable branch is replaced with the same `{ type: 'object', additionalProperties: true }` cycle-break sentinel the resolver already uses for `$ref` cycles. Safety caps (`MAX_REF_CHAIN_DEPTH`, `MAX_NODE_DEPTH`) keep throwing in both modes. Default behavior is byte-for-byte unchanged — first-party / custom-tool authors who typo a `$ref` still see a hard error. 2. **`@composio/mastra`** — opt `wrapTool` into sentinel mode for both `inputParameters` and `outputParameters` and emit one `logger.warn` per `(toolSlug, ref)` pair via a provider-scoped dedup `Set`. The warning names the tool / toolkit / pointer and links to https://github.com/ComposioHQ/composio/issues/3307. ### Why not centralize the dereferencing in `Tools.ts`? - Mastra is the only provider that wraps `outputParameters`. Vercel / OpenAI / Anthropic / Google bind tool input schemas to function-calling APIs that ignore output shapes. - Centralized dereferencing would silently mutate `tools.get()`'s public output shape for callers iterating raw schemas. - PLEN-2244 set the precedent — the provider that owns the validation contract pre-processes its own schemas. This PR mirrors that boundary. ### API-side follow-up The proper long-term fix is for the Composio API to emit a top-level `$defs` block alongside any `$ref` it produces. That belongs in a separate backend ticket — the SDK fix is intentionally independent so we don't block on a backend rollout. The SDK now degrades gracefully regardless of which API version it talks to. ## Test plan Red-green TDD — every new test was confirmed red against the pre-fix `dereferenceJsonSchema` / `MastraProvider`, then green after the fix. - [x] **Core** — 9 new cases in `ts/packages/core/test/utils/jsonSchema.test.ts` under `describe("with onUnresolved: 'sentinel' lenient mode")` covering: missing-target, missing-key, malformed-pointer (non-`#/` ref), mixed schema (resolvable + dangling siblings), `onReplace` reasons, safety-cap-still-throws (chain & node depth), explicit `'throw'` matches default, `onReplace` not called in strict mode. - [x] **Mastra** — new file `ts/packages/providers/mastra/test/mastra-dangling-defs.test.ts` (6 cases, un-mocked `@mastra/schema-compat`): replicates the exact `GMAIL_FETCH_EMAILS.outputParameters` shape; verifies no throw, no surviving `$ref` in the produced schema, exactly one warn per `(slug, ref)` pair across repeat wraps, a separate warn per slug, symmetric tolerance on `inputParameters`, and a regression guard for resolvable `$defs` (PLEN-2244 contract). - [x] **Regression** — all 908 core tests, all 39 existing `mastra.test.ts` cases, and all 3 `mastra-ref.test.ts` cases continue to pass. Full TS workspace test run: 14 packages green, 1322 tests total. - [x] `pnpm typecheck` passes in both `@composio/core` and `@composio/mastra`. - [x] `pnpm lint` on touched files produces no new warnings. - [ ] **Manual** (post-merge, against live API): `composio.tools.get(userId, { tools: ['GMAIL_FETCH_EMAILS'] })` returns a `MastraTool` whose `outputSchema` is defined; SDK logs exactly one warning per process per `(slug, ref)` pair. ## Files ``` ts/packages/core/src/index.ts # new type exports ts/packages/core/src/utils/jsonSchema.ts # opts + lenient branch ts/packages/core/test/utils/jsonSchema.test.ts # 9 new cases ts/packages/providers/mastra/src/index.ts # opt-in + dedup warn ts/packages/providers/mastra/test/mastra-dangling-defs.test.ts # 6 new cases .changeset/fix-mastra-dangling-defs-ref.md # core/mastra patch plans/fix-mastra-dangling-defs-ref.md # design + acceptance log ``` --------- Co-authored-by: jkomyno <12381818+jkomyno@users.noreply.github.com> |
||
|
|
22a9171981 |
fix(core): defer telemetry sends (#3447)
## Summary - Defer telemetry batch processing via microtask scheduling so reaching the batch size no longer starts telemetry network work inline with SDK calls. - Defer SDK init/error telemetry sends and make `flush()` wait for both deferred sends and pending batches. - Remove stale blocking TODOs and add regression coverage for deferred batch/error telemetry behavior. Fixes #3442 ## Tests - `pnpm --filter @composio/json-schema-to-zod build` - `pnpm --filter @composio/core typecheck` - `pnpm --dir ts/packages/core exec vitest run test/telemetry/TelemetryService.test.ts` - `pnpm --filter @composio/core test` - `pnpm exec eslint ts/packages/core/src/telemetry/BatchProcessor.ts ts/packages/core/src/telemetry/Telemetry.ts ts/packages/core/src/services/telemetry/TelemetryService.ts` ## CI - GitHub checks are pending on PR creation; initial `gh pr checks 3447` showed required jobs queued/in progress. |
||
|
|
1692bbee7a |
fix(cli): make output more LLM friendly (#3450)
## Summary - Route Effect pretty logger output to stderr and share a TTY-based interactive detector for human-only CLI UI. - Gate upgrade notices and default browser login waiting on interactive stdio; non-interactive `composio login` now emits session JSON and exits. - Stream `composio run` helper/subagent logs to stderr (or only to the run log with `--logs-off`) without polluting stdout. - Add a CLI patch changeset. ## Tests - `pnpm -C ts/packages/cli exec vitest run test/src/services/update-check.test.ts test/src/commands/login.cmd.test.ts test/src/commands/run.cmd.test.ts` - `pnpm --filter @composio/cli typecheck` - `pnpm typecheck` - `pnpm exec eslint ts/packages/cli/src/utils/stdio.ts ts/packages/cli/src/services/terminal-ui.ts ts/packages/cli/src/services/update-check.ts ts/packages/cli/src/cli-main.ts ts/packages/cli/src/commands/login.cmd.ts ts/packages/cli/src/commands/run.cmd.ts ts/packages/cli/src/services/run-helpers-runtime.ts --no-warn-ignored` - `pnpm exec prettier --check ts/packages/cli/src/utils/stdio.ts ts/packages/cli/src/services/terminal-ui.ts ts/packages/cli/src/services/update-check.ts ts/packages/cli/src/cli-main.ts ts/packages/cli/src/commands/login.cmd.ts ts/packages/cli/src/commands/run.cmd.ts ts/packages/cli/src/services/run-helpers-runtime.ts ts/packages/cli/test/src/services/update-check.test.ts ts/packages/cli/test/src/commands/login.cmd.test.ts` ## Notes - Initial targeted `pnpm --filter @composio/cli test -- ...` ran the full CLI suite and failed before building `@composio/cli-keyring`; after building/installing workspace deps, the targeted Vitest command above passed. |
||
|
|
eb51b923bb |
feat(cli): send x-cli-session-id header on every request (#3430)
## Summary - Pulls the per-cwd CLI session id (already generated by `getCurrentCwdSessionId()` and used as `cli_session_id` on analytics events) and attaches it as the `x-cli-session-id` header on every request from the composio client. - Backend reads the header off `requestInfo`, threads it through `enrichSessionInfo`, and writes `session_info.cli_session_id` on every tool execution log row. Companion hermes PR: ComposioHQ/hermes#9990 ## Why The CLI already tracks a stable per-cwd session id for analytics, but tool execution logs are blind to it — there's no way to filter the logs UI / retool back to a single CLI session. Wiring the header through lets us group all tool calls from one CLI workflow together. ## Test plan - [x] `pnpm --filter @composio/cli typecheck` clean - [ ] Run `composio tools execute <slug>` against a build with the hermes companion deployed, confirm ClickHouse tool log has `session_info.cli_session_id` - [ ] Confirm header is absent (and log field absent) when no cwd session is cached 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
1ba66ca045 |
fix(core): normalize empty output_parameters so MCP tools can execute [PLEN-2450] (#3397)
Closes [PLEN-2450](https://linear.app/composio/issue/PLEN-2450/toolsexecute-fails-for-all-mcp-toolkits-strict-zod-validation-rejects) · refs https://github.com/ComposioHQ/composio/issues/3354 ## Summary `composio.tools.execute('<MCP_TOOL>', ...)` currently throws a `ZodError` for **every** tool from an MCP-backed toolkit (`granola_mcp`, `apify_mcp`, `tavily_mcp`, …) on `@composio/core` 0.6.x–0.9.x. The reporter on #3354 confirmed all three versions hit the identical failure; users are working around it by dropping to `@composio/client` and losing modifiers, custom-tool routing, version checks, and provider wrapping. **Root cause** (`ts/packages/core/src/models/Tools.ts` + `src/types/tool.types.ts`): - `tools.execute` and `tools.get` both run the API response through `transformToolCases → ToolSchema.parse`. - `ParametersSchema` requires `{ type: 'object', properties: {...} }`. - The API returns `output_parameters: {}` for MCP tools that have no declared output schema, so the validator throws. **Fix:** a tiny module-private `normalizeRawToolParameters` helper applied to both `input_parameters` and `output_parameters` inside `transformToolCases`. `null` / `undefined` / `{}` all map to `undefined`; everything else passes through to strict Zod validation. This: - Preserves the existing `outputParameters: undefined` ⇒ "no declared schema" contract — `outputParameters` was already optional in the public `Tool` type, so no public API change. - Fixes both `tools.execute` and `tools.list` (single funnel covers both paths). - Doesn't relax `ParametersSchema` — tools that actually declare a schema remain strictly validated. - Forward-compatible for every present / future `*_mcp` toolkit with no toolkit allow-list. ## Testing Red → green confirmed locally. New `describe('MCP-shaped tool metadata (PLEN-2450)')` block in `tools.test.ts` covers: 1. `getRawComposioToolBySlug` does not throw `ZodError` for `output_parameters: {}`. 2. Empty `output_parameters` is normalized to `undefined` on the transformed `Tool`. 3. Both-empty edge case (`input_parameters: {}` + `output_parameters: {}`). 4. `tools.list` path also tolerates empty `output_parameters`. 5. End-to-end `tools.execute` succeeds against an MCP-shaped fixture. All five tests **fail** on `next` without the helper (reproducing the exact `ZodError` from the report) and **pass** with it. Full `@composio/core` suite: **904 / 904 green**. ```bash cd ts/packages/core pnpm vitest run tools.test -t "MCP-shaped tool metadata" # → PASS (5) FAIL (0) pnpm vitest run # → PASS (904) FAIL (0) ``` ## Test plan - [x] Red phase confirmed: 5 new tests fail with the exact `ZodError` from the report. - [x] Green phase confirmed: 5 new tests pass after the helper lands. - [x] Full `@composio/core` test suite stays green (904 tests). - [x] `pnpm typecheck` clean. - [ ] Optional live sanity: build a tarball and run the reporter's `repro.mjs` against a sandbox user (`pg-test-9f4d0df7-…`) — not blocking; the mocked end-to-end test pins the same path. ## Follow-ups (out of scope) - **Python SDK** — verify whether `composio` Python has the same over-strict Pydantic check and apply the equivalent normalization if so. > Note: not proposing an API-side change. `output_parameters: {}` is the correct JSON Schema for "no declared schema" (the empty schema validates anything); the bug was the SDK's Zod validator being over-strict, not the API. The fix belongs at the SDK layer, where it now lives. Co-authored-by: jkomyno <12381818+jkomyno@users.noreply.github.com> |
||
|
|
5555dee25c |
feat(cli): refresh approval fallback page (#3431)
## Summary - Refresh the browser fallback tool-approval page with the Composio CLI landing page visual language: light dithered background, mono terminal card, and brand-blue actions. - Serve the approval HTML directly from the temporary `127.0.0.1` callback server instead of writing/opening a `file://` page, so approval buttons call back to the active CLI process with relative local routes. - Keep the native macOS sidecar as the preferred prompt when available; the browser prompt remains the fallback when the sidecar is missing or fails before returning a decision. - Add a CLI patch changeset. ## Tests - `pnpm exec eslint ts/packages/cli/src/services/tool-permissions.ts` - `pnpm --filter @composio/cli typecheck:src` - `git diff --check` ## Notes - Initially `typecheck:src` failed before workspace package build artifacts existed in the fresh worktree; after building required workspace dependencies it passed. --------- Co-authored-by: Malay Vasa <malayvasa@gmail.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
93b67e8b2f |
fix(ts-sdk): handle file upload list unions (#3374)
## Summary
This updates the TypeScript SDK's automatic file upload/download
modifier to handle tool schemas that accept either a single file or a
list of files.
Tools can expose file inputs as a composed schema such as:
```json
{
"anyOf": [
{ "type": "object", "file_uploadable": true },
{ "type": "array", "items": { "type": "object", "file_uploadable": true } }
]
}
```
When auto-upload is enabled, the SDK presents those file-uploadable
objects to models as file path strings. If the model supplies a list of
local paths, the old upload resolver selected the first file-bearing
branch, usually the single-file branch, and left the list unchanged.
That means the backend could receive local paths instead of staged `{
name, mimetype, s3key }` descriptors.
## Changes
- Adds runtime-shape-aware composed-schema selection for file
upload/download modifiers.
- Chooses the array branch for list values while preserving single-file
behavior for string/File values.
- Preserves the existing fallback behavior: if no runtime shape matches,
use the first file-bearing variant.
- Keeps `anyOf`, `oneOf`, and `allOf` on the same composed-schema path
used by the SDK today.
- Adds regression coverage for single-file vs multi-file unions, array
item unions, and download parity.
- Adds a patch changeset for `@composio/core`.
## Why
Some file-capable tool schemas are backward compatible at the API level
by accepting both a single file and multiple files. The TypeScript SDK
should transform a list of local paths into a list of staged file
descriptors, just as it already does for direct array schemas.
## Verification
- `pnpm --filter @composio/core exec prettier --check
src/utils/modifiers/FileToolModifier.node.ts
test/tools/fileModifiers.test.ts`
Blocked locally:
- `pnpm --filter @composio/core test -- fileModifiers.test.ts` fails
before collecting tests because this workspace cannot resolve the
unbuilt `@composio/json-schema-to-zod` package entry.
- `pnpm --filter @composio/core typecheck:tsc` is also blocked by
existing local generated-client/workspace dependency errors unrelated to
this patch.
---------
Co-authored-by: Zen <zen@composio.dev>
|
||
|
|
2d52e7f7c0 |
feat(cli): support composio upgrade <version> for specific releases (#3428)
## Summary - `composio upgrade` now accepts an optional `<version>` argument so users can install any published CLI release — stable or beta — without having to wait for the channel pointer to move. - Accepts `0.13.1`, `v0.13.1`, `0.13.1-beta.42`, or the full `@composio/cli@0.13.1` tag (normalized internally). - When a version is provided, the "already on latest" guard is skipped so the command also supports downgrades and reinstalls. `--beta` continues to control the no-arg case. ## Examples ```bash composio upgrade # latest stable (unchanged) composio upgrade --beta # latest beta (unchanged) composio upgrade 0.13.1 # pin to a specific stable composio upgrade 0.13.1-beta.42 # install a specific beta composio upgrade @composio/cli@0.13.1 # full release tag also accepted ``` ## Implementation - `upgrade.cmd.ts`: added optional `version` Args, normalizes input to a `@composio/cli@<semver>` release tag, passes it through to the service. - `upgrade-binary.ts`: `upgrade`/`fetchLatestRelease` now accept a `tag` option that fetches the GitHub release directly via `/releases/tags/<tag>`, bypassing the channel resolver. When a tag is explicit, the update-availability check is skipped. - Falls back to the explicit tag for `installSkillSafe` when the upgrade completes without returning one. ## Test plan - [x] `pnpm typecheck` (CLI package) — clean - [x] `pnpm test` in `ts/packages/cli` — 703 passed, 1 skipped, no regressions in `upgrade-binary.test.ts` - [ ] Manual: `composio upgrade 0.13.0` from a newer beta to confirm downgrade path works against real GitHub releases - [ ] Manual: `composio upgrade --beta` still resolves the latest beta when no version is given 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
878ac4d34b |
Release: update version (#3425)
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.10.0 ### Minor Changes - |
||
|
|
42ebff3f6b |
feat(connected-accounts): namespace SHARED-connection surface under experimental
Aligns the TypeScript SDK with the experimental wire shape used by
Shared Connections. The flat accountType / aclConfigForShared options
on connectedAccounts.link() and session.authorize() have moved under a
single experimental block, and connectedAccounts.updateAcl() has moved
off the class onto a top-level experimental_updateAcl(composio, id, opts)
export — same precedent as experimental_createTool /
experimental_createToolkit.
The experimental namespace is the signal that the shape may change in
future releases. Pinning a SHARED connection in a session config and
direct execute by connectedAccountId are unchanged — only the
connection-create / patch / authorize surfaces are namespaced.
Also surfaces the accountType filter on connectedAccounts.list() so
SHARED connections can be listed without dropping to the raw client.
The wire keeps this as a flat query param, so the SDK keeps it flat too.
@composio/client bumped from 0.1.0-alpha.71 -> 0.1.0-alpha.72 so the
generated typed client carries the Experimental namespaces for
link.create, toolRouter.session.link, and connectedAccounts.patch.
Caller migration:
// before
await composio.connectedAccounts.link('user_id', 'auth_config_id', {
accountType: 'SHARED',
aclConfigForShared: { allowAllUsers: true },
});
await composio.connectedAccounts.updateAcl('ca_abc', { allowAllUsers: true });
await session.authorize('github', {
accountType: 'SHARED',
aclConfigForShared: { allowAllUsers: true },
});
// after
await composio.connectedAccounts.link('user_id', 'auth_config_id', {
experimental: {
accountType: 'SHARED',
aclConfigForShared: { allowAllUsers: true },
},
});
await experimental_updateAcl(composio, 'ca_abc', { allowAllUsers: true });
await session.authorize('github', {
experimental: {
accountType: 'SHARED',
aclConfigForShared: { allowAllUsers: true },
},
});
// new — list SHARED connections
const shared = await composio.connectedAccounts.list({
accountType: 'SHARED',
userIds: ['user_creator'],
});
Tests cover: experimental block forwarding (link + authorize), no-op
when omitted, empty-array preservation, typed error mapping for the
PRIVATE-with-ACL case, experimental_updateAcl body construction +
deny-list handling + ValidationError when no fields are provided, and
list(accountType: 'SHARED') flat-filter delegation.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
02723698b0 |
Release: update version (#3402)
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/cli-local-tools@0.0.3 ### Patch Changes - Updated dependencies [ |
||
|
|
3b98ee0fc2 |
chore: change @composio/core version bump from minor to patch
Demote the connected-accounts-acl changeset from minor to patch, matching PR #3403 by @abir-taheer. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Co-authored-by: abir <abir@composio.dev> |
||
|
|
eba561f771 |
docs(connected-accounts): sanitize public docstrings — remove internal references
Addresses 4 review comments from @abir-taheer on #3392: - transformers/connectedAccounts.ts:21 — remove Hermes PR references - types/connectedAccounts.types.ts:79 — users don't belong to projects - types/connectedAccounts.types.ts:55 — drop backend storage detail - models/ToolRouterSession.ts:330 — remove internal information Swept the full PR diff for similar leaks rather than just the four flagged lines, since the same patterns repeat across the new files: - Removed Hermes PR numbers (#9860 / #9882 / #9902) from inline comments and JSDoc in transformers, types, model, test describe block, and changeset. - Removed "JSONB column on `connected_accounts`" storage detail. - Reworded "any user_id in the project" / "users in the project" / "project member" / "project/org API key" — users don't belong to a project entity in Composio's data model, so the wording was misleading. Replaced with phrasing focused on the mechanism (pinning in a tool-router session, authorisation via creator or API key) and on the `userId` identifier. - Removed "Backend response: 400 with code `ConnectedAccount_...`" blocks from error class JSDoc — surfacing the internal error code name leaked implementation details. - Cleaned up the augmented `RawConnectedAccountResponseWithLabels` intersection — `account_type` and `acl_config_for_shared` are now on the regenerated `@composio/client@0.1.0-alpha.71` types, so the manual augmentation lines (which carried the Hermes refs) can be deleted entirely. Field access still works through the existing intersection used for `word_id` / `alias`. Also tightened a pre-existing leak I introduced earlier in the PR's own JSDoc on `update()` — dropped the "historical JSDoc mentioning alias/credentials" callout since that's internal noise. No behaviour changes — pure docstring / comment / changeset cleanup. Verified: pnpm typecheck clean, 915 tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
483af36070 |
feat(connected-accounts): bump @composio/client to alpha.71, drop casts, add tests + error mapping
Now that #77 in composio-base-ts merged and @composio/client@0.1.0-alpha.71 is published with account_type + acl_config_for_shared in the typed surface, all the forward-compat shims come out. Removed: - AclConfigWireShape, LinkCreateBodyWithAcl, ConnectedAccountPatchBodyWithAcl local types - 3x `as unknown as Parameters<typeof X>[N]` casts in ConnectedAccounts.ts + ToolRouterSession.ts Now uses the generated types directly: - ConnectedAccountPatchParams, ConnectedAccountPatchResponse from @composio/client/resources/connected-accounts - LinkCreateParams + LinkCreateParams.ACLConfigForShared from @composio/client/resources/link - SessionLinkParams + SessionLinkParams.ACLConfigForShared from @composio/client/resources/tool-router/session/session Review fixes from #3392 multi-agent review: - P1-1: moved orphaned JSDoc back onto ComposioLegacyConnectedAccountsEndpoint- RetiredError (was stranded above ComposioSharedAccessDeniedError) - P1-2: added empty-array footgun warning to updateAcl() JSDoc — passing `notAllowedUserIds: []` silently clears the deny list - P1-3: changeset reconciled with PR body (Python ships as separate PR) - P2-9: updateAcl() returns ConnectedAccountPatchResponse instead of void, matching sibling update()/refresh() ergonomics - P2-11: clarifying JSDoc on update() pointing at updateAcl() and noting the pre-existing "alias/credentials" doc is inaccurate (this PR doesn't fix it) - P3-12: callbackUrl/alias guards normalized to `!== undefined` (was a mix of `&&` and `!= null`) — empty strings now propagate correctly - P3-17: refine-guard comment on UpdateConnectedAccountAclParamsSchema noting ZodEffects doesn't expose .shape P2-6/P2-7: typed error mapping for ComposioAclOnlyForSharedError (400) wired at three call sites: - ConnectedAccounts.link() — wraps existing ComposioFailedToCreateConnectedAccountLink catch - ConnectedAccounts.updateAcl() — new catch with rethrow fallback - ToolRouterSession.authorize() — new catch with rethrow fallback Substring match on `'acl_config_for_shared is only valid on SHARED'` — verified against apps/apollo/src/lib/connected_accounts/createConnectedAccount.ts in hermes#9902. ComposioSharedAccessDeniedError and ComposioSharedConnectionNotAccessibleError remain exported but not yet thrown — they'll be wrapped when Tools.execute() and ToolRouterSession.create() error-mapping lands in a follow-up. Tests: 12 new behaviour tests in test/connectedAccounts/connectedAccounts.test.ts covering link() ACL forwarding (5), updateAcl() body construction + empty-object refine + AclOnlyForShared mapping (6), and link() error-mapping fallback (1). 911 tests pass (up from 899). Verified: pnpm typecheck clean, pnpm build clean (publint + attw clean). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
752efd8863 |
refactor(connected-accounts): nest ACL under aclConfigForShared, match merged 9902 contract
The original draft built against 9902's PR description shape — three flat
top-level ACL fields (`allow_all_users`, `allowed_user_ids`,
`not_allowed_user_ids`). The merged design (deployed to staging now)
collapsed them into a single JSONB column and exposes them on the wire
as a nested `acl_config_for_shared` object. This commit reshapes the SDK
to match.
Wire contract changes verified against staging-backend.composio.dev:
POST /connected_accounts/link body: account_type, acl_config_for_shared
POST /connected_accounts body.connection.{account_type, acl_config_for_shared}
PATCH /connected_accounts/{id} body: alias, connection, acl_config_for_shared
GET /connected_accounts item.{account_type, acl_config_for_shared?}
GET /connected_accounts/{id} response.{account_type, acl_config_for_shared?}
POST /tool_router/session/{id}/link body: account_type, acl_config_for_shared
SDK changes:
- types: `ConnectedAccountAclSchema` → `ConnectedAccountAclConfigSchema`
(input — all fields optional) + `ConnectedAccountAclConfigResponseSchema`
(output — all fields populated when block is visible). Added per-user_id
length cap (1..256) matching aclConfig.ts. `link()` options exposes
`aclConfigForShared?` instead of three flat fields. Retrieve response
exposes `aclConfigForShared?` (undefined when caller can't see ACL).
- model: `link()` and `updateAcl()` serialize the SDK's flat camelCase
ACL params into the nested snake_case `acl_config_for_shared` wire
block via a new `serializeAclConfigForWire` helper. Local body types
updated to match.
- transformer: maps `acl_config_for_shared` (nested) → `aclConfigForShared`
(nested camelCase). Forwards `undefined` when the block is absent.
- ToolRouterSession.authorize() options gain `accountType` +
`aclConfigForShared` — the `/tool_router/session/{id}/link` endpoint
accepts the same fields.
- changeset rewritten to document the nested shape.
Verified: pnpm typecheck clean, build clean, 899 tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
84a3a074b3 |
feat(connected-accounts): surface accountType + per-user ACL on SHARED connections
Adds SDK wrappers for Hermes #9860, #9882, #9902 — three Apollo-side features that previously had no high-level surface. Existing call sites are unchanged; new fields/methods are opt-in. - `link()` accepts `accountType` ('PRIVATE' | 'SHARED') and ACL fields (`allowAllUsers`, `allowedUserIds`, `notAllowedUserIds`) to create a SHARED connection in one call. - `get()` / `list()` responses now expose `accountType`. ACL fields are forwarded when present (backend hides them for non-creator/non-API-key callers — left as undefined in the SDK shape). - New `updateAcl(nanoid, params)` method wires the existing `client.connectedAccounts.patch` (PATCH /connected_accounts/{id}) for ACL writes. PATCH semantics: omit a field to leave unchanged; pass empty array to clear an allow/deny list. At least one field required. - New error classes: `ComposioSharedAccessDeniedError` (403), `ComposioAclOnlyForSharedError` (400), `ComposioSharedConnectionNotAccessibleError` (400). The wire-level fields (account_type, allow_all_users, etc.) are not yet in @composio/client@0.1.0-alpha.70's typed surface — they'll land when Stainless regenerates against the post-merge backend spec. Two narrow local types (`LinkCreateBodyWithAcl`, `ConnectedAccountPatchBodyWithAcl`) + boundary casts paper over the gap until then; remove once the client is bumped. Verified: pnpm typecheck clean, build clean, 899 tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
c358ffaa3b |
fix(connected-accounts): SEC-339 gate initiate() warning on response Deprecation header
initiate() previously emitted a one-time deprecation warning whenever the
response carried a redirectable OAuth scheme (OAUTH1, OAUTH2, DCR_OAUTH),
regardless of whether the auth config was Composio-managed (subject to the
2026-07-03 cutover) or custom (unaffected). The wording was conditional —
'If this auth config is Composio-managed…' — so callers using their own
OAuth apps could ignore it, but the warning still printed and added noise
to logs.
Apollo already emits the SEC-339 'Deprecation' / 'Sunset' / 'Link
rel="deprecation"' headers (RFC 9745 / RFC 8594) only on the retiring
branch — managed + redirectable OAuth + LD didn't block. The SDKs now
read the 'Deprecation' header from the response and gate the warning on
its presence. Custom auth configs and non-OAuth schemes get a clean
response from the server and now stay silent in the SDK as well.
TS:
- Chain '.withResponse()' on the underlying client.connectedAccounts.create
call to expose the raw Response. Defensive fallback for tests that mock
create() as a plain Promise.
- Drop the LEGACY_RETIRING_OAUTH_SCHEMES set; the apollo header is now the
sole signal.
- New tests in describe('initiate deprecation header gate', ...) pin the
contract: warns when Deprecation is present, silent when absent, and
one-time-per-process even across multiple managed-OAuth calls. A
mockApiPromiseWithHeaders helper wraps mocked values as APIPromise-shape
thenables so the new tests can simulate apollo's header behavior.
Python:
- Switch to client.connected_accounts.with_raw_response.create so we can
read raw.headers.get('Deprecation'). Defensive fallback to the parsed-
only path for test mocks that don't stub with_raw_response.
- Drop _LEGACY_RETIRING_OAUTH_SCHEMES; same simplification as TS.
- New TestInitiateDeprecationHeaderGate class with the same three pinning
cases. A _set_initiate_response helper routes mock responses through
the with_raw_response surface that initiate() now consumes. Pre-existing
initiate tests migrated to the helper; one assertion that inspected
create.call_args.kwargs now reads with_raw_response.create.call_args.kwargs.
No public API change for either SDK — initiate() returns the same
ConnectionRequest shape and respects the same allowMultiple guard.
ComposioLegacyConnectedAccountsEndpointRetiredError continues to surface
from the 400 retired-path response.
Changeset bumps @composio/core as a patch.
|
||
|
|
49629a7b9d | Release: update version | ||
|
|
28c209225a | Fix invalid changeset package | ||
|
|
711a703ae3 | Add core minor changeset | ||
|
|
fdf4e85350 |
Refine ToolRouter preload and generated attach support (#3364)
## Summary - Add public direct-tools preset constants (`SessionPreset.DIRECT_TOOLS` in TS, `SESSION_PRESET_DIRECT_TOOLS` in Python) and internal `preload.tools = "all"` constants. - Reuse the create-time inline custom tool preload preparation path for `use(..., customTools/customToolkits)` attach flows, including existing-session `preload.tools = "all"` handling for attached customs. - Use generated Stainless attach types where available; keep a narrow Python additive type for the custom-definition `preload` hint until Stainless exposes that field. - Clean up user-facing preload docs/comments, direct custom tool description prefix, and direct/preload examples with normalized `LOCAL_*` assertions. - Add separate changesets for preload behavior and the direct-tools preset. ## Validation - `pnpm --dir ts/packages/core typecheck` - `pnpm --dir ts/packages/core test test/models/toolRouter.test.ts test/models/customTool.test.ts` - `(cd python && .nox/chk/bin/mypy --config-file config/mypy.ini composio/)` - `COMPOSIO_CACHE_DIR=/private/tmp/composio-cache python/.nox/chk/bin/python -m pytest python/tests/test_tool_router.py python/tests/test_custom_tools.py` - `python/.nox/chk/bin/python -m ruff check python/composio/core/models/tool_router.py python/composio/core/models/custom_tool_types.py python/composio/core/models/inline_custom_tools_payload.py python/composio/core/models/custom_tool.py python/composio/core/models/tool_router_constants.py python/tests/test_tool_router.py` - `python/.nox/chk/bin/python -m ruff check python/examples/tool_router/direct_tools_preset.py` - `python/.nox/chk/bin/python -m py_compile python/examples/tool_router/direct_tools_preset.py` - `git diff --check` |
||
|
|
04545a72d3 |
fix(core): expose string | string[] in connectedAccounts public type (#3365)
## Summary Follow-up to #3358. The `.transform()` added on the `connectedAccounts` Zod schema made the inferred TypeScript type resolve to the **post-transform output** (`Record<string, string[]>`), so TS users still hit `error TS2322: Type 'string' is not assignable to type 'string[]'` even though the runtime accepted strings. The runtime fix landed; the public TS surface didn't follow. This PR moves the coercion out of the schema and into `ToolRouter.create`, mirroring the Python implementation. The public type is now `Record<string, string | string[]>` and runtime behavior is unchanged. ## Why CI didn't catch this in #3358 The PR's own test file (`toolRouter.test.ts`) already assigns a `string` to `ToolRouterCreateSessionConfig`, but `ts/packages/core/tsconfig.json` has `"include": ["src/**/*.ts"]` — `test/` is not typechecked. So `tsc --noEmit clean` was technically true while masking the issue. Verified empirically by dropping a typecheck file into `src/` on `next`: ``` src/__type_check.ts(8,7): error TS2322: Type 'string' is not assignable to type 'string[]'. ``` After this PR, the same file compiles cleanly. ## Changes - **`ts/packages/core/src/types/toolRouter.types.ts`**: drop `.transform()` from the `connectedAccounts` schema; `z.infer` now exposes `Record<string, string | string[]>`. - **`ts/packages/core/src/models/ToolRouter.ts`**: coerce `string → [string]` inside `create` before sending to the backend (which expects arrays). Preserves the original `connected_accounts: undefined` behavior when the field is omitted (the parent schema's `.partial()` strips the `default({})`). - **`ts/packages/core/src/types/toolRouter.types.ts`**: fix stale `@param {Record<string, string>}` JSDoc on the same field. - **`.changeset/v31-connected-accounts-array.md`**: drop the inaccurate *"Bumps `@composio/client` to `0.1.0-alpha.70`"* line — that bump landed in a separate commit on `next` (`7c1443838`), not in #3358's diff (`git diff 2bbd791de^1 2bbd791de` shows zero `pnpm-lock.yaml`/`package.json` changes). - **`.changeset/fix-connected-accounts-string-type.md`**: new `patch` changeset for `@composio/core`. ## Test plan - [x] `pnpm exec tsc --noEmit -p tsconfig.json` clean on `@composio/core` - [x] `pnpm exec vitest run` — 883/883 tests pass (incl. 110 in `toolRouter.test.ts`) - [x] `pnpm prettier --check` clean on touched files - [x] Spot-checked: assigning `{ connectedAccounts: { gmail: 'ca_xxx' } }` to `ToolRouterCreateSessionConfig` now typechecks; assigning the array form still typechecks. |
||
|
|
bccd32beae | Refine ToolRouter preload docs and constants | ||
|
|
c96f094b15 |
feat(core): add session.update() for partial config updates (#3362)
## Summary
- Adds `session.update()` method to both TypeScript and Python SDKs
- Calls the existing `PATCH /api/v3/tool_router/session/{id}` endpoint
- Accepts the same config shape as `create()` (toolkits, tools, tags,
auth_configs, connected_accounts, manage_connections, workbench,
multi_account, preload)
- Mutates the session object in-place (preload, configVersion, warnings)
## Usage
### TypeScript
```typescript
const session = await composio.create('user_123', {
toolkits: ['gmail'],
manageConnections: true,
});
await session.update({
toolkits: { enable: ['gmail', 'github'] },
workbench: { enable: false },
});
```
### Python
```python
session = composio.create(user_id='user_123', toolkits=['gmail'])
session.update(
toolkits={'enable': ['gmail', 'github']},
workbench={'enable': False},
)
```
## Test plan
- [x] TypeScript: `tsc --noEmit` passes
- [x] TypeScript: all 874 existing tests pass
- [x] Python: mypy passes
- [x] Python: ruff lint + format clean
- [x] Python: all 82 tool_router tests pass
- [ ] Manual test: create session, call `session.update()`, verify
config changes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
||
|
|
c9b6525bc9 |
fix(core): expose string | string[] in connectedAccounts public type
The Zod `.transform()` added in #3358 made the inferred type of `ToolRouterCreateSessionConfig['connectedAccounts']` resolve to `Record<string, string[]>` (the post-transform output), so TypeScript users still hit `Type 'string' is not assignable to type 'string[]'` even though the runtime accepted strings. The runtime fix landed; the public TS surface didn't follow. Drop the schema transform and coerce inside `ToolRouter.create` instead, mirroring the Python implementation. The public type is now `Record<string, string | string[]>` and behavior is unchanged. While here: - fix the JSDoc on `connectedAccounts` (was `Record<string, string>`) - drop the inaccurate `@composio/client 0.1.0-alpha.70` bump line from the v31-connected-accounts-array changeset (this PR didn't perform that bump; it landed in a separate commit on `next`) |
||
|
|
a0242d7b3a | docs: clarify session use wording | ||
|
|
2d07d26f52 | docs: update session use attach changeset | ||
|
|
ba435b77a0 |
chore: update changeset to include Python SDK
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
81f8027cf6 |
chore: add changeset for session.update() (minor)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
55951f18b0 |
docs: clarify changeset wording per review
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
bd36c57aaf |
fix: accept string | string[] for connectedAccounts, coerce to array
Non-breaking: existing callers passing a single string per toolkit continue to work. The string is silently coerced to a single-element array to match the v3.1 wire format. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
07c9baba9d |
chore: separate changeset for connectedAccounts array type (minor)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
3ece424708 |
chore: add changeset for v3.1 customs use/attach (minor)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
f5c5b84bd3 |
fix(mastra): resolve $ref in tool schemas before applyCompatLayer [PLEN-2244] (#3315)
## Summary Composio tools whose JSON Schema uses internal `$ref` pointers (`#/$defs/...` or the legacy `#/definitions/...`) used to lose all type information when wrapped by `MastraProvider.wrapTool`. The schema would silently round-trip `raw → applyCompatLayer → convertSchemaToZod (drops $ref → permissive anyOf) → zodToJsonSchema (no recovery)`. Customers reported the user-visible surface as *"schema validation error: can't resolve reference"* — AJV (bundled inside `@mastra/schema-compat`) refusing to compile the schema downstream when validating tool input. This PR pre-processes the schema with a new `dereferenceJsonSchema` utility from `@composio/core` *before* it reaches `@mastra/schema-compat`, preserving the type information from `$defs`/`definitions` and avoiding the AJV failure entirely. Closes [PLEN-2244](https://linear.app/composio/issue/PLEN-2244/mastra-provider-schema-validation-error-cant-resolve-reference). ## What changed - **`@composio/core`** — new `dereferenceJsonSchema(schema)` helper (and `JsonSchemaRefResolutionError`): - walks the schema reflectively (no JSON-Schema-keyword allow-list, so future applicators are covered automatically), - inlines internal `$ref` pointers transitively, with a 100-hop depth cap, - shallow-merges sibling keywords next to `$ref` per Draft 2020-12 semantics (siblings win on collision — preserves caller's `description` / `default` / `title`), - breaks recursive cycles with `{ type: 'object', additionalProperties: true }` (matches upstream guidance in [mastra-ai/mastra#15341](https://github.com/mastra-ai/mastra/issues/15341)), - strips `$defs` / `definitions` from the returned root once everything reachable is inlined, - leaves external (`http://`/`https://`) `$ref` pointers untouched so callers can still forward them, - throws `JsonSchemaRefResolutionError` on malformed pointers, missing targets, and over-cap chains. - **`@composio/mastra`** — `wrapTool` now runs `dereferenceJsonSchema` over both `inputParameters` and `outputParameters` before calling `applyCompatLayer`. - **`@mastra/schema-compat`** floor bumped to `^1.2.9` so consumers automatically pick up upstream [PR #15400](https://github.com/mastra-ai/mastra/pull/15400)'s recursive-`$ref` handling and [PR #14530](https://github.com/mastra-ai/mastra/pull/14530)'s Draft-2020-12 AJV switch. - Changeset: `.changeset/fix-mastra-ref-dereference.md` (patch bump for `@composio/core` and `@composio/mastra`). ## Test plan Red → green TDD across two commits — the `test:` commit reproduces PLEN-2244 against the real `@mastra/schema-compat` (no `vi.mock`), the `fix:` commit makes the regression tests pass. - [x] `ts/packages/core/test/utils/jsonSchema.test.ts` — 14 unit tests for `dereferenceJsonSchema` covering: basic resolution, chained refs, container coverage (items / oneOf / anyOf / allOf / not / additionalProperties / patternProperties / prefixItems), legacy `definitions` (Draft 7), `$defs`/`definitions` mixed transitively, sibling-keyword merge per Draft 2020-12, cycle break, `$defs`/`definitions` strip, missing-target error, depth-cap error, external `$ref` preserved, no input mutation, JSON Pointer escape decoding (`~0`/`~1`), array-index pointers. - [x] `ts/packages/providers/mastra/test/mastra-ref.test.ts` — un-mocked integration tests against real `@mastra/schema-compat`: wrapping does not throw, type info from `$defs` survives the round-trip (the `id` field stays `type: 'string'` instead of degrading to permissive `anyOf`), same for Draft-7 `definitions` on output schema, no remaining `$ref` in the produced schemas. - [x] `pnpm --filter @composio/core test` — 852/852 green. - [x] `pnpm --filter @composio/mastra test` — 43/43 green (39 legacy + 4 new). - [x] `pnpm --filter @composio/core --filter @composio/mastra typecheck` — clean. - [x] Existing `mastra.test.ts` (which mocks `@mastra/schema-compat`) is **untouched** and still green. - [x] Secret-hygiene scan: `git diff next..HEAD | grep -E 'sk-[A-Za-z0-9_-]{20,}|OPENAI_API_KEY=[A-Za-z]'` returns empty. ## Why it's a Mastra-only fix The Mastra path is unique in routing JSON Schema through `@mastra/schema-compat`, which embeds AJV. Sibling providers (`openai`, `anthropic`, `vercel`, `langchain`, `google`, `llamaindex`) forward Composio's JSON Schema through `@composio/json-schema-to-zod`, which silently no-ops on unknown nodes. They are not affected today; expanding pre-processing across providers is a separate PR if it ever becomes needed. ## Caveats - The cycle-break sentinel weakens type information for genuinely recursive tool schemas. This is the same trade-off Mastra itself made in [#15341](https://github.com/mastra-ai/mastra/issues/15341); without it the agent crashes entirely. - External `$ref` (`http://`/`https://`) is intentionally left untouched. If a real customer schema ever needs them resolved, that's an incremental follow-up that calls into `@apidevtools/json-schema-ref-parser` only when needed. - The cycle-break currently uses a single sentinel for any cycle; if review prefers the higher-fidelity "keep first expansion, only break on the recursion edge" pattern (mentioned in the research as a refinement), that's a small follow-up. |
||
|
|
2e1c25eb7f |
feat(sdk,docs): SEC-339 link-auth migration support across SDK + docs (#3289)
## Summary End-to-end work to help SDK and direct API users move off the legacy `POST /api/v3/connected_accounts` path for **Composio-managed OAuth** ahead of the [2026-04-24 changelog announcement](/docs/changelog/2026/04/24) — cutover dates **2026-05-08** (new orgs) and **2026-07-03** (all orgs). Pairs with the backend deprecation signals in [ComposioHQ/hermes#9622](https://github.com/ComposioHQ/hermes/pull/9622). Custom auth configs (your own OAuth app) and non-OAuth schemes (API key, bearer, basic) are unaffected throughout. ## SDK changes ### TypeScript (`@composio/core`) - **New error class** `ComposioLegacyConnectedAccountsEndpointRetiredError` in `errors/ConnectedAccountsErrors.ts` — extends `ComposioError`, status 400, with `possibleFixes` pre-populated to point at `link()` and the migration guide. - **`initiate()` wraps the create call** in try/catch and re-throws the new typed error when the response message indicates the retiring path. The match is conservative — substring on stable backend message text, with everything else flowing through unchanged. - **One-time-per-process deprecation warning** via `logger.warn` when the response indicates `OAUTH1` / `OAUTH2` / `DCR_OAUTH`. Wording is conditional ("If this auth config is Composio-managed...") so custom-OAuth users can ignore it without ambiguity. - **JSDoc** on `initiate()` flags the deprecation explicitly with both cutover dates and a link to the migration guide. ### Python (`composio` core) - Mirror exception class `ComposioLegacyConnectedAccountsEndpointRetiredError` in `composio/exceptions.py`. - `initiate()` catches `BadRequestError` from `composio_client`, inspects the message text, and re-raises as the typed exception (preserves `__cause__`). - One-time-per-process `warnings.warn(..., DeprecationWarning, stacklevel=2)` on the redirectable-OAuth response path. - Docstring carries a `.. deprecated::` block with the dates. ## Doc changes | File | Change | |---|---| | `docs/content/docs/tools-direct/authenticating-tools.mdx` | Add a `<Callout type="warn">` to the `OAuth Connections` subsection of `Direct SDK Setup`. The Hosted Authentication section already shows `link()` first; this surfaces the retirement on the `initiate()` subsection where readers most need it. | | `docs/content/docs/auth-configuration/connected-accounts.mdx` | Promote the `Multiple accounts` callout from `info` to `warn`, pin the cutover dates, and route readers to the migration guide. | | `docs/content/docs/auth-configuration/custom-auth-configs.mdx` | Add an `info` callout clarifying that the `initiate()` example shown is *intentionally* fine here (custom auth configs are exempt). Avoids copy-paste confusion. | | `docs/content/reference/errors.mdx` | New section `## Specific error codes` → `### Error 600` with anchor `#error-600`. The `suggested_fix` URL emitted by the backend in the 400 response (`/reference/errors#error-600`) now resolves to real content instead of 404'ing. | | `docs/content/docs/auth-configuration/migrating-initiate-to-link.mdx` | **New page.** Dedicated migration guide. Side-by-side before/after for both languages, the `allow_multiple` replacement pattern, an `is_composio_managed` routing recipe for mixed integrations, notes on detecting the deprecation via SDK warning vs RFC 8594 response headers, and a transition-friendly try/except example. | | `docs/content/docs/auth-configuration/meta.json` | Wire the new migration guide into the Authentication sidebar. | ## Why this scope In the audit before this PR the SDK was the biggest gap — `composio.connectedAccounts.initiate()` (TS) and `composio.connected_accounts.initiate()` (Python) both call the legacy endpoint, so every doc that teaches `initiate()` for OAuth was teaching a path that breaks at cutover. The SDK changes give existing users a typed deprecation path (warning before cutover, typed error after) without forcing a behavior change on the custom-auth-config and non-OAuth users who are unaffected. The doc changes target the two highest-traffic teaching pages for OAuth flows, plug the broken `error-600` URL the backend already references, and add a focused migration guide that consolidates everything callers need. ## How did I test this PR - **TS**: `pnpm tsc --noEmit` in `ts/packages/core` — error count unchanged vs `next` (baseline 53 → 53; all pre-existing, none touch the modified files). The new error class follows the existing `ComposioFailedToCreateConnectedAccountLink` template; the typed-error wrap reuses the `BadRequestError` import and pattern from `errors/ComposioError.ts:13`. - **Python**: confirmed `BadRequestError` is exported from `composio_client` and `connection_data.auth_scheme` is a valid attribute on the response model (`composio_client.types.connected_account_create_response.ConnectionDataUnionMember0` declares `auth_scheme: Literal["OAUTH1"] = FieldInfo(alias="authScheme")` — same shape across all union members). - **Docs**: all internal links use the relative-path convention (`/docs/...`, `/reference/...`) and follow the format used by existing changelog cross-links (e.g., `/docs/changelog/2026/04/24`). The new `#error-600` anchor matches the URL the backend's `suggested_fix` already emits. - **Manual trace**: walked the four decision branches against the modified `initiate()` code paths in both languages — custom auth configs and non-OAuth schemes never trigger either the warning or the typed-error path; managed OAuth triggers the warning on success and the typed error on the eventual 400. Pre-cutover the SDK warning is the loudest signal; post-cutover the typed error is the cleanest catch point. Both are scoped strictly to the affected combination. |