Add Composio tool-calling as opt-in toggle#89
Open
shawnesquivel wants to merge 1 commit into
Open
Conversation
Clicky today can see, hear, speak, and point. This PR adds the missing
verb — act — by giving Claude access to ~1000 connected-app tools (Slack,
Gmail, Linear, Notion, GitHub, etc.) via Composio.
Worker:
- New endpoint POST /chat-tools that runs the Claude ↔ Composio agentic
loop server-side (capped at 5 iterations) and returns a single
non-streaming { text, tool_calls, stop_reason } JSON response.
- /chat is unchanged so the existing streaming + pointing flow keeps
working when the toggle is off.
- Adds @composio/core, @composio/anthropic, @anthropic-ai/sdk and the
nodejs_compat Workers flag (required for Composio's Node-style imports
to bundle).
Swift:
- ClaudeAPI.analyzeImageWithTools mirrors the existing image+history
request shape but POSTs non-streaming to /chat-tools with an
x-clicky-user-id header.
- CompanionManager generates a stable UUID per install and stores it in
UserDefaults under clickyComposioUserId so the same Mac maps to the
same set of connected Composio apps across restarts.
- New "Tools (Composio)" toggle in CompanionPanelView. Off by default —
opt-in because it requires `composio link <toolkit> --user-id <uuid>`
setup out-of-band.
Verified:
- Worker bundles: 268 KB gzipped (well under the 1 MB Workers limit).
- @composio/core loads and runs in the Workers runtime under wrangler dev.
- /chat-tools validates headers, JSON, and propagates upstream errors;
/chat passthrough behaviour unchanged.
- Swift compiles clean (no new lints).
Out of scope for this PR (called out in README): in-app OAuth for tool
connections — for now users run `composio link slack` once against the
Clicky user-id printed by `defaults read so.clicky.leanring-buddy`.
Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Clicky today can see, hear, speak, and point. This PR adds the missing verb — act — by giving Claude access to ~1000 connected-app tools (Slack, Gmail, Linear, Notion, GitHub, etc.) via Composio.
Example use case: hold push-to-talk on a stack trace and say "send this to #eng on Slack". Clicky takes a screenshot, Claude reads it, calls
SLACK_SEND_MESSAGEagainst the user's connected Slack workspace, and replies "Done."The integration is opt-in behind a panel toggle and fully backward-compatible —
/chatand the existing streaming + pointing flow are unchanged.What changed
Worker (
worker/)POST /chat-toolsthat runs the Claude ↔ Composio agentic loop server-side (capped at 5 iterations) and returns a single non-streaming{ text, tool_calls, stop_reason }JSON response. Same input shape as/chatplus anx-clicky-user-idheader./chatis untouched.@composio/core,@composio/anthropic,@anthropic-ai/sdk.wrangler.tomlenables thenodejs_compatflag (required for Composio's Node-style imports to bundle on Workers) and bumpscompatibility_dateto2025-09-23.COMPOSIO_API_KEY(only required if the toggle is on).Swift app (
leanring-buddy/)ClaudeAPI.analyzeImageWithTools(...)— mirrors the existing image + history payload shape but POSTs non-streaming to/chat-tools.CompanionManagergenerates a stable per-install UUID on first launch and stores it inUserDefaultsunderclickyComposioUserIdso the same Mac maps to the same set of connected Composio apps across restarts.CompanionPanelView. Off by default — opt-in because it requires one-timecomposio link <toolkit> --user-id <uuid>setup.[POINT:...]parsing only runs in the streaming path; tools mode is for acting, not pointing.Docs
README.md— new section "Tool-calling with Composio (optional)" with setup steps.AGENTS.md— new endpoint row, secret, architecture decision, key-files entries.Test harness
worker/test-tools.sh— curl-based smoke test againstwrangler devfor the new endpoint.What I verified locally
@composio/coreloads and executes in the Workers runtime underwrangler dev(a fakeCOMPOSIO_API_KEYproduces a clean 401 from Composio's API, confirming the SDK is running, not failing at module load)./chat-toolsvalidates thex-clicky-user-idheader, rejects malformed JSON, and propagates upstream errors as JSON./chatpassthrough behaviour is identical tomain.What I could not verify
Per
AGENTS.mdI did not runxcodebuild(would invalidate TCC permissions). The Swift wiring is reviewable but the full end-to-end voice → tool-call → TTS demo needs to be exercised in Xcode with realCOMPOSIO_API_KEYand at least one toolkit linked.Decisions worth flagging for review
/chat-tools. Streaming + multi-turn tool calls is a meaningful chunk of complexity. Clicky's TTS pipeline buffers until the whole response is ready anyway, so the UX impact is small. Easy to add streaming later./chat. Smaller blast radius and trivially revertable.composio link slackonce. Documented clearly in the README.Test plan
Cmd+R, complete onboarding, flip Tools (Composio) on.defaults read so.clicky.leanring-buddy clickyComposioUserId→ copy theclicky-<uuid>.composio link slack --user-id "clicky-<uuid>"→ complete OAuth.Made with Cursor