chat-agent-toolkit 1.2.33 → 1.2.35

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 (42) hide show
  1. package/dist/research-agent.cjs.js.map +1 -1
  2. package/dist/research-agent.es.js.map +1 -1
  3. package/package.json +1 -1
  4. package/src/config/config-manager.ts +295 -295
  5. package/src/config/config-types.ts +65 -65
  6. package/src/config/environment-variables.ts +16 -16
  7. package/src/config/index.ts +26 -26
  8. package/src/config/language-models-database.ts +1434 -1434
  9. package/src/config/mcp-server-registry.ts +24 -24
  10. package/src/config/model-registry.ts +271 -271
  11. package/src/config/model-tester.ts +211 -211
  12. package/src/config/model-utils.ts +193 -193
  13. package/src/config/provider-ui-config.ts +196 -196
  14. package/src/connectors/open-connector.json +130 -130
  15. package/src/index.ts +26 -26
  16. package/src/memory/ARCHITECTURE.md +302 -302
  17. package/src/memory/README.md +224 -224
  18. package/src/memory/agent-memory-manager.ts +416 -416
  19. package/src/memory/example.ts +343 -343
  20. package/src/memory/index.ts +47 -47
  21. package/src/memory/mastra-integration.ts +604 -604
  22. package/src/memory/storage/drizzle-storage.ts +236 -236
  23. package/src/memory/storage/in-memory-storage.ts +551 -551
  24. package/src/memory/storage/storage-interface.ts +68 -68
  25. package/src/memory/types.ts +125 -125
  26. package/src/models/types.ts +4 -4
  27. package/src/tools/index.ts +13 -13
  28. package/src/tools/open-connector-mastra.ts +270 -270
  29. package/src/tools/open-connector-mcp.ts +170 -170
  30. package/src/tools/qwksearch-api-tools.ts +326 -326
  31. package/src/tools/search/doc-utils.ts +139 -139
  32. package/src/tools/search/document.ts +47 -47
  33. package/src/tools/search/index.ts +14 -14
  34. package/src/tools/search/link-summarizer.ts +112 -112
  35. package/src/tools/search/meta-search-types.ts +62 -62
  36. package/src/tools/search/metaSearchAgent.ts +465 -465
  37. package/src/tools/search/search-handlers.ts +97 -97
  38. package/src/tools/search/suggestionGeneratorAgent.ts +56 -56
  39. package/src/types.d.ts +137 -137
  40. package/src/utils/index.ts +2 -2
  41. package/src/utils/markdown-to-html.ts +53 -53
  42. package/src/utils/outputParser.ts +73 -73
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chat-agent-toolkit",
3
- "version": "1.2.33",
3
+ "version": "1.2.35",
4
4
  "description": "Multi-provider AI agent toolkit: generate language responses, search the web, extract content, and manage memory across 10+ LLM providers.",
5
5
  "author": "vtempest <grokthiscontact@gmail.com>",
6
6
  "license": "AGPL-3.0",
@@ -1,295 +1,295 @@
1
- /**
2
- * @fileoverview Configuration Manager
3
- *
4
- * Manages model providers, MCP servers, and search configuration in memory.
5
- * Handles environment variable loading, provider hashing, and config updates.
6
- */
7
- import type { ConfigModelProvider, MCPServerConfig, Config, UIConfigSections, Model } from "./config-types";
8
- import { getModelProvidersUIConfigSection } from "./provider-ui-config";
9
- import { getEnv } from "./environment-variables";
10
- import { LANGUAGE_MODELS } from "./language-models-database";
11
-
12
- // Maps a provider UI key (from provider-ui-config) to the matching
13
- // `provider` name in the LANGUAGE_MODELS database. Names differ in a few
14
- // cases (e.g. the "gemini" UI key corresponds to the "Google" model list).
15
- const PROVIDER_KEY_TO_DB_NAME: Record<string, string> = {
16
- openai: "openai",
17
- anthropic: "anthropic",
18
- gemini: "google",
19
- groq: "groq",
20
- deepseek: "deepseek",
21
- nvidia: "nvidia",
22
- openrouter: "openrouter",
23
- };
24
-
25
- /**
26
- * Returns the default chat models for a provider from the LANGUAGE_MODELS
27
- * database so that env-based providers expose a usable model list instead of
28
- * an empty one. Returns [] when no matching provider list exists.
29
- */
30
- const getDefaultChatModels = (providerKey: string): Model[] => {
31
- const dbName = PROVIDER_KEY_TO_DB_NAME[providerKey] ?? providerKey;
32
- const entry = LANGUAGE_MODELS.find(
33
- (p) => p.provider.toLowerCase() === dbName.toLowerCase(),
34
- );
35
- if (!entry?.models) return [];
36
-
37
- return entry.models.map((m: any) => ({
38
- name: m.name,
39
- key: m.id,
40
- }));
41
- };
42
-
43
- const hashObj = (obj: { [key: string]: any }) => {
44
- const str = JSON.stringify(obj, Object.keys(obj).sort());
45
- let hash = 0;
46
- for (let i = 0; i < str.length; i++) {
47
- hash = (hash << 5) - hash + str.charCodeAt(i);
48
- hash |= 0;
49
- }
50
- return String(Math.abs(hash).toString(36));
51
- };
52
-
53
- class ConfigManager {
54
- configVersion = 1;
55
- currentConfig: Config = {
56
- version: this.configVersion,
57
- setupComplete: getEnv("SETUP_COMPLETE") === "true" || false,
58
- preferences: {},
59
- personalization: {},
60
- modelProviders: [],
61
- mcpServers: [],
62
- search: {
63
- searxngURL: "",
64
- tavilyApiKey: "",
65
- sourceScrapeCount: 3,
66
- sourceScrapeTimeout: 5,
67
- },
68
- };
69
- uiConfigSections: UIConfigSections = {
70
- preferences: [],
71
- personalization: [],
72
- modelProviders: [],
73
- mcpServers: [],
74
- search: [
75
- {
76
- name: "SearXNG URL",
77
- key: "searxngURL",
78
- type: "string",
79
- required: false,
80
- description: "The URL of your SearXNG instance",
81
- placeholder: "http://localhost:4000",
82
- default: "",
83
- scope: "server",
84
- env: "SEARXNG_API_URL",
85
- },
86
- {
87
- name: "Tavily API Key",
88
- key: "tavilyApiKey",
89
- type: "string",
90
- required: false,
91
- description: "Your Tavily API key for enhanced search capabilities.",
92
- placeholder: "tvly-...",
93
- default: "",
94
- scope: "server",
95
- env: "TAVILY_API_KEY",
96
- },
97
- {
98
- name: "Scrape timeout (seconds)",
99
- key: "sourceScrapeTimeout",
100
- type: "select",
101
- options: [
102
- { name: "3 seconds", value: "3" },
103
- { name: "5 seconds (default)", value: "5" },
104
- { name: "10 seconds", value: "10" },
105
- { name: "15 seconds", value: "15" },
106
- { name: "20 seconds", value: "20" },
107
- ],
108
- required: false,
109
- description: "Maximum time to wait when scraping each source URL.",
110
- default: "5",
111
- scope: "server",
112
- },
113
- ],
114
- };
115
-
116
- private initialized = false;
117
-
118
- constructor() {
119
- // Don't initialize in constructor to avoid circular dependency
120
- // Initialize lazily when config is first accessed
121
- }
122
-
123
- private ensureInitialized() {
124
- if (this.initialized) return;
125
- this.initialize();
126
- this.initialized = true;
127
- }
128
-
129
- private initialize() {
130
- const providerConfigSections = getModelProvidersUIConfigSection();
131
- this.uiConfigSections.modelProviders = providerConfigSections;
132
-
133
- const newProviders: ConfigModelProvider[] = [];
134
-
135
- providerConfigSections.forEach((provider) => {
136
-
137
- const tempConfig: Record<string, any> = {};
138
- const required: string[] = [];
139
-
140
- provider.fields.forEach((field) => {
141
- tempConfig[field.key] =
142
- getEnv(field.env!) || field.default || "";
143
- if (field.required) required.push(field.key);
144
- });
145
-
146
- let configured = true;
147
- required.forEach((r) => {
148
- if (!tempConfig[r]) configured = false;
149
- });
150
-
151
- if (configured) {
152
- const hash = hashObj(tempConfig);
153
- const exists = this.currentConfig.modelProviders.find(
154
- (p) => p.hash === hash,
155
- );
156
-
157
- if (!exists) {
158
- newProviders.push({
159
- id: hash,
160
- name: `${provider.name}`,
161
- type: provider.key,
162
- chatModels: getDefaultChatModels(provider.key),
163
- config: tempConfig,
164
- hash: hash,
165
- isEnvBased: true,
166
- });
167
- }
168
- }
169
- });
170
-
171
- if (newProviders.length > 0) {
172
- this.currentConfig.modelProviders.push(...newProviders);
173
- }
174
-
175
- // Search config from env
176
- this.uiConfigSections.search.forEach((f) => {
177
- if (f.env && !this.currentConfig.search[f.key]) {
178
- this.currentConfig.search[f.key] =
179
- getEnv(f.env) ?? f.default ?? "";
180
- }
181
- });
182
- }
183
-
184
- public getConfig(key: string, defaultValue?: any): any {
185
- this.ensureInitialized();
186
- const nested = key.split(".");
187
- let obj: any = this.currentConfig;
188
-
189
- for (let i = 0; i < nested.length; i++) {
190
- const part = nested[i];
191
- if (obj == null) return defaultValue;
192
- obj = obj[part];
193
- }
194
-
195
- return obj === undefined ? defaultValue : obj;
196
- }
197
-
198
- public updateConfig(key: string, val: any) {
199
- const parts = key.split(".");
200
- if (parts.length === 0) return;
201
-
202
- let target: any = this.currentConfig;
203
- for (let i = 0; i < parts.length - 1; i++) {
204
- const part = parts[i];
205
- if (target[part] === null || typeof target[part] !== "object") {
206
- target[part] = {};
207
- }
208
- target = target[part];
209
- }
210
-
211
- const finalKey = parts[parts.length - 1];
212
- target[finalKey] = val;
213
- }
214
-
215
- public addModelProvider(type: string, name: string, config: any) {
216
- this.ensureInitialized();
217
- const hash = hashObj(config);
218
-
219
- const newModelProvider: ConfigModelProvider = {
220
- id: hash,
221
- name,
222
- type,
223
- config,
224
- chatModels: [],
225
- hash: hash,
226
- };
227
-
228
- this.currentConfig.modelProviders.push(newModelProvider);
229
- return newModelProvider;
230
- }
231
-
232
- public removeModelProvider(id: string) {
233
- this.currentConfig.modelProviders =
234
- this.currentConfig.modelProviders.filter((p) => p.id !== id);
235
- }
236
-
237
- public async updateModelProvider(id: string, name: string, config: any) {
238
- const provider = this.currentConfig.modelProviders.find(
239
- (p) => p.id === id,
240
- );
241
- if (!provider) throw new Error("Provider not found");
242
-
243
- provider.name = name;
244
- provider.config = config;
245
- return provider;
246
- }
247
-
248
- public addProviderModel(providerId: string, type: "chat", model: any) {
249
- const provider = this.currentConfig.modelProviders.find(
250
- (p) => p.id === providerId,
251
- );
252
- if (!provider) throw new Error("Invalid provider id");
253
-
254
- delete model.type;
255
- provider.chatModels.push(model);
256
- return model;
257
- }
258
-
259
- public removeProviderModel(
260
- providerId: string,
261
- type: "chat",
262
- modelKey: string,
263
- ) {
264
- const provider = this.currentConfig.modelProviders.find(
265
- (p) => p.id === providerId,
266
- );
267
- if (!provider) throw new Error("Invalid provider id");
268
-
269
- provider.chatModels = provider.chatModels.filter((m) => m.key !== modelKey);
270
- }
271
-
272
- public isSetupComplete() {
273
- return this.currentConfig.setupComplete;
274
- }
275
-
276
- public markSetupComplete() {
277
- if (!this.currentConfig.setupComplete) {
278
- this.currentConfig.setupComplete = true;
279
- }
280
- }
281
-
282
- public getUIConfigSections(): UIConfigSections {
283
- this.ensureInitialized();
284
- return this.uiConfigSections;
285
- }
286
-
287
- public getCurrentConfig(): Config {
288
- this.ensureInitialized();
289
- return JSON.parse(JSON.stringify(this.currentConfig));
290
- }
291
- }
292
-
293
- const configManager = new ConfigManager();
294
-
295
- export default configManager;
1
+ /**
2
+ * @fileoverview Configuration Manager
3
+ *
4
+ * Manages model providers, MCP servers, and search configuration in memory.
5
+ * Handles environment variable loading, provider hashing, and config updates.
6
+ */
7
+ import type { ConfigModelProvider, MCPServerConfig, Config, UIConfigSections, Model } from "./config-types";
8
+ import { getModelProvidersUIConfigSection } from "./provider-ui-config";
9
+ import { getEnv } from "./environment-variables";
10
+ import { LANGUAGE_MODELS } from "./language-models-database";
11
+
12
+ // Maps a provider UI key (from provider-ui-config) to the matching
13
+ // `provider` name in the LANGUAGE_MODELS database. Names differ in a few
14
+ // cases (e.g. the "gemini" UI key corresponds to the "Google" model list).
15
+ const PROVIDER_KEY_TO_DB_NAME: Record<string, string> = {
16
+ openai: "openai",
17
+ anthropic: "anthropic",
18
+ gemini: "google",
19
+ groq: "groq",
20
+ deepseek: "deepseek",
21
+ nvidia: "nvidia",
22
+ openrouter: "openrouter",
23
+ };
24
+
25
+ /**
26
+ * Returns the default chat models for a provider from the LANGUAGE_MODELS
27
+ * database so that env-based providers expose a usable model list instead of
28
+ * an empty one. Returns [] when no matching provider list exists.
29
+ */
30
+ const getDefaultChatModels = (providerKey: string): Model[] => {
31
+ const dbName = PROVIDER_KEY_TO_DB_NAME[providerKey] ?? providerKey;
32
+ const entry = LANGUAGE_MODELS.find(
33
+ (p) => p.provider.toLowerCase() === dbName.toLowerCase(),
34
+ );
35
+ if (!entry?.models) return [];
36
+
37
+ return entry.models.map((m: any) => ({
38
+ name: m.name,
39
+ key: m.id,
40
+ }));
41
+ };
42
+
43
+ const hashObj = (obj: { [key: string]: any }) => {
44
+ const str = JSON.stringify(obj, Object.keys(obj).sort());
45
+ let hash = 0;
46
+ for (let i = 0; i < str.length; i++) {
47
+ hash = (hash << 5) - hash + str.charCodeAt(i);
48
+ hash |= 0;
49
+ }
50
+ return String(Math.abs(hash).toString(36));
51
+ };
52
+
53
+ class ConfigManager {
54
+ configVersion = 1;
55
+ currentConfig: Config = {
56
+ version: this.configVersion,
57
+ setupComplete: getEnv("SETUP_COMPLETE") === "true" || false,
58
+ preferences: {},
59
+ personalization: {},
60
+ modelProviders: [],
61
+ mcpServers: [],
62
+ search: {
63
+ searxngURL: "",
64
+ tavilyApiKey: "",
65
+ sourceScrapeCount: 3,
66
+ sourceScrapeTimeout: 5,
67
+ },
68
+ };
69
+ uiConfigSections: UIConfigSections = {
70
+ preferences: [],
71
+ personalization: [],
72
+ modelProviders: [],
73
+ mcpServers: [],
74
+ search: [
75
+ {
76
+ name: "SearXNG URL",
77
+ key: "searxngURL",
78
+ type: "string",
79
+ required: false,
80
+ description: "The URL of your SearXNG instance",
81
+ placeholder: "http://localhost:4000",
82
+ default: "",
83
+ scope: "server",
84
+ env: "SEARXNG_API_URL",
85
+ },
86
+ {
87
+ name: "Tavily API Key",
88
+ key: "tavilyApiKey",
89
+ type: "string",
90
+ required: false,
91
+ description: "Your Tavily API key for enhanced search capabilities.",
92
+ placeholder: "tvly-...",
93
+ default: "",
94
+ scope: "server",
95
+ env: "TAVILY_API_KEY",
96
+ },
97
+ {
98
+ name: "Scrape timeout (seconds)",
99
+ key: "sourceScrapeTimeout",
100
+ type: "select",
101
+ options: [
102
+ { name: "3 seconds", value: "3" },
103
+ { name: "5 seconds (default)", value: "5" },
104
+ { name: "10 seconds", value: "10" },
105
+ { name: "15 seconds", value: "15" },
106
+ { name: "20 seconds", value: "20" },
107
+ ],
108
+ required: false,
109
+ description: "Maximum time to wait when scraping each source URL.",
110
+ default: "5",
111
+ scope: "server",
112
+ },
113
+ ],
114
+ };
115
+
116
+ private initialized = false;
117
+
118
+ constructor() {
119
+ // Don't initialize in constructor to avoid circular dependency
120
+ // Initialize lazily when config is first accessed
121
+ }
122
+
123
+ private ensureInitialized() {
124
+ if (this.initialized) return;
125
+ this.initialize();
126
+ this.initialized = true;
127
+ }
128
+
129
+ private initialize() {
130
+ const providerConfigSections = getModelProvidersUIConfigSection();
131
+ this.uiConfigSections.modelProviders = providerConfigSections;
132
+
133
+ const newProviders: ConfigModelProvider[] = [];
134
+
135
+ providerConfigSections.forEach((provider) => {
136
+
137
+ const tempConfig: Record<string, any> = {};
138
+ const required: string[] = [];
139
+
140
+ provider.fields.forEach((field) => {
141
+ tempConfig[field.key] =
142
+ getEnv(field.env!) || field.default || "";
143
+ if (field.required) required.push(field.key);
144
+ });
145
+
146
+ let configured = true;
147
+ required.forEach((r) => {
148
+ if (!tempConfig[r]) configured = false;
149
+ });
150
+
151
+ if (configured) {
152
+ const hash = hashObj(tempConfig);
153
+ const exists = this.currentConfig.modelProviders.find(
154
+ (p) => p.hash === hash,
155
+ );
156
+
157
+ if (!exists) {
158
+ newProviders.push({
159
+ id: hash,
160
+ name: `${provider.name}`,
161
+ type: provider.key,
162
+ chatModels: getDefaultChatModels(provider.key),
163
+ config: tempConfig,
164
+ hash: hash,
165
+ isEnvBased: true,
166
+ });
167
+ }
168
+ }
169
+ });
170
+
171
+ if (newProviders.length > 0) {
172
+ this.currentConfig.modelProviders.push(...newProviders);
173
+ }
174
+
175
+ // Search config from env
176
+ this.uiConfigSections.search.forEach((f) => {
177
+ if (f.env && !this.currentConfig.search[f.key]) {
178
+ this.currentConfig.search[f.key] =
179
+ getEnv(f.env) ?? f.default ?? "";
180
+ }
181
+ });
182
+ }
183
+
184
+ public getConfig(key: string, defaultValue?: any): any {
185
+ this.ensureInitialized();
186
+ const nested = key.split(".");
187
+ let obj: any = this.currentConfig;
188
+
189
+ for (let i = 0; i < nested.length; i++) {
190
+ const part = nested[i];
191
+ if (obj == null) return defaultValue;
192
+ obj = obj[part];
193
+ }
194
+
195
+ return obj === undefined ? defaultValue : obj;
196
+ }
197
+
198
+ public updateConfig(key: string, val: any) {
199
+ const parts = key.split(".");
200
+ if (parts.length === 0) return;
201
+
202
+ let target: any = this.currentConfig;
203
+ for (let i = 0; i < parts.length - 1; i++) {
204
+ const part = parts[i];
205
+ if (target[part] === null || typeof target[part] !== "object") {
206
+ target[part] = {};
207
+ }
208
+ target = target[part];
209
+ }
210
+
211
+ const finalKey = parts[parts.length - 1];
212
+ target[finalKey] = val;
213
+ }
214
+
215
+ public addModelProvider(type: string, name: string, config: any) {
216
+ this.ensureInitialized();
217
+ const hash = hashObj(config);
218
+
219
+ const newModelProvider: ConfigModelProvider = {
220
+ id: hash,
221
+ name,
222
+ type,
223
+ config,
224
+ chatModels: [],
225
+ hash: hash,
226
+ };
227
+
228
+ this.currentConfig.modelProviders.push(newModelProvider);
229
+ return newModelProvider;
230
+ }
231
+
232
+ public removeModelProvider(id: string) {
233
+ this.currentConfig.modelProviders =
234
+ this.currentConfig.modelProviders.filter((p) => p.id !== id);
235
+ }
236
+
237
+ public async updateModelProvider(id: string, name: string, config: any) {
238
+ const provider = this.currentConfig.modelProviders.find(
239
+ (p) => p.id === id,
240
+ );
241
+ if (!provider) throw new Error("Provider not found");
242
+
243
+ provider.name = name;
244
+ provider.config = config;
245
+ return provider;
246
+ }
247
+
248
+ public addProviderModel(providerId: string, type: "chat", model: any) {
249
+ const provider = this.currentConfig.modelProviders.find(
250
+ (p) => p.id === providerId,
251
+ );
252
+ if (!provider) throw new Error("Invalid provider id");
253
+
254
+ delete model.type;
255
+ provider.chatModels.push(model);
256
+ return model;
257
+ }
258
+
259
+ public removeProviderModel(
260
+ providerId: string,
261
+ type: "chat",
262
+ modelKey: string,
263
+ ) {
264
+ const provider = this.currentConfig.modelProviders.find(
265
+ (p) => p.id === providerId,
266
+ );
267
+ if (!provider) throw new Error("Invalid provider id");
268
+
269
+ provider.chatModels = provider.chatModels.filter((m) => m.key !== modelKey);
270
+ }
271
+
272
+ public isSetupComplete() {
273
+ return this.currentConfig.setupComplete;
274
+ }
275
+
276
+ public markSetupComplete() {
277
+ if (!this.currentConfig.setupComplete) {
278
+ this.currentConfig.setupComplete = true;
279
+ }
280
+ }
281
+
282
+ public getUIConfigSections(): UIConfigSections {
283
+ this.ensureInitialized();
284
+ return this.uiConfigSections;
285
+ }
286
+
287
+ public getCurrentConfig(): Config {
288
+ this.ensureInitialized();
289
+ return JSON.parse(JSON.stringify(this.currentConfig));
290
+ }
291
+ }
292
+
293
+ const configManager = new ConfigManager();
294
+
295
+ export default configManager;