Add Composio connector suggestions to composer#180
Conversation
Review Summary by QodoAdd Composio connector suggestions and hardcoded catalog preview WalkthroughsDescription• Add hardcoded Composio connector catalog with live-status merge support • Implement real-time connector suggestions in composer based on exact word matches • Attach connector documentation files instead of inline instruction text • Add Composio logout UI and improve preview/authenticated state handling • Increase connector detail tool limit from 10 to 100 for better coverage Diagramflowchart LR
A["Hardcoded Catalog"] -->|merge live status| B["Composio Connectors"]
C["Composer Draft"] -->|extract query| D["Suggestion Query"]
D -->|rank matches| E["Visible Suggestions"]
E -->|click suggestion| F{Connected?}
F -->|yes| G["Attach Docs File"]
F -->|no| H["Open Directory Panel"]
G -->|remove mention| I["Updated Draft"]
H -->|user connects| I
J["Directory Hub"] -->|show preview| K["Unauthenticated State"]
J -->|merge with live| L["Authenticated State"]
L -->|logout| K
File Changes1. src/components/content/composioComposerSuggestions.ts
|
Code Review by Qodo
1.
|
|
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:
📝 WalkthroughWalkthroughAdds composer Composio connector suggestions (ranking, merging, doc generation, and UI), refactors DirectoryHub to merge hardcoded and live connectors with visible-limit paging and route-driven details, implements client POST + server CLI logout, and wires App routing and a persisted settings toggle for connector suggestions. ChangesComposio Connector Integration
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 9
🤖 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 `@src/api/codexGateway.test.ts`:
- Around line 90-112: The logoutDirectoryComposioCli test is currently nested
inside the listDirectoryComposioConnectors describe block—move it into its own
top-level describe block to improve organization and clarity; locate the test
that stubs global fetch and calls logoutDirectoryComposioCli, cut that it(...)
block and paste it into a new describe('logoutDirectoryComposioCli', () => { ...
}) grouping (keeping the vi.stubGlobal('fetch') setup and the expect asserting
'/codex-api/composio/logout' POST), ensuring any related before/after hooks are
moved or duplicated as needed so the test remains isolated.
In `@src/components/content/composioComposerSuggestions.ts`:
- Line 98: The call to findLatestExactAliasMatch currently passes
value.toLowerCase(), which can cause index misalignment when slicing the
original value due to Unicode case-folding differences; instead pass the
original value (value) so the indexes returned by
findLatestExactAliasMatch(connector, value) align with the original string, and
rely on the regex's case-insensitive flag for matching; update the invocation
and ensure subsequent slicing uses the returned index against the unchanged
value variable.
In `@src/components/content/DirectoryHub.vue`:
- Around line 931-940: The hasMoreComposioConnectors check is using
composioTotal (full dataset) instead of the filtered/sorted results, causing the
"Load more" button to remain when a search yields fewer matches; update
hasMoreComposioConnectors to compare visibleComposioConnectors.value.length
against the total number of filtered/sorted connectors (e.g., compute the
filtered list using filterComposioConnectors(composioConnectors.value,
composioSearchQuery.value) or reuse the sorted variable from
visibleComposioConnectors before slicing) so the comparison reflects the
filtered result count rather than composioTotal.
- Around line 1223-1231: The mergeComposioConnectors function currently maps
only over catalog and drops connectors that exist solely in liveRows; update it
to preserve live-only connectors by producing a union of both sources: keep the
catalog entries merged with liveRows (using the existing bySlug lookup) and then
append any liveRows entries whose slug is not present in catalog (or vice
versa). Reference mergeComposioConnectors, the catalog and liveRows arrays, the
bySlug map and the row/live variables when making the change so the result
returns merged catalog items plus any live-only connectors.
In `@src/components/content/ThreadComposer.vue`:
- Around line 1769-1773: When a duplicate attachment is detected by
fileAttachments.value.some(...) using fileName from
composioConnectorDocumentFileName(connector), the code currently returns early
and leaves the connector trigger text in the draft; update this block so that
before the early return you remove the connector trigger text from the composer
draft (i.e., clear the connector mention from the draft state the component
uses) and then call void nextTick(() => inputRef.value?.focus()); keep the
duplicate check and focus behavior but ensure the connector mention is stripped
first.
- Around line 300-307: The composio suggestion buttons only handle
`@mousedown.prevent` which stops keyboard activation; update the <button> created
in the v-for (class thread-composer-composio-suggestion, v-for over
visibleComposioSuggestions) to also handle `@click` and call the same handler
(applyComposioSuggestion(connector)) so Enter/Space and screen readers can
activate it; keep the existing `@mousedown.prevent` for mouse behavior but do not
prevent or intercept the `@click` handling, and ensure the
:disabled="isInteractionDisabled" remains in place.
In `@src/server/codexAppServerBridge.ts`:
- Around line 6935-6942: The logout POST handler for
'/codex-api/composio/logout' is vulnerable to CSRF; add a same-origin/CSRF check
before calling logoutComposioCli(). Specifically, in the block that checks
req.method === 'POST' && url.pathname === '/codex-api/composio/logout', validate
the request origin by checking req.headers.origin or req.headers.referer matches
the server origin OR require a validated CSRF header/token (e.g. a custom header
like 'x-codex-csrf' that you verify against session/store), and if the check
fails return setJson(res, 403, { error: 'Forbidden' }). Only call
logoutComposioCli() when the origin/token check passes. Ensure you still catch
errors and use getErrorMessage as before.
- Around line 2089-2097: spawnSync is called without a timeout in the logout
flow (the invocation/ result block using spawnSync), which can block if the CLI
hangs; add a timeout option to the spawnSync call (e.g., timeout: <ms>) and
update the error handling for the local variable result to detect a timeout
(result.error && result.error.code === 'ETIMEDOUT' or result.signal indicating
it was killed) and throw a clear timeout-specific Error message; apply the same
change to the other spawnSync uses in this file (the other invocation/result
occurrences mentioned) so all synchronous CLI calls use a consistent timeout and
error path.
In `@tests.md`:
- Around line 375-403: Update the stale test section "Composer suggests matching
Composio connectors while typing" to reflect the new attachment flow: remove or
modify steps and expected results that say clicking a suggestion adds the
"composio-cli" skill chip and appends connector instruction text, and instead
assert the new behavior that a "composio-*.md" attachment is added, the mention
is removed, and no auto skill chip is inserted; also ensure
ranking/connected-state and file-mention precedence expectations remain
consistent with the later documented behavior.
🪄 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: 6799e657-bef5-4a52-8a82-b85c1d5d6bb5
📒 Files selected for processing (13)
AGENTS.mdsrc/App.vuesrc/api/codexGateway.test.tssrc/api/codexGateway.tssrc/components/content/DirectoryHub.vuesrc/components/content/ThreadComposer.vuesrc/components/content/composioComposerSuggestions.test.tssrc/components/content/composioComposerSuggestions.tssrc/components/content/composioConnectorCatalog.test.tssrc/components/content/composioConnectorCatalog.tssrc/server/codexAppServerBridge.tssrc/style.csstests.md
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@src/components/content/composioComposerSuggestions.ts`:
- Around line 137-140: The mapping that builds toolLines uses
tool.description.trim() which will throw if description is undefined; update the
description handling in the toolLines mapping (the arrow mapping that references
detail?.tools and tool.description) to defensively handle undefined by using
optional chaining or a default (e.g., use tool.description?.trim() or
(tool.description ?? '').trim()) and then use the trimmed result to decide the
formatted string so the existing conditional `${tool.name} (${tool.slug}):
${description}` only runs when the trimmed description is non-empty.
- Line 155: The expression calls .trim() directly on
resolvedConnector.description which can be undefined; change the fallback to
ensure a string before trimming (e.g., use resolvedConnector.description ?? ''
or resolvedConnector.description || '' before .trim()) so the final value
becomes (safe string).trim() || 'No connector description is available in the
local Composio catalog.'; target the resolvedConnector.description usage in
composioComposerSuggestions.ts to implement this guard.
🪄 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: d78a10ee-3b97-44ec-8dfb-642929b74376
📒 Files selected for processing (3)
src/components/content/composioComposerSuggestions.test.tssrc/components/content/composioComposerSuggestions.tstests.md
✅ Files skipped from review due to trivial changes (1)
- tests.md
🚧 Files skipped from review as they are similar to previous changes (1)
- src/components/content/composioComposerSuggestions.test.ts
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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 `@src/components/content/DirectoryHub.vue`:
- Around line 1517-1524: The route-driven opener sets
lastRouteComposioConnectorSlug before awaiting openComposioDetail, which allows
a concurrent loadComposio() call to fall back to buildLocalComposioDetail and
skip the later retry; fix openRouteComposioConnector (and the similar block
around the other occurrence) to wait until Composio has finished loading before
locking the slug—e.g., await a composio-ready promise or poll a
composioLoading/composioLoaded flag (the same one used by loadComposio), only
then set lastRouteComposioConnectorSlug.value and composioSearchQuery.value and
call await openComposioDetail(slug) so the live connector detail can be opened
instead of the local fallback.
In `@src/components/content/ThreadComposer.vue`:
- Around line 1748-1764: The function refreshComposioSuggestions currently
always calls Composio APIs; add an early return at its start that checks the
feature toggle (composioSuggestionsEnabled or visibleComposioSuggestions) and
exits when suggestions are disabled so no API calls are made; update
refreshComposioSuggestions to return immediately (respecting the toggle) before
computing composioLoadStartedAt or calling
getDirectoryComposioStatus/listDirectoryComposioConnectors, and ensure any
callers like the watch(draft) invocation rely on that guarded behavior.
- Around line 299-309: The button rendering loop for visibleComposioSuggestions
is binding click and explicit key handlers which cause applyComposioSuggestion
to run twice; remove the `@keydown.enter.prevent` and `@keydown.space.prevent`
attributes from the element(s) with class "thread-composer-composio-suggestion"
(the v-for that uses :key="connector.slug" and calls
applyComposioSuggestion(connector)) and keep the `@click` and optional
`@mousedown.prevent` to preserve mouse behavior—if you need custom keyboard
handling for non-button elements, implement it only for those, but for native
<button> rely on its built-in Enter/Space activation to avoid duplicate
uploads/attachments.
🪄 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: a0d759b2-5a8a-407a-a93d-eeb1142c0888
📒 Files selected for processing (7)
src/api/codexGateway.test.tssrc/components/content/DirectoryHub.vuesrc/components/content/ThreadComposer.vuesrc/components/content/composioComposerSuggestions.test.tssrc/components/content/composioComposerSuggestions.tssrc/server/codexAppServerBridge.tstests.md
🚧 Files skipped from review as they are similar to previous changes (3)
- src/api/codexGateway.test.ts
- src/server/codexAppServerBridge.ts
- tests.md
Summary
Verification
redditandgmail reddit buttshow onlyUse Reddit +;redditorshows no suggestion; light and dark screenshots capturedSummary by CodeRabbit
New Features
Tests
Documentation
Style