Repository navigation
Conversation
- Add @corsair-dev/composio package with build config - Register composio in core constants (BaseProviders, AllProviders)
- Implement REST client for backend.composio.dev/api - Add rate limit and auth error handlers - Define entity schemas for tools, connections, actions
- Tools: list and get tools/integrations - Actions: list, get, and execute actions on connected apps - Connections: list, create, and delete authenticated connections - Apps: list available apps
- Implement trigger.fired, connection.status, action.completed webhooks - Wire up composio() factory function with key builder, endpoint meta, and webhook matcher - Export all endpoint and webhook types
|
@adityalowanshi is attempting to deploy a commit to the corsair Team on Vercel. A member of the Team first needs to authorize it. |
|
- Add @corsair-dev/composio package with build config - Register composio in core constants (BaseProviders, AllProviders)
- Implement REST client for backend.composio.dev/api - Add rate limit and auth error handlers - Define entity schemas for tools, connections, actions
- Tools: list and get tools/integrations - Actions: list, get, and execute actions on connected apps - Connections: list, create, and delete authenticated connections - Apps: list available apps
- Implement trigger.fired, connection.status, action.completed webhooks - Wire up composio() factory function with key builder, endpoint meta, and webhook matcher - Export all endpoint and webhook types
- Implement real HMAC signature verification in verifyComposioWebhookSignature using verifyHmacSignature from corsair/http - Guard JSON.parse in parseBody with try/catch to prevent crash on malformed webhook bodies - Add explanatory comments to type assertions in all endpoint files
e508a33 to
0febbd2
Compare
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to The Composio integration and webhook handling introduce no actionable merge-blocking risk in the supplied evidence, so the PR is merge-ready after normal checks and review. Pre-merge checks ·
|
|
@greptile review |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (7)
packages/composio/webhooks.test.ts (1)
14-39: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winCover the
whsec_key path.Line 15 uses a bare secret. This test does not exercise the Standard Webhooks decoding branch in
packages/composio/webhooks/types.tsLines 85-94. Add a validwhsec_<base64>fixture and sign with the decoded raw key.Proposed test
@@ it('accepts a valid Standard Webhooks signature', () => { const signature = sign(secret, id, ts, body); @@ expect(result.valid).toBe(true); }); + + it('accepts a valid `whsec_` secret', () => { + const result = verifyComposioWebhookSignature( + { + rawBody: body, + headers: { + 'webhook-id': id, + 'webhook-timestamp': ts, + 'webhook-signature': sign(secret, id, ts, body), + }, + payload: JSON.parse(body), + } as never, + `whsec_${Buffer.from(secret, 'utf8').toString('base64')}`, + ); + + expect(result.valid).toBe(true); + });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/composio/webhooks.test.ts` around lines 14 - 39, Update the “accepts a valid Standard Webhooks signature” test and its secret fixture to use a valid whsec_<base64> key, and generate the signature with the decoded raw key so verifyComposioWebhookSignature exercises the Standard Webhooks decoding branch.packages/composio/tsconfig.json (1)
17-19: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueExclude test files from declaration emit.
includematches**/*.test.ts, so the composite build emits declaration files for tests intodist. Add the test pattern toexcludeto keep the published declaration surface limited to the plugin API.♻️ Proposed change
- "exclude": ["dist", "node_modules"], + "exclude": ["dist", "node_modules", "**/*.test.ts"],🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/composio/tsconfig.json` around lines 17 - 19, Update the tsconfig include/exclude configuration by adding a pattern that excludes test files such as *.test.ts from declaration emit, while preserving the existing dist and node_modules exclusions and the plugin source inclusion.packages/composio/endpoints/actions.ts (2)
39-42: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueThrow
ComposioAPIErrorfor input validation failures.These guards throw a plain
Error. The package already definesComposioAPIErrorinpackages/composio/client.ts, and transport failures use it. Callers that branch on the error type will not recognize these validation failures. UseComposioAPIErrorwith a 400 status for consistency.♻️ Proposed change
-import { makeComposioRequest } from '../client'; +import { ComposioAPIError, makeComposioRequest } from '../client';const toolSlug = input.tool_slug ?? input.actionId; if (!toolSlug) { - throw new Error('tool_slug is required'); + throw new ComposioAPIError('tool_slug is required', 400); }Also applies to: 64-67
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/composio/endpoints/actions.ts` around lines 39 - 42, Update the validation guards in the actions endpoint, including the corresponding guard around lines 64–67, to throw the existing ComposioAPIError from client.ts instead of plain Error. Set the error status to 400 while preserving the current validation messages and control flow.
6-12: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExtract the duplicated
omitUndefinedhelper into one module. The same 7-line helper is copied verbatim into three endpoint modules. Define it once inside the package, for example inpackages/composio/endpoints/utils.ts, and import it. The helper stays insidepackages/composio/, so the package remains self-contained.
packages/composio/endpoints/actions.ts#L6-L12: delete the local definition and importomitUndefinedfrom the newpackages/composio/endpoints/utils.ts.packages/composio/endpoints/connections.ts#L6-L12: delete the local definition and importomitUndefinedfrom the same module.packages/composio/endpoints/apps.ts#L6-L12: delete the local definition and importomitUndefinedfrom the same module.♻️ Proposed extraction
New file
packages/composio/endpoints/utils.ts:export type QueryValue = string | number | boolean | undefined; export function omitUndefined( query: Record<string, QueryValue>, ): Record<string, QueryValue> { return Object.fromEntries( Object.entries(query).filter(([, v]) => v !== undefined), ); }Then in each endpoint module:
-function omitUndefined( - query: Record<string, string | number | boolean | undefined>, -): Record<string, string | number | boolean | undefined> { - return Object.fromEntries( - Object.entries(query).filter(([, v]) => v !== undefined), - ); -} +import { omitUndefined } from './utils';As per coding guidelines, "Each plugin should remain self-contained within its own
packages/<plugin>/package" — the new helper module stays insidepackages/composio/.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/composio/endpoints/actions.ts` around lines 6 - 12, Extract the duplicated omitUndefined helper into packages/composio/endpoints/utils.ts, preserving its current filtering behavior and shared QueryValue type. In packages/composio/endpoints/actions.ts lines 6-12, packages/composio/endpoints/connections.ts lines 6-12, and packages/composio/endpoints/apps.ts lines 6-12, remove the local definitions and import omitUndefined from the new module.Source: Coding guidelines
packages/composio/client.ts (1)
50-60: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winPreserve the upstream error body and rate-limit metadata.
ApiErrorcarriesbody,retryAfter,rateLimitReset,rateLimitRemaining, andrateLimitLimit(seepackages/corsair/async-core/ApiError.tslines 4-43).ComposioAPIErrorkeeps onlymessageandstatus. After the shared executor exhausts its retries (packages/corsair/async-core/request.tslines 332-438), callers lose both the Composio error code and the backoff hint, so they cannot schedule a retry or report the specific failure.♻️ Proposed change to retain error detail
export class ComposioAPIError extends Error { constructor( message: string, public readonly status?: number, + public readonly body?: unknown, + public readonly retryAfter?: number, ) { super(message); this.name = 'ComposioAPIError'; } }if (error instanceof ApiError) { - throw new ComposioAPIError(error.message, error.status); + throw new ComposioAPIError( + error.message, + error.status, + error.body, + error.retryAfter, + ); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/composio/client.ts` around lines 50 - 60, Update the ApiError handling in the request try/catch to preserve the upstream error body and rate-limit metadata, including retryAfter, rateLimitReset, rateLimitRemaining, rateLimitLimit, and the Composio error code. Extend or use the ComposioAPIError construction path so callers retain these fields after request retries are exhausted, while preserving existing handling for generic Error and unknown failures.packages/composio/endpoints/types.ts (2)
23-55: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valuePrefer
z.looseObject()over.passthrough()in Zod 4.Zod 4 retains
.passthrough()as a legacy API. Replace these loose object schemas withz.looseObject(). The package declareszodas^4.1.13, and the lockfile resolves version4.4.3.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/composio/endpoints/types.ts` around lines 23 - 55, Replace the legacy .passthrough() calls in ToolSchema and PaginatedToolsSchema with Zod 4’s z.looseObject() construction, preserving each schema’s existing fields and optionality while continuing to allow unknown properties.
179-186: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winOpen Redirect (CWE-601): URL Redirection to Untrusted Site ('Open Redirect')
Reachability: Internal · Exploitability: Moderate
Reachability path
● Entry packages/composio/endpoints/apps.ts:20 omitUndefined │ ▼ ● Hop packages/composio/endpoints/actions.ts │ ▼ ● Sink packages/composio/endpoints/types.tsRestrict redirect URLs to HTTP(S).
z.url()also accepts schemes such asmailto:. Usez.url({ protocol: /^https?$/ }).optional()for bothcallback_urlandredirectUribefore forwarding them as redirect targets.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/composio/endpoints/types.ts` around lines 179 - 186, Update ConnectionCreateInputSchema so both callback_url and the deprecated redirectUri validate with z.url({ protocol: /^https?$/ }).optional(), restricting redirect targets to HTTP and HTTPS while preserving their optional status.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/composio/endpoints/connections.ts`:
- Around line 34-39: Update the event payloads in connectionsList and
connectionCreate to exclude end-user identifiers before calling
logEventFromContext. Replace the connectionsList `{ ...input }` payload with
only non-sensitive fields, and remove user_id from the connectionCreate payload
while preserving the existing event names and statuses.
---
Nitpick comments:
In `@packages/composio/client.ts`:
- Around line 50-60: Update the ApiError handling in the request try/catch to
preserve the upstream error body and rate-limit metadata, including retryAfter,
rateLimitReset, rateLimitRemaining, rateLimitLimit, and the Composio error code.
Extend or use the ComposioAPIError construction path so callers retain these
fields after request retries are exhausted, while preserving existing handling
for generic Error and unknown failures.
In `@packages/composio/endpoints/actions.ts`:
- Around line 39-42: Update the validation guards in the actions endpoint,
including the corresponding guard around lines 64–67, to throw the existing
ComposioAPIError from client.ts instead of plain Error. Set the error status to
400 while preserving the current validation messages and control flow.
- Around line 6-12: Extract the duplicated omitUndefined helper into
packages/composio/endpoints/utils.ts, preserving its current filtering behavior
and shared QueryValue type. In packages/composio/endpoints/actions.ts lines
6-12, packages/composio/endpoints/connections.ts lines 6-12, and
packages/composio/endpoints/apps.ts lines 6-12, remove the local definitions and
import omitUndefined from the new module.
In `@packages/composio/endpoints/types.ts`:
- Around line 23-55: Replace the legacy .passthrough() calls in ToolSchema and
PaginatedToolsSchema with Zod 4’s z.looseObject() construction, preserving each
schema’s existing fields and optionality while continuing to allow unknown
properties.
- Around line 179-186: Update ConnectionCreateInputSchema so both callback_url
and the deprecated redirectUri validate with z.url({ protocol: /^https?$/
}).optional(), restricting redirect targets to HTTP and HTTPS while preserving
their optional status.
In `@packages/composio/tsconfig.json`:
- Around line 17-19: Update the tsconfig include/exclude configuration by adding
a pattern that excludes test files such as *.test.ts from declaration emit,
while preserving the existing dist and node_modules exclusions and the plugin
source inclusion.
In `@packages/composio/webhooks.test.ts`:
- Around line 14-39: Update the “accepts a valid Standard Webhooks signature”
test and its secret fixture to use a valid whsec_<base64> key, and generate the
signature with the decoded raw key so verifyComposioWebhookSignature exercises
the Standard Webhooks decoding branch.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: fb4b5fac-89c4-4410-9a08-7190e4dc9e20
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (21)
packages/composio/api.test.tspackages/composio/client.tspackages/composio/endpoints/actions.tspackages/composio/endpoints/apps.tspackages/composio/endpoints/connections.tspackages/composio/endpoints/index.tspackages/composio/endpoints/tools.tspackages/composio/endpoints/types.tspackages/composio/error-handlers.tspackages/composio/index.tspackages/composio/jest.config.cjspackages/composio/package.jsonpackages/composio/schema/database.tspackages/composio/schema/index.tspackages/composio/tsconfig.jsonpackages/composio/tsup.config.tspackages/composio/webhooks.test.tspackages/composio/webhooks/index.tspackages/composio/webhooks/triggers.tspackages/composio/webhooks/types.tspackages/corsair/core/constants.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/composio/error-handlers.ts`:
- Around line 8-9: Update the rate-limit detection logic around the error
classification function to avoid substring checks on error.message. Prefer an
exact structured status or code field, or parse and match a complete rate-limit
token, so values such as 4290 and unrelated text containing rate_limited are not
classified as rate limits before selecting RATE_LIMIT_ERROR.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 3be874d3-2fc0-4156-a999-5368f8b44316
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (21)
packages/composio/api.test.tspackages/composio/client.tspackages/composio/endpoints/actions.tspackages/composio/endpoints/apps.tspackages/composio/endpoints/connections.tspackages/composio/endpoints/index.tspackages/composio/endpoints/tools.tspackages/composio/endpoints/types.tspackages/composio/error-handlers.tspackages/composio/index.tspackages/composio/jest.config.cjspackages/composio/package.jsonpackages/composio/schema/database.tspackages/composio/schema/index.tspackages/composio/tsconfig.jsonpackages/composio/tsup.config.tspackages/composio/webhooks.test.tspackages/composio/webhooks/index.tspackages/composio/webhooks/triggers.tspackages/composio/webhooks/types.tspackages/corsair/core/constants.ts
🚧 Files skipped from review as they are similar to previous changes (20)
- packages/composio/webhooks/index.ts
- packages/composio/tsconfig.json
- packages/composio/webhooks.test.ts
- packages/composio/endpoints/apps.ts
- packages/composio/endpoints/index.ts
- packages/composio/tsup.config.ts
- packages/composio/webhooks/triggers.ts
- packages/composio/endpoints/tools.ts
- packages/composio/schema/index.ts
- packages/corsair/core/constants.ts
- packages/composio/jest.config.cjs
- packages/composio/package.json
- packages/composio/api.test.ts
- packages/composio/endpoints/actions.ts
- packages/composio/endpoints/connections.ts
- packages/composio/client.ts
- packages/composio/webhooks/types.ts
- packages/composio/index.ts
- packages/composio/endpoints/types.ts
- packages/composio/schema/database.ts
|
@greptile review |
Plugin PR scorecard —
|
| Check | Status | Notes |
|---|---|---|
| R1 — Scope: plugin files only | ✅ | |
| R2 — Tests with assertions | ✅ | |
| R3 — Description complete | ✅ | |
| R3 — Linked issue / claim | ✅ | |
| R4 — Demo video / recording | ✅ |
Rules: PLUGIN_PR_RULES.md · re-runs on every push
# Conflicts: # pnpm-lock.yaml
Comments Outside DiffThese findings could not be posted inline.
|
Revert packages/agiled/readme.md to match main so R1 gate passes.
Unblocks plugin README/metadata CI check.
Keep grouped endpoint table and webhook event rows from local branch.
35741e7 to
3d4035c
Compare
|
@greptileai review |
|
Want your agent to iterate on Greptile's feedback? Try greploops. |
|
@greptileai review |
|
@greptileai review |

Description
Adds the Composio plugin (
@corsair-dev/composio) on Composio REST v3.1 (https://backend.composio.dev/api/v3.1).It covers the 19 operations of the
composiotoolkit listed on corsair.dev/oss/composio that Composio still serves. It also adds the REST calls needed to use them: create a session, list/get/execute tools, list toolkits, and manage connected accounts.Composio runs its meta tools on two routes:
POST /tools/execute/{slug}.POST /tool_router/session/{session_id}/execute_metawith{ slug, arguments }. Composio rejects these outside a session. Callsessions.createfirst to get asession_id.Operations
COMPOSIO_CHECK_ACTIVE_CONNECTIONmeta.checkActiveConnectionPOST /tools/execute/COMPOSIO_CHECK_ACTIVE_CONNECTIONCOMPOSIO_CHECK_ACTIVE_CONNECTIONSmeta.checkActiveConnectionsPOST /tools/execute/COMPOSIO_CHECK_ACTIVE_CONNECTIONSCOMPOSIO_CREATE_PLANmeta.createPlanPOST /tools/execute/COMPOSIO_CREATE_PLANCOMPOSIO_ENABLE_TRIGGERmeta.enableTriggerPOST /tools/execute/COMPOSIO_ENABLE_TRIGGERCOMPOSIO_EXECUTE_TOOLmeta.executeToolPOST /tools/execute/COMPOSIO_EXECUTE_TOOLCOMPOSIO_GET_DEPENDENCY_GRAPHmeta.getDependencyGraphPOST /tools/execute/COMPOSIO_GET_DEPENDENCY_GRAPHCOMPOSIO_GET_REQUIRED_PARAMETERSmeta.getRequiredParametersPOST /tools/execute/COMPOSIO_GET_REQUIRED_PARAMETERSCOMPOSIO_GET_RESPONSE_SCHEMAmeta.getResponseSchemaPOST /tools/execute/COMPOSIO_GET_RESPONSE_SCHEMACOMPOSIO_INITIATE_CONNECTIONmeta.initiateConnectionPOST /tools/execute/COMPOSIO_INITIATE_CONNECTIONCOMPOSIO_LIST_TOOLKITSmeta.listToolkitsPOST /tools/execute/COMPOSIO_LIST_TOOLKITSCOMPOSIO_LIST_TRIGGERSmeta.listTriggersPOST /tools/execute/COMPOSIO_LIST_TRIGGERSCOMPOSIO_WAIT_FOR_CONNECTIONmeta.waitForConnectionPOST /tools/execute/COMPOSIO_WAIT_FOR_CONNECTIONCOMPOSIO_GET_TOOL_SCHEMASmeta.getToolSchemasPOST /tool_router/session/{session_id}/execute_metaCOMPOSIO_MANAGE_CONNECTIONSmeta.manageConnectionsPOST /tool_router/session/{session_id}/execute_metaCOMPOSIO_MULTI_EXECUTE_TOOLmeta.multiExecuteToolPOST /tool_router/session/{session_id}/execute_metaCOMPOSIO_REMOTE_BASH_TOOLmeta.remoteBashToolPOST /tool_router/session/{session_id}/execute_metaCOMPOSIO_REMOTE_WORKBENCHmeta.remoteWorkbenchPOST /tool_router/session/{session_id}/execute_metaCOMPOSIO_SEARCH_TOOLSmeta.searchToolsPOST /tool_router/session/{session_id}/execute_metaCOMPOSIO_WAIT_FOR_CONNECTIONSmeta.waitForConnectionsPOST /tool_router/session/{session_id}/execute_metasessions.createPOST /tool_router/sessiontools.listGET /toolstools.getGET /tools/{tool_slug}tools.executePOST /tools/execute/{tool_slug}toolkits.listGET /toolkitsconnections.listGET /connected_accountsconnections.createPOST /connected_accounts/linkconnections.deleteDELETE /connected_accounts/{id}Argument shapes follow the Composio toolkit reference. Routes and response shapes follow the v3.1 OpenAPI spec.
Not implemented
Six ops listed on corsair.dev are no longer served by Composio:
COMPOSIO_UPSERT_RECIPEandCOMPOSIO_GET_RECIPEwere session meta tools. Composio removed them from theexecute_metaslug enum, and the Composio CLI changelog records the removal (entry 5f004ff: "These slugs were removed from@composio/client").COMPOSIO_CREATE_UPDATE_RECIPE,COMPOSIO_EXECUTE_RECIPE,COMPOSIO_GET_RECIPE_DETAILSandCOMPOSIO_DOWNLOAD_S3_FILEare not in the currentcomposiotoolkit (version20260917_00, 19 tools), and v3.1 has no recipe or S3 download endpoint.Database entities
Entities mirror the v3.1 response objects (tools, toolkits, connected accounts, tool router session) and are written with
upsertByEntityId. A failed write logs a warning and never fails the API call.toolstools.list,tools.gettoolkitstoolkits.listconnectedAccountsconnections.list(row removed byconnections.delete)sessionssession_idsessions.createconnectedAccountsleaves out the API'sstateanddatafields because they hold OAuth tokens and API keys.Auth
Project API key, sent as the
x-api-keyheader. Configure it withcomposio({ key })or theapi_keyauth type.Webhooks
None. corsair.dev lists no triggers for this integration, so the plugin defines no webhooks.
Tests
api.test.tsstubsfetchwith realResponseobjects. For every endpoint it asserts the exact method, URL, query, body and API key header, and it compares the parsed result against a literal value. It also checks that:input_requiredsession result parses,ComposioAPIErrorand is not retried,Retry-Afterthrough to the rate-limit handler with no extra transport retry,connections.deletedrops the row, and a failing write does not fail the call.error-handlers.test.tscovers the retry handlers.Live test
The project key available for this run is rejected by Composio, so no authenticated call could run. Every request still reached
backend.composio.devand returned the documented 401 error body (APIKey_InvalidAPIKey), which confirms the host and each path below:GET /api/v3.1/tools,/toolkitsGET /api/v3.1/tools/COMPOSIO_SEARCH_TOOLSand the six unlisted recipe/S3 slugsChecklist
Before submitting your PR, please verify the following:
pnpm lintand all checks passpnpm typecheckand there are no TypeScript errorspnpm buildand all packages build successfullypnpm testand all tests passScreenshots / Demos (if applicable)
Additional Notes
Auth uses the project API key via
x-api-key, not Connect MCPck_consumer keys.