@customclaw/composio 0.0.6 → 0.0.8
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 +64 -8
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +309 -28
- package/dist/client.d.ts +40 -2
- package/dist/client.js +687 -66
- package/dist/config.d.ts +49 -0
- package/dist/config.js +45 -8
- package/dist/index.d.ts +20 -0
- package/dist/index.js +21 -14
- package/dist/tools/connections.d.ts +20 -2
- package/dist/tools/connections.js +39 -28
- package/dist/tools/execute.d.ts +2 -0
- package/dist/tools/execute.js +5 -1
- package/dist/types.d.ts +15 -0
- package/dist/utils.d.ts +12 -0
- package/dist/utils.js +76 -0
- package/openclaw.plugin.json +39 -0
- package/package.json +3 -2
- package/dist/client.test.d.ts +0 -1
- package/dist/client.test.js +0 -226
package/dist/config.d.ts
CHANGED
|
@@ -9,6 +9,15 @@ export declare const ComposioConfigSchema: z.ZodObject<{
|
|
|
9
9
|
defaultUserId: z.ZodOptional<z.ZodString>;
|
|
10
10
|
allowedToolkits: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
11
11
|
blockedToolkits: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
12
|
+
readOnlyMode: z.ZodDefault<z.ZodBoolean>;
|
|
13
|
+
sessionTags: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
14
|
+
readOnlyHint: "readOnlyHint";
|
|
15
|
+
destructiveHint: "destructiveHint";
|
|
16
|
+
idempotentHint: "idempotentHint";
|
|
17
|
+
openWorldHint: "openWorldHint";
|
|
18
|
+
}>>>;
|
|
19
|
+
allowedToolSlugs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
20
|
+
blockedToolSlugs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
12
21
|
}, z.core.$strip>;
|
|
13
22
|
/**
|
|
14
23
|
* Parse and validate plugin config with environment fallbacks
|
|
@@ -41,6 +50,26 @@ export declare const composioConfigUiHints: {
|
|
|
41
50
|
help: string;
|
|
42
51
|
advanced: boolean;
|
|
43
52
|
};
|
|
53
|
+
readOnlyMode: {
|
|
54
|
+
label: string;
|
|
55
|
+
help: string;
|
|
56
|
+
advanced: boolean;
|
|
57
|
+
};
|
|
58
|
+
sessionTags: {
|
|
59
|
+
label: string;
|
|
60
|
+
help: string;
|
|
61
|
+
advanced: boolean;
|
|
62
|
+
};
|
|
63
|
+
allowedToolSlugs: {
|
|
64
|
+
label: string;
|
|
65
|
+
help: string;
|
|
66
|
+
advanced: boolean;
|
|
67
|
+
};
|
|
68
|
+
blockedToolSlugs: {
|
|
69
|
+
label: string;
|
|
70
|
+
help: string;
|
|
71
|
+
advanced: boolean;
|
|
72
|
+
};
|
|
44
73
|
};
|
|
45
74
|
/**
|
|
46
75
|
* Plugin config schema object for openclaw
|
|
@@ -71,5 +100,25 @@ export declare const composioPluginConfigSchema: {
|
|
|
71
100
|
help: string;
|
|
72
101
|
advanced: boolean;
|
|
73
102
|
};
|
|
103
|
+
readOnlyMode: {
|
|
104
|
+
label: string;
|
|
105
|
+
help: string;
|
|
106
|
+
advanced: boolean;
|
|
107
|
+
};
|
|
108
|
+
sessionTags: {
|
|
109
|
+
label: string;
|
|
110
|
+
help: string;
|
|
111
|
+
advanced: boolean;
|
|
112
|
+
};
|
|
113
|
+
allowedToolSlugs: {
|
|
114
|
+
label: string;
|
|
115
|
+
help: string;
|
|
116
|
+
advanced: boolean;
|
|
117
|
+
};
|
|
118
|
+
blockedToolSlugs: {
|
|
119
|
+
label: string;
|
|
120
|
+
help: string;
|
|
121
|
+
advanced: boolean;
|
|
122
|
+
};
|
|
74
123
|
};
|
|
75
124
|
};
|
package/dist/config.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { LEGACY_ENTRY_FLAT_CONFIG_KEYS, LEGACY_SHAPE_ERROR, SESSION_TAGS, isRecord, normalizeSessionTags, normalizeToolkitList, normalizeToolSlugList, } from "./utils.js";
|
|
2
3
|
/**
|
|
3
4
|
* Zod schema for Composio plugin configuration
|
|
4
5
|
*/
|
|
@@ -8,23 +9,39 @@ export const ComposioConfigSchema = z.object({
|
|
|
8
9
|
defaultUserId: z.string().optional(),
|
|
9
10
|
allowedToolkits: z.array(z.string()).optional(),
|
|
10
11
|
blockedToolkits: z.array(z.string()).optional(),
|
|
12
|
+
readOnlyMode: z.boolean().default(false),
|
|
13
|
+
sessionTags: z.array(z.enum(SESSION_TAGS)).optional(),
|
|
14
|
+
allowedToolSlugs: z.array(z.string()).optional(),
|
|
15
|
+
blockedToolSlugs: z.array(z.string()).optional(),
|
|
11
16
|
});
|
|
12
17
|
/**
|
|
13
18
|
* Parse and validate plugin config with environment fallbacks
|
|
14
19
|
*/
|
|
15
20
|
export function parseComposioConfig(value) {
|
|
16
|
-
const raw = value
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
const raw = isRecord(value) ? value : {};
|
|
22
|
+
const configObj = isRecord(raw.config) ? raw.config : undefined;
|
|
23
|
+
if (configObj) {
|
|
24
|
+
const hasLegacyFlatKeys = LEGACY_ENTRY_FLAT_CONFIG_KEYS.some((key) => key in raw);
|
|
25
|
+
if (hasLegacyFlatKeys) {
|
|
26
|
+
throw new Error(LEGACY_SHAPE_ERROR);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const source = configObj ?? raw;
|
|
30
|
+
const enabled = typeof raw.enabled === "boolean" ? raw.enabled : true;
|
|
31
|
+
const readOnlyMode = typeof source.readOnlyMode === "boolean" ? source.readOnlyMode : false;
|
|
32
|
+
const apiKey = (typeof source.apiKey === "string" && source.apiKey.trim()) ||
|
|
23
33
|
process.env.COMPOSIO_API_KEY ||
|
|
24
34
|
"";
|
|
25
35
|
return ComposioConfigSchema.parse({
|
|
26
|
-
|
|
36
|
+
enabled,
|
|
27
37
|
apiKey,
|
|
38
|
+
defaultUserId: typeof source.defaultUserId === "string" ? source.defaultUserId : undefined,
|
|
39
|
+
allowedToolkits: normalizeToolkitList(Array.isArray(source.allowedToolkits) ? source.allowedToolkits : undefined),
|
|
40
|
+
blockedToolkits: normalizeToolkitList(Array.isArray(source.blockedToolkits) ? source.blockedToolkits : undefined),
|
|
41
|
+
readOnlyMode,
|
|
42
|
+
sessionTags: normalizeSessionTags(Array.isArray(source.sessionTags) ? source.sessionTags : undefined),
|
|
43
|
+
allowedToolSlugs: normalizeToolSlugList(Array.isArray(source.allowedToolSlugs) ? source.allowedToolSlugs : undefined),
|
|
44
|
+
blockedToolSlugs: normalizeToolSlugList(Array.isArray(source.blockedToolSlugs) ? source.blockedToolSlugs : undefined),
|
|
28
45
|
});
|
|
29
46
|
}
|
|
30
47
|
/**
|
|
@@ -54,6 +71,26 @@ export const composioConfigUiHints = {
|
|
|
54
71
|
help: "Block specific toolkits from being used",
|
|
55
72
|
advanced: true,
|
|
56
73
|
},
|
|
74
|
+
readOnlyMode: {
|
|
75
|
+
label: "Read-Only Mode",
|
|
76
|
+
help: "Block likely-destructive tool actions by token matching; allow specific slugs with allowedToolSlugs if needed",
|
|
77
|
+
advanced: true,
|
|
78
|
+
},
|
|
79
|
+
sessionTags: {
|
|
80
|
+
label: "Session Tags",
|
|
81
|
+
help: "Composio Tool Router behavior tags (e.g., readOnlyHint, destructiveHint)",
|
|
82
|
+
advanced: true,
|
|
83
|
+
},
|
|
84
|
+
allowedToolSlugs: {
|
|
85
|
+
label: "Allowed Tool Slugs",
|
|
86
|
+
help: "Optional explicit allowlist for tool slugs (UPPERCASE)",
|
|
87
|
+
advanced: true,
|
|
88
|
+
},
|
|
89
|
+
blockedToolSlugs: {
|
|
90
|
+
label: "Blocked Tool Slugs",
|
|
91
|
+
help: "Explicit denylist for tool slugs (UPPERCASE)",
|
|
92
|
+
advanced: true,
|
|
93
|
+
},
|
|
57
94
|
};
|
|
58
95
|
/**
|
|
59
96
|
* Plugin config schema object for openclaw
|
package/dist/index.d.ts
CHANGED
|
@@ -49,6 +49,26 @@ declare const composioPlugin: {
|
|
|
49
49
|
help: string;
|
|
50
50
|
advanced: boolean;
|
|
51
51
|
};
|
|
52
|
+
readOnlyMode: {
|
|
53
|
+
label: string;
|
|
54
|
+
help: string;
|
|
55
|
+
advanced: boolean;
|
|
56
|
+
};
|
|
57
|
+
sessionTags: {
|
|
58
|
+
label: string;
|
|
59
|
+
help: string;
|
|
60
|
+
advanced: boolean;
|
|
61
|
+
};
|
|
62
|
+
allowedToolSlugs: {
|
|
63
|
+
label: string;
|
|
64
|
+
help: string;
|
|
65
|
+
advanced: boolean;
|
|
66
|
+
};
|
|
67
|
+
blockedToolSlugs: {
|
|
68
|
+
label: string;
|
|
69
|
+
help: string;
|
|
70
|
+
advanced: boolean;
|
|
71
|
+
};
|
|
52
72
|
};
|
|
53
73
|
};
|
|
54
74
|
register(api: any): void;
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { createComposioSearchTool } from "./tools/search.js";
|
|
|
4
4
|
import { createComposioExecuteTool } from "./tools/execute.js";
|
|
5
5
|
import { createComposioConnectionsTool } from "./tools/connections.js";
|
|
6
6
|
import { registerComposioCli } from "./cli.js";
|
|
7
|
+
import { LEGACY_SHAPE_ERROR, hasLegacyFlatEntryConfig } from "./utils.js";
|
|
7
8
|
/**
|
|
8
9
|
* Composio Tool Router Plugin for OpenClaw
|
|
9
10
|
*
|
|
@@ -31,7 +32,27 @@ const composioPlugin = {
|
|
|
31
32
|
"Search, authenticate, and execute tools for Gmail, Slack, GitHub, Notion, and more.",
|
|
32
33
|
configSchema: composioPluginConfigSchema,
|
|
33
34
|
register(api) {
|
|
35
|
+
if (hasLegacyFlatEntryConfig(api?.config)) {
|
|
36
|
+
throw new Error(LEGACY_SHAPE_ERROR);
|
|
37
|
+
}
|
|
34
38
|
const config = parseComposioConfig(api.pluginConfig);
|
|
39
|
+
let client = null;
|
|
40
|
+
const ensureClient = () => {
|
|
41
|
+
if (!config.apiKey) {
|
|
42
|
+
throw new Error("Composio API key required. Run 'openclaw composio setup' or set COMPOSIO_API_KEY.");
|
|
43
|
+
}
|
|
44
|
+
if (!client) {
|
|
45
|
+
client = createComposioClient(config);
|
|
46
|
+
}
|
|
47
|
+
return client;
|
|
48
|
+
};
|
|
49
|
+
// Register CLI commands even without API key so setup/status tooling remains available.
|
|
50
|
+
api.registerCli(({ program }) => registerComposioCli({
|
|
51
|
+
program,
|
|
52
|
+
getClient: config.apiKey ? ensureClient : undefined,
|
|
53
|
+
config,
|
|
54
|
+
logger: api.logger,
|
|
55
|
+
}), { commands: ["composio"] });
|
|
35
56
|
if (!config.enabled) {
|
|
36
57
|
api.logger.debug("[composio] Plugin disabled in config");
|
|
37
58
|
return;
|
|
@@ -40,13 +61,6 @@ const composioPlugin = {
|
|
|
40
61
|
api.logger.warn("[composio] No API key configured. Set COMPOSIO_API_KEY env var or plugins.composio.apiKey in config.");
|
|
41
62
|
return;
|
|
42
63
|
}
|
|
43
|
-
let client = null;
|
|
44
|
-
const ensureClient = () => {
|
|
45
|
-
if (!client) {
|
|
46
|
-
client = createComposioClient(config);
|
|
47
|
-
}
|
|
48
|
-
return client;
|
|
49
|
-
};
|
|
50
64
|
// Register tools (lazily create client on first use)
|
|
51
65
|
api.registerTool({
|
|
52
66
|
...createComposioSearchTool(ensureClient(), config),
|
|
@@ -66,13 +80,6 @@ const composioPlugin = {
|
|
|
66
80
|
return createComposioConnectionsTool(ensureClient(), config).execute(toolCallId, params);
|
|
67
81
|
},
|
|
68
82
|
});
|
|
69
|
-
// Register CLI commands
|
|
70
|
-
api.registerCli(({ program }) => registerComposioCli({
|
|
71
|
-
program,
|
|
72
|
-
client: ensureClient(),
|
|
73
|
-
config,
|
|
74
|
-
logger: api.logger,
|
|
75
|
-
}), { commands: ["composio"] });
|
|
76
83
|
api.logger.info("[composio] Plugin registered with 3 tools and CLI commands");
|
|
77
84
|
},
|
|
78
85
|
};
|
|
@@ -4,10 +4,11 @@ import type { ComposioConfig } from "../types.js";
|
|
|
4
4
|
* Tool parameters for composio_manage_connections
|
|
5
5
|
*/
|
|
6
6
|
export declare const ComposioManageConnectionsToolSchema: import("@sinclair/typebox").TObject<{
|
|
7
|
-
action: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"status">, import("@sinclair/typebox").TLiteral<"create">, import("@sinclair/typebox").TLiteral<"list">]>;
|
|
7
|
+
action: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"status">, import("@sinclair/typebox").TLiteral<"create">, import("@sinclair/typebox").TLiteral<"list">, import("@sinclair/typebox").TLiteral<"accounts">]>;
|
|
8
8
|
toolkit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
9
9
|
toolkits: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
|
|
10
10
|
user_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
11
|
+
statuses: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
|
|
11
12
|
}>;
|
|
12
13
|
/**
|
|
13
14
|
* Create the composio_manage_connections tool
|
|
@@ -17,10 +18,11 @@ export declare function createComposioConnectionsTool(client: ComposioClient, _c
|
|
|
17
18
|
label: string;
|
|
18
19
|
description: string;
|
|
19
20
|
parameters: import("@sinclair/typebox").TObject<{
|
|
20
|
-
action: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"status">, import("@sinclair/typebox").TLiteral<"create">, import("@sinclair/typebox").TLiteral<"list">]>;
|
|
21
|
+
action: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"status">, import("@sinclair/typebox").TLiteral<"create">, import("@sinclair/typebox").TLiteral<"list">, import("@sinclair/typebox").TLiteral<"accounts">]>;
|
|
21
22
|
toolkit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
22
23
|
toolkits: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
|
|
23
24
|
user_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
25
|
+
statuses: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
|
|
24
26
|
}>;
|
|
25
27
|
execute(_toolCallId: string, params: Record<string, unknown>): Promise<{
|
|
26
28
|
content: {
|
|
@@ -32,6 +34,22 @@ export declare function createComposioConnectionsTool(client: ComposioClient, _c
|
|
|
32
34
|
count: number;
|
|
33
35
|
toolkits: string[];
|
|
34
36
|
};
|
|
37
|
+
} | {
|
|
38
|
+
content: {
|
|
39
|
+
type: string;
|
|
40
|
+
text: string;
|
|
41
|
+
}[];
|
|
42
|
+
details: {
|
|
43
|
+
action: string;
|
|
44
|
+
count: number;
|
|
45
|
+
accounts: {
|
|
46
|
+
id: string;
|
|
47
|
+
toolkit: string;
|
|
48
|
+
user_id: string | undefined;
|
|
49
|
+
status: string | undefined;
|
|
50
|
+
auth_config_id: string | undefined;
|
|
51
|
+
}[];
|
|
52
|
+
};
|
|
35
53
|
} | {
|
|
36
54
|
content: {
|
|
37
55
|
type: string;
|
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
-
const CONNECTION_PROBES = {
|
|
3
|
-
affinity: {
|
|
4
|
-
toolSlug: "AFFINITY_GET_METADATA_ON_ALL_LISTS",
|
|
5
|
-
args: { limit: 1 },
|
|
6
|
-
},
|
|
7
|
-
};
|
|
8
2
|
/**
|
|
9
3
|
* Tool parameters for composio_manage_connections
|
|
10
4
|
*/
|
|
11
5
|
export const ComposioManageConnectionsToolSchema = Type.Object({
|
|
12
|
-
action: Type.Union([Type.Literal("status"), Type.Literal("create"), Type.Literal("list")], {
|
|
13
|
-
description: "Action to perform: 'status' to check connections, 'create' to initiate auth, 'list' to list toolkits",
|
|
6
|
+
action: Type.Union([Type.Literal("status"), Type.Literal("create"), Type.Literal("list"), Type.Literal("accounts")], {
|
|
7
|
+
description: "Action to perform: 'status' to check connections, 'create' to initiate auth, 'list' to list toolkits, 'accounts' to inspect connected accounts",
|
|
14
8
|
}),
|
|
15
9
|
toolkit: Type.Optional(Type.String({
|
|
16
10
|
description: "Toolkit name for 'status' or 'create' actions (e.g., 'github', 'gmail')",
|
|
@@ -21,6 +15,9 @@ export const ComposioManageConnectionsToolSchema = Type.Object({
|
|
|
21
15
|
user_id: Type.Optional(Type.String({
|
|
22
16
|
description: "User ID for session scoping (uses default if not provided)",
|
|
23
17
|
})),
|
|
18
|
+
statuses: Type.Optional(Type.Array(Type.String(), {
|
|
19
|
+
description: "Optional connection statuses filter for 'accounts' (e.g., ['ACTIVE'])",
|
|
20
|
+
})),
|
|
24
21
|
});
|
|
25
22
|
/**
|
|
26
23
|
* Create the composio_manage_connections tool
|
|
@@ -30,7 +27,8 @@ export function createComposioConnectionsTool(client, _config) {
|
|
|
30
27
|
name: "composio_manage_connections",
|
|
31
28
|
label: "Composio Manage Connections",
|
|
32
29
|
description: "Manage Composio toolkit connections. Use action='status' to check if a toolkit is connected, " +
|
|
33
|
-
"action='create' to generate an auth URL when disconnected,
|
|
30
|
+
"action='create' to generate an auth URL when disconnected, action='list' to see available toolkits, " +
|
|
31
|
+
"or action='accounts' to inspect connected accounts across user IDs. " +
|
|
34
32
|
"Check connection status before executing tools with composio_execute_tool.",
|
|
35
33
|
parameters: ComposioManageConnectionsToolSchema,
|
|
36
34
|
async execute(_toolCallId, params) {
|
|
@@ -50,6 +48,38 @@ export function createComposioConnectionsTool(client, _config) {
|
|
|
50
48
|
details: response,
|
|
51
49
|
};
|
|
52
50
|
}
|
|
51
|
+
case "accounts": {
|
|
52
|
+
let toolkits;
|
|
53
|
+
if (typeof params.toolkit === "string" && params.toolkit.trim()) {
|
|
54
|
+
toolkits = [params.toolkit.trim()];
|
|
55
|
+
}
|
|
56
|
+
else if (Array.isArray(params.toolkits)) {
|
|
57
|
+
toolkits = params.toolkits.filter((t) => typeof t === "string" && t.trim() !== "");
|
|
58
|
+
}
|
|
59
|
+
const statuses = Array.isArray(params.statuses)
|
|
60
|
+
? params.statuses.filter((s) => typeof s === "string" && s.trim() !== "")
|
|
61
|
+
: ["ACTIVE"];
|
|
62
|
+
const accounts = await client.listConnectedAccounts({
|
|
63
|
+
toolkits,
|
|
64
|
+
userIds: userId ? [userId] : undefined,
|
|
65
|
+
statuses,
|
|
66
|
+
});
|
|
67
|
+
const response = {
|
|
68
|
+
action: "accounts",
|
|
69
|
+
count: accounts.length,
|
|
70
|
+
accounts: accounts.map((a) => ({
|
|
71
|
+
id: a.id,
|
|
72
|
+
toolkit: a.toolkit,
|
|
73
|
+
user_id: a.userId,
|
|
74
|
+
status: a.status,
|
|
75
|
+
auth_config_id: a.authConfigId,
|
|
76
|
+
})),
|
|
77
|
+
};
|
|
78
|
+
return {
|
|
79
|
+
content: [{ type: "text", text: JSON.stringify(response, null, 2) }],
|
|
80
|
+
details: response,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
53
83
|
case "create": {
|
|
54
84
|
const toolkit = String(params.toolkit || "").trim();
|
|
55
85
|
if (!toolkit) {
|
|
@@ -89,25 +119,6 @@ export function createComposioConnectionsTool(client, _config) {
|
|
|
89
119
|
toolkitsToCheck = params.toolkits.filter((t) => typeof t === "string" && t.trim() !== "");
|
|
90
120
|
}
|
|
91
121
|
const statuses = await client.getConnectionStatus(toolkitsToCheck, userId);
|
|
92
|
-
// Fallback probe for API-key style integrations where
|
|
93
|
-
// connection.isActive can be false despite successful tool execution
|
|
94
|
-
if (toolkitsToCheck && toolkitsToCheck.length > 0) {
|
|
95
|
-
for (const status of statuses) {
|
|
96
|
-
if (status.connected)
|
|
97
|
-
continue;
|
|
98
|
-
const probe = CONNECTION_PROBES[String(status.toolkit || "").toLowerCase()];
|
|
99
|
-
if (!probe)
|
|
100
|
-
continue;
|
|
101
|
-
try {
|
|
102
|
-
const probeResult = await client.executeTool(probe.toolSlug, probe.args, userId);
|
|
103
|
-
if (probeResult?.success)
|
|
104
|
-
status.connected = true;
|
|
105
|
-
}
|
|
106
|
-
catch {
|
|
107
|
-
// keep false if probe fails
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
122
|
const response = {
|
|
112
123
|
action: "status",
|
|
113
124
|
count: statuses.length,
|
package/dist/tools/execute.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export declare const ComposioExecuteToolSchema: import("@sinclair/typebox").TObj
|
|
|
7
7
|
tool_slug: import("@sinclair/typebox").TString;
|
|
8
8
|
arguments: import("@sinclair/typebox").TUnknown;
|
|
9
9
|
user_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
10
|
+
connected_account_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
10
11
|
}>;
|
|
11
12
|
/**
|
|
12
13
|
* Create the composio_execute_tool tool
|
|
@@ -19,6 +20,7 @@ export declare function createComposioExecuteTool(client: ComposioClient, _confi
|
|
|
19
20
|
tool_slug: import("@sinclair/typebox").TString;
|
|
20
21
|
arguments: import("@sinclair/typebox").TUnknown;
|
|
21
22
|
user_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
23
|
+
connected_account_id: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
22
24
|
}>;
|
|
23
25
|
execute(_toolCallId: string, params: Record<string, unknown>): Promise<{
|
|
24
26
|
content: {
|
package/dist/tools/execute.js
CHANGED
|
@@ -12,6 +12,9 @@ export const ComposioExecuteToolSchema = Type.Object({
|
|
|
12
12
|
user_id: Type.Optional(Type.String({
|
|
13
13
|
description: "User ID for session scoping (uses default if not provided)",
|
|
14
14
|
})),
|
|
15
|
+
connected_account_id: Type.Optional(Type.String({
|
|
16
|
+
description: "Optional connected account ID to pin execution to a specific account when multiple are connected",
|
|
17
|
+
})),
|
|
15
18
|
});
|
|
16
19
|
/**
|
|
17
20
|
* Create the composio_execute_tool tool
|
|
@@ -43,8 +46,9 @@ export function createComposioExecuteTool(client, _config) {
|
|
|
43
46
|
? rawArgs
|
|
44
47
|
: {};
|
|
45
48
|
const userId = typeof params.user_id === "string" ? params.user_id : undefined;
|
|
49
|
+
const connectedAccountId = typeof params.connected_account_id === "string" ? params.connected_account_id : undefined;
|
|
46
50
|
try {
|
|
47
|
-
const result = await client.executeTool(toolSlug, args, userId);
|
|
51
|
+
const result = await client.executeTool(toolSlug, args, userId, connectedAccountId);
|
|
48
52
|
const response = {
|
|
49
53
|
tool_slug: toolSlug,
|
|
50
54
|
success: result.success,
|
package/dist/types.d.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Composio Tool Router types for OpenClaw integration
|
|
3
3
|
*/
|
|
4
|
+
export type ComposioSessionTag = "readOnlyHint" | "destructiveHint" | "idempotentHint" | "openWorldHint";
|
|
4
5
|
export interface ComposioConfig {
|
|
5
6
|
enabled: boolean;
|
|
6
7
|
apiKey?: string;
|
|
7
8
|
defaultUserId?: string;
|
|
8
9
|
allowedToolkits?: string[];
|
|
9
10
|
blockedToolkits?: string[];
|
|
11
|
+
readOnlyMode?: boolean;
|
|
12
|
+
sessionTags?: ComposioSessionTag[];
|
|
13
|
+
allowedToolSlugs?: string[];
|
|
14
|
+
blockedToolSlugs?: string[];
|
|
10
15
|
}
|
|
11
16
|
export interface ToolSearchResult {
|
|
12
17
|
name: string;
|
|
@@ -26,3 +31,13 @@ export interface ConnectionStatus {
|
|
|
26
31
|
userId?: string;
|
|
27
32
|
authUrl?: string;
|
|
28
33
|
}
|
|
34
|
+
export interface ConnectedAccountSummary {
|
|
35
|
+
id: string;
|
|
36
|
+
toolkit: string;
|
|
37
|
+
userId?: string;
|
|
38
|
+
status?: string;
|
|
39
|
+
authConfigId?: string;
|
|
40
|
+
isDisabled?: boolean;
|
|
41
|
+
createdAt?: string;
|
|
42
|
+
updatedAt?: string;
|
|
43
|
+
}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ComposioSessionTag } from "./types.js";
|
|
2
|
+
export declare const SESSION_TAGS: readonly ["readOnlyHint", "destructiveHint", "idempotentHint", "openWorldHint"];
|
|
3
|
+
export declare const LEGACY_ENTRY_FLAT_CONFIG_KEYS: readonly ["apiKey", "defaultUserId", "allowedToolkits", "blockedToolkits", "readOnlyMode", "sessionTags", "allowedToolSlugs", "blockedToolSlugs"];
|
|
4
|
+
export declare const LEGACY_SHAPE_ERROR = "Legacy Composio config shape detected. Run 'openclaw composio setup'.";
|
|
5
|
+
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
6
|
+
export declare function normalizeToolkitSlug(value: unknown): string;
|
|
7
|
+
export declare function normalizeToolSlug(value: unknown): string;
|
|
8
|
+
export declare function normalizeToolkitList(values?: readonly unknown[]): string[] | undefined;
|
|
9
|
+
export declare function normalizeToolSlugList(values?: readonly unknown[]): string[] | undefined;
|
|
10
|
+
export declare function normalizeSessionTags(values?: readonly unknown[]): ComposioSessionTag[] | undefined;
|
|
11
|
+
export declare function hasLegacyFlatEntryConfig(config: unknown): boolean;
|
|
12
|
+
export declare function stripLegacyFlatConfigKeys(entry: Record<string, unknown>): Record<string, unknown>;
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export const SESSION_TAGS = [
|
|
2
|
+
"readOnlyHint",
|
|
3
|
+
"destructiveHint",
|
|
4
|
+
"idempotentHint",
|
|
5
|
+
"openWorldHint",
|
|
6
|
+
];
|
|
7
|
+
export const LEGACY_ENTRY_FLAT_CONFIG_KEYS = [
|
|
8
|
+
"apiKey",
|
|
9
|
+
"defaultUserId",
|
|
10
|
+
"allowedToolkits",
|
|
11
|
+
"blockedToolkits",
|
|
12
|
+
"readOnlyMode",
|
|
13
|
+
"sessionTags",
|
|
14
|
+
"allowedToolSlugs",
|
|
15
|
+
"blockedToolSlugs",
|
|
16
|
+
];
|
|
17
|
+
export const LEGACY_SHAPE_ERROR = "Legacy Composio config shape detected. Run 'openclaw composio setup'.";
|
|
18
|
+
const SESSION_TAG_SET = new Set(SESSION_TAGS);
|
|
19
|
+
export function isRecord(value) {
|
|
20
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
21
|
+
}
|
|
22
|
+
export function normalizeToolkitSlug(value) {
|
|
23
|
+
return String(value ?? "").trim().toLowerCase();
|
|
24
|
+
}
|
|
25
|
+
export function normalizeToolSlug(value) {
|
|
26
|
+
return String(value ?? "").trim().toUpperCase();
|
|
27
|
+
}
|
|
28
|
+
export function normalizeToolkitList(values) {
|
|
29
|
+
if (!values || values.length === 0)
|
|
30
|
+
return undefined;
|
|
31
|
+
const normalized = values
|
|
32
|
+
.filter((item) => typeof item === "string")
|
|
33
|
+
.map((item) => normalizeToolkitSlug(item))
|
|
34
|
+
.filter(Boolean);
|
|
35
|
+
if (normalized.length === 0)
|
|
36
|
+
return undefined;
|
|
37
|
+
return Array.from(new Set(normalized));
|
|
38
|
+
}
|
|
39
|
+
export function normalizeToolSlugList(values) {
|
|
40
|
+
if (!values || values.length === 0)
|
|
41
|
+
return undefined;
|
|
42
|
+
const normalized = values
|
|
43
|
+
.filter((item) => typeof item === "string")
|
|
44
|
+
.map((item) => normalizeToolSlug(item))
|
|
45
|
+
.filter(Boolean);
|
|
46
|
+
if (normalized.length === 0)
|
|
47
|
+
return undefined;
|
|
48
|
+
return Array.from(new Set(normalized));
|
|
49
|
+
}
|
|
50
|
+
export function normalizeSessionTags(values) {
|
|
51
|
+
if (!values || values.length === 0)
|
|
52
|
+
return undefined;
|
|
53
|
+
const normalized = values
|
|
54
|
+
.filter((item) => typeof item === "string")
|
|
55
|
+
.map((item) => item.trim())
|
|
56
|
+
.filter((item) => SESSION_TAG_SET.has(item));
|
|
57
|
+
if (normalized.length === 0)
|
|
58
|
+
return undefined;
|
|
59
|
+
return Array.from(new Set(normalized));
|
|
60
|
+
}
|
|
61
|
+
export function hasLegacyFlatEntryConfig(config) {
|
|
62
|
+
const root = isRecord(config) ? config : undefined;
|
|
63
|
+
const plugins = isRecord(root?.plugins) ? root.plugins : undefined;
|
|
64
|
+
const entries = isRecord(plugins?.entries) ? plugins.entries : undefined;
|
|
65
|
+
const composioEntry = isRecord(entries?.composio) ? entries.composio : undefined;
|
|
66
|
+
if (!composioEntry)
|
|
67
|
+
return false;
|
|
68
|
+
return LEGACY_ENTRY_FLAT_CONFIG_KEYS.some((key) => key in composioEntry);
|
|
69
|
+
}
|
|
70
|
+
export function stripLegacyFlatConfigKeys(entry) {
|
|
71
|
+
const sanitized = { ...entry };
|
|
72
|
+
for (const key of LEGACY_ENTRY_FLAT_CONFIG_KEYS) {
|
|
73
|
+
delete sanitized[key];
|
|
74
|
+
}
|
|
75
|
+
return sanitized;
|
|
76
|
+
}
|
package/openclaw.plugin.json
CHANGED
|
@@ -27,6 +27,25 @@
|
|
|
27
27
|
"type": "array",
|
|
28
28
|
"items": { "type": "string" },
|
|
29
29
|
"description": "Block specific toolkits"
|
|
30
|
+
},
|
|
31
|
+
"readOnlyMode": {
|
|
32
|
+
"type": "boolean",
|
|
33
|
+
"description": "Block likely destructive tool actions by default"
|
|
34
|
+
},
|
|
35
|
+
"sessionTags": {
|
|
36
|
+
"type": "array",
|
|
37
|
+
"items": { "type": "string", "enum": ["readOnlyHint", "destructiveHint", "idempotentHint", "openWorldHint"] },
|
|
38
|
+
"description": "Optional Tool Router behavior tags"
|
|
39
|
+
},
|
|
40
|
+
"allowedToolSlugs": {
|
|
41
|
+
"type": "array",
|
|
42
|
+
"items": { "type": "string" },
|
|
43
|
+
"description": "Optional explicit allowlist for tool slugs (UPPERCASE)"
|
|
44
|
+
},
|
|
45
|
+
"blockedToolSlugs": {
|
|
46
|
+
"type": "array",
|
|
47
|
+
"items": { "type": "string" },
|
|
48
|
+
"description": "Explicit denylist for tool slugs (UPPERCASE)"
|
|
30
49
|
}
|
|
31
50
|
}
|
|
32
51
|
},
|
|
@@ -53,6 +72,26 @@
|
|
|
53
72
|
"label": "Blocked Toolkits",
|
|
54
73
|
"help": "Block specific toolkits from being used",
|
|
55
74
|
"advanced": true
|
|
75
|
+
},
|
|
76
|
+
"readOnlyMode": {
|
|
77
|
+
"label": "Read-Only Mode",
|
|
78
|
+
"help": "Block likely-destructive tool actions by default",
|
|
79
|
+
"advanced": true
|
|
80
|
+
},
|
|
81
|
+
"sessionTags": {
|
|
82
|
+
"label": "Session Tags",
|
|
83
|
+
"help": "Tool Router behavior tags (e.g., readOnlyHint, destructiveHint)",
|
|
84
|
+
"advanced": true
|
|
85
|
+
},
|
|
86
|
+
"allowedToolSlugs": {
|
|
87
|
+
"label": "Allowed Tool Slugs",
|
|
88
|
+
"help": "Optional explicit allowlist for tool slugs (UPPERCASE)",
|
|
89
|
+
"advanced": true
|
|
90
|
+
},
|
|
91
|
+
"blockedToolSlugs": {
|
|
92
|
+
"label": "Blocked Tool Slugs",
|
|
93
|
+
"help": "Explicit denylist for tool slugs (UPPERCASE)",
|
|
94
|
+
"advanced": true
|
|
56
95
|
}
|
|
57
96
|
}
|
|
58
97
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@customclaw/composio",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Composio Tool Router plugin for OpenClaw — access 1000+ third-party integrations",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
]
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
|
-
"build": "tsc",
|
|
14
|
+
"build": "rm -rf dist && tsc",
|
|
15
15
|
"test": "vitest run",
|
|
16
|
+
"test:live": "vitest run src/live.integration.test.ts",
|
|
16
17
|
"prepublishOnly": "npm run build"
|
|
17
18
|
},
|
|
18
19
|
"files": [
|
package/dist/client.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|