agent-pulse 1.1.0 → 1.3.0
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 +99 -10
- package/dist/agent.d.ts +2 -2
- package/dist/agent.js +99 -46
- package/dist/providers/google.d.ts +2 -2
- package/dist/providers/google.js +29 -4
- package/dist/providers/grok.d.ts +2 -2
- package/dist/providers/grok.js +27 -3
- package/dist/providers/openai.d.ts +2 -2
- package/dist/providers/openai.js +27 -3
- package/dist/types.d.ts +13 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,7 +49,6 @@ const agentWithKey = new Agent({
|
|
|
49
49
|
provider: new openAI('gpt-4o', process.env.CUSTOM_KEY_NAME || 'your-key'),
|
|
50
50
|
system: 'You are a helpful assistant.'
|
|
51
51
|
});
|
|
52
|
-
```
|
|
53
52
|
|
|
54
53
|
// Real-time typing effect
|
|
55
54
|
agent.on('token', (chunk) => {
|
|
@@ -132,7 +131,8 @@ import { Agent, OpenAIProvider, GoogleProvider, GrokProvider } from 'agent-pulse
|
|
|
132
131
|
| `files` | string[] | Array of file paths or content strings to include in context. |
|
|
133
132
|
| `tools` | Array | List of executable tools with Zod schemas. |
|
|
134
133
|
| `output_schema` | ZodSchema | Enforce structured JSON output (if supported by provider). |
|
|
135
|
-
| `saveFunction` | function | Async function to persist messages (`(msg) => Promise<void>`). |
|
|
134
|
+
| `saveFunction` | function | Async function to persist messages (`(msg: AgentMessage) => Promise<void>`). |
|
|
135
|
+
| `max_tool_iterations` | number | Max iterations for tool call loops (default: 1). |
|
|
136
136
|
|
|
137
137
|
## Events
|
|
138
138
|
|
|
@@ -154,7 +154,8 @@ The `response` event and the `agent.run()` promise resolve to a standardized `Ag
|
|
|
154
154
|
|
|
155
155
|
```typescript
|
|
156
156
|
{
|
|
157
|
-
content: string | object, // The Markdown text or
|
|
157
|
+
content: string | object, // The Markdown text, parsed JSON, or tool result (if iterations=1)
|
|
158
|
+
message?: string, // The original LLM text response (useful when a tool is also called)
|
|
158
159
|
usage: {
|
|
159
160
|
input_tokens: number,
|
|
160
161
|
output_tokens: number,
|
|
@@ -167,6 +168,9 @@ The `response` event and the `agent.run()` promise resolve to a standardized `Ag
|
|
|
167
168
|
}
|
|
168
169
|
```
|
|
169
170
|
|
|
171
|
+
> [!NOTE]
|
|
172
|
+
> If an LLM responds with both text and a tool call (common in Gemini), `content` stays consistent with legacy behavior (holding the tool result), while the new `message` field preserves the original LLM text.
|
|
173
|
+
|
|
170
174
|
You can access token usage stats from the `usage` property.
|
|
171
175
|
|
|
172
176
|
## Error Codes
|
|
@@ -226,7 +230,18 @@ if (result.content?.type === 'INTENT_COMPLETE') {
|
|
|
226
230
|
}
|
|
227
231
|
```
|
|
228
232
|
|
|
229
|
-
#### Option B:
|
|
233
|
+
#### Option B: Handling Text + Tool (Gemini Style)
|
|
234
|
+
When using models like Gemini that often provide a text explanation *and* a tool call in one turn, use the `message` field to access the text.
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
const result = await agent.run("Tell me a joke and then get the weather.");
|
|
238
|
+
|
|
239
|
+
// If weatherTool was called:
|
|
240
|
+
console.log(result.message); // "Sure! Here's a joke: ... Now, let me get the weather for you."
|
|
241
|
+
console.log(result.content); // { temp: 20, unit: 'celsius' } (The tool result)
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
#### Option C: Events (Side Effects)
|
|
230
245
|
Best for logging, UI updates, or real-time monitoring.
|
|
231
246
|
|
|
232
247
|
```typescript
|
|
@@ -238,11 +253,85 @@ agent.on('tool_start', (evt) => {
|
|
|
238
253
|
agent.on('tool_end', (evt) => {
|
|
239
254
|
console.log(`[UI] ✔️ Tool finished:`, evt.result);
|
|
240
255
|
});
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
### 2. Multi-Turn Tool Calling (Autonomous Agent)
|
|
260
|
+
|
|
261
|
+
By setting `max_tool_iterations`, the agent can autonomously call tools, receive results, and reason until it has a final answer.
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
const agent = new Agent({
|
|
265
|
+
name: 'researcher',
|
|
266
|
+
provider: new openAI('gpt-4o'),
|
|
267
|
+
tools: [weatherTool, searchTool],
|
|
268
|
+
max_tool_iterations: 5 // Allow up to 5 loop turns
|
|
269
|
+
});
|
|
241
270
|
|
|
242
|
-
await agent.run("
|
|
271
|
+
const result = await agent.run("What's the weather like in London today?");
|
|
272
|
+
// Agent calls weatherTool -> receives result -> reasons -> returns final text.
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### 3. Manual Tool Responses (Client-Side Loops)
|
|
276
|
+
|
|
277
|
+
If your agent is running on a server but needs the **client** to perform an action (like opening a modal or reading a local file), you can return a UI instruction and then send the result back in the next `run()` call.
|
|
278
|
+
|
|
279
|
+
#### OpenAI Example
|
|
280
|
+
```typescript
|
|
281
|
+
const agent = new Agent({
|
|
282
|
+
name: 'account-mgr',
|
|
283
|
+
provider: new openAI('gpt-4o'),
|
|
284
|
+
tools: [requestConfirmationTool]
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// 1. First Run: Agent requests a tool call
|
|
288
|
+
const res = await agent.run("Delete my account ACC-123");
|
|
289
|
+
|
|
290
|
+
// 2. Client handles the tool call manually (e.g., shows a modal)
|
|
291
|
+
const confirmed = await myUi.showModal(res.content.payload);
|
|
292
|
+
|
|
293
|
+
// 3. Second Run: Send the result back to the agent
|
|
294
|
+
const final = await agent.run([
|
|
295
|
+
{ role: 'user', content: "Delete my account ACC-123" },
|
|
296
|
+
{
|
|
297
|
+
role: 'assistant',
|
|
298
|
+
content: null,
|
|
299
|
+
tool_calls: [{ id: 'call_123', name: 'request_delete', arguments: { id: 'ACC-123' } }]
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
role: 'tool',
|
|
303
|
+
tool_call_id: 'call_123',
|
|
304
|
+
content: JSON.stringify({ confirmed })
|
|
305
|
+
}
|
|
306
|
+
]);
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
#### Gemini Example
|
|
310
|
+
The same pattern works for Gemini! While Google's API uses a different internal format (`functionResponse`), **Agent Pulse** handles the mapping for you. Simply use the standardized `tool` role:
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
const agent = new Agent({
|
|
314
|
+
name: 'gemini-agent',
|
|
315
|
+
provider: new google('gemini-1.5-flash')
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
const final = await agent.run([
|
|
319
|
+
{ role: 'user', content: "Search for weather" },
|
|
320
|
+
{
|
|
321
|
+
role: 'assistant',
|
|
322
|
+
content: null,
|
|
323
|
+
tool_calls: [{ id: 'call_abc', name: 'get_weather', arguments: { loc: 'London' } }]
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
role: 'tool',
|
|
327
|
+
tool_call_id: 'call_abc',
|
|
328
|
+
name: 'get_weather', // Required for Gemini
|
|
329
|
+
content: JSON.stringify({ temp: 20 })
|
|
330
|
+
}
|
|
331
|
+
]);
|
|
243
332
|
```
|
|
244
333
|
|
|
245
|
-
###
|
|
334
|
+
### 4. File Input
|
|
246
335
|
|
|
247
336
|
Pass file content context to the agent.
|
|
248
337
|
|
|
@@ -257,7 +346,7 @@ const agent = new Agent({
|
|
|
257
346
|
});
|
|
258
347
|
```
|
|
259
348
|
|
|
260
|
-
###
|
|
349
|
+
### 4. Structured Output (JSON)
|
|
261
350
|
|
|
262
351
|
Enforce a specific JSON schema for the response.
|
|
263
352
|
|
|
@@ -285,7 +374,7 @@ agent.on('response', (result) => {
|
|
|
285
374
|
await agent.run("How do I make pancakes?");
|
|
286
375
|
```
|
|
287
376
|
|
|
288
|
-
###
|
|
377
|
+
### 5. Server-Side Streaming (SSE)
|
|
289
378
|
|
|
290
379
|
Bridge agent events to a Server-Sent Events stream for frontend consumption (e.g., in Express).
|
|
291
380
|
|
|
@@ -311,7 +400,7 @@ app.get('/chat', async (req, res) => {
|
|
|
311
400
|
});
|
|
312
401
|
```
|
|
313
402
|
|
|
314
|
-
###
|
|
403
|
+
### 6. Google Search Grounding
|
|
315
404
|
|
|
316
405
|
Enable real-time search results and citations with Google models.
|
|
317
406
|
|
|
@@ -359,7 +448,7 @@ const agent = new Agent({
|
|
|
359
448
|
provider: new MyProvider('my-model')
|
|
360
449
|
});
|
|
361
450
|
```
|
|
362
|
-
|
|
451
|
+
## To locally link the package
|
|
363
452
|
|
|
364
453
|
1. Run `npm link` in the agent-pulse directory
|
|
365
454
|
2. Run `npm link agent-pulse --legacy-peer-deps` in your project directory
|
package/dist/agent.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
|
-
import { AgentConfig, AgentResponse } from './types';
|
|
2
|
+
import { AgentConfig, AgentResponse, AgentMessage } from './types';
|
|
3
3
|
export declare class Agent extends EventEmitter {
|
|
4
4
|
private config;
|
|
5
5
|
private provider;
|
|
6
6
|
constructor(config: AgentConfig);
|
|
7
|
-
run(inputContext: string |
|
|
7
|
+
run(inputContext: string | AgentMessage[]): Promise<AgentResponse>;
|
|
8
8
|
}
|
package/dist/agent.js
CHANGED
|
@@ -11,64 +11,96 @@ class Agent extends events_1.EventEmitter {
|
|
|
11
11
|
async run(inputContext) {
|
|
12
12
|
this.emit('start', { timestamp: Date.now(), inputContext });
|
|
13
13
|
const startTime = Date.now();
|
|
14
|
-
//
|
|
14
|
+
// 1. Initialize message history
|
|
15
|
+
let messages = [];
|
|
16
|
+
if (Array.isArray(inputContext)) {
|
|
17
|
+
messages = [...inputContext];
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
const content = typeof inputContext === 'string' ? inputContext : String(inputContext);
|
|
21
|
+
const userContent = this.config.prompt ? `${this.config.prompt}\n\n${content}` : content;
|
|
22
|
+
messages.push({ role: 'user', content: userContent });
|
|
23
|
+
}
|
|
24
|
+
// Persistence: Save initial User Message if it's new
|
|
15
25
|
if (typeof inputContext === 'string' && this.config.saveFunction) {
|
|
16
26
|
try {
|
|
17
|
-
|
|
27
|
+
const lastMsg = messages[messages.length - 1];
|
|
28
|
+
await this.config.saveFunction(lastMsg);
|
|
18
29
|
}
|
|
19
30
|
catch (err) {
|
|
20
31
|
console.error("Failed to save user message:", err);
|
|
21
32
|
}
|
|
22
33
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
finalPrompt = inputContext;
|
|
27
|
-
}
|
|
28
|
-
else {
|
|
29
|
-
const prompt = typeof inputContext === 'string' ? inputContext : String(inputContext);
|
|
30
|
-
finalPrompt = this.config.prompt ? `${this.config.prompt}\n\n${prompt}` : prompt;
|
|
31
|
-
}
|
|
34
|
+
let iterations = 0;
|
|
35
|
+
const maxIterations = this.config.max_tool_iterations || 1;
|
|
36
|
+
let lastResponse = null;
|
|
32
37
|
try {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
// Execute the tool
|
|
41
|
-
// Note: In this lightweight framework, we return the tool result as the final content.
|
|
42
|
-
// This supports the "Intent Detection" pattern where the goal is to trigger an action, not just chat.
|
|
43
|
-
this.emit('tool_start', { tool: tool.name, arguments: call.arguments });
|
|
44
|
-
const result = await tool.execute(call.arguments);
|
|
45
|
-
this.emit('tool_end', { tool: tool.name, result });
|
|
46
|
-
response.content = result;
|
|
47
|
-
}
|
|
48
|
-
catch (e) {
|
|
49
|
-
console.error(`Error executing tool ${tool.name}:`, e);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
38
|
+
while (iterations < maxIterations) {
|
|
39
|
+
iterations++;
|
|
40
|
+
const response = await this.provider.generate(this.config.system, messages, this.config.files, this.config.tools, this.config.config, this.config.output_schema, (token) => this.emit('token', token));
|
|
41
|
+
lastResponse = response;
|
|
42
|
+
// Capture the original text as the "message" (LLM's primary text response)
|
|
43
|
+
if (typeof response.content === 'string') {
|
|
44
|
+
lastResponse.message = response.content;
|
|
52
45
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (this.config.saveFunction) {
|
|
58
|
-
try {
|
|
59
|
-
await this.config.saveFunction({
|
|
46
|
+
// Handle Tool Execution
|
|
47
|
+
if (response.tool_calls && this.config.tools) {
|
|
48
|
+
// Add Assistant's tool call message to history
|
|
49
|
+
const assistantMsg = {
|
|
60
50
|
role: 'assistant',
|
|
61
|
-
content: response.content,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
51
|
+
content: response.content || null,
|
|
52
|
+
tool_calls: response.tool_calls
|
|
53
|
+
};
|
|
54
|
+
messages.push(assistantMsg);
|
|
55
|
+
if (this.config.saveFunction) {
|
|
56
|
+
await this.config.saveFunction(assistantMsg);
|
|
57
|
+
}
|
|
58
|
+
let lastToolResult = null;
|
|
59
|
+
for (const call of response.tool_calls) {
|
|
60
|
+
const tool = this.config.tools.find(t => t.name === call.name);
|
|
61
|
+
if (tool) {
|
|
62
|
+
try {
|
|
63
|
+
this.emit('tool_start', { tool: tool.name, arguments: call.arguments });
|
|
64
|
+
const result = await tool.execute(call.arguments);
|
|
65
|
+
this.emit('tool_end', { tool: tool.name, result });
|
|
66
|
+
lastToolResult = result;
|
|
67
|
+
const toolMsg = {
|
|
68
|
+
role: 'tool',
|
|
69
|
+
tool_call_id: call.id,
|
|
70
|
+
name: tool.name,
|
|
71
|
+
content: typeof result === 'string' ? result : JSON.stringify(result)
|
|
72
|
+
};
|
|
73
|
+
messages.push(toolMsg);
|
|
74
|
+
if (this.config.saveFunction) {
|
|
75
|
+
await this.config.saveFunction(toolMsg);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
console.error(`Error executing tool ${tool.name}:`, e);
|
|
80
|
+
// Add error as tool result so LLM knows what happened
|
|
81
|
+
const errorMsg = {
|
|
82
|
+
role: 'tool',
|
|
83
|
+
tool_call_id: call.id,
|
|
84
|
+
name: tool.name,
|
|
85
|
+
content: `Error: ${e instanceof Error ? e.message : String(e)}`
|
|
86
|
+
};
|
|
87
|
+
messages.push(errorMsg);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// For the "Intent Detection" pattern (maxIterations = 1),
|
|
92
|
+
// we return the last tool result as the content to preserve legacy behavior.
|
|
93
|
+
if (maxIterations === 1 && lastToolResult !== null) {
|
|
94
|
+
lastResponse.content = lastToolResult;
|
|
95
|
+
}
|
|
96
|
+
// If we have more iterations, continue the loop
|
|
97
|
+
if (iterations < maxIterations) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
68
100
|
}
|
|
101
|
+
// If no tool calls OR we reached limit, break and return
|
|
102
|
+
break;
|
|
69
103
|
}
|
|
70
|
-
this.emit('response', response);
|
|
71
|
-
return response;
|
|
72
104
|
}
|
|
73
105
|
catch (error) {
|
|
74
106
|
this.emit('error', {
|
|
@@ -78,6 +110,27 @@ class Agent extends events_1.EventEmitter {
|
|
|
78
110
|
});
|
|
79
111
|
throw error;
|
|
80
112
|
}
|
|
113
|
+
if (!lastResponse) {
|
|
114
|
+
throw new Error("Agent failed to generate a response");
|
|
115
|
+
}
|
|
116
|
+
// Add latency to meta
|
|
117
|
+
lastResponse.meta.latency_ms = Date.now() - startTime;
|
|
118
|
+
// Persistence: Save Final Assistant Response
|
|
119
|
+
if (this.config.saveFunction) {
|
|
120
|
+
try {
|
|
121
|
+
await this.config.saveFunction({
|
|
122
|
+
role: 'assistant',
|
|
123
|
+
content: lastResponse.content,
|
|
124
|
+
usage: lastResponse.usage,
|
|
125
|
+
meta: lastResponse.meta
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
console.error("Failed to save assistant response:", err);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
this.emit('response', lastResponse);
|
|
133
|
+
return lastResponse;
|
|
81
134
|
}
|
|
82
135
|
}
|
|
83
136
|
exports.Agent = Agent;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { LLMProvider, AgentTool, AgentResponse } from '../types';
|
|
1
|
+
import { LLMProvider, AgentTool, AgentResponse, AgentMessage } from '../types';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
export declare class GoogleProvider implements LLMProvider {
|
|
4
4
|
private client;
|
|
5
5
|
private model;
|
|
6
6
|
constructor(model: string, apiKey?: string);
|
|
7
|
-
generate(system: string | undefined, prompt: string |
|
|
7
|
+
generate(system: string | undefined, prompt: string | AgentMessage[], files: string[] | undefined, tools: AgentTool[] | undefined, config: Record<string, any> | undefined, output_schema: z.ZodType<any> | undefined, onToken: (token: string) => void): Promise<AgentResponse>;
|
|
8
8
|
}
|
package/dist/providers/google.js
CHANGED
|
@@ -59,10 +59,35 @@ class GoogleProvider {
|
|
|
59
59
|
let contents;
|
|
60
60
|
if (Array.isArray(prompt)) {
|
|
61
61
|
// Mapping standardized history to Google's format
|
|
62
|
-
contents = prompt.map(m =>
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
contents = prompt.map(m => {
|
|
63
|
+
const parts = [];
|
|
64
|
+
if (m.role === 'tool') {
|
|
65
|
+
parts.push({
|
|
66
|
+
functionResponse: {
|
|
67
|
+
name: m.name,
|
|
68
|
+
response: typeof m.content === 'string' ? JSON.parse(m.content) : m.content
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
return { role: 'user', parts }; // SDK v2 uses 'user' for function response
|
|
72
|
+
}
|
|
73
|
+
if (m.tool_calls) {
|
|
74
|
+
for (const tc of m.tool_calls) {
|
|
75
|
+
parts.push({
|
|
76
|
+
functionCall: {
|
|
77
|
+
name: tc.name,
|
|
78
|
+
args: tc.arguments
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (m.content) {
|
|
84
|
+
parts.push({ text: m.content });
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
role: m.role === 'assistant' ? 'model' : 'user',
|
|
88
|
+
parts
|
|
89
|
+
};
|
|
90
|
+
});
|
|
66
91
|
// Handle files by appending to the last message if it's from user
|
|
67
92
|
if (files && files.length > 0) {
|
|
68
93
|
const lastMsg = contents[contents.length - 1];
|
package/dist/providers/grok.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { LLMProvider, AgentTool, AgentResponse } from '../types';
|
|
1
|
+
import { LLMProvider, AgentTool, AgentResponse, AgentMessage } from '../types';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
export declare class GrokProvider implements LLMProvider {
|
|
4
4
|
private client;
|
|
5
5
|
private model;
|
|
6
6
|
constructor(model: string, apiKey?: string);
|
|
7
|
-
generate(system: string | undefined, prompt: string |
|
|
7
|
+
generate(system: string | undefined, prompt: string | AgentMessage[], files: string[] | undefined, tools: AgentTool[] | undefined, config: Record<string, any> | undefined, output_schema: z.ZodType<any> | undefined, onToken: (token: string) => void): Promise<AgentResponse>;
|
|
8
8
|
}
|
package/dist/providers/grok.js
CHANGED
|
@@ -24,9 +24,33 @@ class GrokProvider {
|
|
|
24
24
|
messages.push({ role: 'system', content: system });
|
|
25
25
|
}
|
|
26
26
|
if (Array.isArray(prompt)) {
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
// Mapping AgentMessage to OpenAI messages (Grok is compatible)
|
|
28
|
+
for (const msg of prompt) {
|
|
29
|
+
if (msg.role === 'user') {
|
|
30
|
+
messages.push({ role: 'user', content: msg.content });
|
|
31
|
+
}
|
|
32
|
+
else if (msg.role === 'assistant') {
|
|
33
|
+
messages.push({
|
|
34
|
+
role: 'assistant',
|
|
35
|
+
content: msg.content || null,
|
|
36
|
+
tool_calls: msg.tool_calls?.map(tc => ({
|
|
37
|
+
id: tc.id,
|
|
38
|
+
type: 'function',
|
|
39
|
+
function: {
|
|
40
|
+
name: tc.name,
|
|
41
|
+
arguments: typeof tc.arguments === 'string' ? tc.arguments : JSON.stringify(tc.arguments)
|
|
42
|
+
}
|
|
43
|
+
}))
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
else if (msg.role === 'tool') {
|
|
47
|
+
messages.push({
|
|
48
|
+
role: 'tool',
|
|
49
|
+
tool_call_id: msg.tool_call_id,
|
|
50
|
+
content: typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content)
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
30
54
|
}
|
|
31
55
|
else {
|
|
32
56
|
// Handle files - read markdown files and inject into prompt
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { LLMProvider, AgentTool, AgentResponse } from '../types';
|
|
1
|
+
import { LLMProvider, AgentTool, AgentResponse, AgentMessage } from '../types';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
export declare class OpenAIProvider implements LLMProvider {
|
|
4
4
|
private client;
|
|
5
5
|
private model;
|
|
6
6
|
constructor(model: string, apiKey?: string);
|
|
7
|
-
generate(system: string | undefined, prompt: string |
|
|
7
|
+
generate(system: string | undefined, prompt: string | AgentMessage[], files: string[] | undefined, tools: AgentTool[] | undefined, config: Record<string, any> | undefined, output_schema: z.ZodType<any> | undefined, onToken: (token: string) => void): Promise<AgentResponse>;
|
|
8
8
|
}
|
package/dist/providers/openai.js
CHANGED
|
@@ -22,9 +22,33 @@ class OpenAIProvider {
|
|
|
22
22
|
messages.push({ role: 'system', content: system });
|
|
23
23
|
}
|
|
24
24
|
if (Array.isArray(prompt)) {
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
// Mapping AgentMessage to OpenAI messages
|
|
26
|
+
for (const msg of prompt) {
|
|
27
|
+
if (msg.role === 'user') {
|
|
28
|
+
messages.push({ role: 'user', content: msg.content });
|
|
29
|
+
}
|
|
30
|
+
else if (msg.role === 'assistant') {
|
|
31
|
+
messages.push({
|
|
32
|
+
role: 'assistant',
|
|
33
|
+
content: msg.content || null,
|
|
34
|
+
tool_calls: msg.tool_calls?.map(tc => ({
|
|
35
|
+
id: tc.id,
|
|
36
|
+
type: 'function',
|
|
37
|
+
function: {
|
|
38
|
+
name: tc.name,
|
|
39
|
+
arguments: typeof tc.arguments === 'string' ? tc.arguments : JSON.stringify(tc.arguments)
|
|
40
|
+
}
|
|
41
|
+
}))
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
else if (msg.role === 'tool') {
|
|
45
|
+
messages.push({
|
|
46
|
+
role: 'tool',
|
|
47
|
+
tool_call_id: msg.tool_call_id,
|
|
48
|
+
content: typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content)
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
28
52
|
}
|
|
29
53
|
else {
|
|
30
54
|
// Handle files - read markdown files and inject into prompt
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
export interface AgentMessage {
|
|
3
|
+
role: 'system' | 'user' | 'assistant' | 'tool';
|
|
4
|
+
content: string | any;
|
|
5
|
+
name?: string;
|
|
6
|
+
tool_calls?: any[];
|
|
7
|
+
tool_call_id?: string;
|
|
8
|
+
usage?: any;
|
|
9
|
+
meta?: any;
|
|
10
|
+
}
|
|
2
11
|
export interface AgentConfig {
|
|
3
12
|
name: string;
|
|
4
13
|
provider: LLMProvider;
|
|
@@ -8,7 +17,8 @@ export interface AgentConfig {
|
|
|
8
17
|
config?: Record<string, any>;
|
|
9
18
|
tools?: AgentTool[];
|
|
10
19
|
output_schema?: z.ZodType<any>;
|
|
11
|
-
saveFunction?: (message:
|
|
20
|
+
saveFunction?: (message: AgentMessage) => Promise<void> | void;
|
|
21
|
+
max_tool_iterations?: number;
|
|
12
22
|
}
|
|
13
23
|
export interface AgentTool {
|
|
14
24
|
name: string;
|
|
@@ -19,6 +29,7 @@ export interface AgentTool {
|
|
|
19
29
|
export interface AgentResponse {
|
|
20
30
|
content: string | object;
|
|
21
31
|
tool_calls?: any[];
|
|
32
|
+
message?: string;
|
|
22
33
|
usage: {
|
|
23
34
|
input_tokens: number;
|
|
24
35
|
output_tokens: number;
|
|
@@ -41,5 +52,5 @@ export interface AgentError {
|
|
|
41
52
|
details?: any;
|
|
42
53
|
}
|
|
43
54
|
export interface LLMProvider {
|
|
44
|
-
generate(system: string | undefined, prompt: string |
|
|
55
|
+
generate(system: string | undefined, prompt: string | AgentMessage[], files: string[] | undefined, tools: AgentTool[] | undefined, config: Record<string, any> | undefined, output_schema: z.ZodType<any> | undefined, onToken: (token: string) => void): Promise<AgentResponse>;
|
|
45
56
|
}
|