@avee1234/agent-kit 0.3.4 → 0.3.6

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 CHANGED
@@ -6,341 +6,190 @@
6
6
 
7
7
  TypeScript-first library for building stateful, persistent AI agents.
8
8
 
9
- <p align="center">
10
- <img src="assets/demo.svg" alt="agent-kit demo — memory persists across sessions" width="750" />
11
- </p>
12
-
13
- ## Why agent-kit?
9
+ **[Live Playground](https://www.abhi-agent-kit.space)** | **[Blog Post](https://abhid.substack.com/p/i-built-an-open-source-ai-agent-framework)** | **[npm](https://www.npmjs.com/package/@avee1234/agent-kit)** | **[Docs](https://abhid1234.github.io/agent-kit/)**
14
10
 
15
- - **Persistent memory across sessions** — SQLite store keeps conversation history and auto-summarizes old exchanges. Restart your process; the agent still remembers.
16
- - **Simple tool system** — define a tool in five lines with `Tool.create`. No decorator magic, no class inheritance.
17
- - **Built-in observability** — subscribe to `message`, `tool:start`, `tool:end`, and `error` events. No paid add-on required.
18
- - **TypeScript-first with great types** — strict types throughout. Your editor autocompletes `AgentConfig`, `ToolDefinition`, `AgentEvent`, and everything else.
11
+ ---
19
12
 
20
- ## Installation
21
-
22
- ```bash
23
- npm install @avee1234/agent-kit
24
- ```
13
+ ## Why agent-kit?
25
14
 
26
- ## Quick Start
15
+ <p align="center">
16
+ <img src="https://substack-post-media.s3.amazonaws.com/public/images/a427e237-04d0-421e-b1b7-ae2567c1d5d6_1883x981.png" alt="Comparison with LangChain, Vercel AI SDK, CrewAI" width="700" />
17
+ </p>
27
18
 
28
- ```typescript
29
- import { Agent, Tool, Memory } from '@avee1234/agent-kit';
19
+ - **Persistent memory across sessions** — SQLite or PostgreSQL. Restart your process; the agent still remembers.
20
+ - **Simple tool system** — define a tool in 5 lines with `Tool.create`. No decorators, no class inheritance.
21
+ - **Multi-agent coordination** — 4 strategies: Sequential, Parallel, Debate, Hierarchical.
22
+ - **Built-in observability** — subscribe to `tool:start`, `tool:end`, `memory:save` events. No paid add-on.
23
+ - **TypeScript-first** — strict types throughout. Your editor autocompletes everything.
30
24
 
31
- const echo = Tool.create({
32
- name: 'echo',
33
- description: 'Echo a message back',
34
- parameters: { message: { type: 'string', description: 'Text to echo' } },
35
- execute: async ({ message }) => String(message),
36
- });
25
+ ---
37
26
 
38
- const agent = new Agent({
39
- name: 'my-agent',
40
- memory: new Memory({ store: 'sqlite' }),
41
- tools: [echo],
42
- system: 'You are a helpful assistant.',
43
- });
27
+ ## 4 Core Concepts
44
28
 
45
- const response = await agent.chat('Say hello');
46
- console.log(response.content);
47
- ```
29
+ <p align="center">
30
+ <img src="https://substack-post-media.s3.amazonaws.com/public/images/b36d2dd8-ee82-4798-864d-e56c1801293e_1883x1267.png" alt="Agent, Tool, Memory, Team — 4 core concepts" width="700" />
31
+ </p>
48
32
 
49
- No model config required — `Agent` ships with a built-in `MockAdapter` so you can develop and test without any API keys.
33
+ <p align="center">
34
+ <img src="https://substack-post-media.s3.amazonaws.com/public/images/6ffd48ee-59bc-4c0f-8b0f-3cae0e674a4c_1455x1470.png" alt="Agent, Tool, Memory, Team — with code examples" width="700" />
35
+ </p>
50
36
 
51
- ## Research Assistant Demo
37
+ ---
52
38
 
53
- The `examples/research-assistant` directory contains a full CLI agent that searches the web, saves notes, and remembers research across sessions.
39
+ ## Installation
54
40
 
55
41
  ```bash
56
- cd examples/research-assistant
57
- npm install
58
- npm start
42
+ npm install @avee1234/agent-kit
59
43
  ```
60
44
 
61
- Then chat with it:
45
+ Or scaffold a new project:
62
46
 
47
+ ```bash
48
+ npx @avee1234/agent-kit init my-agent
63
49
  ```
64
- > Find recent papers on transformer alternatives
65
- > What did I research last time?
66
- > Save a note about Mamba architecture
67
- ```
68
-
69
- Kill the process and restart — memory persists in `research.db`.
70
-
71
- ## Core Concepts
72
50
 
73
- ### Agent
51
+ ---
74
52
 
75
- The main class. Runs a tool-calling loop, manages memory context, and emits observability events.
53
+ ## Quick Start
76
54
 
77
55
  ```typescript
78
- import { Agent } from '@avee1234/agent-kit';
56
+ import { Agent, Tool, Memory } from '@avee1234/agent-kit';
57
+
58
+ const searchTool = Tool.create({
59
+ name: 'web_search',
60
+ description: 'Search the web',
61
+ parameters: { query: { type: 'string' } },
62
+ execute: async ({ query }) => fetch(`https://api.search.com?q=${query}`).then(r => r.json()),
63
+ });
79
64
 
80
65
  const agent = new Agent({
81
- name: 'assistant',
66
+ name: 'research-assistant',
82
67
  model: { provider: 'ollama', model: 'llama3' },
83
68
  memory: new Memory({ store: 'sqlite' }),
84
- tools: [myTool],
85
- system: 'You are a helpful assistant.',
86
- maxToolRounds: 10,
69
+ tools: [searchTool],
70
+ system: 'You are a research assistant.',
87
71
  });
88
- ```
89
-
90
- | Option | Type | Default | Description |
91
- |---|---|---|---|
92
- | `name` | `string` | required | Unique identifier for this agent |
93
- | `model` | `ModelAdapter \| ModelConfig` | `MockAdapter` | Model to use for completions |
94
- | `memory` | `Memory` | none | Memory instance for persistence |
95
- | `tools` | `Tool[]` | `[]` | Tools the agent can call |
96
- | `system` | `string` | none | System prompt |
97
- | `maxToolRounds` | `number` | `10` | Max consecutive tool call rounds |
98
-
99
- **Methods:**
100
-
101
- - `agent.chat(input: string): Promise<ModelResponse>` — send a message, get a response
102
- - `agent.stream(input: string): AsyncIterable<ModelChunk>` — stream the response
103
- - `agent.on(type, handler)` / `agent.off(type, handler)` — subscribe to events
104
72
 
105
- ### Tool
106
-
107
- Wraps a function so the agent can call it.
108
-
109
- ```typescript
110
- import { Tool } from '@avee1234/agent-kit';
111
-
112
- const getWeather = Tool.create({
113
- name: 'get_weather',
114
- description: 'Get current weather for a city',
115
- parameters: {
116
- city: { type: 'string', description: 'City name', required: true },
117
- units: { type: 'string', enum: ['celsius', 'fahrenheit'] },
118
- },
119
- execute: async ({ city, units }) => {
120
- const u = units ?? 'celsius';
121
- const res = await fetch(`https://wttr.in/${city}?format=j1`);
122
- return res.json();
123
- },
124
- });
73
+ const response = await agent.chat('Find recent papers on transformers');
125
74
  ```
126
75
 
127
- | Field | Type | Description |
128
- |---|---|---|
129
- | `name` | `string` | Tool name (used by the model) |
130
- | `description` | `string` | What the tool does |
131
- | `parameters` | `Record<string, ParameterDef>` | JSON Schema-style parameter definitions |
132
- | `execute` | `(params) => Promise<unknown>` | The function to run |
76
+ No model config required ships with a built-in `MockAdapter` for development and testing without API keys.
133
77
 
134
- `ParameterDef` fields: `type`, `description`, `enum`, `required`.
78
+ ---
135
79
 
136
- ### Memory
137
-
138
- Manages conversation persistence and context retrieval.
139
-
140
- ```typescript
141
- import { Memory } from '@avee1234/agent-kit';
80
+ ## The "Wow Moment": Memory That Survives Restarts
142
81
 
143
- // In-memory (default, testing)
144
- new Memory()
145
- new Memory({ store: 'memory' })
146
-
147
- // SQLite (persists across restarts)
148
- new Memory({ store: 'sqlite' })
149
- new Memory({ store: 'sqlite', path: './myagent.db' })
150
-
151
- // Custom store
152
- new Memory({ store: myCustomStore })
153
- ```
154
-
155
- | Option | Type | Default | Description |
156
- |---|---|---|---|
157
- | `store` | `'memory' \| 'sqlite' \| MemoryStore` | `'memory'` | Storage backend |
158
- | `path` | `string` | `./agent-memory.db` | SQLite file path (sqlite only) |
159
- | `windowSize` | `number` | `20` | Number of recent messages to include in context |
160
- | `summarizeAfter` | `number` | `20` | Summarize after this many new messages |
161
-
162
- Auto-summarization: when `summarizeAfter` messages accumulate, the agent summarizes them and stores the summary. Older context is retrieved via `searchSummaries`.
163
-
164
- ### Team (Multi-Agent Coordination)
82
+ <p align="center">
83
+ <img src="https://substack-post-media.s3.amazonaws.com/public/images/fe5daa4c-39a6-4754-abf5-b5ec12ad3ebb_1406x768.png" alt="Agent remembers context across process restarts" width="700" />
84
+ </p>
165
85
 
166
- Coordinate multiple agents on a single task using four strategies.
86
+ Kill the process, restart it, same SQLite file the agent picks up where it left off.
167
87
 
168
- **Sequential** — agents run in order, each getting the previous agent's output:
88
+ <p align="center">
89
+ <img src="https://substack-post-media.s3.amazonaws.com/public/images/299b2c3f-97e2-4e85-baaf-81edd3965c7c_1406x602.png" alt="Short-term → Summarization → Long-term memory pipeline" width="700" />
90
+ </p>
169
91
 
170
- ```typescript
171
- import { Agent, Team } from '@avee1234/agent-kit';
92
+ ---
172
93
 
173
- const team = new Team({
174
- agents: [researcher, writer],
175
- strategy: 'sequential',
176
- });
177
- const result = await team.run('Research AI frameworks and write a summary');
178
- // writer receives researcher's output as context
179
- ```
94
+ ## Multi-Agent Coordination
180
95
 
181
- **Parallel** — all agents run concurrently, results merged:
96
+ <p align="center">
97
+ <img src="https://substack-post-media.s3.amazonaws.com/public/images/ec242300-00e3-47b8-a399-695c235ecf84_1406x1402.png" alt="4 coordination strategies: Sequential, Parallel, Debate, Hierarchical" width="700" />
98
+ </p>
182
99
 
183
100
  ```typescript
184
101
  const team = new Team({
185
102
  agents: [researcher, writer, critic],
186
- strategy: 'parallel',
187
- });
188
- const result = await team.run('Analyze this codebase');
189
- // result.responses has each agent's individual output
190
- ```
191
-
192
- **Debate** — agents take turns critiquing and refining:
193
-
194
- ```typescript
195
- const team = new Team({
196
- agents: [proposer, critic],
197
103
  strategy: 'debate',
198
104
  maxRounds: 3,
199
105
  });
200
106
  const result = await team.run('What is the best database for embeddings?');
201
- // 3 rounds of back-and-forth, then final answer
202
107
  ```
203
108
 
204
- **Hierarchical** — a manager delegates tasks to specialists:
109
+ ---
110
+
111
+ ## Built-In Observability
112
+
113
+ <p align="center">
114
+ <img src="https://substack-post-media.s3.amazonaws.com/public/images/1588753c-8afa-4f9e-8e30-39090368c641_1406x471.png" alt="Real-time event stream: tool:start, tool:end, memory" width="700" />
115
+ </p>
205
116
 
206
117
  ```typescript
207
- const team = new Team({
208
- agents: [researcher, writer, critic],
209
- strategy: 'hierarchical',
210
- manager: new Agent({ name: 'manager', system: 'You coordinate a team of specialists.' }),
211
- });
212
- const result = await team.run('Write a blog post about transformer alternatives');
213
- // manager decides who does what and when
118
+ agent.on('*', (e) => console.log(e.type, e.data, e.latencyMs));
214
119
  ```
215
120
 
216
- | Option | Type | Default | Description |
217
- |--------|------|---------|-------------|
218
- | `agents` | `Agent[]` | — | The agents to coordinate |
219
- | `strategy` | `string` | — | `'sequential'`, `'parallel'`, `'debate'`, or `'hierarchical'` |
220
- | `manager` | `Agent` | — | Required for hierarchical strategy |
221
- | `maxRounds` | `number` | `3` | Number of debate rounds |
222
- | `maxDelegations` | `number` | `10` | Max delegations for hierarchical |
121
+ No LangSmith, no third-party service. Just `EventEmitter` pipe it to whatever you use.
223
122
 
224
- ## Model Configuration
225
-
226
- ### Mock (zero config, built-in)
123
+ ---
227
124
 
228
- If you omit `model`, the agent uses `MockAdapter` — it echoes inputs and simulates tool calls. Useful for testing.
125
+ ## Where Each Tool Shines
229
126
 
230
- ```typescript
231
- import { MockAdapter } from '@avee1234/agent-kit';
127
+ <p align="center">
128
+ <img src="https://substack-post-media.s3.amazonaws.com/public/images/4ac5f833-33a0-4c48-92fe-20c27f4426e2_1406x565.png" alt="Comparison table: LangChain vs Vercel AI SDK vs CrewAI vs agent-kit" width="700" />
129
+ </p>
232
130
 
233
- const agent = new Agent({ name: 'test', model: new MockAdapter() });
234
- ```
131
+ ---
235
132
 
236
- ### Ollama (local models)
133
+ ## Model Configuration
237
134
 
238
135
  ```typescript
239
- const agent = new Agent({
240
- name: 'local-agent',
241
- model: { provider: 'ollama', model: 'llama3' },
242
- // baseURL defaults to http://localhost:11434/v1
243
- });
244
- ```
245
-
246
- ### OpenAI-compatible endpoints
136
+ // Mock (zero config, built-in — great for testing)
137
+ const agent = new Agent({ name: 'test' });
247
138
 
248
- Works with Together AI, OpenRouter, Anyscale, LM Studio, and any other OpenAI-compatible API.
249
-
250
- ```typescript
251
- import { OpenAICompatibleAdapter } from '@avee1234/agent-kit';
139
+ // Ollama (local models)
140
+ const agent = new Agent({ name: 'local', model: { provider: 'ollama', model: 'llama3' } });
252
141
 
142
+ // Google AI Studio (Gemini)
253
143
  const agent = new Agent({
254
- name: 'agent',
144
+ name: 'gemini',
255
145
  model: new OpenAICompatibleAdapter({
256
- baseURL: 'https://api.together.xyz/v1',
257
- model: 'meta-llama/Llama-3-70b-chat-hf',
258
- apiKey: process.env.TOGETHER_API_KEY,
146
+ baseURL: 'https://generativelanguage.googleapis.com/v1beta/openai',
147
+ model: 'gemini-2.0-flash',
148
+ apiKey: process.env.GOOGLE_AI_API_KEY,
259
149
  }),
260
150
  });
261
- ```
262
-
263
- ## Events
264
-
265
- Subscribe to events for logging, tracing, or custom observability.
266
-
267
- ```typescript
268
- agent.on('message', (e) => {
269
- console.log(`[${e.data.role}] ${e.data.content}`);
270
- });
271
-
272
- agent.on('tool:start', (e) => {
273
- console.log(`Calling ${e.data.toolName}...`);
274
- });
275
151
 
276
- agent.on('tool:end', (e) => {
277
- console.log(`${e.data.toolName} finished in ${e.latencyMs}ms`);
278
- });
279
-
280
- agent.on('memory:retrieve', (e) => {
281
- console.log(`Loaded ${e.data.recentMessages} messages, ${e.data.summaries} summaries`);
282
- });
283
-
284
- agent.on('error', (e) => {
285
- console.error(`Error: ${e.data.message}`);
286
- });
287
-
288
- // Catch all events
289
- agent.on('*', (e) => {
290
- myTracer.record(e);
152
+ // Any OpenAI-compatible endpoint (Together, OpenRouter, Groq, etc.)
153
+ const agent = new Agent({
154
+ name: 'agent',
155
+ model: new OpenAICompatibleAdapter({ baseURL: '...', model: '...', apiKey: '...' }),
291
156
  });
292
157
  ```
293
158
 
294
- | Event type | `data` fields | Description |
295
- |---|---|---|
296
- | `message` | `role`, `content` | User or assistant message |
297
- | `tool:start` | `toolName`, `toolCallId`, `arguments` | Tool call started |
298
- | `tool:end` | `toolName`, `toolCallId`, `result`, `latencyMs` | Tool call finished |
299
- | `memory:retrieve` | `recentMessages`, `summaries` | Memory context loaded |
300
- | `error` | `message`, `toolName`, `toolCallId` | Error during tool execution |
159
+ ---
301
160
 
302
- All events include `type`, `timestamp`, and `agentId` fields from `AgentEvent`.
161
+ ## Try It Live
303
162
 
304
- ## Custom MemoryStore
163
+ <p align="center">
164
+ <img src="https://substack-post-media.s3.amazonaws.com/public/images/381c61cd-cc61-46de-9351-460ec3b78012_1405x563.png" alt="Live playground powered by Google Cloud Run and Gemini" width="700" />
165
+ </p>
305
166
 
306
- Implement the `MemoryStore` interface to plug in any storage backend (PostgreSQL, Redis, DynamoDB, etc.).
167
+ **[www.abhi-agent-kit.space](https://www.abhi-agent-kit.space)**
307
168
 
308
- ```typescript
309
- import type { MemoryStore } from '@avee1234/agent-kit';
310
- import type { Message, Summary } from '@avee1234/agent-kit';
169
+ 4 pre-built agents with real-time tool execution, persistent memory, and live event streaming. Powered by Gemini 2.0 Flash on Google Cloud Run.
311
170
 
312
- class MyStore implements MemoryStore {
313
- async saveMessages(agentId: string, messages: Message[]): Promise<void> {
314
- // persist messages
315
- }
171
+ ---
316
172
 
317
- async getRecentMessages(agentId: string, limit: number): Promise<Message[]> {
318
- // return most recent `limit` messages
319
- }
173
+ ## What You Can Build
320
174
 
321
- async saveSummary(agentId: string, summary: Summary): Promise<void> {
322
- // persist summary
323
- }
175
+ <p align="center">
176
+ <img src="https://substack-post-media.s3.amazonaws.com/public/images/97e622f7-78f6-4066-bd2b-4ce4452b78f4_1405x936.png" alt="What I'd do differently — lessons learned" width="700" />
177
+ </p>
324
178
 
325
- async searchSummaries(agentId: string, query: string, limit: number): Promise<Summary[]> {
326
- // return relevant summaries (keyword or vector search)
327
- }
328
- }
179
+ - **Travel planner** destination search + weather + flight/hotel booking + budget calculator
180
+ - **Research assistant** web search + note-taking + session memory
181
+ - **Customer support** — order lookup + conversation history
182
+ - **Code reviewer** — security analysis + style checking
183
+ - **Data analyst** — SQL queries + chart generation + persistent findings
184
+ - **Personal assistant** — calendar + email + long-term preferences
329
185
 
330
- const agent = new Agent({
331
- name: 'agent',
332
- memory: new Memory({ store: new MyStore() }),
333
- });
334
- ```
186
+ ---
335
187
 
336
- ## What You Can Build
188
+ ## Read More
337
189
 
338
- - **Research assistant** — web search + note-taking + session memory
339
- - **Customer support bot** — ticket creation + knowledge base lookup + conversation history
340
- - **Code reviewer** — file read/write tools + PR comment integration
341
- - **Data analyst** — SQL query tool + chart generation + persistent findings
342
- - **Personal assistant** — calendar access + email tools + long-term user preferences
343
- - **DevOps incident responder** — log search + runbook lookup + alert suppression
190
+ - **[Blog Post](https://abhid.substack.com/p/i-built-an-open-source-ai-agent-framework)** — the full story of why and how I built agent-kit
191
+ - **[Documentation](https://abhid1234.github.io/agent-kit/)** — API reference, guides, and examples
192
+ - **[npm](https://www.npmjs.com/package/@avee1234/agent-kit)** — `npm install @avee1234/agent-kit`
344
193
 
345
194
  ## Contributing
346
195
 
package/dist/index.cjs CHANGED
@@ -95,7 +95,7 @@ var OpenAICompatibleAdapter = class {
95
95
  async chat(messages, tools) {
96
96
  const body = {
97
97
  model: this.config.model,
98
- messages: messages.map((m) => this.toOpenAIMessage(m))
98
+ messages: messages.map((m) => this.toOpenAIMessage(m, messages))
99
99
  };
100
100
  if (tools?.length) {
101
101
  body.tools = tools.map((t) => ({
@@ -148,7 +148,7 @@ var OpenAICompatibleAdapter = class {
148
148
  if (this.config.apiKey) headers["Authorization"] = `Bearer ${this.config.apiKey}`;
149
149
  const body = {
150
150
  model: this.config.model,
151
- messages: messages.map((m) => this.toOpenAIMessage(m)),
151
+ messages: messages.map((m) => this.toOpenAIMessage(m, messages)),
152
152
  stream: true
153
153
  };
154
154
  if (tools?.length) {
@@ -201,7 +201,7 @@ var OpenAICompatibleAdapter = class {
201
201
  }
202
202
  }
203
203
  }
204
- toOpenAIMessage(msg) {
204
+ toOpenAIMessage(msg, allMessages) {
205
205
  const result = { role: msg.role, content: msg.content };
206
206
  if (msg.toolCalls) {
207
207
  result.tool_calls = msg.toolCalls.map((tc) => ({
@@ -210,7 +210,25 @@ var OpenAICompatibleAdapter = class {
210
210
  function: { name: tc.name, arguments: tc.arguments }
211
211
  }));
212
212
  }
213
- if (msg.toolCallId) result.tool_call_id = msg.toolCallId;
213
+ if (msg.toolCallId) {
214
+ result.tool_call_id = msg.toolCallId;
215
+ let foundName = false;
216
+ if (allMessages) {
217
+ for (const m of allMessages) {
218
+ if (m.toolCalls) {
219
+ const tc = m.toolCalls.find((t) => t.id === msg.toolCallId);
220
+ if (tc) {
221
+ result.name = tc.name;
222
+ foundName = true;
223
+ break;
224
+ }
225
+ }
226
+ }
227
+ }
228
+ if (!foundName) {
229
+ result.name = "tool_result";
230
+ }
231
+ }
214
232
  return result;
215
233
  }
216
234
  };