This PR: - fixes #4023, where Python provider Pydantic models silently reduced property-less object arguments such as `METABASE_POST_API_CARD.dataset_query` to `{}` - fixes #4064, where the Zod and Effect converters rejected the same free-form object content - fixes #4022, where Google Gemini rejected nested property-bearing schemas that omitted `type: "object"` - supersedes https://github.com/ComposioHQ/composio/pull/4037 with complete Python handling for open, closed, pattern-constrained, and schema-valued dynamic keys - supersedes https://github.com/ComposioHQ/composio/pull/4065 with one cross-SDK contract covering Zod, Effect, Python, CLI validation, and provider boundaries - supersedes https://github.com/ComposioHQ/composio/pull/4077 by incorporating its complete-schema Claude Agent SDK registration and root constraint handling - supersedes https://github.com/ComposioHQ/composio/pull/4047 with its corrected Google-only normalization, including property-map and reserved-key safety - keeps https://github.com/ComposioHQ/composio/pull/4094 as a stacked Python-provider follow-up because framework serialization and CrewAI error handling are downstream of schema conversion - includes minor Changesets for `@composio/core`, `@composio/json-schema-to-zod`, and `@composio/claude-agent-sdk`; the fixed release group also bumps `@composio/slim`, and `@composio/google` carries a patch Changeset A tool argument declared as a bare `{ "type": "object" }` could be rejected, reduced to `{}`, or lose its root constraints depending on the SDK boundary. This PR makes TypeScript and Python agree on free-form objects and dynamic keys, and protects that agreement with a shared corpus. ## Relationship to other work ### Superseded PRs - #4037 fixes the narrow Python property-less-object reproduction by allowing Pydantic extras, but does not enforce `patternProperties`, schema-valued `additionalProperties`, or closed-object rejection. This PR preserves the reported Metabase payload while enforcing the complete object contract. - #4065 fixes property-less objects in the Zod and Effect converters. This PR incorporates that behavior, expands the dynamic-key semantics, and proves parity with Python and the provider-facing paths. - #4077 preserves root constraints through `ToolSchema.parse` and the Claude Agent SDK. This PR incorporates that work and tests it against the same cross-SDK corpus. - #4047 targets #4022. This PR incorporates its Google schema normalization with a structure-aware walker that preserves property maps, instance values, and reserved keys. ### Follow-up and adjacent PRs - #4094 is intentionally separate and stacked on this PR. This PR defines which arguments a JSON Schema accepts and what Pydantic/Zod/Effect preserve. #4094 handles the later framework boundary where CrewAI, LangChain, and LangGraph serialize an already-validated model, restoring aliases, distinguishing absent values from explicit nulls and defaults, preserving dynamic extras, and returning structured CrewAI validation failures. - #4093 is the narrower CrewAI-only proposal for #4092. #4094 incorporates that fix and broadens it to the two other providers that use the same generated Pydantic models, so #4093 is not duplicated here. Keeping #4094 separate leaves this PR focused on the shared cross-SDK conversion contract. It also isolates provider-specific framework hooks and Python error-shape behavior, which have a different compatibility and test surface and do not require TypeScript Changesets. ## What changed - Property-less object schemas are open by default. Their content is accepted and preserved at the root, in nested objects, and in array items. An explicit `additionalProperties: false` still closes them. - Objects that declare `properties` remain strict when `additionalProperties` is omitted. This is Composio's established tool-input behavior. - `ToolSchema.parse` now accepts bare object roots, keeps root `patternProperties`, accepts schema-valued `additionalProperties`, and exposes optional `properties` in its public type. - The Zod and Effect converters apply every matching `patternProperties` schema. A schema-valued `additionalProperties` applies only to keys not claimed by a declared property or pattern. - Python validates dynamic values with Draft 7 JSON Schema before Pydantic materializes defaults. This avoids coercive or incomplete Pydantic representations changing whether input is accepted. - Python supports local JSON Pointer references in dynamic-key schemas. Unresolved, external, and anchored references fail during model construction instead of silently weakening validation. - Accepted Python dynamic keys remain available through both `model_dump()` and attribute access, which is required by agentic providers such as LangChain. - Gemini now exposes free-form object arguments as `Dict[str, Any]` in the generated callable signature. - `@composio/google` adds missing object types before emitting Google GenAI declarations while preserving property maps and instance-valued schema annotations. - The Claude Agent SDK provider registers the complete object schema instead of a raw property map, so root rules reach MCP validation. - The Effect converter reports dynamic-key schema defects while compiling the schema, rather than as input errors blaming the arguments. `@cfworker/json-schema` compiles `patternProperties` keys and resolves `$ref` lazily, so the defect previously reached the caller as an input validation failure. The scope matches Python's: `patternProperties` keys, and references inside a `patternProperties` or schema-valued `additionalProperties` subschema, followed transitively. References elsewhere stay with the interpreter, so a dangling reference in a branch validation never visits keeps working. ## Behavior changes Three existing fail-open paths now reject invalid input: 1. Python agentic providers reject unknown keys when an object declares properties and omits `additionalProperties`, instead of dropping those keys. This also covers a property-less object that sets `additionalProperties: false`, which Python previously left to Pydantic's default `extra="ignore"`. 2. The Claude Agent SDK provider rejects undeclared arguments through MCP validation instead of stripping them and running the tool. 3. The CLI rejects a tool schema whose `patternProperties` key is not a valid regular expression, or whose dynamic-key subschema carries an unresolvable reference, when it compiles the schema. This can fail a call that previously succeeded: the interpreter surfaced such a defect only if validation descended into that part of the schema, so a payload that stayed out of the affected branch ran against a schema that could not fully validate it. Gemini is affected differently: it uses `json_schema_to_pydantic_type` to build a callable signature, but does not use `json_schema_to_model`, so the agentic-provider unknown-key behavior does not apply. ## Cross-SDK contract The TypeScript and Python fixtures contain the same 24 cases and are required to remain byte-identical: ```text ts/packages/core/test/fixtures/json-schema-conversion/object-cases.json python/tests/fixtures/json-schema-conversion/object-cases.json ``` The corpus covers open and closed objects, overlapping patterns, schema-valued additional properties, empty schemas, enums, nested strict containers, false schemas, type unions, local references, JSON integer semantics, default materialization, and intentional Composio strictness. Each case has one shared acceptance result. Converter-specific expected outputs are separate because Zod and Pydantic materialize defaults while Effect validates without transforming output. Any acceptance difference requires an explicit divergence reason. The decoding rules and the cross-language invariants have one definition. `@composio/core` owns the loader at `ts/packages/core/test/fixtures/json-schema-conversion/corpus.ts`, and the Zod, Effect, and CLI suites re-export it rather than each carrying a copy. It reads the corpus through `resolveJsonModule`, which is already enabled in every consumer, so no test project needs `@types/node` to load a fixture. ## Releases and documentation - Three explicit minor Changesets cover `@composio/core`, `@composio/json-schema-to-zod`, and `@composio/claude-agent-sdk`. - `@composio/core` and `@composio/slim` are a fixed Changesets group, so the core Changeset automatically schedules the matching minor release of `@composio/slim`; no duplicate slim Changeset is required. - `@composio/google` has a patch Changeset and requires `@composio/core >=0.16.0 <1.0.0`, preventing installation with older Core versions that lack the shared normalizer. - `@composio/json-schema-to-effect-schema` is private. The CLI and CLI local tools are excluded from Changesets, so the CLI's user-facing fix is recorded in `ts/packages/cli/CHANGELOG.md`. - Python does not use Changesets. It now declares `jsonschema>=4.23.0` directly in both package metadata sources, and the generated `uv.lock` is refreshed with the repository-pinned uv version. - The docs changelog distinguishes Python agentic-provider behavior, Gemini signature behavior, and Claude Agent SDK registration behavior. ## Verification Local verification after the final implementation: - Python: `nox -s tst` (`1002 passed, 34 skipped`) and `nox -s chk` - Gemini provider: `32 passed` with the provider installed editable - TypeScript: core `1088`, Zod `118`, Effect `65`, Claude Agent SDK `24`, Google `14`, and focused CLI validation `9` - Affected TypeScript typechecks - `pnpm validate:changesets` and Changesets status against the PR exact `next` base - Detached Changesets versioning and a strict-peer packed consumer: Core/Slim `0.16.0`, Google `0.10.2`, Zod `0.3.0`, and Claude Agent SDK `0.11.0` - Python sdist and wheel build, with both artifacts passing `twine check` - Prettier, Ruff formatting, `uv lock --check`, byte-identical fixture comparison, and `git diff --check` Closes #4022, #4023, and #4064.
composio.dev • Documentation • Quickstart • Changelog
Composio
Composio gives your AI agents 1000+ pre-authenticated toolkits, per-user sessions, authentication, triggers, and a sandbox, so you can ship agents that turn intent into action.
This is the Composio SDK monorepo. It contains:
@composio/core: TypeScript SDKcomposio: Python SDKcomposioCLI: search, execute, and script tools from your shell- Provider adapters for OpenAI Agents, Claude Agent SDK, Vercel AI SDK, LangChain, and more
Quickstart
Create a session for a user, hand its tools to your agent, and let the agent take action across 1000+ apps. Grab a COMPOSIO_API_KEY from the dashboard first.
TypeScript
npm install @composio/core @composio/openai-agents @openai/agents
@composio/coreintentionally packages its TypeScript source and SDK docs so the installed package is inspectable to coding agents. If you want a smaller install with the same API, use@composio/slim.
import { Composio } from "@composio/core";
import { OpenAIAgentsProvider } from "@composio/openai-agents";
import { Agent, run } from "@openai/agents";
const composio = new Composio({ provider: new OpenAIAgentsProvider() });
// Each session is scoped to one of your users
const session = await composio.create("user_123");
const tools = await session.tools();
const agent = new Agent({
name: "Personal Assistant",
instructions: "You are a helpful assistant. Use Composio tools to take action.",
tools,
});
const result = await run(agent, "Summarize my emails from today");
console.log(result.finalOutput);
Python
pip install composio composio-openai-agents openai-agents
from composio import Composio
from composio_openai_agents import OpenAIAgentsProvider
from agents import Agent, Runner
composio = Composio(provider=OpenAIAgentsProvider())
# Each session is scoped to one of your users
session = composio.create(user_id="user_123")
tools = session.tools()
agent = Agent(
name="Personal Assistant",
instructions="You are a helpful assistant. Use Composio tools to take action.",
tools=tools,
)
result = Runner.run_sync(starting_agent=agent, input="Summarize my emails from today")
print(result.final_output)
By default a session gets meta tools that discover, authenticate, and execute app tools at runtime, so you don't load hundreds of tool definitions into context. Store session.session_id and reuse it with composio.use() across turns. See what a session is and configuring sessions for restricting toolkits, auth configs, and connected accounts.
Prefer MCP? Every session also exposes a hosted MCP endpoint. Pass mcp: true to composio.create() and point Claude, Cursor, or any MCP client at session.mcp.url. See sessions via MCP.
CLI
The composio CLI runs Composio from your shell and gives coding agents like Claude Code a local tool surface.
curl -fsSL https://composio.dev/install | sh
The installer puts composio on your PATH for future terminals. Open a new terminal, then run composio login. See INSTALL.md for shell setup overrides, including COMPOSIO_INSTALL_SHELL=none for install-only runs.
Use composio search to find tools, composio execute to run them, composio link to connect accounts, and composio run to script workflows in TypeScript. See the CLI docs.
Providers
A provider adapts Composio tools to your agent framework's native tool format:
| Provider | TypeScript | Python |
|---|---|---|
| OpenAI | @composio/openai |
composio-openai |
| OpenAI Agents | @composio/openai-agents |
composio-openai-agents |
| Anthropic | @composio/anthropic |
composio-anthropic |
| Claude Agent SDK | @composio/claude-agent-sdk |
composio-claude-agent-sdk |
| Vercel AI SDK | @composio/vercel |
— |
| Google GenAI | @composio/google |
composio-gemini, composio-google |
| Google ADK | — | composio-google-adk |
| LangChain | @composio/langchain |
composio-langchain |
| LangGraph | via @composio/langchain |
composio-langgraph |
| LlamaIndex | @composio/llamaindex |
composio-llamaindex |
| Mastra | @composio/mastra |
— |
| Pi | @composio/experimental* |
— |
| Cloudflare Workers AI | @composio/cloudflare |
— |
| CrewAI | — | composio-crewai |
| AutoGen | — | composio-autogen |
* The Pi provider is experimental and ships from @composio/experimental.
Don't see your framework? Build a custom provider, or skip providers entirely and connect over MCP.
All packages
Everything published from this repo:
| Package | Description |
|---|---|
@composio/core |
TypeScript SDK |
@composio/slim |
@composio/core without packaged source or docs; same API, smaller install |
composio CLI |
Standalone CLI binary: curl -fsSL https://composio.dev/install | sh |
@composio/experimental |
Experimental integrations, including the Pi provider |
@composio/json-schema-to-zod |
JSON Schema to Zod conversion |
@composio/* provider adapters |
OpenAI, OpenAI Agents, Anthropic, Claude Agent SDK, Vercel, Google, LangChain, LlamaIndex, Mastra, Cloudflare |
composio |
Python SDK |
composio-* provider adapters |
OpenAI, OpenAI Agents, Anthropic, Claude Agent SDK, Gemini, Google, Google ADK, LangChain, LangGraph, LlamaIndex, CrewAI, AutoGen |
Repository layout
ts/ TypeScript SDK workspace
packages/core/ @composio/core
packages/providers/ Provider adapters
packages/cli/ Composio CLI
python/ Python SDK and provider packages
docs/ Documentation site (docs.composio.dev)
The TypeScript SDK is tested against Node 22+; the Python SDK supports Python 3.10+.
Development
mise install # pinned toolchain (Node, Python, pnpm)
pnpm install
pnpm build
pnpm test
Python commands run from python/; see python/README.md. We welcome contributions to both SDKs; read the contribution guidelines before submitting pull requests.
Support
License
MIT. See LICENSE.