mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-05-16 18:25:17 +02:00
Enhance Composio connection handling and improve rendering logic
- Added a 'hidden' property to ComposioConnectCardData to prevent rendering of duplicate connection cards. - Updated App and ChatSidebar components to skip rendering if the card is marked as hidden. - Refactored ComposioConnectCard to utilize a ref for callback firing, ensuring onConnected is only called once. - Improved instructions for Composio integration to clarify usage and loading of the composio-integration skill. This update streamlines the user experience by avoiding duplicate connection prompts and enhances the overall clarity of integration instructions.
This commit is contained in:
parent
a2c92c7491
commit
5284b10cd4
7 changed files with 156 additions and 32 deletions
|
|
@ -16,33 +16,14 @@ async function getComposioToolsPrompt(): Promise<string> {
|
|||
const connectedToolkits = composioAccountsRepo.getConnectedToolkits();
|
||||
const connectedSection = connectedToolkits.length > 0
|
||||
? `**Currently connected:** ${connectedToolkits.map(slug => CURATED_TOOLKITS.find(t => t.slug === slug)?.displayName ?? slug).join(', ')}`
|
||||
: `**No services connected yet.** Use \`composio-list-toolkits\` to show available integrations, or \`composio-connect-toolkit\` to help the user connect one.`;
|
||||
: `**No services connected yet.** Load the \`composio-integration\` skill to help the user connect one.`;
|
||||
|
||||
return `
|
||||
## Composio Integrations
|
||||
|
||||
You can connect to external services (Gmail, Slack, GitHub, Notion, etc.) via Composio.
|
||||
|
||||
${connectedSection}
|
||||
|
||||
**CRITICAL: NEVER say "I can't access [service]" or "I don't have access to [service]" without FIRST trying Composio.** If a user asks about ANY third-party service (LinkedIn, Gmail, GitHub, Slack, etc.), your FIRST action must be to check \`composio-list-toolkits\` or try \`composio-connect-toolkit\`. Never give up before trying.
|
||||
|
||||
**Discovery & Execution Flow:**
|
||||
1. When the user asks to interact with a service (e.g., "get my LinkedIn profile", "check my email", "list GitHub issues"):
|
||||
a. Check if the service is connected (via \`composio-list-toolkits\` or the connected list above)
|
||||
b. If NOT connected, call \`composio-connect-toolkit\` immediately — do NOT ask for confirmation
|
||||
c. If connected, proceed to search and execute
|
||||
2. Use \`composio-search-tools\` with SHORT keyword queries (e.g., "list issues", "send email", "get profile") — avoid long sentences.
|
||||
3. Read the \`inputSchema\` from search results carefully — note which fields are in \`required\`.
|
||||
4. Call \`composio-execute-tool\` with the tool slug, toolkit slug, AND all required \`arguments\`. For tools with empty \`properties: {}\`, pass \`arguments: {}\`.
|
||||
|
||||
**Important:**
|
||||
- Use short keyword search queries, NOT full sentences (good: "list issues", bad: "get all open issues for a GitHub repository")
|
||||
- ALWAYS pass required arguments to composio-execute-tool — read the inputSchema from search results
|
||||
- **If a tool call fails, fix the arguments and retry IMMEDIATELY — do NOT stop and narrate the error to the user.**
|
||||
- **Multi-part requests:** When the user asks to "connect X and then do Y", complete BOTH parts. If part 1 (connect) is already done, proceed directly to part 2.
|
||||
- Confirm with the user before executing tools that send messages, create items, or modify data (NOT for read-only queries or connecting)
|
||||
- Connecting a toolkit is always safe — just do it when needed, don't ask permission
|
||||
Load the \`composio-integration\` skill when the user asks to interact with any third-party service. NEVER say "I can't access [service]" without loading the skill and trying Composio first.
|
||||
`;
|
||||
}
|
||||
|
||||
|
|
@ -67,9 +48,9 @@ You're an insightful, encouraging assistant who combines meticulous clarity with
|
|||
## What Rowboat Is
|
||||
Rowboat is an agentic assistant for everyday work - emails, meetings, projects, and people. Users give you tasks like "draft a follow-up email," "prep me for this meeting," or "summarize where we are with this project." You figure out what context you need, pull from emails and meetings, and get it done.
|
||||
|
||||
**Email Drafting:** When users ask you to **draft** or **compose** emails (e.g., "draft a follow-up to Monica", "write an email to John about the project"), load the \`draft-emails\` skill first. Do NOT load this skill for reading, fetching, or checking emails — use Composio tools for that instead.
|
||||
**Email Drafting:** When users ask you to **draft** or **compose** emails (e.g., "draft a follow-up to Monica", "write an email to John about the project"), load the \`draft-emails\` skill first. Do NOT load this skill for reading, fetching, or checking emails — use the \`composio-integration\` skill for that instead.
|
||||
|
||||
**Live Email/Calendar/Service Queries:** When users ask to **read**, **fetch**, **check**, or **view** emails, calendar events, or any data from a connected service (e.g., "what's my latest email?", "check my inbox", "what meetings do I have today?"), use \`composio-search-tools\` and \`composio-execute-tool\` to query the connected service directly. Do NOT look in local \`gmail_sync/\` or \`calendar_sync/\` folders — use Composio for live data.
|
||||
**Third-Party Services:** When users ask to interact with any external service (Gmail, GitHub, Slack, LinkedIn, Notion, Google Sheets, Jira, etc.) — reading emails, listing issues, sending messages, fetching profiles — load the \`composio-integration\` skill first. Do NOT look in local \`gmail_sync/\` or \`calendar_sync/\` folders for live data.
|
||||
|
||||
**Meeting Prep:** When users ask you to prepare for a meeting, prep for a call, or brief them on attendees, load the \`meeting-prep\` skill first. It provides structured guidance for gathering context about attendees from the knowledge base and creating useful meeting briefs.
|
||||
|
||||
|
|
@ -210,9 +191,9 @@ Always consult this catalog first so you load the right skills before taking act
|
|||
- Never start a response with a heading. Lead with a sentence or two of context first.
|
||||
- Avoid deeply nested bullets. If nesting beyond 2 levels, restructure.
|
||||
|
||||
## Tool Priority: Composio First, Then MCP
|
||||
## Tool Priority
|
||||
|
||||
For third-party services (GitHub, Gmail, Slack, etc.), use \`composio-*\` builtin tools first. Only fall back to MCP tools for capabilities Composio doesn't cover (web search, file scraping, audio). See the dynamic "Composio Integrations" section below for full details.
|
||||
For third-party services (GitHub, Gmail, Slack, etc.), load the \`composio-integration\` skill. For capabilities Composio doesn't cover (web search, file scraping, audio), use MCP tools via the \`mcp-integration\` skill.
|
||||
|
||||
## Execution Reminders
|
||||
- Explore existing files and structure before creating new assets.
|
||||
|
|
@ -252,10 +233,7 @@ ${runtimeContextPrompt}
|
|||
- \`web-search\` - Search the web. Returns rich results with full text, highlights, and metadata. The \`category\` parameter defaults to \`general\` (full web search) — only use a specific category like \`news\`, \`company\`, \`research paper\` etc. when the query is clearly about that type. For everyday queries (weather, restaurants, prices, how-to), use \`general\`.
|
||||
- \`app-navigation\` - Control the app UI: open notes, switch views, filter/search the knowledge base, manage saved views. **Load the \`app-navigation\` skill before using this tool.**
|
||||
- \`save-to-memory\` - Save observations about the user to the agent memory system. Use this proactively during conversations.
|
||||
- \`composio-list-toolkits\` — List available integrations (Gmail, Slack, GitHub, etc.) and their connection status
|
||||
- \`composio-search-tools\` — Search for tools by use case (e.g., "send email", "create issue"); returns tool slugs and input schemas
|
||||
- \`composio-execute-tool\` — Execute a Composio tool by slug with parameters from search results
|
||||
- \`composio-connect-toolkit\` — Connect a service (Gmail, Slack, GitHub, etc.) via OAuth directly from chat
|
||||
- \`composio-list-toolkits\`, \`composio-search-tools\`, \`composio-execute-tool\`, \`composio-connect-toolkit\` — Composio integration tools. Load the \`composio-integration\` skill for usage guidance.
|
||||
|
||||
**Prefer these tools whenever possible** — they work instantly with zero friction. For file operations inside \`~/.rowboat/\`, always use these instead of \`executeCommand\`.
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,127 @@
|
|||
export const skill = String.raw`
|
||||
# Composio Integration
|
||||
|
||||
**Load this skill** when the user asks to interact with ANY third-party service — email, GitHub, Slack, LinkedIn, Notion, Jira, Google Sheets, calendar, etc. This skill provides the complete workflow for discovering, connecting, and executing Composio tools.
|
||||
|
||||
## Available Tools
|
||||
|
||||
| Tool | Purpose |
|
||||
|------|---------|
|
||||
| **composio-list-toolkits** | List all available integrations and their connection status |
|
||||
| **composio-search-tools** | Search for tools by use case; returns slugs and input schemas |
|
||||
| **composio-execute-tool** | Execute a tool by slug with parameters |
|
||||
| **composio-connect-toolkit** | Connect a service via OAuth (opens browser) |
|
||||
|
||||
## Toolkit Slugs (exact values for toolkitSlug parameter)
|
||||
|
||||
| Service | Slug |
|
||||
|---------|------|
|
||||
| Gmail | \`gmail\` |
|
||||
| Google Calendar | \`googlecalendar\` |
|
||||
| Google Sheets | \`googlesheets\` |
|
||||
| Google Docs | \`googledocs\` |
|
||||
| Google Drive | \`googledrive\` |
|
||||
| Slack | \`slack\` |
|
||||
| GitHub | \`github\` |
|
||||
| Notion | \`notion\` |
|
||||
| Linear | \`linear\` |
|
||||
| Jira | \`jira\` |
|
||||
| Asana | \`asana\` |
|
||||
| Trello | \`trello\` |
|
||||
| HubSpot | \`hubspot\` |
|
||||
| Salesforce | \`salesforce\` |
|
||||
| LinkedIn | \`linkedin\` |
|
||||
| X (Twitter) | \`twitter\` |
|
||||
| Reddit | \`reddit\` |
|
||||
| Dropbox | \`dropbox\` |
|
||||
| OneDrive | \`onedrive\` |
|
||||
| Microsoft Outlook | \`microsoft_outlook\` |
|
||||
| Microsoft Teams | \`microsoft_teams\` |
|
||||
| Calendly | \`calendly\` |
|
||||
| Cal.com | \`cal\` |
|
||||
| Intercom | \`intercom\` |
|
||||
| Zendesk | \`zendesk\` |
|
||||
| Airtable | \`airtable\` |
|
||||
|
||||
**IMPORTANT:** Always use these exact slugs. Do NOT guess — e.g., Google Sheets is \`googlesheets\` (no underscore), not \`google_sheets\`.
|
||||
|
||||
## Critical: Check First, Connect Second
|
||||
|
||||
**BEFORE calling composio-connect-toolkit, ALWAYS check if the service is already connected.** The system prompt includes a "Currently connected" list. If the service is there, skip connecting and go straight to search + execute.
|
||||
|
||||
**Flow:**
|
||||
1. Check if the service is in the "Currently connected" list (in the system prompt above)
|
||||
2. If **connected** → go directly to step 4
|
||||
3. If **NOT connected** → call \`composio-connect-toolkit\` once, wait for user to authenticate, then continue
|
||||
4. Call \`composio-search-tools\` with SHORT keyword queries
|
||||
5. Read the \`inputSchema\` from results — note \`required\` fields
|
||||
6. Call \`composio-execute-tool\` with slug, toolkit, and all required arguments
|
||||
|
||||
**NEVER call composio-connect-toolkit for a service that's already connected.** This creates duplicate connect cards in the UI.
|
||||
|
||||
## Search Query Tips
|
||||
|
||||
Use **short keyword queries**, not full sentences:
|
||||
|
||||
| ✅ Good | ❌ Bad |
|
||||
|---------|--------|
|
||||
| "list issues" | "get all open issues for a GitHub repository" |
|
||||
| "send email" | "send an email to someone using Gmail" |
|
||||
| "get profile" | "fetch the authenticated user's profile details" |
|
||||
| "create spreadsheet" | "create a new Google Sheets spreadsheet with data" |
|
||||
|
||||
If the first search returns 0 results, try a different short query (e.g., "issues" instead of "list issues").
|
||||
|
||||
## Passing Arguments
|
||||
|
||||
**ALWAYS include the \`arguments\` field** when calling \`composio-execute-tool\`, even if the tool has no required parameters.
|
||||
|
||||
- Read the \`inputSchema\` from search results carefully
|
||||
- Extract user-provided values into the correct fields (e.g., "rowboatlabs/rowboat" → \`owner: "rowboatlabs", repo: "rowboat"\`)
|
||||
- For tools with empty \`properties: {}\`, pass \`arguments: {}\`
|
||||
- For tools with required fields, pass all of them
|
||||
|
||||
### Example: GitHub Issues
|
||||
|
||||
User says: "Get me the open issues on rowboatlabs/rowboat"
|
||||
|
||||
1. \`composio-search-tools({ query: "list issues", toolkitSlug: "github" })\`
|
||||
→ finds \`GITHUB_ISSUES_LIST_FOR_REPO\` with required: ["owner", "repo"]
|
||||
2. \`composio-execute-tool({ toolSlug: "GITHUB_ISSUES_LIST_FOR_REPO", toolkitSlug: "github", arguments: { owner: "rowboatlabs", repo: "rowboat", state: "open", per_page: 100 } })\`
|
||||
|
||||
### Example: Gmail Fetch
|
||||
|
||||
User says: "What's my latest email?"
|
||||
|
||||
1. \`composio-search-tools({ query: "fetch emails", toolkitSlug: "gmail" })\`
|
||||
→ finds \`GMAIL_FETCH_EMAILS\`
|
||||
2. \`composio-execute-tool({ toolSlug: "GMAIL_FETCH_EMAILS", toolkitSlug: "gmail", arguments: { user_id: "me", max_results: 5 } })\`
|
||||
|
||||
### Example: LinkedIn Profile (no-arg tool)
|
||||
|
||||
User says: "Get my LinkedIn profile"
|
||||
|
||||
1. \`composio-search-tools({ query: "get profile", toolkitSlug: "linkedin" })\`
|
||||
→ finds \`LINKEDIN_GET_MY_INFO\` with properties: {}
|
||||
2. \`composio-execute-tool({ toolSlug: "LINKEDIN_GET_MY_INFO", toolkitSlug: "linkedin", arguments: {} })\`
|
||||
|
||||
## Error Recovery
|
||||
|
||||
- **If a tool call fails** (missing fields, 500 error): Fix the arguments and retry IMMEDIATELY. Do NOT stop and narrate the error to the user.
|
||||
- **If search returns 0 results**: Try a different short query. If still 0, the tool may not exist for that service.
|
||||
- **If a tool requires connection**: Call \`composio-connect-toolkit\` once, then retry after connection.
|
||||
|
||||
## Multi-Part Requests
|
||||
|
||||
When the user says "connect X and then do Y" — complete BOTH parts in one turn:
|
||||
1. If X is already connected (check the connected list), skip to Y immediately
|
||||
2. If X needs connecting, connect it, then proceed to Y after authentication
|
||||
|
||||
## Confirmation Rules
|
||||
|
||||
- **Read-only actions** (fetch, list, get, search): Execute without asking
|
||||
- **Mutating actions** (send email, create issue, post, delete): Show the user what you're about to do and confirm before executing
|
||||
- **Connecting a toolkit**: Always safe — just do it when needed
|
||||
`;
|
||||
|
||||
export default skill;
|
||||
|
|
@ -12,6 +12,7 @@ import backgroundAgentsSkill from "./background-agents/skill.js";
|
|||
import createPresentationsSkill from "./create-presentations/skill.js";
|
||||
|
||||
import appNavigationSkill from "./app-navigation/skill.js";
|
||||
import composioIntegrationSkill from "./composio-integration/skill.js";
|
||||
|
||||
const CURRENT_DIR = path.dirname(fileURLToPath(import.meta.url));
|
||||
const CATALOG_PREFIX = "src/application/assistant/skills";
|
||||
|
|
@ -84,6 +85,12 @@ const definitions: SkillDefinition[] = [
|
|||
summary: "Discovering, executing, and integrating MCP tools. Use this to check what external capabilities are available and execute MCP tools on behalf of users.",
|
||||
content: mcpIntegrationSkill,
|
||||
},
|
||||
{
|
||||
id: "composio-integration",
|
||||
title: "Composio Integration",
|
||||
summary: "Interact with third-party services (Gmail, GitHub, Slack, LinkedIn, Notion, Jira, Google Sheets, etc.) via Composio. Search, connect, and execute tools.",
|
||||
content: composioIntegrationSkill,
|
||||
},
|
||||
{
|
||||
id: "deletion-guardrails",
|
||||
title: "Deletion Guardrails",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue