chat-agent-toolkit 1.2.2 → 1.2.3
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 +6 -6
- package/dist/config/config-manager.d.ts +23 -0
- package/dist/config/config-types.d.ts +58 -0
- package/dist/config/environment-variables.d.ts +6 -0
- package/dist/config/index.d.ts +18 -0
- package/dist/config/language-models-database.d.ts +93 -0
- package/dist/config/mcp-server-registry.d.ts +7 -0
- package/dist/config/model-registry.d.ts +69 -0
- package/dist/config/model-tester.d.ts +51 -0
- package/dist/config/model-utils.d.ts +44 -0
- package/dist/config/provider-ui-config.d.ts +6 -0
- package/dist/index.d.ts +23 -0
- package/dist/memory/agent-memory-manager.d.ts +125 -0
- package/dist/memory/example.d.ts +36 -0
- package/dist/memory/index.d.ts +18 -0
- package/dist/memory/mastra-integration.d.ts +146 -0
- package/dist/memory/storage/drizzle-storage.d.ts +82 -0
- package/dist/memory/storage/in-memory-storage.d.ts +75 -0
- package/dist/memory/storage/storage-interface.d.ts +37 -0
- package/dist/memory/types.d.ts +122 -0
- package/dist/models/providers.d.ts +5 -0
- package/dist/models/registry.d.ts +4 -0
- package/dist/models/types.d.ts +4 -0
- package/dist/research-agent.cjs.js +2 -0
- package/dist/research-agent.cjs.js.map +1 -0
- package/dist/research-agent.es.js +2 -0
- package/dist/research-agent.es.js.map +1 -0
- package/dist/search.d.ts +5 -0
- package/dist/tools/index.d.ts +12 -0
- package/dist/tools/open-connector-mastra.d.ts +137 -0
- package/dist/tools/open-connector-mcp.d.ts +88 -0
- package/dist/tools/qwksearch-api-tools.d.ts +149 -0
- package/dist/tools/search/doc-utils.d.ts +11 -0
- package/dist/tools/search/document.d.ts +14 -0
- package/dist/tools/search/index.d.ts +12 -0
- package/dist/tools/search/link-summarizer.d.ts +7 -0
- package/dist/tools/search/meta-search-types.d.ts +50 -0
- package/dist/tools/search/metaSearchAgent.d.ts +21 -0
- package/dist/tools/search/search-handlers.d.ts +27 -0
- package/dist/tools/search/suggestionGeneratorAgent.d.ts +8 -0
- package/dist/types.d.ts +2 -0
- package/dist/utils/chat-helpers.d.ts +10 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/markdown-to-html.d.ts +5 -0
- package/dist/utils/outputParser.d.ts +22 -0
- package/dist/utils/provider-image-cropper.d.ts +120 -0
- package/package.json +14 -5
- package/src/config/config-manager.ts +0 -8
- package/src/config/environment-variables.ts +11 -3
- package/src/config/language-models-database.ts +50 -42
- package/src/config/model-registry.ts +20 -5
- package/src/config/model-tester.ts +2 -2
- package/src/connectors/{composio.json → open-connector.json} +21 -45
- package/src/index.ts +3 -0
- package/src/memory/ARCHITECTURE.md +1 -1
- package/src/memory/example.ts +6 -6
- package/src/memory/mastra-integration.ts +6 -11
- package/src/memory/storage/drizzle-storage.ts +60 -29
- package/src/memory/storage/in-memory-storage.ts +2 -2
- package/src/memory/storage/storage-interface.ts +1 -1
- package/src/models/types.ts +1 -1
- package/src/tools/{composio-mastra.ts → open-connector-mastra.ts} +58 -93
- package/src/tools/open-connector-mcp.ts +170 -0
- package/src/tools/search/doc-utils.ts +36 -8
- package/src/tools/search/metaSearchAgent.ts +11 -0
- package/src/tools/search/search-handlers.ts +13 -1
- package/src/tools/search/suggestionGeneratorAgent.ts +5 -3
- package/src/tools/composio-mcp.ts +0 -205
|
@@ -14,15 +14,40 @@ import type {
|
|
|
14
14
|
} from "../types";
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* Drizzle
|
|
17
|
+
* The Drizzle table passed to {@link DrizzleMemoryStorage} must expose these
|
|
18
|
+
* columns (see {@link createMemorySchema} for the expected shape).
|
|
19
|
+
*/
|
|
20
|
+
export interface MemoryTable {
|
|
21
|
+
id: any;
|
|
22
|
+
user_id: any;
|
|
23
|
+
memory_type: any;
|
|
24
|
+
content: any;
|
|
25
|
+
importance: any;
|
|
26
|
+
access_count: any;
|
|
27
|
+
metadata: any;
|
|
28
|
+
created_at: any;
|
|
29
|
+
updated_at: any;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Drizzle-based storage adapter.
|
|
34
|
+
*
|
|
35
|
+
* Pass the Drizzle database instance and the memory table object defined in
|
|
36
|
+
* your schema (not a table-name string) so queries reference real columns:
|
|
37
|
+
*
|
|
38
|
+
* ```ts
|
|
39
|
+
* import { sqliteTable, text, integer, real } from "drizzle-orm/sqlite-core";
|
|
40
|
+
* const userMemories = sqliteTable("user_memories", { ... });
|
|
41
|
+
* const storage = new DrizzleMemoryStorage(db, userMemories);
|
|
42
|
+
* ```
|
|
18
43
|
*/
|
|
19
44
|
export class DrizzleMemoryStorage implements IMemoryStorage {
|
|
20
45
|
private db: any;
|
|
21
|
-
private
|
|
46
|
+
private table: MemoryTable & Record<string, any>;
|
|
22
47
|
|
|
23
|
-
constructor(db: any,
|
|
48
|
+
constructor(db: any, table: MemoryTable & Record<string, any>) {
|
|
24
49
|
this.db = db;
|
|
25
|
-
this.
|
|
50
|
+
this.table = table;
|
|
26
51
|
}
|
|
27
52
|
|
|
28
53
|
/**
|
|
@@ -36,7 +61,7 @@ export class DrizzleMemoryStorage implements IMemoryStorage {
|
|
|
36
61
|
metadata?: Record<string, any>,
|
|
37
62
|
): Promise<string> {
|
|
38
63
|
const result = await this.db
|
|
39
|
-
.insert(this.
|
|
64
|
+
.insert(this.table)
|
|
40
65
|
.values({
|
|
41
66
|
user_id: userId,
|
|
42
67
|
memory_type: memoryType,
|
|
@@ -47,7 +72,7 @@ export class DrizzleMemoryStorage implements IMemoryStorage {
|
|
|
47
72
|
created_at: new Date(),
|
|
48
73
|
updated_at: new Date(),
|
|
49
74
|
})
|
|
50
|
-
.returning({ id:
|
|
75
|
+
.returning({ id: this.table.id });
|
|
51
76
|
|
|
52
77
|
return result[0]?.id;
|
|
53
78
|
}
|
|
@@ -61,31 +86,35 @@ export class DrizzleMemoryStorage implements IMemoryStorage {
|
|
|
61
86
|
limit: number = 10,
|
|
62
87
|
options: MemorySearchOptions = {},
|
|
63
88
|
): Promise<MemoryRecord[]> {
|
|
64
|
-
const conditions = [eq(
|
|
89
|
+
const conditions = [eq(this.table.user_id, userId)];
|
|
65
90
|
|
|
66
91
|
if (query && query.trim()) {
|
|
67
|
-
conditions.push(like(
|
|
92
|
+
conditions.push(like(this.table.content, `%${query}%`));
|
|
68
93
|
}
|
|
69
94
|
|
|
70
95
|
if (options.memoryType) {
|
|
71
|
-
conditions.push(eq(
|
|
96
|
+
conditions.push(eq(this.table.memory_type, options.memoryType));
|
|
72
97
|
}
|
|
73
98
|
|
|
74
99
|
const results = await this.db
|
|
75
100
|
.select({
|
|
76
|
-
id:
|
|
77
|
-
user_id:
|
|
78
|
-
memory_type:
|
|
79
|
-
content:
|
|
80
|
-
importance:
|
|
81
|
-
access_count:
|
|
82
|
-
metadata:
|
|
83
|
-
created_at:
|
|
84
|
-
updated_at:
|
|
101
|
+
id: this.table.id,
|
|
102
|
+
user_id: this.table.user_id,
|
|
103
|
+
memory_type: this.table.memory_type,
|
|
104
|
+
content: this.table.content,
|
|
105
|
+
importance: this.table.importance,
|
|
106
|
+
access_count: this.table.access_count,
|
|
107
|
+
metadata: this.table.metadata,
|
|
108
|
+
created_at: this.table.created_at,
|
|
109
|
+
updated_at: this.table.updated_at,
|
|
85
110
|
})
|
|
86
|
-
.from(this.
|
|
111
|
+
.from(this.table)
|
|
87
112
|
.where(and(...conditions))
|
|
88
|
-
.orderBy(
|
|
113
|
+
.orderBy(
|
|
114
|
+
desc(this.table.importance),
|
|
115
|
+
desc(this.table.access_count),
|
|
116
|
+
desc(this.table.updated_at),
|
|
117
|
+
)
|
|
89
118
|
.limit(Math.min(limit, 50)); // Cap at 50 for performance
|
|
90
119
|
|
|
91
120
|
return results as MemoryRecord[];
|
|
@@ -110,13 +139,15 @@ export class DrizzleMemoryStorage implements IMemoryStorage {
|
|
|
110
139
|
return [];
|
|
111
140
|
}
|
|
112
141
|
|
|
113
|
-
const conditions = searchTerms.map((term) =>
|
|
142
|
+
const conditions = searchTerms.map((term) =>
|
|
143
|
+
like(this.table.content, `%${term}%`),
|
|
144
|
+
);
|
|
114
145
|
|
|
115
146
|
const results = await this.db
|
|
116
147
|
.select()
|
|
117
|
-
.from(this.
|
|
118
|
-
.where(and(eq(
|
|
119
|
-
.orderBy(desc(
|
|
148
|
+
.from(this.table)
|
|
149
|
+
.where(and(eq(this.table.user_id, userId), or(...conditions)))
|
|
150
|
+
.orderBy(desc(this.table.importance), desc(this.table.updated_at))
|
|
120
151
|
.limit(limit);
|
|
121
152
|
|
|
122
153
|
return results as MemoryRecord[];
|
|
@@ -134,7 +165,7 @@ export class DrizzleMemoryStorage implements IMemoryStorage {
|
|
|
134
165
|
|
|
135
166
|
if (updates.access_count !== undefined) {
|
|
136
167
|
if (typeof updates.access_count === "object" && updates.access_count.increment) {
|
|
137
|
-
updateData.access_count = sql
|
|
168
|
+
updateData.access_count = sql`${this.table.access_count} + ${updates.access_count.increment}`;
|
|
138
169
|
} else {
|
|
139
170
|
updateData.access_count = updates.access_count;
|
|
140
171
|
}
|
|
@@ -148,14 +179,14 @@ export class DrizzleMemoryStorage implements IMemoryStorage {
|
|
|
148
179
|
updateData.metadata = updates.metadata;
|
|
149
180
|
}
|
|
150
181
|
|
|
151
|
-
await this.db.update(this.
|
|
182
|
+
await this.db.update(this.table).set(updateData).where(eq(this.table.id, id));
|
|
152
183
|
}
|
|
153
184
|
|
|
154
185
|
/**
|
|
155
186
|
* Delete a memory record
|
|
156
187
|
*/
|
|
157
188
|
async deleteMemory(id: string): Promise<void> {
|
|
158
|
-
await this.db.delete(this.
|
|
189
|
+
await this.db.delete(this.table).where(eq(this.table.id, id));
|
|
159
190
|
}
|
|
160
191
|
|
|
161
192
|
/**
|
|
@@ -164,8 +195,8 @@ export class DrizzleMemoryStorage implements IMemoryStorage {
|
|
|
164
195
|
async getMemoryById(id: string): Promise<MemoryRecord | null> {
|
|
165
196
|
const results = await this.db
|
|
166
197
|
.select()
|
|
167
|
-
.from(this.
|
|
168
|
-
.where(eq(
|
|
198
|
+
.from(this.table)
|
|
199
|
+
.where(eq(this.table.id, id))
|
|
169
200
|
.limit(1);
|
|
170
201
|
|
|
171
202
|
return (results[0] as MemoryRecord) || null;
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* - Conflict resolution
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import {
|
|
14
|
+
import { writeLanguageResponse } from "write-language";
|
|
15
15
|
import type { IMemoryStorage } from "./storage-interface";
|
|
16
16
|
import type {
|
|
17
17
|
MemoryRecord,
|
|
@@ -422,7 +422,7 @@ export class SimpleMemory {
|
|
|
422
422
|
conversationText: string,
|
|
423
423
|
): Promise<ExtractedFact[]> {
|
|
424
424
|
try {
|
|
425
|
-
const { extract: factsResponse } = await
|
|
425
|
+
const { extract: factsResponse } = await writeLanguageResponse({
|
|
426
426
|
agent: "remember-facts",
|
|
427
427
|
chat_history: conversationText,
|
|
428
428
|
provider: "groq",
|
package/src/models/types.ts
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview
|
|
2
|
+
* @fileoverview OpenConnector + Mastra Integration
|
|
3
3
|
*
|
|
4
|
-
* Connects
|
|
5
|
-
*
|
|
4
|
+
* Connects OpenConnector's MCP endpoint to Mastra agents.
|
|
5
|
+
* OpenConnector provides the tools, Mastra provides the agent framework.
|
|
6
6
|
*
|
|
7
7
|
* Architecture:
|
|
8
|
-
* 1.
|
|
9
|
-
* 2. Configure Mastra MCPClient with URL + headers
|
|
8
|
+
* 1. Connect to OpenConnector Worker URL at /mcp/sse
|
|
9
|
+
* 2. Configure Mastra MCPClient with URL + auth headers
|
|
10
10
|
* 3. Get tools with mcp.listTools() or mcp.listToolsets()
|
|
11
11
|
* 4. Create Mastra Agent with tools
|
|
12
12
|
* 5. Execute agent.generate() with multi-step tool calling
|
|
13
13
|
*
|
|
14
|
-
* @see https://
|
|
14
|
+
* @see https://github.com/OpenSourceAGI/open-connector
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { Composio } from '@composio/core';
|
|
18
17
|
import { Agent } from '@mastra/core/agent';
|
|
19
18
|
import { MCPClient } from '@mastra/mcp';
|
|
20
|
-
import type { Tool } from '@mastra/core';
|
|
21
19
|
|
|
22
20
|
/**
|
|
23
|
-
* Configuration for
|
|
21
|
+
* Configuration for OpenConnector + Mastra integration
|
|
24
22
|
*/
|
|
25
|
-
export interface
|
|
26
|
-
/**
|
|
27
|
-
|
|
23
|
+
export interface OpenConnectorMastraConfig {
|
|
24
|
+
/** OpenConnector admin token */
|
|
25
|
+
adminToken: string;
|
|
26
|
+
/** Base URL of the deployed OpenConnector Worker */
|
|
27
|
+
baseUrl: string;
|
|
28
28
|
/** User ID for scoping the session */
|
|
29
29
|
userId: string;
|
|
30
|
-
/**
|
|
31
|
-
|
|
30
|
+
/** Apps to enable */
|
|
31
|
+
apps: string[];
|
|
32
32
|
/** Agent configuration */
|
|
33
33
|
agent: {
|
|
34
34
|
id: string;
|
|
@@ -42,67 +42,36 @@ export interface ComposioMastraConfig {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
45
|
+
* OpenConnector + Mastra session manager
|
|
46
46
|
* Handles MCP connection lifecycle and agent creation
|
|
47
47
|
*/
|
|
48
|
-
export class
|
|
49
|
-
private composio: Composio;
|
|
48
|
+
export class OpenConnectorMastraSession {
|
|
50
49
|
private mcpClient: MCPClient | null = null;
|
|
51
50
|
private agent: Agent | null = null;
|
|
52
|
-
private sessionEndpoint: { url: string; headers: Record<string, string> } | null =
|
|
53
|
-
null;
|
|
54
51
|
|
|
55
|
-
constructor(private config:
|
|
56
|
-
this.composio = new Composio({
|
|
57
|
-
apiKey: config.composioApiKey,
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Create Composio Tool Router session
|
|
63
|
-
* Returns MCP endpoint URL + auth headers
|
|
64
|
-
*/
|
|
65
|
-
private async createSession() {
|
|
66
|
-
if (this.sessionEndpoint) {
|
|
67
|
-
return this.sessionEndpoint;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Create Composio session with specified toolkits
|
|
71
|
-
const session = await this.composio.toolsets.create({
|
|
72
|
-
userId: this.config.userId,
|
|
73
|
-
toolkits: this.config.toolkits,
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
this.sessionEndpoint = {
|
|
77
|
-
url: session.mcp.url,
|
|
78
|
-
headers: {
|
|
79
|
-
'x-api-key': this.config.composioApiKey,
|
|
80
|
-
...session.mcp.headers,
|
|
81
|
-
},
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
return this.sessionEndpoint;
|
|
85
|
-
}
|
|
52
|
+
constructor(private config: OpenConnectorMastraConfig) {}
|
|
86
53
|
|
|
87
54
|
/**
|
|
88
55
|
* Get or create Mastra MCP client
|
|
89
|
-
* Connects to
|
|
56
|
+
* Connects to OpenConnector's MCP endpoint via HTTP
|
|
90
57
|
*/
|
|
91
58
|
async getMCPClient(): Promise<MCPClient> {
|
|
92
59
|
if (this.mcpClient) {
|
|
93
60
|
return this.mcpClient;
|
|
94
61
|
}
|
|
95
62
|
|
|
96
|
-
const
|
|
63
|
+
const mcpUrl = `${this.config.baseUrl}/mcp/sse`;
|
|
97
64
|
|
|
98
65
|
// Create Mastra MCP client
|
|
99
66
|
this.mcpClient = new MCPClient({
|
|
100
|
-
id: `
|
|
67
|
+
id: `open-connector-${this.config.userId}`,
|
|
101
68
|
servers: {
|
|
102
|
-
|
|
103
|
-
url: new URL(
|
|
69
|
+
openconnector: {
|
|
70
|
+
url: new URL(mcpUrl),
|
|
104
71
|
requestInit: {
|
|
105
|
-
headers:
|
|
72
|
+
headers: {
|
|
73
|
+
Authorization: `Bearer ${this.config.adminToken}`,
|
|
74
|
+
},
|
|
106
75
|
},
|
|
107
76
|
},
|
|
108
77
|
},
|
|
@@ -112,16 +81,16 @@ export class ComposioMastraSession {
|
|
|
112
81
|
}
|
|
113
82
|
|
|
114
83
|
/**
|
|
115
|
-
* Get tools from
|
|
84
|
+
* Get tools from OpenConnector MCP
|
|
116
85
|
* Use for static agent setup (same tools for all requests)
|
|
117
86
|
*/
|
|
118
|
-
async getTools()
|
|
87
|
+
async getTools() {
|
|
119
88
|
const mcp = await this.getMCPClient();
|
|
120
89
|
return await mcp.listTools();
|
|
121
90
|
}
|
|
122
91
|
|
|
123
92
|
/**
|
|
124
|
-
* Get toolsets from
|
|
93
|
+
* Get toolsets from OpenConnector MCP
|
|
125
94
|
* Use for dynamic per-request tool configuration
|
|
126
95
|
*/
|
|
127
96
|
async getToolsets() {
|
|
@@ -130,7 +99,7 @@ export class ComposioMastraSession {
|
|
|
130
99
|
}
|
|
131
100
|
|
|
132
101
|
/**
|
|
133
|
-
* Create or get Mastra agent with
|
|
102
|
+
* Create or get Mastra agent with OpenConnector tools
|
|
134
103
|
* Agent is cached and reused across generate() calls
|
|
135
104
|
*/
|
|
136
105
|
async getAgent(): Promise<Agent> {
|
|
@@ -163,7 +132,8 @@ export class ComposioMastraSession {
|
|
|
163
132
|
prompt: string,
|
|
164
133
|
options?: {
|
|
165
134
|
maxSteps?: number;
|
|
166
|
-
context
|
|
135
|
+
/** Extra context messages passed to the agent (model messages) */
|
|
136
|
+
context?: any[];
|
|
167
137
|
}
|
|
168
138
|
) {
|
|
169
139
|
const agent = await this.getAgent();
|
|
@@ -184,20 +154,20 @@ export class ComposioMastraSession {
|
|
|
184
154
|
this.mcpClient = null;
|
|
185
155
|
}
|
|
186
156
|
this.agent = null;
|
|
187
|
-
this.sessionEndpoint = null;
|
|
188
157
|
}
|
|
189
158
|
}
|
|
190
159
|
|
|
191
160
|
/**
|
|
192
|
-
* Quick helper to create
|
|
161
|
+
* Quick helper to create an OpenConnector + Mastra agent
|
|
193
162
|
* For one-off usage without session management
|
|
194
163
|
*
|
|
195
164
|
* @example
|
|
196
165
|
* ```ts
|
|
197
|
-
* const result = await
|
|
198
|
-
*
|
|
166
|
+
* const result = await createOpenConnectorMastraAgent({
|
|
167
|
+
* adminToken: process.env.OPEN_CONNECTOR_ADMIN_TOKEN!,
|
|
168
|
+
* baseUrl: 'https://open-connector.example.workers.dev',
|
|
199
169
|
* userId: 'user-123',
|
|
200
|
-
*
|
|
170
|
+
* apps: ['gmail', 'slack'],
|
|
201
171
|
* agent: {
|
|
202
172
|
* id: 'email-agent',
|
|
203
173
|
* name: 'Email Assistant',
|
|
@@ -207,20 +177,23 @@ export class ComposioMastraSession {
|
|
|
207
177
|
* }).generate('Check my unread emails');
|
|
208
178
|
* ```
|
|
209
179
|
*/
|
|
210
|
-
export async function
|
|
211
|
-
|
|
180
|
+
export async function createOpenConnectorMastraAgent(
|
|
181
|
+
config: OpenConnectorMastraConfig
|
|
182
|
+
) {
|
|
183
|
+
const session = new OpenConnectorMastraSession(config);
|
|
212
184
|
await session.getAgent(); // Initialize
|
|
213
185
|
return session;
|
|
214
186
|
}
|
|
215
187
|
|
|
216
188
|
/**
|
|
217
|
-
* Create Mastra agent with dynamic per-request
|
|
189
|
+
* Create Mastra agent with dynamic per-request apps
|
|
218
190
|
* Better for multi-user scenarios where tools vary per request
|
|
219
191
|
*
|
|
220
192
|
* @example
|
|
221
193
|
* ```ts
|
|
222
|
-
* const agent = await
|
|
223
|
-
*
|
|
194
|
+
* const agent = await createDynamicOpenConnectorAgent({
|
|
195
|
+
* adminToken: process.env.OPEN_CONNECTOR_ADMIN_TOKEN!,
|
|
196
|
+
* baseUrl: 'https://open-connector.example.workers.dev',
|
|
224
197
|
* agent: {
|
|
225
198
|
* id: 'dynamic-agent',
|
|
226
199
|
* name: 'Dynamic Assistant',
|
|
@@ -229,16 +202,17 @@ export async function createComposioMastraAgent(config: ComposioMastraConfig) {
|
|
|
229
202
|
* },
|
|
230
203
|
* });
|
|
231
204
|
*
|
|
232
|
-
* // Each request can have different userId/
|
|
205
|
+
* // Each request can have different userId/apps
|
|
233
206
|
* const result = await agent.generate({
|
|
234
207
|
* userId: 'user-123',
|
|
235
|
-
*
|
|
208
|
+
* apps: ['gmail'],
|
|
236
209
|
* prompt: 'Check emails',
|
|
237
210
|
* });
|
|
238
211
|
* ```
|
|
239
212
|
*/
|
|
240
|
-
export async function
|
|
241
|
-
|
|
213
|
+
export async function createDynamicOpenConnectorAgent(config: {
|
|
214
|
+
adminToken: string;
|
|
215
|
+
baseUrl: string;
|
|
242
216
|
agent: {
|
|
243
217
|
id: string;
|
|
244
218
|
name: string;
|
|
@@ -247,33 +221,24 @@ export async function createDynamicComposioAgent(config: {
|
|
|
247
221
|
maxSteps?: number;
|
|
248
222
|
};
|
|
249
223
|
}) {
|
|
250
|
-
const composio = new Composio({
|
|
251
|
-
apiKey: config.composioApiKey,
|
|
252
|
-
});
|
|
253
|
-
|
|
254
224
|
return {
|
|
255
225
|
async generate(params: {
|
|
256
226
|
userId: string;
|
|
257
|
-
|
|
227
|
+
apps: string[];
|
|
258
228
|
prompt: string;
|
|
259
229
|
maxSteps?: number;
|
|
260
230
|
}) {
|
|
261
|
-
|
|
262
|
-
const session = await composio.toolsets.create({
|
|
263
|
-
userId: params.userId,
|
|
264
|
-
toolkits: params.toolkits,
|
|
265
|
-
});
|
|
231
|
+
const mcpUrl = `${config.baseUrl}/mcp/sse`;
|
|
266
232
|
|
|
267
233
|
// Connect MCP client
|
|
268
234
|
const mcp = new MCPClient({
|
|
269
|
-
id: `
|
|
235
|
+
id: `open-connector-${params.userId}`,
|
|
270
236
|
servers: {
|
|
271
|
-
|
|
272
|
-
url: new URL(
|
|
237
|
+
openconnector: {
|
|
238
|
+
url: new URL(mcpUrl),
|
|
273
239
|
requestInit: {
|
|
274
240
|
headers: {
|
|
275
|
-
|
|
276
|
-
...session.mcp.headers,
|
|
241
|
+
Authorization: `Bearer ${config.adminToken}`,
|
|
277
242
|
},
|
|
278
243
|
},
|
|
279
244
|
},
|
|
@@ -284,18 +249,18 @@ export async function createDynamicComposioAgent(config: {
|
|
|
284
249
|
// Get toolsets for this request
|
|
285
250
|
const toolsets = await mcp.listToolsets();
|
|
286
251
|
|
|
287
|
-
// Create agent
|
|
252
|
+
// Create agent; toolsets are provided per-request at generate time
|
|
288
253
|
const agent = new Agent({
|
|
289
254
|
id: config.agent.id,
|
|
290
255
|
name: config.agent.name,
|
|
291
256
|
instructions: config.agent.instructions,
|
|
292
257
|
model: config.agent.model,
|
|
293
|
-
toolsets,
|
|
294
258
|
});
|
|
295
259
|
|
|
296
|
-
// Execute
|
|
260
|
+
// Execute with dynamic toolsets
|
|
297
261
|
return await agent.generate(params.prompt, {
|
|
298
262
|
maxSteps: params.maxSteps || config.agent.maxSteps || 5,
|
|
263
|
+
toolsets,
|
|
299
264
|
});
|
|
300
265
|
} finally {
|
|
301
266
|
await mcp.disconnect();
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview OpenConnector MCP Integration for AI SDK v5
|
|
3
|
+
*
|
|
4
|
+
* OpenConnector is a self-hosted Cloudflare Workers integration platform
|
|
5
|
+
* that provides OAuth-managed access to 100+ apps. This module creates
|
|
6
|
+
* MCP clients connected to OpenConnector's HTTP endpoints, fetches
|
|
7
|
+
* available tools, and passes them to AI SDK models.
|
|
8
|
+
*
|
|
9
|
+
* Architecture:
|
|
10
|
+
* 1. Connect to OpenConnector Worker URL at /mcp/sse
|
|
11
|
+
* 2. Authenticate with admin token via Authorization header
|
|
12
|
+
* 3. Fetch tools with client.tools()
|
|
13
|
+
* 4. Pass to streamText/generateText
|
|
14
|
+
*
|
|
15
|
+
* @see https://github.com/OpenSourceAGI/open-connector
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { createMCPClient } from '@ai-sdk/mcp';
|
|
19
|
+
import type { MCPClient } from '@ai-sdk/mcp';
|
|
20
|
+
import type { ToolSet } from 'ai';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Configuration for OpenConnector MCP session
|
|
24
|
+
*/
|
|
25
|
+
export interface OpenConnectorMCPConfig {
|
|
26
|
+
/** OpenConnector admin token (OPEN_CONNECTOR_ADMIN_TOKEN) */
|
|
27
|
+
adminToken: string;
|
|
28
|
+
/** Base URL of the deployed OpenConnector Worker */
|
|
29
|
+
baseUrl: string;
|
|
30
|
+
/** User ID to scope the session */
|
|
31
|
+
userId: string;
|
|
32
|
+
/** Apps to enable (e.g., ['gmail', 'notion', 'slack']) */
|
|
33
|
+
apps: string[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* OpenConnector MCP session wrapper
|
|
38
|
+
* Manages the lifecycle of MCP client connections to OpenConnector
|
|
39
|
+
*/
|
|
40
|
+
export class OpenConnectorMCPSession {
|
|
41
|
+
private client: MCPClient | null = null;
|
|
42
|
+
|
|
43
|
+
constructor(private config: OpenConnectorMCPConfig) {}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Get or create the MCP client connection
|
|
47
|
+
* Uses HTTP SSE transport as provided by OpenConnector
|
|
48
|
+
*/
|
|
49
|
+
async getClient(): Promise<MCPClient> {
|
|
50
|
+
if (this.client) {
|
|
51
|
+
return this.client;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Construct MCP endpoint URL
|
|
55
|
+
const mcpUrl = `${this.config.baseUrl}/mcp/sse`;
|
|
56
|
+
|
|
57
|
+
// Connect to OpenConnector MCP endpoint via HTTP
|
|
58
|
+
this.client = await createMCPClient({
|
|
59
|
+
transport: {
|
|
60
|
+
type: 'http',
|
|
61
|
+
url: mcpUrl,
|
|
62
|
+
headers: {
|
|
63
|
+
Authorization: `Bearer ${this.config.adminToken}`,
|
|
64
|
+
},
|
|
65
|
+
redirect: 'error',
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
return this.client;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Get all available tools from OpenConnector MCP
|
|
74
|
+
* These tools can be passed directly to streamText/generateText
|
|
75
|
+
*
|
|
76
|
+
* @returns Tools object compatible with AI SDK
|
|
77
|
+
*/
|
|
78
|
+
async getTools(): Promise<ToolSet> {
|
|
79
|
+
const client = await this.getClient();
|
|
80
|
+
return (await client.tools()) as ToolSet;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Close the MCP connection
|
|
85
|
+
* Should be called after request completion or in finally block
|
|
86
|
+
*/
|
|
87
|
+
async close() {
|
|
88
|
+
if (this.client) {
|
|
89
|
+
await this.client.close();
|
|
90
|
+
this.client = null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Health check for the OpenConnector Worker
|
|
96
|
+
*/
|
|
97
|
+
async healthCheck(): Promise<boolean> {
|
|
98
|
+
try {
|
|
99
|
+
const response = await fetch(`${this.config.baseUrl}/health`, {
|
|
100
|
+
headers: {
|
|
101
|
+
Authorization: `Bearer ${this.config.adminToken}`,
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
return response.ok;
|
|
105
|
+
} catch {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Helper function to create a one-shot OpenConnector MCP session
|
|
113
|
+
* For quick tool usage without managing session lifecycle
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```ts
|
|
117
|
+
* const tools = await getOpenConnectorTools({
|
|
118
|
+
* adminToken: process.env.OPEN_CONNECTOR_ADMIN_TOKEN!,
|
|
119
|
+
* baseUrl: 'https://open-connector.example.workers.dev',
|
|
120
|
+
* userId: 'user-123',
|
|
121
|
+
* apps: ['gmail', 'slack'],
|
|
122
|
+
* });
|
|
123
|
+
*
|
|
124
|
+
* const result = await generateText({
|
|
125
|
+
* model: openai('gpt-4o'),
|
|
126
|
+
* prompt: 'Check my unread emails',
|
|
127
|
+
* tools,
|
|
128
|
+
* });
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
export async function getOpenConnectorTools(
|
|
132
|
+
config: OpenConnectorMCPConfig
|
|
133
|
+
): Promise<ToolSet> {
|
|
134
|
+
const session = new OpenConnectorMCPSession(config);
|
|
135
|
+
try {
|
|
136
|
+
return await session.getTools();
|
|
137
|
+
} finally {
|
|
138
|
+
await session.close();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Create a reusable OpenConnector MCP session
|
|
144
|
+
* Better for multiple requests with the same apps
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```ts
|
|
148
|
+
* const session = await createOpenConnectorSession({
|
|
149
|
+
* adminToken: process.env.OPEN_CONNECTOR_ADMIN_TOKEN!,
|
|
150
|
+
* baseUrl: 'https://open-connector.example.workers.dev',
|
|
151
|
+
* userId: 'user-123',
|
|
152
|
+
* apps: ['gmail', 'notion'],
|
|
153
|
+
* });
|
|
154
|
+
*
|
|
155
|
+
* try {
|
|
156
|
+
* const tools = await session.getTools();
|
|
157
|
+
* const result = await streamText({ model, messages, tools });
|
|
158
|
+
* } finally {
|
|
159
|
+
* await session.close();
|
|
160
|
+
* }
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
export async function createOpenConnectorSession(
|
|
164
|
+
config: OpenConnectorMCPConfig
|
|
165
|
+
): Promise<OpenConnectorMCPSession> {
|
|
166
|
+
const session = new OpenConnectorMCPSession(config);
|
|
167
|
+
// Pre-initialize the connection
|
|
168
|
+
await session.getClient();
|
|
169
|
+
return session;
|
|
170
|
+
}
|