@customclaw/composio 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +184 -0
- package/THIRD-PARTY-NOTICES +31 -0
- package/dist/cli.d.ts +18 -0
- package/dist/cli.js +162 -0
- package/dist/client.d.ts +94 -0
- package/dist/client.js +386 -0
- package/dist/config.d.ts +75 -0
- package/dist/config.js +64 -0
- package/dist/index.d.ts +56 -0
- package/dist/index.js +125 -0
- package/dist/tools/bash.d.ts +42 -0
- package/dist/tools/bash.js +59 -0
- package/dist/tools/connections.d.ts +89 -0
- package/dist/tools/connections.js +112 -0
- package/dist/tools/execute.d.ts +46 -0
- package/dist/tools/execute.js +63 -0
- package/dist/tools/multi-execute.d.ts +52 -0
- package/dist/tools/multi-execute.js +87 -0
- package/dist/tools/search.d.ts +50 -0
- package/dist/tools/search.js +71 -0
- package/dist/tools/workbench.d.ts +48 -0
- package/dist/tools/workbench.js +76 -0
- package/dist/types.d.ts +46 -0
- package/dist/types.js +4 -0
- package/openclaw.plugin.json +58 -0
- package/package.json +36 -0
package/dist/client.js
ADDED
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { Composio } from "@composio/core";
|
|
2
|
+
/**
|
|
3
|
+
* Composio client wrapper using Tool Router pattern
|
|
4
|
+
*/
|
|
5
|
+
export class ComposioClient {
|
|
6
|
+
client;
|
|
7
|
+
config;
|
|
8
|
+
sessionCache = new Map();
|
|
9
|
+
constructor(config) {
|
|
10
|
+
if (!config.apiKey) {
|
|
11
|
+
throw new Error("Composio API key required. Set COMPOSIO_API_KEY env var or plugins.composio.apiKey in config.");
|
|
12
|
+
}
|
|
13
|
+
this.config = config;
|
|
14
|
+
this.client = new Composio({ apiKey: config.apiKey });
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Get the user ID to use for API calls
|
|
18
|
+
*/
|
|
19
|
+
getUserId(overrideUserId) {
|
|
20
|
+
return overrideUserId || this.config.defaultUserId || "default";
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Get or create a Tool Router session for a user
|
|
24
|
+
*/
|
|
25
|
+
async getSession(userId) {
|
|
26
|
+
if (this.sessionCache.has(userId)) {
|
|
27
|
+
return this.sessionCache.get(userId);
|
|
28
|
+
}
|
|
29
|
+
const session = await this.client.toolRouter.create(userId);
|
|
30
|
+
this.sessionCache.set(userId, session);
|
|
31
|
+
return session;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Check if a toolkit is allowed based on config
|
|
35
|
+
*/
|
|
36
|
+
isToolkitAllowed(toolkit) {
|
|
37
|
+
const { allowedToolkits, blockedToolkits } = this.config;
|
|
38
|
+
if (blockedToolkits?.includes(toolkit.toLowerCase())) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
if (allowedToolkits && allowedToolkits.length > 0) {
|
|
42
|
+
return allowedToolkits.includes(toolkit.toLowerCase());
|
|
43
|
+
}
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Execute a Tool Router meta-tool
|
|
48
|
+
*/
|
|
49
|
+
async executeMetaTool(toolName, args) {
|
|
50
|
+
const response = await this.client.client.tools.execute(toolName, {
|
|
51
|
+
arguments: args,
|
|
52
|
+
});
|
|
53
|
+
return response;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Search for tools matching a query using COMPOSIO_SEARCH_TOOLS
|
|
57
|
+
*/
|
|
58
|
+
async searchTools(query, options) {
|
|
59
|
+
const userId = this.getUserId(options?.userId);
|
|
60
|
+
const session = await this.getSession(userId);
|
|
61
|
+
try {
|
|
62
|
+
const response = await this.executeMetaTool("COMPOSIO_SEARCH_TOOLS", {
|
|
63
|
+
queries: [{ use_case: query }],
|
|
64
|
+
session: { id: session.sessionId },
|
|
65
|
+
});
|
|
66
|
+
if (!response.successful || !response.data) {
|
|
67
|
+
throw new Error(response.error || "Search failed");
|
|
68
|
+
}
|
|
69
|
+
const data = response.data;
|
|
70
|
+
const searchResults = data.results || [];
|
|
71
|
+
const toolSchemas = data.tool_schemas || {};
|
|
72
|
+
const results = [];
|
|
73
|
+
const seenSlugs = new Set();
|
|
74
|
+
for (const result of searchResults) {
|
|
75
|
+
const allSlugs = [
|
|
76
|
+
...(result.primary_tool_slugs || []),
|
|
77
|
+
...(result.related_tool_slugs || []),
|
|
78
|
+
];
|
|
79
|
+
for (const slug of allSlugs) {
|
|
80
|
+
if (seenSlugs.has(slug))
|
|
81
|
+
continue;
|
|
82
|
+
seenSlugs.add(slug);
|
|
83
|
+
const schema = toolSchemas[slug];
|
|
84
|
+
const toolkit = schema?.toolkit || slug.split("_")[0] || "";
|
|
85
|
+
if (!this.isToolkitAllowed(toolkit))
|
|
86
|
+
continue;
|
|
87
|
+
if (options?.toolkits && options.toolkits.length > 0) {
|
|
88
|
+
if (!options.toolkits.some(t => t.toLowerCase() === toolkit.toLowerCase())) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
results.push({
|
|
93
|
+
name: slug,
|
|
94
|
+
slug: slug,
|
|
95
|
+
description: schema?.description || "",
|
|
96
|
+
toolkit: toolkit,
|
|
97
|
+
parameters: schema?.input_schema || {},
|
|
98
|
+
});
|
|
99
|
+
if (options?.limit && results.length >= options.limit)
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
if (options?.limit && results.length >= options.limit)
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
return results;
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
throw new Error(`Failed to search tools: ${err instanceof Error ? err.message : String(err)}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Execute a single tool using COMPOSIO_MULTI_EXECUTE_TOOL
|
|
113
|
+
*/
|
|
114
|
+
async executeTool(toolSlug, args, userId) {
|
|
115
|
+
const uid = this.getUserId(userId);
|
|
116
|
+
const session = await this.getSession(uid);
|
|
117
|
+
const toolkit = toolSlug.split("_")[0]?.toLowerCase() || "";
|
|
118
|
+
if (!this.isToolkitAllowed(toolkit)) {
|
|
119
|
+
return {
|
|
120
|
+
success: false,
|
|
121
|
+
error: `Toolkit '${toolkit}' is not allowed by plugin configuration`,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
const response = await this.executeMetaTool("COMPOSIO_MULTI_EXECUTE_TOOL", {
|
|
126
|
+
tools: [{ tool_slug: toolSlug, arguments: args }],
|
|
127
|
+
session: { id: session.sessionId },
|
|
128
|
+
sync_response_to_workbench: false,
|
|
129
|
+
});
|
|
130
|
+
if (!response.successful) {
|
|
131
|
+
return { success: false, error: response.error || "Execution failed" };
|
|
132
|
+
}
|
|
133
|
+
const results = response.data?.results || [];
|
|
134
|
+
const result = results[0];
|
|
135
|
+
if (!result) {
|
|
136
|
+
return { success: false, error: "No result returned" };
|
|
137
|
+
}
|
|
138
|
+
// Response data is nested under result.response
|
|
139
|
+
const toolResponse = result.response;
|
|
140
|
+
return {
|
|
141
|
+
success: toolResponse.successful,
|
|
142
|
+
data: toolResponse.data,
|
|
143
|
+
error: toolResponse.error ?? undefined,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
return {
|
|
148
|
+
success: false,
|
|
149
|
+
error: err instanceof Error ? err.message : String(err),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Execute multiple tools in parallel using COMPOSIO_MULTI_EXECUTE_TOOL
|
|
155
|
+
*/
|
|
156
|
+
async multiExecute(executions, userId) {
|
|
157
|
+
const uid = this.getUserId(userId);
|
|
158
|
+
const session = await this.getSession(uid);
|
|
159
|
+
// Filter out blocked toolkits and limit to 50
|
|
160
|
+
const allowedExecutions = executions
|
|
161
|
+
.filter(exec => {
|
|
162
|
+
const toolkit = exec.tool_slug.split("_")[0]?.toLowerCase() || "";
|
|
163
|
+
return this.isToolkitAllowed(toolkit);
|
|
164
|
+
})
|
|
165
|
+
.slice(0, 50);
|
|
166
|
+
if (allowedExecutions.length === 0) {
|
|
167
|
+
return { results: [] };
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
const response = await this.executeMetaTool("COMPOSIO_MULTI_EXECUTE_TOOL", {
|
|
171
|
+
tools: allowedExecutions.map(exec => ({
|
|
172
|
+
tool_slug: exec.tool_slug,
|
|
173
|
+
arguments: exec.arguments,
|
|
174
|
+
})),
|
|
175
|
+
session: { id: session.sessionId },
|
|
176
|
+
sync_response_to_workbench: false,
|
|
177
|
+
});
|
|
178
|
+
if (!response.successful) {
|
|
179
|
+
return {
|
|
180
|
+
results: allowedExecutions.map(exec => ({
|
|
181
|
+
tool_slug: exec.tool_slug,
|
|
182
|
+
success: false,
|
|
183
|
+
error: response.error || "Execution failed",
|
|
184
|
+
})),
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
const apiResults = response.data?.results || [];
|
|
188
|
+
return {
|
|
189
|
+
results: apiResults.map(r => ({
|
|
190
|
+
tool_slug: r.tool_slug,
|
|
191
|
+
success: r.response.successful,
|
|
192
|
+
data: r.response.data,
|
|
193
|
+
error: r.response.error ?? undefined,
|
|
194
|
+
})),
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
catch (err) {
|
|
198
|
+
return {
|
|
199
|
+
results: allowedExecutions.map(exec => ({
|
|
200
|
+
tool_slug: exec.tool_slug,
|
|
201
|
+
success: false,
|
|
202
|
+
error: err instanceof Error ? err.message : String(err),
|
|
203
|
+
})),
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Get connection status for toolkits using session.toolkits()
|
|
209
|
+
*/
|
|
210
|
+
async getConnectionStatus(toolkits, userId) {
|
|
211
|
+
const uid = this.getUserId(userId);
|
|
212
|
+
const session = await this.getSession(uid);
|
|
213
|
+
try {
|
|
214
|
+
const response = await session.toolkits();
|
|
215
|
+
const allToolkits = response.items || [];
|
|
216
|
+
const statuses = [];
|
|
217
|
+
if (toolkits && toolkits.length > 0) {
|
|
218
|
+
// Check specific toolkits
|
|
219
|
+
for (const toolkit of toolkits) {
|
|
220
|
+
if (!this.isToolkitAllowed(toolkit))
|
|
221
|
+
continue;
|
|
222
|
+
const found = allToolkits.find(t => t.slug.toLowerCase() === toolkit.toLowerCase());
|
|
223
|
+
statuses.push({
|
|
224
|
+
toolkit,
|
|
225
|
+
connected: found?.connection?.isActive ?? false,
|
|
226
|
+
userId: uid,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
// Return all connected toolkits
|
|
232
|
+
for (const tk of allToolkits) {
|
|
233
|
+
if (!this.isToolkitAllowed(tk.slug))
|
|
234
|
+
continue;
|
|
235
|
+
if (!tk.connection?.isActive)
|
|
236
|
+
continue;
|
|
237
|
+
statuses.push({
|
|
238
|
+
toolkit: tk.slug,
|
|
239
|
+
connected: true,
|
|
240
|
+
userId: uid,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return statuses;
|
|
245
|
+
}
|
|
246
|
+
catch (err) {
|
|
247
|
+
throw new Error(`Failed to get connection status: ${err instanceof Error ? err.message : String(err)}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Create an auth connection for a toolkit using session.authorize()
|
|
252
|
+
*/
|
|
253
|
+
async createConnection(toolkit, userId) {
|
|
254
|
+
const uid = this.getUserId(userId);
|
|
255
|
+
if (!this.isToolkitAllowed(toolkit)) {
|
|
256
|
+
return { error: `Toolkit '${toolkit}' is not allowed by plugin configuration` };
|
|
257
|
+
}
|
|
258
|
+
try {
|
|
259
|
+
const session = await this.getSession(uid);
|
|
260
|
+
const result = await session.authorize(toolkit);
|
|
261
|
+
return { authUrl: result.redirectUrl || result.url || "" };
|
|
262
|
+
}
|
|
263
|
+
catch (err) {
|
|
264
|
+
return {
|
|
265
|
+
error: err instanceof Error ? err.message : String(err),
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* List available toolkits
|
|
271
|
+
*/
|
|
272
|
+
async listToolkits(userId) {
|
|
273
|
+
const uid = this.getUserId(userId);
|
|
274
|
+
try {
|
|
275
|
+
const session = await this.getSession(uid);
|
|
276
|
+
const response = await session.toolkits();
|
|
277
|
+
const allToolkits = response.items || [];
|
|
278
|
+
return allToolkits
|
|
279
|
+
.map(tk => tk.slug)
|
|
280
|
+
.filter(slug => this.isToolkitAllowed(slug));
|
|
281
|
+
}
|
|
282
|
+
catch (err) {
|
|
283
|
+
const errObj = err;
|
|
284
|
+
if (errObj?.status === 401) {
|
|
285
|
+
throw new Error("Invalid Composio API key. Get a valid key from platform.composio.dev/settings");
|
|
286
|
+
}
|
|
287
|
+
const apiMsg = errObj?.error?.error?.message;
|
|
288
|
+
throw new Error(`Failed to list toolkits: ${apiMsg || (err instanceof Error ? err.message : String(err))}`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Disconnect a toolkit
|
|
293
|
+
*/
|
|
294
|
+
async disconnectToolkit(toolkit, userId) {
|
|
295
|
+
const uid = this.getUserId(userId);
|
|
296
|
+
try {
|
|
297
|
+
const response = await this.client.connectedAccounts.list({ userId: uid });
|
|
298
|
+
const connections = (Array.isArray(response)
|
|
299
|
+
? response
|
|
300
|
+
: response?.items || []);
|
|
301
|
+
const conn = connections.find(c => c.toolkit?.slug?.toLowerCase() === toolkit.toLowerCase());
|
|
302
|
+
if (!conn) {
|
|
303
|
+
return { success: false, error: `No connection found for toolkit '${toolkit}'` };
|
|
304
|
+
}
|
|
305
|
+
await this.client.connectedAccounts.delete({ connectedAccountId: conn.id });
|
|
306
|
+
// Clear session cache to refresh connection status
|
|
307
|
+
this.sessionCache.delete(uid);
|
|
308
|
+
return { success: true };
|
|
309
|
+
}
|
|
310
|
+
catch (err) {
|
|
311
|
+
return {
|
|
312
|
+
success: false,
|
|
313
|
+
error: err instanceof Error ? err.message : String(err),
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Get the assistive prompt for the agent
|
|
319
|
+
*/
|
|
320
|
+
async getAssistivePrompt(userId) {
|
|
321
|
+
const uid = this.getUserId(userId);
|
|
322
|
+
const session = await this.getSession(uid);
|
|
323
|
+
return session.experimental.assistivePrompt;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Execute Python code in the remote workbench using COMPOSIO_REMOTE_WORKBENCH
|
|
327
|
+
*/
|
|
328
|
+
async executeWorkbench(code, options) {
|
|
329
|
+
const uid = this.getUserId(options?.userId);
|
|
330
|
+
const session = await this.getSession(uid);
|
|
331
|
+
try {
|
|
332
|
+
const response = await this.executeMetaTool("COMPOSIO_REMOTE_WORKBENCH", {
|
|
333
|
+
code_to_execute: code,
|
|
334
|
+
session_id: session.sessionId,
|
|
335
|
+
...(options?.thought ? { thought: options.thought } : {}),
|
|
336
|
+
...(options?.currentStep ? { current_step: options.currentStep } : {}),
|
|
337
|
+
...(options?.currentStepMetric ? { current_step_metric: options.currentStepMetric } : {}),
|
|
338
|
+
});
|
|
339
|
+
if (!response.successful) {
|
|
340
|
+
return { success: false, error: response.error || "Workbench execution failed" };
|
|
341
|
+
}
|
|
342
|
+
return {
|
|
343
|
+
success: true,
|
|
344
|
+
output: response.data,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
catch (err) {
|
|
348
|
+
return {
|
|
349
|
+
success: false,
|
|
350
|
+
error: err instanceof Error ? err.message : String(err),
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Execute bash commands in the remote sandbox using COMPOSIO_REMOTE_BASH_TOOL
|
|
356
|
+
*/
|
|
357
|
+
async executeBash(command, userId) {
|
|
358
|
+
const uid = this.getUserId(userId);
|
|
359
|
+
const session = await this.getSession(uid);
|
|
360
|
+
try {
|
|
361
|
+
const response = await this.executeMetaTool("COMPOSIO_REMOTE_BASH_TOOL", {
|
|
362
|
+
command,
|
|
363
|
+
session_id: session.sessionId,
|
|
364
|
+
});
|
|
365
|
+
if (!response.successful) {
|
|
366
|
+
return { success: false, error: response.error || "Bash execution failed" };
|
|
367
|
+
}
|
|
368
|
+
return {
|
|
369
|
+
success: true,
|
|
370
|
+
output: response.data,
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
catch (err) {
|
|
374
|
+
return {
|
|
375
|
+
success: false,
|
|
376
|
+
error: err instanceof Error ? err.message : String(err),
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Create a Composio client instance
|
|
383
|
+
*/
|
|
384
|
+
export function createComposioClient(config) {
|
|
385
|
+
return new ComposioClient(config);
|
|
386
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { ComposioConfig } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Zod schema for Composio plugin configuration
|
|
5
|
+
*/
|
|
6
|
+
export declare const ComposioConfigSchema: z.ZodObject<{
|
|
7
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
8
|
+
apiKey: z.ZodOptional<z.ZodString>;
|
|
9
|
+
defaultUserId: z.ZodOptional<z.ZodString>;
|
|
10
|
+
allowedToolkits: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
11
|
+
blockedToolkits: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
12
|
+
}, z.core.$strip>;
|
|
13
|
+
/**
|
|
14
|
+
* Parse and validate plugin config with environment fallbacks
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseComposioConfig(value: unknown): ComposioConfig;
|
|
17
|
+
/**
|
|
18
|
+
* UI hints for configuration fields
|
|
19
|
+
*/
|
|
20
|
+
export declare const composioConfigUiHints: {
|
|
21
|
+
enabled: {
|
|
22
|
+
label: string;
|
|
23
|
+
help: string;
|
|
24
|
+
};
|
|
25
|
+
apiKey: {
|
|
26
|
+
label: string;
|
|
27
|
+
help: string;
|
|
28
|
+
sensitive: boolean;
|
|
29
|
+
};
|
|
30
|
+
defaultUserId: {
|
|
31
|
+
label: string;
|
|
32
|
+
help: string;
|
|
33
|
+
};
|
|
34
|
+
allowedToolkits: {
|
|
35
|
+
label: string;
|
|
36
|
+
help: string;
|
|
37
|
+
advanced: boolean;
|
|
38
|
+
};
|
|
39
|
+
blockedToolkits: {
|
|
40
|
+
label: string;
|
|
41
|
+
help: string;
|
|
42
|
+
advanced: boolean;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Plugin config schema object for openclaw
|
|
47
|
+
*/
|
|
48
|
+
export declare const composioPluginConfigSchema: {
|
|
49
|
+
parse: typeof parseComposioConfig;
|
|
50
|
+
uiHints: {
|
|
51
|
+
enabled: {
|
|
52
|
+
label: string;
|
|
53
|
+
help: string;
|
|
54
|
+
};
|
|
55
|
+
apiKey: {
|
|
56
|
+
label: string;
|
|
57
|
+
help: string;
|
|
58
|
+
sensitive: boolean;
|
|
59
|
+
};
|
|
60
|
+
defaultUserId: {
|
|
61
|
+
label: string;
|
|
62
|
+
help: string;
|
|
63
|
+
};
|
|
64
|
+
allowedToolkits: {
|
|
65
|
+
label: string;
|
|
66
|
+
help: string;
|
|
67
|
+
advanced: boolean;
|
|
68
|
+
};
|
|
69
|
+
blockedToolkits: {
|
|
70
|
+
label: string;
|
|
71
|
+
help: string;
|
|
72
|
+
advanced: boolean;
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
};
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Zod schema for Composio plugin configuration
|
|
4
|
+
*/
|
|
5
|
+
export const ComposioConfigSchema = z.object({
|
|
6
|
+
enabled: z.boolean().default(true),
|
|
7
|
+
apiKey: z.string().optional(),
|
|
8
|
+
defaultUserId: z.string().optional(),
|
|
9
|
+
allowedToolkits: z.array(z.string()).optional(),
|
|
10
|
+
blockedToolkits: z.array(z.string()).optional(),
|
|
11
|
+
});
|
|
12
|
+
/**
|
|
13
|
+
* Parse and validate plugin config with environment fallbacks
|
|
14
|
+
*/
|
|
15
|
+
export function parseComposioConfig(value) {
|
|
16
|
+
const raw = value && typeof value === "object" && !Array.isArray(value)
|
|
17
|
+
? value
|
|
18
|
+
: {};
|
|
19
|
+
// Allow API key from config.apiKey, top-level apiKey, or environment
|
|
20
|
+
const configObj = raw.config;
|
|
21
|
+
const apiKey = (typeof configObj?.apiKey === "string" && configObj.apiKey.trim()) ||
|
|
22
|
+
(typeof raw.apiKey === "string" && raw.apiKey.trim()) ||
|
|
23
|
+
process.env.COMPOSIO_API_KEY ||
|
|
24
|
+
"";
|
|
25
|
+
return ComposioConfigSchema.parse({
|
|
26
|
+
...raw,
|
|
27
|
+
apiKey,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* UI hints for configuration fields
|
|
32
|
+
*/
|
|
33
|
+
export const composioConfigUiHints = {
|
|
34
|
+
enabled: {
|
|
35
|
+
label: "Enable Composio",
|
|
36
|
+
help: "Enable or disable the Composio Tool Router integration",
|
|
37
|
+
},
|
|
38
|
+
apiKey: {
|
|
39
|
+
label: "API Key",
|
|
40
|
+
help: "Composio API key from platform.composio.dev/settings",
|
|
41
|
+
sensitive: true,
|
|
42
|
+
},
|
|
43
|
+
defaultUserId: {
|
|
44
|
+
label: "Default User ID",
|
|
45
|
+
help: "Default user ID for session scoping (optional)",
|
|
46
|
+
},
|
|
47
|
+
allowedToolkits: {
|
|
48
|
+
label: "Allowed Toolkits",
|
|
49
|
+
help: "Restrict to specific toolkits (e.g., github, gmail)",
|
|
50
|
+
advanced: true,
|
|
51
|
+
},
|
|
52
|
+
blockedToolkits: {
|
|
53
|
+
label: "Blocked Toolkits",
|
|
54
|
+
help: "Block specific toolkits from being used",
|
|
55
|
+
advanced: true,
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Plugin config schema object for openclaw
|
|
60
|
+
*/
|
|
61
|
+
export const composioPluginConfigSchema = {
|
|
62
|
+
parse: parseComposioConfig,
|
|
63
|
+
uiHints: composioConfigUiHints,
|
|
64
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { parseComposioConfig } from "./config.js";
|
|
2
|
+
/**
|
|
3
|
+
* Composio Tool Router Plugin for OpenClaw
|
|
4
|
+
*
|
|
5
|
+
* Provides access to 1000+ third-party tools through Composio's unified interface.
|
|
6
|
+
* Tools include: Gmail, Slack, GitHub, Notion, Linear, Jira, and many more.
|
|
7
|
+
*
|
|
8
|
+
* Configuration (in openclaw config):
|
|
9
|
+
* ```json
|
|
10
|
+
* {
|
|
11
|
+
* "plugins": {
|
|
12
|
+
* "composio": {
|
|
13
|
+
* "enabled": true,
|
|
14
|
+
* "apiKey": "your-composio-api-key"
|
|
15
|
+
* }
|
|
16
|
+
* }
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* Or set COMPOSIO_API_KEY environment variable.
|
|
21
|
+
*/
|
|
22
|
+
declare const composioPlugin: {
|
|
23
|
+
id: string;
|
|
24
|
+
name: string;
|
|
25
|
+
description: string;
|
|
26
|
+
configSchema: {
|
|
27
|
+
parse: typeof parseComposioConfig;
|
|
28
|
+
uiHints: {
|
|
29
|
+
enabled: {
|
|
30
|
+
label: string;
|
|
31
|
+
help: string;
|
|
32
|
+
};
|
|
33
|
+
apiKey: {
|
|
34
|
+
label: string;
|
|
35
|
+
help: string;
|
|
36
|
+
sensitive: boolean;
|
|
37
|
+
};
|
|
38
|
+
defaultUserId: {
|
|
39
|
+
label: string;
|
|
40
|
+
help: string;
|
|
41
|
+
};
|
|
42
|
+
allowedToolkits: {
|
|
43
|
+
label: string;
|
|
44
|
+
help: string;
|
|
45
|
+
advanced: boolean;
|
|
46
|
+
};
|
|
47
|
+
blockedToolkits: {
|
|
48
|
+
label: string;
|
|
49
|
+
help: string;
|
|
50
|
+
advanced: boolean;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
register(api: any): void;
|
|
55
|
+
};
|
|
56
|
+
export default composioPlugin;
|