clementine-agent 1.11.0 → 1.11.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.
|
@@ -98,11 +98,11 @@ export async function getPreferredUserId() {
|
|
|
98
98
|
// calls have to pass *some* user_id, and we want it to match whatever the
|
|
99
99
|
// user already has if possible. detectPreferredUserId() picks the user_id
|
|
100
100
|
// with the most existing connections, falling back to this constant.
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
const DEFAULT_NEW_CONNECTION_USER_ID = '';
|
|
101
|
+
// Used only when there are no existing connections to learn from. The real
|
|
102
|
+
// path is detectPreferredUserId() reading the user_id off existing records
|
|
103
|
+
// via the raw client — that's how we match Composio's web-UI auto-generated
|
|
104
|
+
// IDs like `pg-test-<uuid>`.
|
|
105
|
+
const DEFAULT_NEW_CONNECTION_USER_ID = 'default';
|
|
106
106
|
export function clementineUserId() {
|
|
107
107
|
return readComposioEnv('COMPOSIO_USER_ID') || DEFAULT_NEW_CONNECTION_USER_ID;
|
|
108
108
|
}
|
|
@@ -114,35 +114,41 @@ async function detectPreferredUserId(composio) {
|
|
|
114
114
|
return explicit;
|
|
115
115
|
if (detectedPreferredUserId !== null)
|
|
116
116
|
return detectedPreferredUserId;
|
|
117
|
-
// The
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
|
|
117
|
+
// The high-level wrapper's list() drops the snake_case `user_id` field
|
|
118
|
+
// during its camelCase transformation, so connections look like they have
|
|
119
|
+
// no user_id. Use the raw client (snake_case shape) to actually read the
|
|
120
|
+
// user_id Composio's web UI assigned (typically `pg-test-<uuid>` for
|
|
121
|
+
// dashboard-created connections). Without this, we'd default to "default"
|
|
122
|
+
// and composio.create() / toolkits.authorize() would never see existing
|
|
123
|
+
// connections — every tool call would 401.
|
|
124
124
|
try {
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
125
|
+
const rawClient = composio.client;
|
|
126
|
+
const resp = await rawClient.connectedAccounts.list({});
|
|
127
|
+
const items = (resp?.items ?? []);
|
|
128
|
+
const counts = new Map();
|
|
129
|
+
for (const it of items) {
|
|
130
|
+
// Prefer ACTIVE connections — expired ones often outnumber active ones
|
|
131
|
+
// (3 outlooks: 1 ACTIVE + 2 EXPIRED in real data).
|
|
132
|
+
if (it.status === 'ACTIVE' && typeof it.user_id === 'string' && it.user_id.length > 0) {
|
|
133
|
+
counts.set(it.user_id, (counts.get(it.user_id) ?? 0) + 2); // weight active higher
|
|
134
|
+
}
|
|
135
|
+
else if (typeof it.user_id === 'string' && it.user_id.length > 0) {
|
|
136
|
+
counts.set(it.user_id, (counts.get(it.user_id) ?? 0) + 1);
|
|
138
137
|
}
|
|
139
|
-
catch { /* try next */ }
|
|
140
138
|
}
|
|
139
|
+
if (counts.size > 0) {
|
|
140
|
+
const top = [...counts.entries()].sort((a, b) => b[1] - a[1])[0][0];
|
|
141
|
+
logger.info({ userId: top, candidates: counts.size }, 'Detected Composio user_id from existing connections');
|
|
142
|
+
detectedPreferredUserId = top;
|
|
143
|
+
return top;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
logger.warn({ err }, 'Raw client user_id probe failed — using fallback');
|
|
141
148
|
}
|
|
142
|
-
// No connections
|
|
143
|
-
// empty string,
|
|
144
|
-
//
|
|
145
|
-
// the user creates in Composio's dashboard.
|
|
149
|
+
// No existing connections. Fall back to "default" — composio.create()
|
|
150
|
+
// requires a non-empty string, and "default" is the conventional
|
|
151
|
+
// single-tenant value that Composio's quickstart uses.
|
|
146
152
|
detectedPreferredUserId = DEFAULT_NEW_CONNECTION_USER_ID;
|
|
147
153
|
return DEFAULT_NEW_CONNECTION_USER_ID;
|
|
148
154
|
}
|
|
@@ -48,29 +48,23 @@ export async function buildComposioMcpServers(slugs) {
|
|
|
48
48
|
}
|
|
49
49
|
return out;
|
|
50
50
|
}
|
|
51
|
-
async function buildOne(composio, slug,
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
const authConfig = (await composio.authConfigs.list({ toolkit: slug })).items[0];
|
|
51
|
+
async function buildOne(composio, slug, _connected) {
|
|
52
|
+
// composio.tools.get() returns the FLAT toolkit tools (OUTLOOK_LIST_MESSAGES,
|
|
53
|
+
// GMAIL_SEND_EMAIL, …) — exactly the namespacing the agent expects as
|
|
54
|
+
// mcp__outlook__OUTLOOK_LIST_MESSAGES. The alternative, composio.create()
|
|
55
|
+
// + session.tools(), uses Composio's tool-router pattern and only returns
|
|
56
|
+
// 5 meta-tools (COMPOSIO_SEARCH_TOOLS, COMPOSIO_MULTI_EXECUTE_TOOL, …),
|
|
57
|
+
// which doesn't match what the agent calls. Verified empirically:
|
|
58
|
+
// tools.get returns 50+ actual Outlook tools.
|
|
60
59
|
const userId = await getPreferredUserId();
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
...(activeCount >= 2
|
|
66
|
-
? { multiAccount: { enable: true, requireExplicitSelection: true } }
|
|
67
|
-
: {}),
|
|
68
|
-
});
|
|
69
|
-
const tools = await session.tools();
|
|
60
|
+
const toolsRaw = await composio.tools.get(userId, { toolkits: [slug], limit: 200 });
|
|
61
|
+
// tools.get can return an array OR an object depending on provider; normalise.
|
|
62
|
+
const toolsArr = Array.isArray(toolsRaw) ? toolsRaw : Object.values(toolsRaw);
|
|
63
|
+
const tools = toolsArr.filter((t) => t && typeof t.name === 'string' && typeof t.handler === 'function');
|
|
70
64
|
return createSdkMcpServer({
|
|
71
65
|
name: slug,
|
|
72
66
|
version: '0.1.0',
|
|
73
|
-
tools,
|
|
67
|
+
tools: tools,
|
|
74
68
|
});
|
|
75
69
|
}
|
|
76
70
|
//# sourceMappingURL=mcp-bridge.js.map
|