Adds composio-sdk/ with SKILL.md, AGENTS.md, and 18 rule files covering Tool Router, direct execution, triggers, and auth patterns. Source: composiohq/skills Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5.8 KiB
5.8 KiB
title, impact, description, tags
| title | impact | description | tags | |||||
|---|---|---|---|---|---|---|---|---|
| Direct Tool Execution for Applications | HIGH | Core patterns for manually executing Composio tools in traditional applications without agent frameworks |
|
Direct Tool Execution for Applications
When building traditional applications without agent frameworks, use composio.tools.execute() to manually execute tools.
Basic Execution
// Execute with a specific version (REQUIRED)
const result = await composio.tools.execute('GITHUB_GET_ISSUES', {
userId: 'default',
arguments: { owner: 'composio', repo: 'sdk' },
version: '12082025_00', // Specific version required
});
Version Management
CRITICAL: When manually executing tools (especially in workflows), a specific version is required. Using 'latest' will throw an error.
Why version pinning is required:
- Tool argument schemas can change between versions
- Using
'latest'in workflows can cause runtime errors when tools are updated - Pinned versions ensure workflow stability and predictability
- Version validation prevents production issues from schema mismatches
See Tool Version Management for detailed version strategies.
Parameters
ExecuteParams Object
{
userId: string, // User ID for connected account lookup
arguments: object, // Tool-specific input parameters
version?: string, // Toolkit version (required for manual execution)
dangerouslySkipVersionCheck?: boolean // Bypass version validation (NOT recommended)
}
Execution Modifiers
Transform requests and responses with modifiers:
const result = await composio.tools.execute(
'GITHUB_GET_ISSUES',
{
userId: 'default',
arguments: { owner: 'composio', repo: 'sdk' },
version: '12082025_00',
},
{
beforeExecute: ({ toolSlug, toolkitSlug, params }) => {
// Modify params before execution
console.log('Executing:', toolSlug);
return {
...params,
arguments: {
...params.arguments,
per_page: 100 // Add default parameter
}
};
},
afterExecute: ({ toolSlug, toolkitSlug, result }) => {
// Transform result after execution
console.log('Completed:', toolSlug);
return {
...result,
timestamp: new Date().toISOString()
};
},
}
);
Response Format
interface ToolExecuteResponse {
data: any; // Tool-specific response data
error: string | null; // Error message if execution failed
successful: boolean; // Whether execution succeeded
}
Error Handling
try {
const result = await composio.tools.execute('GITHUB_GET_ISSUES', {
userId: 'user_123',
arguments: { owner: 'composio', repo: 'sdk' },
version: '12082025_00',
});
if (!result.successful) {
console.error('Tool execution failed:', result.error);
// Handle error case
return;
}
// Process successful result
console.log('Issues:', result.data);
} catch (error) {
if (error.name === 'ComposioToolNotFoundError') {
console.error('Tool not found');
} else if (error.name === 'ComposioToolExecutionError') {
console.error('Execution error:', error.message);
} else {
console.error('Unexpected error:', error);
}
}
Common Error Types
ComposioCustomToolsNotInitializedError: Custom tools instance not initializedComposioToolNotFoundError: Tool with the given slug not foundComposioToolExecutionError: Error during tool execution- Version validation errors: Thrown when version is missing or
'latest'is used
Best Practices
- Always specify versions: Use explicit versions or configure at initialization
- Handle errors gracefully: Check
successfulflag and handleerrorfield - Validate arguments: Ensure all required parameters are provided
- Use modifiers sparingly: Only add modifiers when necessary for transformation
- Log execution details: Track which tools are executed for debugging
- Test with real data: Validate execution with actual connected accounts
- Handle authentication errors: User may not have connected account for toolkit
Common Patterns
Execute with retry logic
async function executeWithRetry(slug, params, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const result = await composio.tools.execute(slug, params);
if (result.successful) return result;
console.log(`Retry ${i + 1}/${maxRetries}`);
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
} catch (error) {
if (i === maxRetries - 1) throw error;
}
}
}
Execute multiple tools in sequence
async function executeWorkflow(userId) {
// Step 1: Get repository
const repo = await composio.tools.execute('GITHUB_GET_REPO', {
userId,
arguments: { owner: 'composio', repo: 'sdk' },
version: '12082025_00',
});
if (!repo.successful) {
throw new Error(`Failed to get repo: ${repo.error}`);
}
// Step 2: Create issue using data from step 1
const issue = await composio.tools.execute('GITHUB_CREATE_ISSUE', {
userId,
arguments: {
owner: 'composio',
repo: 'sdk',
title: `Update for ${repo.data.name}`,
body: 'Automated issue creation'
},
version: '12082025_00',
});
return { repo: repo.data, issue: issue.data };
}
Execute with parameter validation
async function sendSlackMessage(userId, channel, text) {
// Validate inputs
if (!channel.startsWith('#')) {
throw new Error('Channel must start with #');
}
if (text.length > 4000) {
throw new Error('Message too long');
}
const result = await composio.tools.execute('SLACK_SEND_MESSAGE', {
userId,
arguments: { channel, text },
version: '10082025_01',
});
return result;
}