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.
Files changed (68) hide show
  1. package/README.md +6 -6
  2. package/dist/config/config-manager.d.ts +23 -0
  3. package/dist/config/config-types.d.ts +58 -0
  4. package/dist/config/environment-variables.d.ts +6 -0
  5. package/dist/config/index.d.ts +18 -0
  6. package/dist/config/language-models-database.d.ts +93 -0
  7. package/dist/config/mcp-server-registry.d.ts +7 -0
  8. package/dist/config/model-registry.d.ts +69 -0
  9. package/dist/config/model-tester.d.ts +51 -0
  10. package/dist/config/model-utils.d.ts +44 -0
  11. package/dist/config/provider-ui-config.d.ts +6 -0
  12. package/dist/index.d.ts +23 -0
  13. package/dist/memory/agent-memory-manager.d.ts +125 -0
  14. package/dist/memory/example.d.ts +36 -0
  15. package/dist/memory/index.d.ts +18 -0
  16. package/dist/memory/mastra-integration.d.ts +146 -0
  17. package/dist/memory/storage/drizzle-storage.d.ts +82 -0
  18. package/dist/memory/storage/in-memory-storage.d.ts +75 -0
  19. package/dist/memory/storage/storage-interface.d.ts +37 -0
  20. package/dist/memory/types.d.ts +122 -0
  21. package/dist/models/providers.d.ts +5 -0
  22. package/dist/models/registry.d.ts +4 -0
  23. package/dist/models/types.d.ts +4 -0
  24. package/dist/research-agent.cjs.js +2 -0
  25. package/dist/research-agent.cjs.js.map +1 -0
  26. package/dist/research-agent.es.js +2 -0
  27. package/dist/research-agent.es.js.map +1 -0
  28. package/dist/search.d.ts +5 -0
  29. package/dist/tools/index.d.ts +12 -0
  30. package/dist/tools/open-connector-mastra.d.ts +137 -0
  31. package/dist/tools/open-connector-mcp.d.ts +88 -0
  32. package/dist/tools/qwksearch-api-tools.d.ts +149 -0
  33. package/dist/tools/search/doc-utils.d.ts +11 -0
  34. package/dist/tools/search/document.d.ts +14 -0
  35. package/dist/tools/search/index.d.ts +12 -0
  36. package/dist/tools/search/link-summarizer.d.ts +7 -0
  37. package/dist/tools/search/meta-search-types.d.ts +50 -0
  38. package/dist/tools/search/metaSearchAgent.d.ts +21 -0
  39. package/dist/tools/search/search-handlers.d.ts +27 -0
  40. package/dist/tools/search/suggestionGeneratorAgent.d.ts +8 -0
  41. package/dist/types.d.ts +2 -0
  42. package/dist/utils/chat-helpers.d.ts +10 -0
  43. package/dist/utils/index.d.ts +2 -0
  44. package/dist/utils/markdown-to-html.d.ts +5 -0
  45. package/dist/utils/outputParser.d.ts +22 -0
  46. package/dist/utils/provider-image-cropper.d.ts +120 -0
  47. package/package.json +14 -5
  48. package/src/config/config-manager.ts +0 -8
  49. package/src/config/environment-variables.ts +11 -3
  50. package/src/config/language-models-database.ts +50 -42
  51. package/src/config/model-registry.ts +20 -5
  52. package/src/config/model-tester.ts +2 -2
  53. package/src/connectors/{composio.json → open-connector.json} +21 -45
  54. package/src/index.ts +3 -0
  55. package/src/memory/ARCHITECTURE.md +1 -1
  56. package/src/memory/example.ts +6 -6
  57. package/src/memory/mastra-integration.ts +6 -11
  58. package/src/memory/storage/drizzle-storage.ts +60 -29
  59. package/src/memory/storage/in-memory-storage.ts +2 -2
  60. package/src/memory/storage/storage-interface.ts +1 -1
  61. package/src/models/types.ts +1 -1
  62. package/src/tools/{composio-mastra.ts → open-connector-mastra.ts} +58 -93
  63. package/src/tools/open-connector-mcp.ts +170 -0
  64. package/src/tools/search/doc-utils.ts +36 -8
  65. package/src/tools/search/metaSearchAgent.ts +11 -0
  66. package/src/tools/search/search-handlers.ts +13 -1
  67. package/src/tools/search/suggestionGeneratorAgent.ts +5 -3
  68. package/src/tools/composio-mcp.ts +0 -205
@@ -3,8 +3,13 @@
3
3
  * @description Document utilities: fallback docs, reranking, and formatting.
4
4
  */
5
5
  import type { Document } from "./document";
6
- import path from "node:path";
7
- import fs from "node:fs";
6
+
7
+ export interface R2CredentialsInput {
8
+ accountId: string;
9
+ accessKeyId: string;
10
+ secretAccessKey: string;
11
+ bucket: string;
12
+ }
8
13
 
9
14
  export function buildFallbackDocs(query: string): Document[] {
10
15
  const trimmedQuery = (query || "").trim();
@@ -31,22 +36,45 @@ export function normalizeSourcesOutput(output: unknown, query: string): Document
31
36
  return buildFallbackDocs(query);
32
37
  }
33
38
 
39
+ async function downloadExtractedContent(fileId: string, r2Credentials: R2CredentialsInput): Promise<{ title: string; content: string } | null> {
40
+ try {
41
+ const { manageStorage } = await import("manage-storage");
42
+ const config = {
43
+ provider: "cloudflare" as const,
44
+ BUCKET_NAME: r2Credentials.bucket,
45
+ ACCESS_KEY_ID: r2Credentials.accessKeyId,
46
+ SECRET_ACCESS_KEY: r2Credentials.secretAccessKey,
47
+ BUCKET_URL: `https://${r2Credentials.accountId}.r2.cloudflarestorage.com`,
48
+ };
49
+ const extractedKey = `${fileId}-extracted.json`;
50
+ const data = await manageStorage("download", { ...config, key: extractedKey });
51
+ const parsed = JSON.parse(data);
52
+ return { title: parsed.title || "Uploaded Document", content: parsed.content || "" };
53
+ } catch (error) {
54
+ console.error(`[rerankDocs] Failed to download extracted content for fileId ${fileId}:`, error);
55
+ return null;
56
+ }
57
+ }
58
+
34
59
  export async function rerankDocs(
35
60
  query: string,
36
61
  docs: Document[],
37
62
  fileIds: string[],
38
63
  optimizationMode: "speed" | "balanced" | "quality",
64
+ r2Credentials?: R2CredentialsInput,
39
65
  ): Promise<Document[]> {
40
66
  if (docs.length === 0 && fileIds.length === 0) {
41
67
  return docs;
42
68
  }
43
69
 
44
- const filesData = fileIds.map((file) => {
45
- const filePath = path.join(process.cwd(), "uploads", file);
46
- const contentPath = filePath + "-extracted.json";
47
- const content = JSON.parse(fs.readFileSync(contentPath, "utf8"));
48
- return { fileName: content.title, content: content.content };
49
- });
70
+ let filesData: { fileName: string; content: string }[] = [];
71
+
72
+ if (fileIds.length > 0 && r2Credentials) {
73
+ const results = await Promise.all(
74
+ fileIds.map((fileId) => downloadExtractedContent(fileId, r2Credentials))
75
+ );
76
+ filesData = results.filter((r) => r !== null) as { fileName: string; content: string }[];
77
+ }
50
78
 
51
79
  if (query.toLocaleLowerCase() === "summarize") {
52
80
  return docs.slice(0, 15);
@@ -35,6 +35,7 @@ import {
35
35
  rerankDocs,
36
36
  processDocs,
37
37
  normalizeSourcesOutput,
38
+ type R2CredentialsInput,
38
39
  } from "./doc-utils";
39
40
  import { groupAndSummarizeDocs } from "./link-summarizer";
40
41
 
@@ -350,11 +351,21 @@ class MetaSearchAgent implements MetaSearchAgentType {
350
351
  docs = result.docs;
351
352
  }
352
353
 
354
+ const r2Credentials: R2CredentialsInput | undefined = process.env.R2_ACCOUNT_ID
355
+ ? {
356
+ accountId: process.env.R2_ACCOUNT_ID,
357
+ accessKeyId: process.env.R2_ACCESS_KEY_ID || "",
358
+ secretAccessKey: process.env.R2_SECRET_ACCESS_KEY || "",
359
+ bucket: process.env.R2_UPLOADS_BUCKET || "qwksearch-uploads",
360
+ }
361
+ : undefined;
362
+
353
363
  const sortedDocs = await rerankDocs(
354
364
  query,
355
365
  docs ?? [],
356
366
  fileIds,
357
367
  optimizationMode,
368
+ r2Credentials,
358
369
  );
359
370
 
360
371
  const sources = normalizeSourcesOutput(sortedDocs, message);
@@ -7,9 +7,21 @@
7
7
  * See extract-webpage/src/search/index.ts for an example.
8
8
  */
9
9
  import MetaSearchAgent from "./metaSearchAgent";
10
- import prompts from "write-language/prompts/search-prompts";
10
+ import {
11
+ webSearchRetrieverPrompt,
12
+ webSearchResponsePrompt,
13
+ webSearchRetrieverFewShots,
14
+ writingAssistantPrompt,
15
+ } from "write-language";
11
16
  import type { Config } from "./meta-search-types";
12
17
 
18
+ const prompts = {
19
+ webSearchRetrieverPrompt,
20
+ webSearchResponsePrompt,
21
+ webSearchRetrieverFewShots,
22
+ writingAssistantPrompt,
23
+ };
24
+
13
25
  /**
14
26
  * Creates search handler instances with provided search functions.
15
27
  * Pass in search functions from extract-webpage to enable web search.
@@ -8,8 +8,8 @@ import { LineListOutputParser } from "../../utils/outputParser";
8
8
  import { formatChatHistoryAsString } from "../../utils";
9
9
  import type { ChatTurnMessage } from "./meta-search-types";
10
10
 
11
- const suggestionGeneratorPrompt = `
12
- You are an AI suggestion generator for an AI powered search engine. You will be given a conversation below. You need to generate 4-5 suggestions based on the conversation. The suggestion should be relevant to the conversation that can be used by the user to ask the chat model for more information.
11
+ const createSuggestionGeneratorPrompt = (maxQuestions: number = 4) => `
12
+ You are an AI suggestion generator for an AI powered search engine. You will be given a conversation below. You need to generate ${maxQuestions} suggestions based on the conversation. The suggestion should be relevant to the conversation that can be used by the user to ask the chat model for more information.
13
13
  You need to make sure the suggestions are relevant to the conversation and are helpful to the user. Keep a note that the user might use these suggestions to ask a chat model for more information.
14
14
  Make sure the suggestions are medium in length and are informative and relevant to the conversation.
15
15
 
@@ -27,6 +27,7 @@ Conversation:
27
27
 
28
28
  type SuggestionGeneratorInput = {
29
29
  chat_history: ChatTurnMessage[];
30
+ maxQuestions?: number;
30
31
  };
31
32
 
32
33
  const outputParser = new LineListOutputParser({
@@ -37,7 +38,8 @@ const generateSuggestions = async (
37
38
  input: SuggestionGeneratorInput,
38
39
  llm: LanguageModel,
39
40
  ): Promise<string[]> => {
40
- const prompt = suggestionGeneratorPrompt.replace(
41
+ const maxQuestions = input.maxQuestions ?? 4;
42
+ const prompt = createSuggestionGeneratorPrompt(maxQuestions).replace(
41
43
  "{chat_history}",
42
44
  formatChatHistoryAsString(input.chat_history),
43
45
  );
@@ -1,205 +0,0 @@
1
- /**
2
- * @fileoverview Composio MCP Integration for AI SDK v5
3
- *
4
- * Composio provides dynamic MCP endpoints through sessions/Tool Router.
5
- * This module creates MCP clients connected to Composio's HTTP endpoints,
6
- * fetches available tools, and passes them to AI SDK models.
7
- *
8
- * Architecture:
9
- * 1. Create Composio session → Get MCP URL + headers
10
- * 2. Connect with createMCPClient (HTTP transport)
11
- * 3. Fetch tools with client.tools()
12
- * 4. Pass to streamText/generateText
13
- *
14
- * @see https://composio.dev/toolkits/ai_ml_api/framework/ai-sdk
15
- * @see https://ai-sdk.dev/docs/ai-sdk-core/mcp-tools
16
- */
17
-
18
- import { Composio } from '@composio/core';
19
- import { createMCPClient } from '@ai-sdk/mcp';
20
- import type { MCPClient } from '@ai-sdk/mcp';
21
-
22
- /**
23
- * Configuration for Composio MCP session
24
- */
25
- export interface ComposioMCPConfig {
26
- /** Composio API key */
27
- apiKey: string;
28
- /** User ID to scope the session */
29
- userId: string;
30
- /** Toolkits to enable (e.g., ['GMAIL', 'NOTION', 'SLACK']) */
31
- toolkits: string[];
32
- /** Optional: Additional MCP headers (e.g., x-api-key if org requires it) */
33
- additionalHeaders?: Record<string, string>;
34
- }
35
-
36
- /**
37
- * Composio MCP session wrapper
38
- * Manages the lifecycle of MCP client connections to Composio
39
- */
40
- export class ComposioMCPSession {
41
- private composio: Composio;
42
- private client: MCPClient | null = null;
43
- private mcpEndpoint: { url: string; headers: Record<string, string> } | null = null;
44
-
45
- constructor(private config: ComposioMCPConfig) {
46
- this.composio = new Composio({
47
- apiKey: config.apiKey,
48
- });
49
- }
50
-
51
- /**
52
- * Create Composio Tool Router session and get MCP endpoint
53
- * This returns the HTTP URL and auth headers for the MCP server
54
- */
55
- private async getOrCreateEndpoint() {
56
- if (this.mcpEndpoint) {
57
- return this.mcpEndpoint;
58
- }
59
-
60
- // Create dynamic Composio session with specified toolkits
61
- const session = await this.composio.toolkits.authorize({
62
- userId: this.config.userId,
63
- toolkits: this.config.toolkits,
64
- });
65
-
66
- // Extract MCP endpoint info
67
- this.mcpEndpoint = {
68
- url: session.mcp.url,
69
- headers: {
70
- ...session.mcp.headers,
71
- ...this.config.additionalHeaders,
72
- },
73
- };
74
-
75
- return this.mcpEndpoint;
76
- }
77
-
78
- /**
79
- * Get or create the MCP client connection
80
- * Uses HTTP transport as recommended by Composio
81
- */
82
- async getClient(): Promise<MCPClient> {
83
- if (this.client) {
84
- return this.client;
85
- }
86
-
87
- const endpoint = await this.getOrCreateEndpoint();
88
-
89
- // Connect to Composio MCP endpoint via HTTP
90
- this.client = await createMCPClient({
91
- transport: {
92
- type: 'http',
93
- url: endpoint.url,
94
- headers: endpoint.headers,
95
- redirect: 'error',
96
- },
97
- });
98
-
99
- return this.client;
100
- }
101
-
102
- /**
103
- * Get all available tools from Composio MCP
104
- * These tools can be passed directly to streamText/generateText
105
- *
106
- * @returns Tools object compatible with AI SDK
107
- */
108
- async getTools() {
109
- const client = await this.getClient();
110
- return await client.tools();
111
- }
112
-
113
- /**
114
- * Close the MCP connection
115
- * Should be called after request completion or in finally block
116
- */
117
- async close() {
118
- if (this.client) {
119
- await this.client.close();
120
- this.client = null;
121
- }
122
- }
123
-
124
- /**
125
- * Get list of available toolkits from Composio
126
- * Useful for discovering what integrations are available
127
- */
128
- static async listAvailableToolkits(apiKey: string): Promise<string[]> {
129
- const composio = new Composio({ apiKey });
130
- const toolkits = await composio.toolkits.list();
131
- return toolkits.map((t) => t.name);
132
- }
133
-
134
- /**
135
- * Check if a user has authenticated a specific toolkit
136
- * Returns true if the user can access the toolkit's tools
137
- */
138
- async isToolkitAuthenticated(toolkit: string): Promise<boolean> {
139
- try {
140
- const integrations = await this.composio.integrations.list({
141
- appName: toolkit,
142
- });
143
- return integrations.length > 0;
144
- } catch {
145
- return false;
146
- }
147
- }
148
- }
149
-
150
- /**
151
- * Helper function to create a one-shot Composio MCP session
152
- * For quick tool usage without managing session lifecycle
153
- *
154
- * @example
155
- * ```ts
156
- * const tools = await getComposioTools({
157
- * apiKey: process.env.COMPOSIO_API_KEY!,
158
- * userId: 'user-123',
159
- * toolkits: ['GMAIL', 'SLACK'],
160
- * });
161
- *
162
- * const result = await generateText({
163
- * model: openai('gpt-4o'),
164
- * prompt: 'Check my unread emails',
165
- * tools,
166
- * });
167
- * ```
168
- */
169
- export async function getComposioTools(config: ComposioMCPConfig) {
170
- const session = new ComposioMCPSession(config);
171
- try {
172
- return await session.getTools();
173
- } finally {
174
- await session.close();
175
- }
176
- }
177
-
178
- /**
179
- * Create a reusable Composio MCP session
180
- * Better for multiple requests with the same toolkits
181
- *
182
- * @example
183
- * ```ts
184
- * const session = await createComposioSession({
185
- * apiKey: process.env.COMPOSIO_API_KEY!,
186
- * userId: 'user-123',
187
- * toolkits: ['GMAIL', 'NOTION'],
188
- * });
189
- *
190
- * try {
191
- * const tools = await session.getTools();
192
- * const result = await streamText({ model, messages, tools });
193
- * } finally {
194
- * await session.close();
195
- * }
196
- * ```
197
- */
198
- export async function createComposioSession(
199
- config: ComposioMCPConfig
200
- ): Promise<ComposioMCPSession> {
201
- const session = new ComposioMCPSession(config);
202
- // Pre-initialize the connection
203
- await session.getClient();
204
- return session;
205
- }