This PR:
- builds on top of https://github.com/ComposioHQ/composio/pull/4475
- stores `composio execute` responses over 40,000 UTF-8 bytes in a
session file, replacing the check for more than 10,000 o200k tokens
added in https://github.com/ComposioHQ/composio/pull/2979
- keeps `tokenCount` in the stored-output summary as an estimate
(`ceil(sizeBytes / 4)`), adds `sizeBytes`, and logs `Response stored in
<path> (N KB, ~M tokens)`
- removes `js-tiktoken` and the `execute-output-encoder-runtime`
companion from https://github.com/ComposioHQ/composio/pull/4469, with
its tsdown entry, build-guard and startup-import patterns, upgrade
fixture entry, and the encoder fallback and special-token tests
- keeps `execute-output-encoder-runtime.mjs` in the three uninstall
lists, so installs that shipped it can still remove the leftover file
- behavior change: a 10–40KB response of more than 10,000 tokens now
prints inline, and dense non-ASCII output (about 1–2 bytes per token)
can print inline at up to ~20,000 tokens
- verified: CLI typecheck, full CLI vitest (131 files, 1343 passed, 1
skipped), `test/release-workflow.test.ts`, and
`build-companion-modules.ts` with the executable graph check
## Context
Nothing reads `tokenCount` as a number: it appears only in the
stored-output summary, the two log lines, session history, and a debug
log in `run-helpers-runtime.ts`. o200k is not the tokenizer of the model
that reads the output, so the exact count only moved the cutoff. It cost
the 2.3MB rank table, ~330ms after large tool calls (measured in #4469,
not re-measured here), and a separately shipped companion whose absence
made `composio run` require a repair download after an upgrade.
Atomic Agent is a local-first AI agent (CLI and TUI) that ships a
built-in Composio integration. It connects to the hosted tool router
over Streamable HTTP MCP, so Composio tools are registered at startup as
`mcp.composio.*`.
This adds it to the Composio Connect client list alongside the other
terminal agents.
**Changes**
- New `ConnectClientOption` entry in
`docs/content/docs/composio-connect.mdx`
- Client icon at `docs/public/images/clients/atomic-agent.svg`
- `atomic agent` appended to the page keywords
The setup steps document the agent's own flow (Integrations tab, or
`COMPOSIO_API_KEY` in its `.env`) rather than a CLI install, since the
integration is native.
Repo: https://github.com/AtomicBot-ai/atomic-agent
Happy to adjust the wording, the description, or the placement, or to
close this if you would rather add the entry yourselves.
This PR:
- fixes the raw `:raises ...:` reST directives leaking into the
generated Python SDK reference, flagged by [Greptile on the
auto-generated docs
PR](https://github.com/ComposioHQ/composio/pull/4479#discussion_r4004672537)
- teaches `python/scripts/generate-docs.py` to parse `:raises Exc:`
docstring fields (plus `:raise`/`:except`/`:throws` synonyms) into a
structured `**Raises**` section, with indented continuation-line support
- normalizes inline reST in all rendered prose:
`:class:`/`:func:`/`:meth:`/`:mod:` roles honor `~` short-name
semantics, and double-backtick literals become single-backtick inline
code
- regenerates `docs/content/reference/sdk-reference/python/` pages
- adds regression tests for raises parsing and reST normalization in
`python/tests/test_generate_docs.py`
## Context
The Python SDK reference pages are generated by
`python/scripts/generate-docs.py` (workflow: `generate-sdk-docs.yml`),
so the fix lives in the generator rather than the MDX — hand-edits would
be overwritten by the next auto-regen PR. Unrecognized `:raises` lines
previously fell through into the `:returns:` description text.
## Summary
`PusherService.subscribe` binds `pusher:subscription_error` after the
Pusher subscription call returns. `pusher-js` dispatches this event
asynchronously without catching listener exceptions, so authentication,
permission, server, or network subscription failures could escape as
uncaught exceptions in Node applications.
Fixes#4445
## Changes
- Log asynchronous Pusher subscription errors at the SDK error boundary
instead of throwing from the event callback.
- Add regression coverage that emits `pusher:subscription_error` after
`subscribe()` resolves and verifies that it does not throw.
- Add a patch changeset for the fixed `@composio/core`/`@composio/slim`
package group.
## Type of change
- [x] Bug fix
- [ ] New feature
- [ ] Refactor/Chore
- [ ] Documentation
- [ ] Breaking change
## How Has This Been Tested?
- Node `v24.17.0` / pnpm `11.8.0`
- `pnpm --filter @composio/core exec vitest run
test/services/pusher.test.ts test/utils/pusher.test.ts` — 2 files, 5
tests passed
- `pnpm --filter @composio/core test` — 55 test files passed; 1,289
tests passed and 2 existing tests reported expected failures; command
exited successfully
- `pnpm --filter @composio/core typecheck`
- `pnpm lint` — passed with existing repository warnings
- `pnpm validate:changesets`
- `pusher-js` `v8.6.0` runtime probe confirmed that an exception thrown
from a `pusher:subscription_error` listener reaches Node's
`uncaughtException` handler; the regression test verifies the SDK
callback no longer throws.
## Screenshots (if applicable)
Not applicable.
## Checklist
- [x] I have read the Code of Conduct and this PR adheres to it
- [x] I ran linters/tests locally and they passed
- [x] I updated documentation as needed
- [x] I added tests or explain why not applicable
- [x] I added a changeset if this change affects published packages
## Additional context
This patch is intentionally limited to the live `PusherService` path.
XHR timeout handling is a separate concern and is not included here. The
older unreferenced `PusherUtils` helper is unchanged to keep this fix
scoped to the path used by `Triggers`.
## Summary
Fixes#4147.
Updates stale OpenAI Assistants API examples to use the Responses API,
matching OpenAI's current migration guidance that the Assistants API is
deprecated and shuts down on August 26, 2026.
## Changes
- Rewrote the Python OpenAI demo to use `OpenAIResponsesProvider` and
`client.responses.create`.
- Replaced the TypeScript provider docs' Assistants/Threads examples
with a Responses API tool-call loop.
- Removed deprecated `openai.beta.assistants` / `openai.beta.threads`
references from the targeted demo and docs page.
## Type of change
- [ ] Bug fix
- [ ] New feature
- [ ] Refactor/Chore
- [x] Documentation
- [ ] Breaking change
## How Has This Been Tested?
- `python -m py_compile
python/providers/openai/openai_assistant_demo.py` (passed)
- `rg -n
"openai\.beta|Assistants|assistants|threads|waitAndHandleAssistant|AssistantStream"
python/providers/openai/openai_assistant_demo.py
ts/docs/providers/openai.md` (no matches)
- `git diff --check` (passed)
## Screenshots (if applicable)
N/A
## Checklist
- [x] I have read the Code of Conduct and this PR adheres to it
- [x] I ran linters/tests locally and they passed
- [x] I updated documentation as needed
- [ ] I added tests or explain why not applicable (not applicable;
docs/demo cleanup only)
- [x] I added a changeset if this change affects published packages (not
applicable; docs/demo only)
## Additional context
The OpenAI platform docs mark the Assistants API as deprecated and
direct new agentic flows to the Responses API. This PR keeps Composio's
public OpenAI examples aligned with that path.
pysher performs the channel-auth request synchronously inside
pusher.subscribe(), so an auth rejection raised on the websocket thread
before pusher:subscription_error could ever be bound or fire. The new
on_subscription_error callback was skipped for exactly the failures it
documents, and callers waited out the full connect timeout for a
generic ComposioSDKTimeoutError.
- _connection_handler catches subscribe() failures and routes them
through the error path (log + callback with {'error': ...}).
- The failure is recorded on the subscription and the connect() wait
loop re-raises it on its next poll, so subscribe() fails promptly
with the underlying error and still tears down the pusher.
- Update the Python reference, guide, and docstrings; add regression
coverage for the handler routing, the failure record, and fast-fail.
Addresses the Cursor Bugbot comment on triggers.py:1023.
## Summary
Adds canonical guidance for common Composio product-integration
decisions and makes the main paths easy to find from the Knowledge Base
homepage. This PR is independent of #4258 and #4277 and targets `next`
directly.
## Changes
- Add guides for the Composio skill, consumer-agent architecture,
B2B-agent architecture, and moving from prototype to production
- Expand the white-labeling guide with a minimal setup path and FAQ
- Add five Start here cards to `/kb`, before support topics and toolkit
browsing
- Update OAuth callback examples and add relevant sidebar and quickstart
cross-links
## Type of change
- [x] Documentation
## How Has This Been Tested?
- `bun test tests/static/` (528 passed)
- `bun run lint:links`
- `bun run types:check`
- `bun run lint`
- `bun run build`
## Checklist
- [x] I have read the Code of Conduct and this PR adheres to it
- [x] I ran linters/tests locally and they passed
- [x] I updated documentation and structural homepage coverage
- [x] No changeset is required for docs-only changes
The containment around the subscription error callback only caught
synchronous throws. TypeScript accepts an async function against a
void-returning callback type, so a rejected promise escaped as an
unhandled rejection after subscribe() resolved - on modern Node that
can terminate the process, the same failure class this PR contains.
Route the callback result through Promise.resolve(...).catch so both
sync throws and async rejections land in the same contained logger
path, and add a regression test for the async case.
Addresses greptile-apps P1 and Cursor Bugbot review comments.
Mirror the TypeScript API surface from the previous commit:
- Triggers.subscribe accepts an optional on_subscription_error callback,
threaded through _SubcriptionBuilder.connect and bound to pysher's
pusher:subscription_error event on the trigger channel.
- TriggerSubscription._handle_subscription_error logs the failure at the
SDK boundary and invokes the callback with the parsed payload (or
{'raw': frame} for malformed frames); callback exceptions are
contained and logged so a faulty handler cannot tear down pysher's
dispatch thread.
- The parameter is optional; existing callers are unaffected.
- Update the Python triggers reference and the subscribing-to-events
guide.
Python never bound pusher:subscription_error at all, so subscription
failures after connect() were previously invisible to hosts.
The handleAssistantMessage, waitAndHandleAssistantStreamToolCalls, and
waitAndHandleAssistantToolCalls methods target the OpenAI Assistants
API, which shuts down on August 26, 2026. Add a deprecation warning
pointing new flows at OpenAIResponsesProvider.
- Use gpt-5 in the Responses API examples; gpt-4 predates the Responses
API and the repo's other Responses examples use gpt-5.
- Print response.output_text instead of indexing into content items,
which assumes non-empty message content.
- Add the OpenAIResponsesProvider type surface to the Type Definitions
section, which previously only showed the chat completions provider.
- Use gpt-5 like the rest of the repo's examples (getting-started.md,
the pre-PR demo) instead of the gpt-5.2 id used nowhere else.
- Print response.output_text instead of dumping the raw Response object,
matching the final line of the demo.
- PusherService.subscribe and Triggers.subscribe accept an optional
onSubscriptionError callback invoked with the raw pusher
pusher:subscription_error payload, giving hosts a programmatic signal
for post-resolution subscription failures (previously log-only).
- Exceptions thrown from the callback are contained and logged, never
rethrown, so a faulty handler cannot crash the host.
- The parameter is optional; existing callers are unaffected.
- Document the new parameter in the TypeScript triggers reference and
the subscribing-to-events guide; bump the changeset to minor for the
new API surface.
Applies review finding #1 from the PR #4448 review.
## Summary
- classify the existing harness integration guide as both a
general-agent and coding-agent example
- preserve the coding-agent tag because the same integration pattern
applies there too
## Validation
- bun test tests/static/content.test.ts
- git diff --check
Full docs typechecking could not start in this fresh worktree because
fumadocs-mdx is not installed.
- Log the full pusher:subscription_error payload (type, error, status)
instead of a flattened String(data.error) so operators can tell auth
failures from permission failures.
- Log the subscription success message only when Pusher dispatches
pusher:subscription_succeeded, not when subscribe() returns.
- Extend regression coverage for both behaviors.
Applies review findings #2 and #3 from the PR #4448 review.
## Summary
`transformToolkitRetrieveResponse` projects `auth_config_details[]` key
by key and silently dropped
three keys the pinned client declares. `is_secret` and
`legacy_template_name` are snake_case, so zod
stripped them; `auth_hint_url` was never listed.
The API documents `is_secret` as "Clients use it to decide whether to
mask the input". Without it a
consumer rendering its own credential form cannot tell an API key from a
shop subdomain, so a field holding a secret is not reported as one.
## Changes
- Map auth fields explicitly; add `isSecret`, `legacyTemplateName` and
`authHintUrl` to the schemas
- Spread optional keys conditionally, so a key the API omits stays
absent rather than `undefined`,
which would beat a caller's fallback
- Add a runtime test over all four field groups, plus a type-level test
that fails the build on an
unlisted client key in any group. It catches new wire keys, not an
assignment removed from the
mapper; the runtime test pins that for the keys known today
- Add a patch changeset for `@composio/core`
## Type of change
- [x] Bug fix
- [ ] New feature
- [ ] Refactor/Chore
- [ ] Documentation
- [ ] Breaking change
## How Has This Been Tested?
- `pnpm --filter @composio/core test`: 55 files, 1288 passed, 2 expected
fail; typecheck and
`validate:changesets` exit 0
- `pnpm lint:packages`: exit 0 with 54 pre-existing warnings, one in a
file this PR touches; no new
warning on added lines
- The runtime test fails 5 of its 7 cases on `origin/next`; the two
green on both are the regression
guards. The type-level test was checked against all four client
interfaces
- Node 24.18.0; `mise.toml` pins 24.17.0, unavailable here, so it was
not run under it. Not
run: the root workspace suite (its `test:toolchain` needs Bun), Docker
E2E, the Python suite
## Screenshots (if applicable)
N/A
## Checklist
- [x] I have read the Code of Conduct and this PR adheres to it
- [x] I ran linters/tests locally and they passed, with the exceptions
listed above
- [x] I updated documentation as needed (none needed: the new keys carry
TSDoc; the SDK reference is
generated from unchanged signatures)
- [x] I added tests or explain why not applicable
- [x] I added a changeset if this change affects published packages
## Additional context
Left out on purpose: `user_visible` and `required_scopes`, in the spec
but not the pinned client;
`deprecated_auth_provider_details`, which the client marks deprecated;
and the keys this transformer
drops outside `auth_config_details`, all pre-existing and adjacent.
One behavior change: the eager mapping now throws if an auth config
detail arrives without its
`auth_config_creation` group, where the pass-through still returned the
connection fields. The
client declares both groups required and non-nullable, so this affects
only out-of-contract
responses.
## Summary
Auto-generated Python SDK reference docs from `python/composio/`.
Regenerates pages at `docs/content/reference/sdk-reference/python/` to
reflect changes in the Python package's public API (new methods, updated
signatures, changed types).
Replacing the pass-through with an eager projection changed the failure mode for
an auth config detail that omits a field group. Passing the group through left
`undefined` in place, which zod rejected as a handled validation error;
`transformToolkitAuthFieldGroup` instead reads `group.required`, so the same
response now throws a `TypeError` before validation runs and crashes
`toolkits.get()`.
Default a missing or null group, and a missing list inside a group, to empty
lists. This repo's docs pipeline already assumes that shape: the schemas in
`docs/lib/toolkit-api.ts` carry `.catch({ required: [], optional: [] })` on the
same fields. Normalizing also keeps the other group usable when only one is
absent, which is typically the one the caller asked for, where a validation
error would have returned nothing.
Reported by greptile-apps on #4411.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Atomic Agent is a local-first agent (CLI and TUI) that ships a built-in
Composio integration: it connects to the hosted tool router over
Streamable HTTP MCP, so tools are registered at startup as
mcp.composio.*.
Setup is done from the Integrations tab or by adding COMPOSIO_API_KEY to
the agent's .env, so the entry documents that flow rather than the CLI
install used by other terminal agents.
- parse :raises Exc: docstring fields (plus Sphinx synonyms) into a
structured Raises section instead of leaking raw directives into the
Returns description
- normalize inline reST in all rendered prose: roles (:class:, :func:,
:meth:, ...) honor ~ short-name semantics; double-backtick literals
become single-backtick inline code
- regenerate docs/content/reference/sdk-reference/python/ pages
- add regression tests for raises parsing and reST normalization
Flagged by Greptile on the legacy-repo auto-PR (ComposioHQ/composio#4479).
Fixes for four `composio` CLI issues found while using the released
binary (v0.4.0). Each item below was reproduced from source on `next`
before the change and re-run after it. All commands were run with stdin
from `/dev/null`.
## 1. Bare `--stream` on `composio listen` is rejected
**Repro (before):**
```
$ composio listen GMAIL_NEW_GMAIL_MESSAGE --stream
Received unknown argument: '--stream='
<usage text>
exit=1
```
The command's own EXAMPLES block shows `composio listen
GMAIL_NEW_GMAIL_MESSAGE -p @trigger.json --stream`, and
`--stream=.data.text` / `--stream '.data.text'` both work.
**Cause:** `normalizeListenStreamFlag` in `src/commands/index.ts`
rewrites a valueless `--stream` to `--stream=`. `@effect/cli` only
recognises `--flag=value` when the value is non-empty (`FLAG_REGEX =
/^(--[^=]+)(?:=(.+))?$/`), so `--stream=` is treated as an unknown
argument.
**Change:** rewrite bare `--stream` to the two tokens `--stream ''`
instead. The listen handler already treats an empty path as "stream the
whole payload", so no handler change is needed.
**After:** `composio listen GMAIL_NEW_GMAIL_MESSAGE --stream` and `...
--stream --max-events 1` both parse and proceed to trigger creation.
Tests added in `listen.cmd.test.ts` cover bare `--stream` at the end of
argv and followed by another option.
## 2. Help examples reference a tool slug that no longer exists
**Repro (before):**
```
$ composio --help full | grep SLACK_
SLACK_SEND_A_MESSAGE_TO_A_SLACK_CHANNEL -d '{ channel: "general", text: "Hello" }'
$ composio execute SLACK_SEND_A_MESSAGE_TO_A_SLACK_CHANNEL --dry-run -d '{ channel: "general", text: "Hello team" }'
services/HttpServerError
Caused by: 404 {"error":{"message":"Tool SLACK_SEND_A_MESSAGE_TO_A_SLACK_CHANNEL not found","code":2401,"slug":"Tool_ToolNotFound",...}}
exit=1
```
The current slug is `SLACK_SEND_MESSAGE`. Its input schema (`composio
tools info SLACK_SEND_MESSAGE`) has `channel`, `markdown_text`,
`blocks`, `thread_ts`, ... and no `text` key.
**Change:** the three occurrences in `src/commands/root-help.ts`
(execute examples, the `run` script example, and the root help snippet)
now use `SLACK_SEND_MESSAGE` with `markdown_text`. No other file in the
repo references the old slug.
## 3. `composio tools info <bad-slug>` prints nothing and exits 0
**Repro (before):**
```
$ composio tools info BOGUS_TOOL_XYZ; echo exit=$?
exit=0
$ composio tools info BOGUS_TOOL_XYZ 2>/dev/null | wc -c
0
```
`tools info` catches the 404 with the shared `handleHttpServerError`
helper, which logs through `ui.log.error` (rendered only when stderr is
a TTY) and returns a fallback value, so the command completes
successfully with no output when piped.
**Change:** `src/effects/handle-http-error.ts` now sets
`process.exitCode = 1` (the convention used elsewhere in the CLI, e.g.
`toolkits search`) and, when stderr is not a TTY, writes the error
message plainly via `ui.error` so it is still visible. The decorated
log/hint/suggestion flow is unchanged. This helper is shared by the
`info`/`create`/`enable`/`disable`/`status` commands for tools,
triggers, auth configs and connected accounts, all of which return early
on the same failure path, so they now exit non-zero on an API error as
well.
**After:**
```
$ composio tools info BOGUS_TOOL_XYZ; echo exit=$?
Tool "BOGUS_TOOL_XYZ" not found.
exit=1
```
Tests added in `tools.info.cmd.test.ts` assert the exit code and message
for an unknown slug, and that a valid slug leaves the exit code
untouched.
## 4. `composio listen <unknown-slug>` reports a missing connection
instead of an unknown slug
**Repro (before):**
```
$ composio listen BOGUS_SLUG_XYZ
commands/ListenCommandError • No active connected account found for toolkit "bogus" and consumer user "...". Run `composio link bogus` first.
exit=1
```
The toolkit is inferred from the slug prefix and the connected-account
lookup runs without checking that the trigger type exists, so a typo
sends the user to link an account for a toolkit that does not exist.
**Change:** in `src/commands/listen.cmd.ts`, when no active connected
account matches, the command now retrieves the trigger type first. A 404
fails with a new `unknown_trigger` reason; any other outcome falls
through to the existing connected-account error. The same lookup runs
when creating the temporary trigger fails, because an active account for
the inferred toolkit (e.g. `GMAIL_NEW_GMAIL_MESAGE` with Gmail linked)
skips the first check; a 404 there replaces the generic `create_trigger`
error. The happy path makes no additional request.
**After:**
```
$ composio listen BOGUS_SLUG_XYZ
commands/ListenCommandError • Unknown trigger slug "BOGUS_SLUG_XYZ". List available slugs with `composio triggers list <toolkit>`.
exit=1
```
The test layer gained a `triggersTypes.retrieve` mock (the base client
would otherwise hit the network), and `listen.cmd.test.ts` covers the
unknown-slug case both without an account and with an active account for
the inferred toolkit (the test layer's `triggerInstances.upsert` can now
reject unknown slugs via `triggersData.rejectUnknownTriggerSlugs`). The
existing missing-connection test now provides a
`GMAIL_NEW_GMAIL_MESSAGE` trigger-type fixture so it still exercises the
connected-account branch.
## Also: `listen` example used a trigger with an empty config
While updating the help examples above, the `-p` example `composio
listen SLACK_RECEIVE_MESSAGE -p '{ trigger_config: { channel: "C123" }
}'` was replaced. `composio triggers info SLACK_RECEIVE_MESSAGE` returns
`"config": {"properties": {}, ...}`, so that example configures nothing.
`SLACK_CHANNEL_MESSAGE_RECEIVED` takes `channel_id`, so the example now
uses that trigger and key. Same one-line change in
`skills-src/composio-cli/index.ts`, which is the source for the
generated CLI skill.
## Changelog
All four fixes are recorded under Unreleased in
`ts/packages/cli/CHANGELOG.md` (the CLI is excluded from Changesets).
## Verification
- `pnpm typecheck` (src + test) in `ts/packages/cli`
- `pnpm test` in `ts/packages/cli` (validate:skills,
validate:boundaries, vitest)
- `oxlint` and `prettier --check` on the changed files
- Live re-runs of each repro above against the API from source
- listen: replace `Effect.catchAll`, which no longer exists in
effect@4.0.0-rc.112, with `Effect.result` and narrow the lookup failure
with `NotFoundError` from @composio/client instead of a structural
status check.
- tests: `it.scoped` is gone from @effect/vitest v4 (`it.effect` already
provides a Scope); switch the new cases over and assert the exit code on
`triggers info` too, so the shared handler's contract is covered by more
than one command.
- handle-http-error: also print the hint plainly when stderr is not a TTY.
- changelog: record the four user-visible fixes.
Claude-Session: https://claude.ai/code/session_01SvfF1wniMJsBDo5PaBjm2Y