chat-agent-toolkit 1.2.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.
- package/README.md +234 -0
- package/package.json +101 -0
- package/src/config/config-manager.ts +319 -0
- package/src/config/config-types.ts +65 -0
- package/src/config/environment-variables.ts +8 -0
- package/src/config/index.ts +26 -0
- package/src/config/language-models-database.ts +1426 -0
- package/src/config/mcp-server-registry.ts +24 -0
- package/src/config/model-registry.ts +256 -0
- package/src/config/model-tester.ts +211 -0
- package/src/config/model-utils.ts +193 -0
- package/src/config/provider-ui-config.ts +196 -0
- package/src/connectors/composio.json +154 -0
- package/src/index.ts +22 -0
- package/src/memory/ARCHITECTURE.md +302 -0
- package/src/memory/MASTRA_INTEGRATION.md +106 -0
- package/src/memory/README.md +224 -0
- package/src/memory/agent-memory-manager.ts +416 -0
- package/src/memory/example.ts +343 -0
- package/src/memory/index.ts +47 -0
- package/src/memory/mastra-integration.ts +609 -0
- package/src/memory/storage/drizzle-storage.ts +205 -0
- package/src/memory/storage/in-memory-storage.ts +551 -0
- package/src/memory/storage/storage-interface.ts +68 -0
- package/src/memory/types.ts +125 -0
- package/src/models/providers.ts +5 -0
- package/src/models/registry.ts +4 -0
- package/src/models/types.ts +4 -0
- package/src/search.ts +5 -0
- package/src/tools/composio-mastra.ts +305 -0
- package/src/tools/composio-mcp.ts +205 -0
- package/src/tools/index.ts +13 -0
- package/src/tools/qwksearch-api-tools.ts +327 -0
- package/src/tools/search/doc-utils.ts +75 -0
- package/src/tools/search/document.ts +47 -0
- package/src/tools/search/index.ts +13 -0
- package/src/tools/search/link-summarizer.ts +112 -0
- package/src/tools/search/meta-search-types.ts +62 -0
- package/src/tools/search/metaSearchAgent.ts +454 -0
- package/src/tools/search/search-handlers.ts +85 -0
- package/src/tools/search/suggestionGeneratorAgent.ts +54 -0
- package/src/types.d.ts +137 -0
- package/src/utils/README.md +98 -0
- package/src/utils/chat-helpers.ts +18 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/markdown-to-html.ts +53 -0
- package/src/utils/outputParser.ts +73 -0
- package/src/utils/provider-image-cropper.ts +130 -0
package/README.md
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# agent-toolkit
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
Multi-provider AI agent toolkit for generating language responses, searching the web, extracting page content, and managing long-term memory across 10+ LLM providers.
|
|
5
|
+
|
|
6
|
+
Built on top of the [Vercel AI SDK](https://sdk.vercel.ai), with a small registry of pre-tuned agent prompts (research, summarization, citation answering, query resolution, knowledge-graph extraction, etc.) and tool wrappers around the [QwkSearch](https://qwksearch.com) API.
|
|
7
|
+
|
|
8
|
+
## Language Intelligence Providers
|
|
9
|
+
|
|
10
|
+
| Provider | 🌍 | Top Model (Others) | 🏆 Benchmarks | 📄 Docs | 🔑 Keys | 💰 Funding |
|
|
11
|
+
| ---------------------- | --- | --------------------------------------------- | --------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | ------------ |
|
|
12
|
+
| **Anthropic** | 🇺🇸 | Claude Mythos / Opus (Sonnet, Haiku) | 🥇 GPQA Diamond 94.6% · 🥇 SWE-bench 93.9% · 🧬 PhD reasoning | [Docs](https://docs.anthropic.com/en/docs/welcome) | [Keys](https://console.anthropic.com/settings/keys) | ~$60B |
|
|
13
|
+
| **OpenAI** | 🇺🇸 | GPT / o3 / Codex (o1, o4, o4-mini, gpt-4o) | 🥇 AIME 2025 100% · 🥇 SWE-bench Pro · 📚 MMLU-Pro 90% | [Docs](https://platform.openai.com/docs/overview) | [Keys](https://platform.openai.com/api-keys) | ~$180B |
|
|
14
|
+
| **Google** | 🇺🇸 | Gemini Pro (Flash, Flash-Lite, Gemma) | 🥇 GPQA 94.1% · 🥇 LiveCodeBench Elo 2439 · 🌐 #1 in 6/13 Vals | [Docs](https://cloud.google.com/vertex-ai/generative-ai/docs/learn/models) | [Keys](https://cloud.google.com/vertex-ai/generative-ai/docs/start/express-mode/overview#api-keys) | Public |
|
|
15
|
+
| **xAI** | 🇺🇸 | Grok Heavy (Grok-3, Grok Vision) | 🥇 AIME 2025 100% · 🧮 Math competition · ⚡ X integration | [Docs](https://docs.x.ai/docs#models) | [Keys](https://console.x.ai/) | ~$45B |
|
|
16
|
+
| **Meta** | 🇺🇸 | Llama Maverick / Scout (Llama 3.x, CodeLlama) | 🥇 DocVQA 94.4% · 🥇 10M token context · 📊 ChartQA 90% | [Docs](https://www.llama.com/docs/overview/) | [Keys](https://www.llama.com/llama-downloads/) | Public |
|
|
17
|
+
| **NVIDIA** | 🇺🇸 | Nemotron-Cascade (Llama Nemotron, Kimi) | 🥇 LCB v6 87.2% · 🏅 IMO+IOI+ICPC gold · 🧮 AIME 98.6% | [Docs](https://docs.api.nvidia.com/nim/reference/llm-apis) | [Keys](https://build.nvidia.com/settings/api-keys) | Public |
|
|
18
|
+
| **Perplexity** | 🇺🇸 | Sonar Reasoning Pro (Sonar Deep Research) | 🥇 Search Arena · 🔍 #1 web-grounded QA · 🌐 Real-time retrieval | [Docs](https://docs.perplexity.ai/models/model-cards) | [Keys](https://www.perplexity.ai/account/api/keys) | ~$1B |
|
|
19
|
+
| **Groq** | 🇺🇸 | (Llama, DeepSeek, Gemma, Mistral, Qwen) | ⚡ #1 inference speed · 🏎️ Fastest TTFT · 🔧 LPU hardware | [Docs](https://console.groq.com/docs/overview) | [Keys](https://console.groq.com/keys) | ~$640M |
|
|
20
|
+
| **Mistral** | 🇫🇷 | Mistral Large (Small 4, Codestral, Devstral) | 🥈 Arena Elo 1418 · 🌍 Multilingual MMLU 85.5% · 🚀 Fastest TTFT | [Docs](https://docs.mistral.ai/) | [Keys](https://console.mistral.ai/api-keys/) | ~$3.1B |
|
|
21
|
+
| **Together** | 🇺🇸 | (Llama, Mistral, Gemma, Qwen, DeepSeek) | 🏗️ Widest open hosting · 💸 Best open-source pricing · 🔧 Fine-tuning | [Docs](https://docs.together.ai/docs/quickstart) | [Keys](https://api.together.xyz/settings/api-keys) | ~$225M |
|
|
22
|
+
| **Moonshot** | 🇨🇳 | Kimi Reasoning (K2.6, K2) | 🥇 AIME open 96.1% · 🥇 MATH-500 98% · 🥇 HumanEval 99% | [Docs](https://platform.moonshot.cn/docs) | [Keys](https://platform.moonshot.cn/console/api-keys) | ~$3.9B |
|
|
23
|
+
| **Zhipu** | 🇨🇳 | GLM Reasoning / GLM-4.7 (GLM-4V, CogView) | 🥇 Chatbot Arena Elo 1451 · 🥇 MMLU 96% · 🧮 AIME 95.7% | [Docs](https://bigmodel.cn/dev/api) | [Keys](https://bigmodel.cn/usercenter/apikeys) | ~$1.8B |
|
|
24
|
+
| **Alibaba** | 🇨🇳 | Qwen-Coder / Qwen (Qwen-VL, Qwen-Audio) | 🥇 Codeforces Elo 2056 · 💻 SWE-bench 69.6% · 🏎️ LCB 70.7% | [Docs](https://www.alibabacloud.com/help/en/model-studio/developer-reference/use-qwen-by-calling-api) | [Keys](https://bailian.console.aliyun.com/?apiKey=1) | Public |
|
|
25
|
+
| **DeepSeek** | 🇨🇳 | DeepSeek (DeepSeek-Coder, DeepSeek-VL) | 🥇 IMO gold (open) · 📚 MMLU-Pro 81.2 · 🧮 AIME 87.5% | [Docs](https://api-docs.deepseek.com/) | [Keys](https://platform.deepseek.com/api_keys) | Bootstrapped |
|
|
26
|
+
| **Cloudflare** | 🇺🇸 | (Llama, Mistral, Gemma, Qwen, DeepSeek) | 🌐 Edge inference · ⚡ Serverless CDN scale · 🔒 Privacy-first | [Docs](https://developers.cloudflare.com/workers-ai/) | [Keys](https://dash.cloudflare.com/profile/api-tokens) | Public |
|
|
27
|
+
| **Ollama** | 🇺🇸 | (Llama, Mistral, Gemma, Qwen, DeepSeek) | 🖥️ #1 local inference · 🔒 Fully offline · 🆓 Free self-hosted | [Docs](https://ollama.com/docs) | [Keys](https://ollama.com/settings/keys) | ~$20M |
|
|
28
|
+
|
|
29
|
+
## Amazon Bedrock Provider
|
|
30
|
+
|
|
31
|
+
Use Vercel AI SDK's official Bedrock provider: install `@ai-sdk/amazon-bedrock`, configure AWS auth, then call `bedrock('model-id')` in `generateText` or `streamText`. [ai-sdk](https://ai-sdk.dev/providers/ai-sdk-providers/amazon-bedrock)
|
|
32
|
+
|
|
33
|
+
### Install
|
|
34
|
+
|
|
35
|
+
- Run `pnpm add ai @ai-sdk/amazon-bedrock` or the npm/yarn equivalent. [vercel](https://vercel.com/changelog/amazon-bedrock-provider-for-the-vercel-ai-sdk-now-available)
|
|
36
|
+
- Import either `bedrock` directly or `createAmazonBedrock` for custom config. [ai-sdk](https://ai-sdk.dev/providers/ai-sdk-providers/amazon-bedrock)
|
|
37
|
+
|
|
38
|
+
### Env setup
|
|
39
|
+
|
|
40
|
+
- Simplest path: set `AWS_BEARER_TOKEN_BEDROCK` with a Bedrock API key; the docs say API key auth is the recommended method. [ai-sdk](https://ai-sdk.dev/providers/ai-sdk-providers/amazon-bedrock)
|
|
41
|
+
- SigV4 also works with `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_REGION`, and the provider can also use the AWS credential chain. [ai-sdk](https://ai-sdk.dev/providers/ai-sdk-providers/amazon-bedrock)
|
|
42
|
+
|
|
43
|
+
### Minimal example
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { generateText } from 'ai';
|
|
47
|
+
import { bedrock } from '@ai-sdk/amazon-bedrock';
|
|
48
|
+
|
|
49
|
+
const { text } = await generateText({
|
|
50
|
+
model: bedrock('anthropic.claude-3-haiku-20240307-v1:0'),
|
|
51
|
+
prompt: 'Explain Bedrock in one sentence.',
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
console.log(text);
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Custom region
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { createAmazonBedrock } from '@ai-sdk/amazon-bedrock';
|
|
61
|
+
|
|
62
|
+
export const amazonBedrock = createAmazonBedrock({
|
|
63
|
+
region: 'us-east-1',
|
|
64
|
+
apiKey: process.env.AWS_BEARER_TOKEN_BEDROCK,
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Notes
|
|
69
|
+
|
|
70
|
+
- You must enable model access in the AWS Bedrock console first; access is not granted by default. [ai-sdk](https://ai-sdk.dev/providers/ai-sdk-providers/amazon-bedrock)
|
|
71
|
+
- `streamText` is supported too, and Bedrock-specific options like guardrails can be passed via `providerOptions.bedrock`. [ai-sdk](https://ai-sdk.dev/providers/ai-sdk-providers/amazon-bedrock)
|
|
72
|
+
|
|
73
|
+
## Install
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npm install ai-research-agent
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Quick start
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
import { generateLanguageResponse } from "ai-research-agent";
|
|
83
|
+
|
|
84
|
+
const response = await generateLanguageResponse({
|
|
85
|
+
provider: "groq",
|
|
86
|
+
apiKey: process.env.GROQ_API_KEY,
|
|
87
|
+
agent: "question",
|
|
88
|
+
query: "Explain transformer attention in two sentences.",
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
console.log(response.content);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`response.content` is HTML by default (set `html: false` for raw Markdown). Agents that define an `after` hook also return parsed data on `response.extract`.
|
|
95
|
+
|
|
96
|
+
### Using Amazon Bedrock
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import { generateLanguageResponse } from "ai-research-agent";
|
|
100
|
+
|
|
101
|
+
const response = await generateLanguageResponse({
|
|
102
|
+
provider: "amazon",
|
|
103
|
+
apiKey: process.env.AWS_BEARER_TOKEN_BEDROCK, // or "region:accessKeyId:secretAccessKey"
|
|
104
|
+
model: "anthropic.claude-3-5-sonnet-20241022-v2:0",
|
|
105
|
+
agent: "question",
|
|
106
|
+
query: "Explain transformer attention in two sentences.",
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
console.log(response.content);
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Supported providers
|
|
113
|
+
|
|
114
|
+
| Provider | ID | Default model | Notes |
|
|
115
|
+
| --------------- | ------------ | ----------------------------------------------- | ------------------------------------------------- |
|
|
116
|
+
| Anthropic | `anthropic` | `claude-3-7-sonnet-20250219` | |
|
|
117
|
+
| OpenAI | `openai` | `gpt-4o` | |
|
|
118
|
+
| Groq | `groq` | `meta-llama/llama-4-maverick-17b-128e-instruct` | |
|
|
119
|
+
| Google Vertex | `google` | Gemini 2.x | |
|
|
120
|
+
| XAI | `xai` | `grok-beta` | |
|
|
121
|
+
| Amazon Bedrock | `amazon` | `anthropic.claude-3-5-sonnet-20241022-v2:0` | apiKey = bearer token or `region:key:secret` |
|
|
122
|
+
| Cloudflare | `cloudflare` | `llama-4-scout-17b-16e-instruct` | apiKey =`token:accountId` |
|
|
123
|
+
| Together AI | `togetherai` | `meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo` | |
|
|
124
|
+
| Perplexity | `perplexity` | `sonar` | |
|
|
125
|
+
| NVIDIA NIM | `nvidia` | `moonshotai/kimi-k2.5` | |
|
|
126
|
+
| Ollama | `ollama` | `llama3.2` | Local — no key required |
|
|
127
|
+
|
|
128
|
+
The full registry (including context lengths) is exported as `LANGUAGE_MODELS`.
|
|
129
|
+
|
|
130
|
+
## Built-in agents
|
|
131
|
+
|
|
132
|
+
The `agent` option selects a prompt template from [`AGENT_PROMPTS`](src/agents/agent-prompts.ts):
|
|
133
|
+
|
|
134
|
+
- `question` — general-purpose Q&A with chat history.
|
|
135
|
+
- `question-research-engine` — long-form, journalistic, citation-style answer.
|
|
136
|
+
- `query-resolution` — rephrases a follow-up question into standalone search queries.
|
|
137
|
+
- `query-resolution-search` — classifies a query and proposes search categories as JSON.
|
|
138
|
+
- `summarize`, `summarize-bullets`, `summary-longtext` — single-shot and reduce-style summarization.
|
|
139
|
+
- `answer-cite-sources` — answers a query against a `{context}` block with `[n]` citations.
|
|
140
|
+
- `suggest-followups` — emits 4–5 follow-up questions inside `<suggestions>` tags.
|
|
141
|
+
- `remember-user` — extracts factual user memories as structured JSON.
|
|
142
|
+
- `knowledge-graph-nodes` — builds a temporal knowledge graph from a document.
|
|
143
|
+
- `results-relevance-filter` — picks the most relevant URLs from a search result list.
|
|
144
|
+
|
|
145
|
+
Templates use `{variableName}` placeholders that are filled from the options object (`query`, `article`, `chat_history`, `context`, etc.).
|
|
146
|
+
|
|
147
|
+
## Agent tools
|
|
148
|
+
|
|
149
|
+
`AGENT_TOOLS` registers callable tools that the ReAct agent attaches automatically when a prompt declares them in its `tools` array:
|
|
150
|
+
|
|
151
|
+
- `web_search` — QwkSearch metasearch over 100+ engines.
|
|
152
|
+
- `extract_page` — Mozilla Readability + Mercury extraction with PDF and YouTube support.
|
|
153
|
+
- `generate_ai_response` — proxy to QwkSearch's hosted `/language` endpoint.
|
|
154
|
+
|
|
155
|
+
Set `QWKSEARCH_URL` and `QWKSEARCH_API_KEY` in the environment, or pass `baseURL`/`apiKey` per-call.
|
|
156
|
+
|
|
157
|
+
## Memory
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import {
|
|
161
|
+
SimpleMemory,
|
|
162
|
+
MemoryAgent,
|
|
163
|
+
DrizzleMemoryStorage,
|
|
164
|
+
} from "ai-research-agent";
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
- `SimpleMemory` — in-memory store implementing `IMemoryStorage`.
|
|
168
|
+
- `DrizzleMemoryStorage` — Drizzle ORM-backed persistence; pair with `createMemorySchema()`.
|
|
169
|
+
- `MemoryAgent` — high-level wrapper that uses the `remember-user` agent to extract facts from chat turns and writes them to a storage backend.
|
|
170
|
+
|
|
171
|
+
See [src/memory/README.md](src/memory/README.md) and [src/memory/ARCHITECTURE.md](src/memory/ARCHITECTURE.md) for details.
|
|
172
|
+
|
|
173
|
+
## Package layout
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
src/
|
|
177
|
+
agents/ # prompt + tool registry, generate function, model list
|
|
178
|
+
agent-prompts.ts # AGENT_PROMPTS, extractJSONFromLanguageReply
|
|
179
|
+
agent-tools.ts # AGENT_TOOLS (web_search, extract_page, ...)
|
|
180
|
+
generate-language.ts # generateLanguageResponse — main entry point
|
|
181
|
+
generate-language-types.ts
|
|
182
|
+
language-model-names.ts # LANGUAGE_MODELS, LANGUAGE_PROVIDERS
|
|
183
|
+
llm-providers.ts # createLLMProvider — chat-model factory
|
|
184
|
+
index.ts # barrel export
|
|
185
|
+
memory/ # SimpleMemory, MemoryAgent, Drizzle storage
|
|
186
|
+
providers/ # alternate provider abstractions (model registry)
|
|
187
|
+
utils/ # markdown-to-html, document helpers
|
|
188
|
+
index.ts # public entry — re-exports agents + memory
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Build
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
npm run build # vite build
|
|
195
|
+
npm run make # clean + build with extra heap
|
|
196
|
+
npm run test # vitest
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Vite bundles ES + CJS targets to `dist/`, emits `.d.ts` files alongside, and applies a `fs/promises` polyfill so the bundle works in browser and edge runtimes (Cloudflare Workers, Vercel Edge).
|
|
200
|
+
|
|
201
|
+
## Resources
|
|
202
|
+
|
|
203
|
+
### Documentation & Guides
|
|
204
|
+
- [Vercel AI SDK generateText docs](https://sdk.vercel.ai/docs/reference/ai-sdk-core/generate-text)
|
|
205
|
+
- [Hugging Face tutorials](https://huggingface.co/learn)
|
|
206
|
+
- [Illustrated Transformer](https://jalammar.github.io/illustrated-transformer/)
|
|
207
|
+
- [Building a Transformer with PyTorch](https://www.datacamp.com/tutorial/building-a-transformer-with-py-torch)
|
|
208
|
+
- [LLM training example](https://github.com/vtempest/ai-research-agent/blob/master/packages/neural-net/src/train/predict-next-word.js)
|
|
209
|
+
|
|
210
|
+
### Transformer Architecture Visualizations
|
|
211
|
+
|
|
212
|
+
<img src="https://i.imgur.com/uW6E9VJ.gif" alt="Transformer architecture visualization" />
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
## Alternative Agents Frameworks
|
|
216
|
+
|
|
217
|
+
| # | Framework | Features | Stars | Language | Maker |
|
|
218
|
+
|---:|---|---|---:|---|---|
|
|
219
|
+
| 1 | [Hermes Agent](https://github.com/NousResearch/hermes-agent) | Self-improving agent with a built-in learning loop; distills reusable skills from past runs, persists experience across sessions, "grows with you" over time | 211k | Python | Nous Research |
|
|
220
|
+
| 2 | [AutoGPT](https://github.com/Significant-Gravitas/AutoGPT) | One of the original autonomous agents; goal-driven loop that self-prompts to decompose and execute tasks. Now a low-code platform: visual block-based builder, deploy/run continuous agents, and an agent marketplace | 185k | Python/TypeScript | Significant Gravitas |
|
|
221
|
+
| 3 | [n8n](https://github.com/n8n-io/n8n) | Workflow automation, native AI features, 400+ integrations, visual/code hybrid | 175k | TypeScript | n8n.io |
|
|
222
|
+
| 4 | [LangChain / LangGraph](https://github.com/langchain-ai/langchain) | Full ecosystem: LangChain for chains/model+tool abstractions, [LangGraph](https://github.com/langchain-ai/langgraph) (36.7k) for graph-native orchestration with explicit state, branching, loops, checkpoints, human-in-the-loop, durable execution, streaming; [LangGraphJS](https://github.com/langchain-ai/langgraphjs) (3.1k) mirrors it for JS runtimes | 141k | Python + TS/JS | LangChain AI |
|
|
223
|
+
| 5 | [Dify](https://github.com/langgenius/dify) | Visual workflow builder, RAG pipelines, agent apps, deployment tooling | 130k–147k+ | TypeScript | LangGenius |
|
|
224
|
+
| 6 | [OpenHands](https://github.com/All-Hands-AI/OpenHands) | Autonomous dev agent — writes/edits code, runs shell commands, browses the web, executes in a sandbox; strong local secure-workflow story | 80k | Python | All-Hands-AI (formerly OpenDevin) |
|
|
225
|
+
| 7 | [MetaGPT](https://github.com/FoundationAgents/MetaGPT) | Simulates a software company (PM/architect/dev/QA roles), SOP-driven pipelines, generates specs, docs, and code from one prompt | 69k | Python | Foundation Agents |
|
|
226
|
+
| 8 | [Mem0](https://github.com/mem0ai/mem0) | Memory layer, not an orchestrator: extraction, consolidation, scoped retrieval, long-term user/agent memory; drops into any framework | 60k | Python/TypeScript | mem0ai |
|
|
227
|
+
| 9 | [AutoGen](https://github.com/microsoft/autogen) | Dialogue-first multi-agent conversations, async event-driven messaging, distributed collaboration, observability, code execution | 60k | Python | Microsoft |
|
|
228
|
+
| 10 | [CrewAI](https://github.com/crewAIInc/crewAI) | Role-based "crews," task delegation and collaboration, memory, checkpointing, async flows; lean (no LangChain dependency) | 55k | Python | CrewAI Inc. / João Moura |
|
|
229
|
+
| 11 | [LlamaIndex](https://github.com/run-llama/llama_index) | Retrieval-centric agents, event-driven Workflows, RAG-first data connectors, memory, structured query planning | 51k | Python | LlamaIndex |
|
|
230
|
+
| 12 | [smolagents](https://github.com/huggingface/smolagents) | Minimal code-first agents that write actions as Python code, sandboxed execution, tiny surface area, model-agnostic | 28k | Python | Hugging Face |
|
|
231
|
+
| 13 | [OpenAI Agents SDK](https://github.com/openai/openai-agents-python) | Lightweight agent loop, handoffs between agents, guardrails, sessions, built-in tracing, sandboxed tool execution | 28k | Python/TypeScript | OpenAI |
|
|
232
|
+
| 14 | [Mastra](https://github.com/mastra-ai/mastra) | TS-native, batteries-included: agents, graph-based workflows (`.then()`/`.branch()`/`.parallel()`), 40+ model routing, observational memory, human-in-the-loop, authored MCP servers, built-in evals + observability; deploys standalone or inside React/Next/Node | 26k | TypeScript | Mastra (mastra.ai) |
|
|
233
|
+
| 15 | [Vercel AI SDK](https://github.com/vercel/ai) | Streaming, tool calling, structured outputs, agent loops, MCP support, provider-agnostic, first-class UI hooks; runs on edge/Workers | 25k | TypeScript | Vercel |
|
|
234
|
+
| 16 | [Zep](https://github.com/getzep/zep) | Agent memory platform built on a temporal knowledge graph; long-term context, fact extraction, cross-session recall | 4.7k | Python/TypeScript | getzep |
|
package/package.json
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "chat-agent-toolkit",
|
|
3
|
+
"version": "1.2.1",
|
|
4
|
+
"description": "Multi-provider AI agent toolkit: generate language responses, search the web, extract content, and manage memory across 10+ LLM providers.",
|
|
5
|
+
"author": "vtempest <grokthiscontact@gmail.com>",
|
|
6
|
+
"license": "AGPL-3.0",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/OpenSourceAGI/qwksearch-research-agent"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/OpenSourceAGI/qwksearch-research-agent/issues"
|
|
13
|
+
},
|
|
14
|
+
"main": "./dist/research-agent.cjs.js",
|
|
15
|
+
"types": "./dist/types.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/types.d.ts",
|
|
19
|
+
"import": "./dist/research-agent.es.js",
|
|
20
|
+
"require": "./dist/research-agent.cjs.js"
|
|
21
|
+
},
|
|
22
|
+
"./*": {
|
|
23
|
+
"types": "./src/*.ts",
|
|
24
|
+
"react-server": "./src/*",
|
|
25
|
+
"import": "./src/*",
|
|
26
|
+
"require": "./src/*"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"typesVersions": {
|
|
30
|
+
"*": {
|
|
31
|
+
"*": [
|
|
32
|
+
"src/*"
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist",
|
|
38
|
+
"src"
|
|
39
|
+
],
|
|
40
|
+
"sideEffects": false,
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "vite build",
|
|
43
|
+
"test": "vitest",
|
|
44
|
+
"test-ui": "vitest --ui --watch",
|
|
45
|
+
"make": "rm -rf dist/*; NODE_OPTIONS=--max-old-space-size=15192 vite build",
|
|
46
|
+
"ship": "npx standard-version --release-as patch && npm publish --access public"
|
|
47
|
+
},
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"next": ">=15.0.0",
|
|
50
|
+
"vinext": ">=0.1.0 || >=1.0.0-0"
|
|
51
|
+
},
|
|
52
|
+
"peerDependenciesMeta": {
|
|
53
|
+
"next": {
|
|
54
|
+
"optional": true
|
|
55
|
+
},
|
|
56
|
+
"vinext": {
|
|
57
|
+
"optional": true
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@vitest/ui": "^4.0.18",
|
|
62
|
+
"terser": "^5.46.0",
|
|
63
|
+
"typedoc-plugin-markdown": "^4.10.0",
|
|
64
|
+
"typescript": "^5.9.3",
|
|
65
|
+
"vite": "^8.1.3",
|
|
66
|
+
"vite-plugin-dts": "^5.0.3",
|
|
67
|
+
"vite-plugin-node-polyfills": "^0.28.0",
|
|
68
|
+
"vitest": "^4.0.18"
|
|
69
|
+
},
|
|
70
|
+
"dependencies": {
|
|
71
|
+
"@ai-sdk/anthropic": "^2.0.0",
|
|
72
|
+
"@ai-sdk/google": "^2.0.0",
|
|
73
|
+
"@ai-sdk/groq": "^2.0.0",
|
|
74
|
+
"@ai-sdk/openai": "^2.0.0",
|
|
75
|
+
"@composio/core": "^0.10.0",
|
|
76
|
+
"@mastra/core": "^0.1.0",
|
|
77
|
+
"@mastra/mcp": "^0.1.0",
|
|
78
|
+
"ai": "^5.0.0",
|
|
79
|
+
"drizzle-orm": "^0.45.1",
|
|
80
|
+
"qwksearch-api-client": "^0.0.12",
|
|
81
|
+
"zod": "^4.3.6"
|
|
82
|
+
},
|
|
83
|
+
"keywords": [
|
|
84
|
+
"ai-agent",
|
|
85
|
+
"llm",
|
|
86
|
+
"research-agent",
|
|
87
|
+
"vercel-ai-sdk",
|
|
88
|
+
"nlp",
|
|
89
|
+
"web-search",
|
|
90
|
+
"knowledge-graph",
|
|
91
|
+
"multi-provider",
|
|
92
|
+
"groq",
|
|
93
|
+
"openai",
|
|
94
|
+
"anthropic",
|
|
95
|
+
"ollama",
|
|
96
|
+
"hacktoberfest"
|
|
97
|
+
],
|
|
98
|
+
"publishConfig": {
|
|
99
|
+
"access": "public"
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,319 @@
|
|
|
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: "Source pages to scrape",
|
|
99
|
+
key: "sourceScrapeCount",
|
|
100
|
+
type: "select",
|
|
101
|
+
options: [
|
|
102
|
+
{ name: "Disabled (snippet only)", value: "0" },
|
|
103
|
+
{ name: "1 page", value: "1" },
|
|
104
|
+
{ name: "2 pages", value: "2" },
|
|
105
|
+
{ name: "3 pages (default)", value: "3" },
|
|
106
|
+
{ name: "5 pages", value: "5" },
|
|
107
|
+
],
|
|
108
|
+
required: false,
|
|
109
|
+
description: "Number of top search result URLs to fully scrape.",
|
|
110
|
+
default: "3",
|
|
111
|
+
scope: "server",
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: "Scrape timeout (seconds)",
|
|
115
|
+
key: "sourceScrapeTimeout",
|
|
116
|
+
type: "select",
|
|
117
|
+
options: [
|
|
118
|
+
{ name: "3 seconds", value: "3" },
|
|
119
|
+
{ name: "5 seconds (default)", value: "5" },
|
|
120
|
+
{ name: "10 seconds", value: "10" },
|
|
121
|
+
{ name: "15 seconds", value: "15" },
|
|
122
|
+
{ name: "20 seconds", value: "20" },
|
|
123
|
+
],
|
|
124
|
+
required: false,
|
|
125
|
+
description: "Maximum time to wait when scraping each source URL.",
|
|
126
|
+
default: "5",
|
|
127
|
+
scope: "server",
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
private initialized = false;
|
|
133
|
+
|
|
134
|
+
constructor() {
|
|
135
|
+
// Don't initialize in constructor to avoid circular dependency
|
|
136
|
+
// Initialize lazily when config is first accessed
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private ensureInitialized() {
|
|
140
|
+
if (this.initialized) return;
|
|
141
|
+
this.initialize();
|
|
142
|
+
this.initialized = true;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private initialize() {
|
|
146
|
+
const providerConfigSections = getModelProvidersUIConfigSection();
|
|
147
|
+
this.uiConfigSections.modelProviders = providerConfigSections;
|
|
148
|
+
|
|
149
|
+
const newProviders: ConfigModelProvider[] = [];
|
|
150
|
+
|
|
151
|
+
// Check if OPENROUTER_API_KEY exists - prioritize OpenRouter for guests
|
|
152
|
+
const hasOpenRouter = !!getEnv("OPENROUTER_API_KEY");
|
|
153
|
+
|
|
154
|
+
providerConfigSections.forEach((provider) => {
|
|
155
|
+
// If OpenRouter is configured, ONLY load OpenRouter for guests
|
|
156
|
+
// Skip all other providers (NVIDIA, DeepSeek, etc.)
|
|
157
|
+
if (hasOpenRouter && provider.key.toLowerCase() !== "openrouter") {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const tempConfig: Record<string, any> = {};
|
|
162
|
+
const required: string[] = [];
|
|
163
|
+
|
|
164
|
+
provider.fields.forEach((field) => {
|
|
165
|
+
tempConfig[field.key] =
|
|
166
|
+
getEnv(field.env!) || field.default || "";
|
|
167
|
+
if (field.required) required.push(field.key);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
let configured = true;
|
|
171
|
+
required.forEach((r) => {
|
|
172
|
+
if (!tempConfig[r]) configured = false;
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
if (configured) {
|
|
176
|
+
const hash = hashObj(tempConfig);
|
|
177
|
+
const exists = this.currentConfig.modelProviders.find(
|
|
178
|
+
(p) => p.hash === hash,
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
if (!exists) {
|
|
182
|
+
newProviders.push({
|
|
183
|
+
id: hash,
|
|
184
|
+
name: `${provider.name}`,
|
|
185
|
+
type: provider.key,
|
|
186
|
+
chatModels: getDefaultChatModels(provider.key),
|
|
187
|
+
config: tempConfig,
|
|
188
|
+
hash: hash,
|
|
189
|
+
isEnvBased: true,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
if (newProviders.length > 0) {
|
|
196
|
+
this.currentConfig.modelProviders.push(...newProviders);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Search config from env
|
|
200
|
+
this.uiConfigSections.search.forEach((f) => {
|
|
201
|
+
if (f.env && !this.currentConfig.search[f.key]) {
|
|
202
|
+
this.currentConfig.search[f.key] =
|
|
203
|
+
getEnv(f.env) ?? f.default ?? "";
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
public getConfig(key: string, defaultValue?: any): any {
|
|
209
|
+
this.ensureInitialized();
|
|
210
|
+
const nested = key.split(".");
|
|
211
|
+
let obj: any = this.currentConfig;
|
|
212
|
+
|
|
213
|
+
for (let i = 0; i < nested.length; i++) {
|
|
214
|
+
const part = nested[i];
|
|
215
|
+
if (obj == null) return defaultValue;
|
|
216
|
+
obj = obj[part];
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return obj === undefined ? defaultValue : obj;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
public updateConfig(key: string, val: any) {
|
|
223
|
+
const parts = key.split(".");
|
|
224
|
+
if (parts.length === 0) return;
|
|
225
|
+
|
|
226
|
+
let target: any = this.currentConfig;
|
|
227
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
228
|
+
const part = parts[i];
|
|
229
|
+
if (target[part] === null || typeof target[part] !== "object") {
|
|
230
|
+
target[part] = {};
|
|
231
|
+
}
|
|
232
|
+
target = target[part];
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const finalKey = parts[parts.length - 1];
|
|
236
|
+
target[finalKey] = val;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
public addModelProvider(type: string, name: string, config: any) {
|
|
240
|
+
this.ensureInitialized();
|
|
241
|
+
const hash = hashObj(config);
|
|
242
|
+
|
|
243
|
+
const newModelProvider: ConfigModelProvider = {
|
|
244
|
+
id: hash,
|
|
245
|
+
name,
|
|
246
|
+
type,
|
|
247
|
+
config,
|
|
248
|
+
chatModels: [],
|
|
249
|
+
hash: hash,
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
this.currentConfig.modelProviders.push(newModelProvider);
|
|
253
|
+
return newModelProvider;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
public removeModelProvider(id: string) {
|
|
257
|
+
this.currentConfig.modelProviders =
|
|
258
|
+
this.currentConfig.modelProviders.filter((p) => p.id !== id);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
public async updateModelProvider(id: string, name: string, config: any) {
|
|
262
|
+
const provider = this.currentConfig.modelProviders.find(
|
|
263
|
+
(p) => p.id === id,
|
|
264
|
+
);
|
|
265
|
+
if (!provider) throw new Error("Provider not found");
|
|
266
|
+
|
|
267
|
+
provider.name = name;
|
|
268
|
+
provider.config = config;
|
|
269
|
+
return provider;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
public addProviderModel(providerId: string, type: "chat", model: any) {
|
|
273
|
+
const provider = this.currentConfig.modelProviders.find(
|
|
274
|
+
(p) => p.id === providerId,
|
|
275
|
+
);
|
|
276
|
+
if (!provider) throw new Error("Invalid provider id");
|
|
277
|
+
|
|
278
|
+
delete model.type;
|
|
279
|
+
provider.chatModels.push(model);
|
|
280
|
+
return model;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
public removeProviderModel(
|
|
284
|
+
providerId: string,
|
|
285
|
+
type: "chat",
|
|
286
|
+
modelKey: string,
|
|
287
|
+
) {
|
|
288
|
+
const provider = this.currentConfig.modelProviders.find(
|
|
289
|
+
(p) => p.id === providerId,
|
|
290
|
+
);
|
|
291
|
+
if (!provider) throw new Error("Invalid provider id");
|
|
292
|
+
|
|
293
|
+
provider.chatModels = provider.chatModels.filter((m) => m.key !== modelKey);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
public isSetupComplete() {
|
|
297
|
+
return this.currentConfig.setupComplete;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
public markSetupComplete() {
|
|
301
|
+
if (!this.currentConfig.setupComplete) {
|
|
302
|
+
this.currentConfig.setupComplete = true;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
public getUIConfigSections(): UIConfigSections {
|
|
307
|
+
this.ensureInitialized();
|
|
308
|
+
return this.uiConfigSections;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
public getCurrentConfig(): Config {
|
|
312
|
+
this.ensureInitialized();
|
|
313
|
+
return JSON.parse(JSON.stringify(this.currentConfig));
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const configManager = new ConfigManager();
|
|
318
|
+
|
|
319
|
+
export default configManager;
|