Skip to content

Add Composio tool-calling as opt-in toggle#89

Open
shawnesquivel wants to merge 1 commit into
farzaa:mainfrom
shawnesquivel:feature/composio-tools
Open

Add Composio tool-calling as opt-in toggle#89
shawnesquivel wants to merge 1 commit into
farzaa:mainfrom
shawnesquivel:feature/composio-tools

Conversation

@shawnesquivel
Copy link
Copy Markdown

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_MESSAGE against the user's connected Slack workspace, and replies "Done."

The integration is opt-in behind a panel toggle and fully backward-compatible/chat and the existing streaming + pointing flow are unchanged.

What changed

Worker (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. Same input shape as /chat plus an x-clicky-user-id header.
  • /chat is untouched.
  • Adds @composio/core, @composio/anthropic, @anthropic-ai/sdk.
  • wrangler.toml enables the nodejs_compat flag (required for Composio's Node-style imports to bundle on Workers) and bumps compatibility_date to 2025-09-23.
  • Worker secret: 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.
  • CompanionManager generates a stable per-install UUID on first launch 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 one-time composio 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 against wrangler dev for the new endpoint.

What I verified locally

  • Worker bundles: 268 KB gzipped (well under the 1 MB Workers limit).
  • @composio/core loads and executes in the Workers runtime under wrangler dev (a fake COMPOSIO_API_KEY produces a clean 401 from Composio's API, confirming the SDK is running, not failing at module load).
  • /chat-tools validates the x-clicky-user-id header, rejects malformed JSON, and propagates upstream errors as JSON.
  • /chat passthrough behaviour is identical to main.
  • Swift compiles clean — no new lints.

What I could not verify

Per AGENTS.md I did not run xcodebuild (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 real COMPOSIO_API_KEY and at least one toolkit linked.

Decisions worth flagging for review

  1. Non-streaming for /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.
  2. New endpoint instead of branching /chat. Smaller blast radius and trivially revertable.
  3. Per-install UUID for the Composio user-id. Stable across restarts but not portable across Macs — fine for v1, can be swapped for the user's email (already collected in onboarding) in a follow-up.
  4. No in-app OAuth. First PR keeps Clicky's binary small and avoids an OAuth flow — users run composio link slack once. Documented clearly in the README.

Test plan

  • In Xcode, Cmd+R, complete onboarding, flip Tools (Composio) on.
  • In a terminal: defaults read so.clicky.leanring-buddy clickyComposioUserId → copy the clicky-<uuid>.
  • composio link slack --user-id "clicky-<uuid>" → complete OAuth.
  • Hold push-to-talk on something on screen and say "send a message to #general on Slack saying hello from Clicky".
  • Confirm the message appears in Slack and Clicky speaks back a confirmation.
  • Toggle Tools off, repeat — verify streaming + pointing still works exactly as before.

Made with Cursor

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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant