feat: add native agent with conversation history

This commit is contained in:
William Valentin
2026-02-02 20:56:46 -08:00
parent 70c3960527
commit 69309e58bc
4 changed files with 119 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
export { NativeAgent, type NativeAgentConfig } from './native/index.js';
+79
View File
@@ -0,0 +1,79 @@
import { describe, it, expect, vi } from 'vitest';
import { NativeAgent } from './agent.js';
import type { ModelClient, ChatResponse } from '../../models/types.js';
describe('NativeAgent', () => {
it('processes message and returns response', async () => {
const mockClient: ModelClient = {
chat: vi.fn().mockResolvedValue({
content: 'Hello! How can I help you?',
stopReason: 'end_turn',
usage: { inputTokens: 10, outputTokens: 8 },
} satisfies ChatResponse),
};
const agent = new NativeAgent({
modelClient: mockClient,
systemPrompt: 'You are Flynn, a helpful assistant.',
});
const response = await agent.process('Hello');
expect(response).toBe('Hello! How can I help you?');
expect(mockClient.chat).toHaveBeenCalledWith({
messages: [{ role: 'user', content: 'Hello' }],
system: 'You are Flynn, a helpful assistant.',
});
});
it('maintains conversation history', async () => {
const mockClient: ModelClient = {
chat: vi.fn().mockResolvedValue({
content: 'Response',
stopReason: 'end_turn',
usage: { inputTokens: 10, outputTokens: 5 },
} satisfies ChatResponse),
};
const agent = new NativeAgent({
modelClient: mockClient,
systemPrompt: 'System',
});
await agent.process('First message');
await agent.process('Second message');
expect(mockClient.chat).toHaveBeenLastCalledWith({
messages: [
{ role: 'user', content: 'First message' },
{ role: 'assistant', content: 'Response' },
{ role: 'user', content: 'Second message' },
],
system: 'System',
});
});
it('resets conversation history', async () => {
const mockClient: ModelClient = {
chat: vi.fn().mockResolvedValue({
content: 'Response',
stopReason: 'end_turn',
usage: { inputTokens: 10, outputTokens: 5 },
} satisfies ChatResponse),
};
const agent = new NativeAgent({
modelClient: mockClient,
systemPrompt: 'System',
});
await agent.process('Message 1');
agent.reset();
await agent.process('Message 2');
expect(mockClient.chat).toHaveBeenLastCalledWith({
messages: [{ role: 'user', content: 'Message 2' }],
system: 'System',
});
});
});
+38
View File
@@ -0,0 +1,38 @@
import type { ModelClient, Message } from '../../models/types.js';
export interface NativeAgentConfig {
modelClient: ModelClient;
systemPrompt: string;
}
export class NativeAgent {
private modelClient: ModelClient;
private systemPrompt: string;
private history: Message[] = [];
constructor(config: NativeAgentConfig) {
this.modelClient = config.modelClient;
this.systemPrompt = config.systemPrompt;
}
async process(userMessage: string): Promise<string> {
this.history.push({ role: 'user', content: userMessage });
const response = await this.modelClient.chat({
messages: [...this.history],
system: this.systemPrompt,
});
this.history.push({ role: 'assistant', content: response.content });
return response.content;
}
reset(): void {
this.history = [];
}
getHistory(): Message[] {
return [...this.history];
}
}
+1
View File
@@ -0,0 +1 @@
export { NativeAgent, type NativeAgentConfig } from './agent.js';