@agentionai/agents 0.13.0 → 0.14.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 +16 -1
- package/dist/agents/llamacpp/LlamaCppAgent.d.ts +6 -29
- package/dist/agents/llamacpp/LlamaCppAgent.js +9 -227
- package/dist/agents/openai-compatible/OpenAICompatibleAgent.d.ts +48 -0
- package/dist/agents/openai-compatible/OpenAICompatibleAgent.js +249 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -1
- package/dist/llamacpp.d.ts +2 -0
- package/dist/llamacpp.js +4 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -119,7 +119,7 @@ const agent = new GeminiAgent({
|
|
|
119
119
|
const response = await agent.execute("What's the weather in Paris?");
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
-
### Local Models (Ollama / llama.cpp)
|
|
122
|
+
### Local Models (Ollama / llama.cpp / OpenAI-compatible servers)
|
|
123
123
|
|
|
124
124
|
Run models on your own machine — no API key required. Same agent interface as every other provider:
|
|
125
125
|
|
|
@@ -151,6 +151,21 @@ const response = await ollama.execute('What can you run locally?');
|
|
|
151
151
|
const models = await ollama.listModels();
|
|
152
152
|
```
|
|
153
153
|
|
|
154
|
+
**Custom OpenAI-compatible server** (vLLM, LM Studio, Together AI, Groq, …): extend `OpenAICompatibleAgent` directly:
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
import { OpenAICompatibleAgent, OpenAICompatibleConfig } from '@agentionai/agents/llamacpp';
|
|
158
|
+
|
|
159
|
+
class VLLMAgent extends OpenAICompatibleAgent {
|
|
160
|
+
constructor(config: Omit<OpenAICompatibleConfig, 'vendor'>) {
|
|
161
|
+
super({ ...config, vendor: 'llamacpp', baseURL: config.baseURL ?? 'http://localhost:8000/v1' });
|
|
162
|
+
}
|
|
163
|
+
protected getVendorName() { return 'vLLM'; }
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
[Full guide →](https://docs.agention.ai/guide/agents#custom-openai-compatible-agents)
|
|
168
|
+
|
|
154
169
|
### Built-In Tools
|
|
155
170
|
|
|
156
171
|
Use a provider's own server-side tools (executed by the provider, not locally) alongside your custom tools:
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { BaseAgent, BaseAgentConfig, TokenUsage } from "../BaseAgent";
|
|
4
|
-
import { History, MessageContent } from "../../history/History";
|
|
1
|
+
import { History } from "../../history/History";
|
|
2
|
+
import { OpenAICompatibleAgent, OpenAICompatibleConfig } from "../openai-compatible/OpenAICompatibleAgent";
|
|
5
3
|
import { LlamaCppModel } from "../model-types";
|
|
6
|
-
type
|
|
4
|
+
type LlamaCppConfig = Omit<OpenAICompatibleConfig, "baseURL" | "model" | "vendor"> & {
|
|
7
5
|
/** Base URL of the llama.cpp server's OpenAI-compatible API (default: `http://localhost:8080/v1`) */
|
|
8
6
|
baseURL?: string;
|
|
9
7
|
model?: LlamaCppModel;
|
|
10
|
-
maxTokens?: number;
|
|
11
8
|
};
|
|
12
9
|
/**
|
|
13
10
|
* Agent for locally-hosted models served by a llama.cpp server (`llama-server`),
|
|
@@ -21,7 +18,6 @@ type AgentConfig = BaseAgentConfig & {
|
|
|
21
18
|
* id: "1",
|
|
22
19
|
* name: "Assistant",
|
|
23
20
|
* description: "A helpful assistant",
|
|
24
|
-
* apiKey: "",
|
|
25
21
|
* baseURL: "http://localhost:8080/v1",
|
|
26
22
|
* });
|
|
27
23
|
*
|
|
@@ -33,28 +29,9 @@ type AgentConfig = BaseAgentConfig & {
|
|
|
33
29
|
* const models = await agent.listModels();
|
|
34
30
|
* ```
|
|
35
31
|
*/
|
|
36
|
-
export declare class LlamaCppAgent extends
|
|
37
|
-
|
|
38
|
-
protected
|
|
39
|
-
/** Token usage from the last execution (for metrics tracking) */
|
|
40
|
-
lastTokenUsage?: TokenUsage;
|
|
41
|
-
/** Current visualization event ID */
|
|
42
|
-
private vizEventId?;
|
|
43
|
-
/** Count of tool calls in current execution */
|
|
44
|
-
private currentToolCallCount;
|
|
45
|
-
constructor(config: Omit<AgentConfig, "vendor">, history?: History);
|
|
46
|
-
/**
|
|
47
|
-
* List the models currently available on the llama.cpp server (via its
|
|
48
|
-
* OpenAI-compatible `/v1/models` endpoint).
|
|
49
|
-
*/
|
|
50
|
-
listModels(): Promise<Model[]>;
|
|
51
|
-
protected getToolDefinitions(): ChatCompletionTool[];
|
|
52
|
-
protected process(_input: string): Promise<string>;
|
|
53
|
-
execute(input: string | MessageContent[]): Promise<string>;
|
|
54
|
-
private callLlamaCpp;
|
|
55
|
-
protected handleResponse(response: ChatCompletion): Promise<string>;
|
|
56
|
-
private handleToolCalls;
|
|
57
|
-
protected parseUsage(response: ChatCompletion): TokenUsage;
|
|
32
|
+
export declare class LlamaCppAgent extends OpenAICompatibleAgent {
|
|
33
|
+
constructor(config: LlamaCppConfig, history?: History);
|
|
34
|
+
protected getVendorName(): string;
|
|
58
35
|
}
|
|
59
36
|
export {};
|
|
60
37
|
//# sourceMappingURL=LlamaCppAgent.d.ts.map
|
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.LlamaCppAgent = void 0;
|
|
7
|
-
const
|
|
8
|
-
const BaseAgent_1 = require("../BaseAgent");
|
|
9
|
-
const AgentEvent_1 = require("../AgentEvent");
|
|
10
|
-
const AgentError_1 = require("../errors/AgentError");
|
|
11
|
-
const transformers_1 = require("../../history/transformers");
|
|
12
|
-
const VizReporter_1 = require("../../viz/VizReporter");
|
|
13
|
-
const VizConfig_1 = require("../../viz/VizConfig");
|
|
4
|
+
const OpenAICompatibleAgent_1 = require("../openai-compatible/OpenAICompatibleAgent");
|
|
14
5
|
/**
|
|
15
6
|
* Agent for locally-hosted models served by a llama.cpp server (`llama-server`),
|
|
16
7
|
* which exposes an OpenAI-compatible `/v1/chat/completions` API.
|
|
@@ -23,7 +14,6 @@ const VizConfig_1 = require("../../viz/VizConfig");
|
|
|
23
14
|
* id: "1",
|
|
24
15
|
* name: "Assistant",
|
|
25
16
|
* description: "A helpful assistant",
|
|
26
|
-
* apiKey: "",
|
|
27
17
|
* baseURL: "http://localhost:8080/v1",
|
|
28
18
|
* });
|
|
29
19
|
*
|
|
@@ -35,227 +25,19 @@ const VizConfig_1 = require("../../viz/VizConfig");
|
|
|
35
25
|
* const models = await agent.listModels();
|
|
36
26
|
* ```
|
|
37
27
|
*/
|
|
38
|
-
class LlamaCppAgent extends
|
|
28
|
+
class LlamaCppAgent extends OpenAICompatibleAgent_1.OpenAICompatibleAgent {
|
|
39
29
|
constructor(config, history) {
|
|
40
|
-
super({ ...config, vendor: "llamacpp" }, history);
|
|
41
|
-
/** Count of tool calls in current execution */
|
|
42
|
-
this.currentToolCallCount = 0;
|
|
43
30
|
const vendorConfig = config.vendorConfig?.llamacpp || {};
|
|
44
31
|
const baseURL = config.baseURL ?? vendorConfig.baseURL ?? "http://localhost:8080/v1";
|
|
45
|
-
|
|
46
|
-
|
|
32
|
+
super({
|
|
33
|
+
...config,
|
|
34
|
+
vendor: "llamacpp",
|
|
47
35
|
baseURL,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
model: config.model || "default",
|
|
51
|
-
baseURL,
|
|
52
|
-
maxTokens: config.maxTokens,
|
|
53
|
-
temperature: config.temperature,
|
|
54
|
-
topP: config.topP,
|
|
55
|
-
stopSequences: config.stopSequences,
|
|
56
|
-
seed: config.seed,
|
|
57
|
-
presencePenalty: config.presencePenalty,
|
|
58
|
-
frequencyPenalty: config.frequencyPenalty,
|
|
59
|
-
apiKey: config.apiKey,
|
|
60
|
-
};
|
|
61
|
-
this.addSystemMessage(this.getSystemMessage());
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* List the models currently available on the llama.cpp server (via its
|
|
65
|
-
* OpenAI-compatible `/v1/models` endpoint).
|
|
66
|
-
*/
|
|
67
|
-
async listModels() {
|
|
68
|
-
try {
|
|
69
|
-
const page = await this.client.models.list();
|
|
70
|
-
return page.data;
|
|
71
|
-
}
|
|
72
|
-
catch (error) {
|
|
73
|
-
throw new AgentError_1.ExecutionError(`Failed to list llama.cpp models: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
getToolDefinitions() {
|
|
77
|
-
return Array.from(this.tools.values()).map((tool) => {
|
|
78
|
-
const prompt = tool.getPrompt();
|
|
79
|
-
return {
|
|
80
|
-
type: "function",
|
|
81
|
-
function: {
|
|
82
|
-
name: prompt.name,
|
|
83
|
-
description: prompt.description,
|
|
84
|
-
parameters: prompt.input_schema,
|
|
85
|
-
},
|
|
86
|
-
};
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
async process(_input) {
|
|
90
|
-
return "";
|
|
91
|
-
}
|
|
92
|
-
async execute(input) {
|
|
93
|
-
this.emit(AgentEvent_1.AgentEvent.BEFORE_EXECUTE, input);
|
|
94
|
-
this.lastTokenUsage = undefined;
|
|
95
|
-
this.currentToolCallCount = 0;
|
|
96
|
-
const inputPreview = typeof input === "string" ? input : JSON.stringify(input);
|
|
97
|
-
if (VizConfig_1.vizConfig.isEnabled()) {
|
|
98
|
-
this.vizEventId = VizReporter_1.vizReporter.agentStart(this.id, this.name, this.config.model, "llamacpp", inputPreview);
|
|
99
|
-
}
|
|
100
|
-
if (this.history.transient) {
|
|
101
|
-
this.history.clear();
|
|
102
|
-
this.addSystemMessage(this.getSystemMessage());
|
|
103
|
-
}
|
|
104
|
-
if (typeof input === "string") {
|
|
105
|
-
this.addTextToHistory("user", input);
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
this.addMessageToHistory("user", input);
|
|
109
|
-
}
|
|
110
|
-
this.history.setSessionAnchor();
|
|
111
|
-
this.history.beginExecution();
|
|
112
|
-
try {
|
|
113
|
-
const response = await this.callLlamaCpp();
|
|
114
|
-
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, response);
|
|
115
|
-
return await this.handleResponse(response);
|
|
116
|
-
}
|
|
117
|
-
catch (error) {
|
|
118
|
-
if (error instanceof openai_1.default.APIError) {
|
|
119
|
-
const apiError = new AgentError_1.ApiError(`llama.cpp API error: ${error.message}`, error.status, error);
|
|
120
|
-
this.emit(AgentEvent_1.AgentEvent.ERROR, apiError);
|
|
121
|
-
if (this.vizEventId) {
|
|
122
|
-
VizReporter_1.vizReporter.agentError(this.vizEventId, "ApiError", apiError.message, error.status === 429);
|
|
123
|
-
this.vizEventId = undefined;
|
|
124
|
-
}
|
|
125
|
-
throw apiError;
|
|
126
|
-
}
|
|
127
|
-
if (error instanceof AgentError_1.ExecutionError || error instanceof AgentError_1.ApiError) {
|
|
128
|
-
this.emit(AgentEvent_1.AgentEvent.ERROR, error);
|
|
129
|
-
if (this.vizEventId) {
|
|
130
|
-
VizReporter_1.vizReporter.agentError(this.vizEventId, error.constructor.name, error.message, false);
|
|
131
|
-
this.vizEventId = undefined;
|
|
132
|
-
}
|
|
133
|
-
throw error;
|
|
134
|
-
}
|
|
135
|
-
const executionError = new AgentError_1.ExecutionError(`llama.cpp error: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
136
|
-
this.emit(AgentEvent_1.AgentEvent.ERROR, executionError);
|
|
137
|
-
if (this.vizEventId) {
|
|
138
|
-
VizReporter_1.vizReporter.agentError(this.vizEventId, "ExecutionError", executionError.message, false);
|
|
139
|
-
this.vizEventId = undefined;
|
|
140
|
-
}
|
|
141
|
-
throw executionError;
|
|
142
|
-
}
|
|
143
|
-
finally {
|
|
144
|
-
this.history.endExecution();
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
async callLlamaCpp() {
|
|
148
|
-
const messages = transformers_1.chatCompletionsTransformer.toProvider(this.history.getEntries());
|
|
149
|
-
const tools = this.tools.size > 0 ? this.getToolDefinitions() : undefined;
|
|
150
|
-
return this.client.chat.completions.create({
|
|
151
|
-
model: this.config.model,
|
|
152
|
-
messages,
|
|
153
|
-
tools,
|
|
154
|
-
stream: false,
|
|
155
|
-
max_tokens: this.config.maxTokens,
|
|
156
|
-
temperature: this.config.temperature,
|
|
157
|
-
top_p: this.config.topP,
|
|
158
|
-
stop: this.config.stopSequences,
|
|
159
|
-
seed: this.config.seed,
|
|
160
|
-
presence_penalty: this.config.presencePenalty,
|
|
161
|
-
frequency_penalty: this.config.frequencyPenalty,
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
async handleResponse(response) {
|
|
165
|
-
const usage = this.parseUsage(response);
|
|
166
|
-
if (this.lastTokenUsage) {
|
|
167
|
-
this.lastTokenUsage.input_tokens += usage.input_tokens;
|
|
168
|
-
this.lastTokenUsage.output_tokens += usage.output_tokens;
|
|
169
|
-
this.lastTokenUsage.total_tokens += usage.total_tokens;
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
this.lastTokenUsage = { ...usage };
|
|
173
|
-
}
|
|
174
|
-
const choice = response.choices[0];
|
|
175
|
-
const message = choice.message;
|
|
176
|
-
if (choice.finish_reason === "length") {
|
|
177
|
-
const error = new AgentError_1.MaxTokensExceededError("Response exceeded maximum token limit", this.config.maxTokens || 1024);
|
|
178
|
-
this.emit(AgentEvent_1.AgentEvent.MAX_TOKENS_EXCEEDED, error);
|
|
179
|
-
this.emit(AgentEvent_1.AgentEvent.ERROR, error);
|
|
180
|
-
if (this.vizEventId) {
|
|
181
|
-
VizReporter_1.vizReporter.agentError(this.vizEventId, "MaxTokensExceededError", error.message, false);
|
|
182
|
-
this.vizEventId = undefined;
|
|
183
|
-
}
|
|
184
|
-
throw error;
|
|
185
|
-
}
|
|
186
|
-
const hasToolCalls = message.tool_calls && message.tool_calls.length > 0;
|
|
187
|
-
if (!hasToolCalls) {
|
|
188
|
-
const textContent = message.content || "";
|
|
189
|
-
const entry = transformers_1.chatCompletionsTransformer.fromProviderMessage(message);
|
|
190
|
-
this.addToHistory(entry);
|
|
191
|
-
this.emit(AgentEvent_1.AgentEvent.DONE, message, usage);
|
|
192
|
-
if (this.vizEventId) {
|
|
193
|
-
VizReporter_1.vizReporter.agentComplete(this.vizEventId, {
|
|
194
|
-
input: this.lastTokenUsage?.input_tokens || 0,
|
|
195
|
-
output: this.lastTokenUsage?.output_tokens || 0,
|
|
196
|
-
total: this.lastTokenUsage?.total_tokens || 0,
|
|
197
|
-
}, "end_turn", this.currentToolCallCount > 0, this.currentToolCallCount, textContent);
|
|
198
|
-
this.vizEventId = undefined;
|
|
199
|
-
}
|
|
200
|
-
return textContent;
|
|
201
|
-
}
|
|
202
|
-
// Tool calls detected
|
|
203
|
-
const toolCalls = message.tool_calls;
|
|
204
|
-
this.emit(AgentEvent_1.AgentEvent.TOOL_USE, toolCalls);
|
|
205
|
-
this.currentToolCallCount += toolCalls.length;
|
|
206
|
-
const assistantEntry = transformers_1.chatCompletionsTransformer.fromProviderMessage(message);
|
|
207
|
-
this.addToHistory(assistantEntry);
|
|
208
|
-
const toolResults = await this.handleToolCalls(toolCalls);
|
|
209
|
-
for (const result of toolResults) {
|
|
210
|
-
const resultEntry = transformers_1.chatCompletionsTransformer.toolResultEntry(result.toolCallId, result.content);
|
|
211
|
-
this.addToHistory(resultEntry);
|
|
212
|
-
}
|
|
213
|
-
// Continue conversation with tool results
|
|
214
|
-
try {
|
|
215
|
-
const newResponse = await this.callLlamaCpp();
|
|
216
|
-
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, newResponse);
|
|
217
|
-
return this.handleResponse(newResponse);
|
|
218
|
-
}
|
|
219
|
-
catch (error) {
|
|
220
|
-
const executionError = new AgentError_1.ExecutionError(`llama.cpp error during tool response: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
221
|
-
this.emit(AgentEvent_1.AgentEvent.ERROR, executionError);
|
|
222
|
-
throw executionError;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
async handleToolCalls(toolCalls) {
|
|
226
|
-
return Promise.all(toolCalls.map(async (toolCall) => {
|
|
227
|
-
const toolName = toolCall.type === "function" ? toolCall.function.name : "";
|
|
228
|
-
const tool = this.tools.get(toolName);
|
|
229
|
-
const toolCallId = toolCall.id;
|
|
230
|
-
if (toolCall.type !== "function" || !tool) {
|
|
231
|
-
const errorMessage = `Tool '${toolName}' not found`;
|
|
232
|
-
const error = new AgentError_1.ToolExecutionError(errorMessage, toolName, toolCall.type === "function" ? toolCall.function.arguments : undefined);
|
|
233
|
-
this.emit(AgentEvent_1.AgentEvent.TOOL_ERROR, error);
|
|
234
|
-
return { toolCallId, content: errorMessage };
|
|
235
|
-
}
|
|
236
|
-
try {
|
|
237
|
-
const args = JSON.parse(toolCall.function.arguments || "{}");
|
|
238
|
-
const result = await tool.execute(this.getId(), this.getName(), args, toolCallId, this.config.model, "llamacpp");
|
|
239
|
-
return { toolCallId, content: JSON.stringify(result) };
|
|
240
|
-
}
|
|
241
|
-
catch (error) {
|
|
242
|
-
const errorMessage = `Error executing tool '${toolName}': ${error instanceof Error ? error.message : "Unknown error"}`;
|
|
243
|
-
if (this.debug) {
|
|
244
|
-
console.error(errorMessage);
|
|
245
|
-
}
|
|
246
|
-
const toolError = new AgentError_1.ToolExecutionError(errorMessage, toolName, toolCall.function.arguments);
|
|
247
|
-
this.emit(AgentEvent_1.AgentEvent.TOOL_ERROR, toolError);
|
|
248
|
-
return { toolCallId, content: errorMessage };
|
|
249
|
-
}
|
|
250
|
-
}));
|
|
36
|
+
model: config.model ?? "default",
|
|
37
|
+
}, history);
|
|
251
38
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
return {
|
|
255
|
-
input_tokens: usage?.prompt_tokens ?? 0,
|
|
256
|
-
output_tokens: usage?.completion_tokens ?? 0,
|
|
257
|
-
total_tokens: usage?.total_tokens ?? 0,
|
|
258
|
-
};
|
|
39
|
+
getVendorName() {
|
|
40
|
+
return "llama.cpp";
|
|
259
41
|
}
|
|
260
42
|
}
|
|
261
43
|
exports.LlamaCppAgent = LlamaCppAgent;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import OpenAI from "openai";
|
|
2
|
+
import { ChatCompletion, ChatCompletionTool } from "openai/resources/chat/completions";
|
|
3
|
+
import { Model } from "openai/resources/models";
|
|
4
|
+
import { BaseAgent, BaseAgentConfig, TokenUsage } from "../BaseAgent";
|
|
5
|
+
import { AgentVendor } from "../AgentConfig";
|
|
6
|
+
import { History, MessageContent } from "../../history/History";
|
|
7
|
+
export type OpenAICompatibleConfig = BaseAgentConfig & {
|
|
8
|
+
/** Base URL of the OpenAI-compatible `/v1` endpoint (required) */
|
|
9
|
+
baseURL: string;
|
|
10
|
+
model?: string;
|
|
11
|
+
maxTokens?: number;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Abstract base class for agents that talk to any OpenAI-compatible
|
|
15
|
+
* `/v1/chat/completions` endpoint (llama.cpp, vLLM, LM Studio, etc.).
|
|
16
|
+
*
|
|
17
|
+
* Subclasses must implement:
|
|
18
|
+
* - `getVendorName()` — human-readable name used in error messages (e.g. `"llama.cpp"`)
|
|
19
|
+
*
|
|
20
|
+
* Subclasses may override:
|
|
21
|
+
* - `buildExtraRequestParams()` — extra fields merged into the completions request
|
|
22
|
+
*/
|
|
23
|
+
export declare abstract class OpenAICompatibleAgent extends BaseAgent {
|
|
24
|
+
protected client: OpenAI;
|
|
25
|
+
protected config: Partial<OpenAICompatibleConfig>;
|
|
26
|
+
lastTokenUsage?: TokenUsage;
|
|
27
|
+
private vizEventId?;
|
|
28
|
+
private currentToolCallCount;
|
|
29
|
+
constructor(config: OpenAICompatibleConfig & {
|
|
30
|
+
vendor: AgentVendor;
|
|
31
|
+
}, history?: History);
|
|
32
|
+
/** Human-readable vendor name used in error messages (e.g. `"llama.cpp"`). */
|
|
33
|
+
protected abstract getVendorName(): string;
|
|
34
|
+
/** Extra fields to merge into the chat completions request. Override for vendor-specific params. */
|
|
35
|
+
protected buildExtraRequestParams(): Record<string, unknown>;
|
|
36
|
+
/**
|
|
37
|
+
* List the models available on the server via the `/v1/models` endpoint.
|
|
38
|
+
*/
|
|
39
|
+
listModels(): Promise<Model[]>;
|
|
40
|
+
protected getToolDefinitions(): ChatCompletionTool[];
|
|
41
|
+
protected process(_input: string): Promise<string>;
|
|
42
|
+
execute(input: string | MessageContent[]): Promise<string>;
|
|
43
|
+
private callProvider;
|
|
44
|
+
protected handleResponse(response: ChatCompletion): Promise<string>;
|
|
45
|
+
private handleToolCalls;
|
|
46
|
+
protected parseUsage(response: ChatCompletion): TokenUsage;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=OpenAICompatibleAgent.d.ts.map
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.OpenAICompatibleAgent = void 0;
|
|
7
|
+
const openai_1 = __importDefault(require("openai"));
|
|
8
|
+
const BaseAgent_1 = require("../BaseAgent");
|
|
9
|
+
const AgentEvent_1 = require("../AgentEvent");
|
|
10
|
+
const AgentError_1 = require("../errors/AgentError");
|
|
11
|
+
const transformers_1 = require("../../history/transformers");
|
|
12
|
+
const VizReporter_1 = require("../../viz/VizReporter");
|
|
13
|
+
const VizConfig_1 = require("../../viz/VizConfig");
|
|
14
|
+
/**
|
|
15
|
+
* Abstract base class for agents that talk to any OpenAI-compatible
|
|
16
|
+
* `/v1/chat/completions` endpoint (llama.cpp, vLLM, LM Studio, etc.).
|
|
17
|
+
*
|
|
18
|
+
* Subclasses must implement:
|
|
19
|
+
* - `getVendorName()` — human-readable name used in error messages (e.g. `"llama.cpp"`)
|
|
20
|
+
*
|
|
21
|
+
* Subclasses may override:
|
|
22
|
+
* - `buildExtraRequestParams()` — extra fields merged into the completions request
|
|
23
|
+
*/
|
|
24
|
+
class OpenAICompatibleAgent extends BaseAgent_1.BaseAgent {
|
|
25
|
+
constructor(config, history) {
|
|
26
|
+
super(config, history);
|
|
27
|
+
this.currentToolCallCount = 0;
|
|
28
|
+
this.client = new openai_1.default({
|
|
29
|
+
apiKey: config.apiKey || "not-needed",
|
|
30
|
+
baseURL: config.baseURL,
|
|
31
|
+
});
|
|
32
|
+
this.config = {
|
|
33
|
+
model: config.model,
|
|
34
|
+
baseURL: config.baseURL,
|
|
35
|
+
maxTokens: config.maxTokens,
|
|
36
|
+
temperature: config.temperature,
|
|
37
|
+
topP: config.topP,
|
|
38
|
+
stopSequences: config.stopSequences,
|
|
39
|
+
seed: config.seed,
|
|
40
|
+
presencePenalty: config.presencePenalty,
|
|
41
|
+
frequencyPenalty: config.frequencyPenalty,
|
|
42
|
+
apiKey: config.apiKey,
|
|
43
|
+
};
|
|
44
|
+
this.addSystemMessage(this.getSystemMessage());
|
|
45
|
+
}
|
|
46
|
+
/** Extra fields to merge into the chat completions request. Override for vendor-specific params. */
|
|
47
|
+
buildExtraRequestParams() {
|
|
48
|
+
return {};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* List the models available on the server via the `/v1/models` endpoint.
|
|
52
|
+
*/
|
|
53
|
+
async listModels() {
|
|
54
|
+
try {
|
|
55
|
+
const page = await this.client.models.list();
|
|
56
|
+
return page.data;
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
throw new AgentError_1.ExecutionError(`Failed to list ${this.getVendorName()} models: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
getToolDefinitions() {
|
|
63
|
+
return Array.from(this.tools.values()).map((tool) => {
|
|
64
|
+
const prompt = tool.getPrompt();
|
|
65
|
+
return {
|
|
66
|
+
type: "function",
|
|
67
|
+
function: {
|
|
68
|
+
name: prompt.name,
|
|
69
|
+
description: prompt.description,
|
|
70
|
+
parameters: prompt.input_schema,
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
async process(_input) {
|
|
76
|
+
return "";
|
|
77
|
+
}
|
|
78
|
+
async execute(input) {
|
|
79
|
+
this.emit(AgentEvent_1.AgentEvent.BEFORE_EXECUTE, input);
|
|
80
|
+
this.lastTokenUsage = undefined;
|
|
81
|
+
this.currentToolCallCount = 0;
|
|
82
|
+
const inputPreview = typeof input === "string" ? input : JSON.stringify(input);
|
|
83
|
+
if (VizConfig_1.vizConfig.isEnabled()) {
|
|
84
|
+
this.vizEventId = VizReporter_1.vizReporter.agentStart(this.id, this.name, this.config.model, this.vendor, inputPreview);
|
|
85
|
+
}
|
|
86
|
+
if (this.history.transient) {
|
|
87
|
+
this.history.clear();
|
|
88
|
+
this.addSystemMessage(this.getSystemMessage());
|
|
89
|
+
}
|
|
90
|
+
if (typeof input === "string") {
|
|
91
|
+
this.addTextToHistory("user", input);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
this.addMessageToHistory("user", input);
|
|
95
|
+
}
|
|
96
|
+
this.history.setSessionAnchor();
|
|
97
|
+
this.history.beginExecution();
|
|
98
|
+
try {
|
|
99
|
+
const response = await this.callProvider();
|
|
100
|
+
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, response);
|
|
101
|
+
return await this.handleResponse(response);
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
if (error instanceof openai_1.default.APIError) {
|
|
105
|
+
const apiError = new AgentError_1.ApiError(`${this.getVendorName()} API error: ${error.message}`, error.status, error);
|
|
106
|
+
this.emit(AgentEvent_1.AgentEvent.ERROR, apiError);
|
|
107
|
+
if (this.vizEventId) {
|
|
108
|
+
VizReporter_1.vizReporter.agentError(this.vizEventId, "ApiError", apiError.message, error.status === 429);
|
|
109
|
+
this.vizEventId = undefined;
|
|
110
|
+
}
|
|
111
|
+
throw apiError;
|
|
112
|
+
}
|
|
113
|
+
if (error instanceof AgentError_1.AgentError) {
|
|
114
|
+
this.emit(AgentEvent_1.AgentEvent.ERROR, error);
|
|
115
|
+
if (this.vizEventId) {
|
|
116
|
+
VizReporter_1.vizReporter.agentError(this.vizEventId, error.constructor.name, error.message, false);
|
|
117
|
+
this.vizEventId = undefined;
|
|
118
|
+
}
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
const executionError = new AgentError_1.ExecutionError(`${this.getVendorName()} error: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
122
|
+
this.emit(AgentEvent_1.AgentEvent.ERROR, executionError);
|
|
123
|
+
if (this.vizEventId) {
|
|
124
|
+
VizReporter_1.vizReporter.agentError(this.vizEventId, "ExecutionError", executionError.message, false);
|
|
125
|
+
this.vizEventId = undefined;
|
|
126
|
+
}
|
|
127
|
+
throw executionError;
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
this.history.endExecution();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async callProvider() {
|
|
134
|
+
const messages = transformers_1.chatCompletionsTransformer.toProvider(this.history.getEntries());
|
|
135
|
+
const tools = this.tools.size > 0 ? this.getToolDefinitions() : undefined;
|
|
136
|
+
return this.client.chat.completions.create({
|
|
137
|
+
model: this.config.model,
|
|
138
|
+
messages,
|
|
139
|
+
tools,
|
|
140
|
+
stream: false,
|
|
141
|
+
max_tokens: this.config.maxTokens,
|
|
142
|
+
temperature: this.config.temperature,
|
|
143
|
+
top_p: this.config.topP,
|
|
144
|
+
stop: this.config.stopSequences,
|
|
145
|
+
seed: this.config.seed,
|
|
146
|
+
presence_penalty: this.config.presencePenalty,
|
|
147
|
+
frequency_penalty: this.config.frequencyPenalty,
|
|
148
|
+
...this.buildExtraRequestParams(),
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
async handleResponse(response) {
|
|
152
|
+
const usage = this.parseUsage(response);
|
|
153
|
+
if (this.lastTokenUsage) {
|
|
154
|
+
this.lastTokenUsage.input_tokens += usage.input_tokens;
|
|
155
|
+
this.lastTokenUsage.output_tokens += usage.output_tokens;
|
|
156
|
+
this.lastTokenUsage.total_tokens += usage.total_tokens;
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
this.lastTokenUsage = { ...usage };
|
|
160
|
+
}
|
|
161
|
+
const choice = response.choices[0];
|
|
162
|
+
const message = choice.message;
|
|
163
|
+
if (choice.finish_reason === "length") {
|
|
164
|
+
const error = new AgentError_1.MaxTokensExceededError("Response exceeded maximum token limit", this.config.maxTokens || 1024);
|
|
165
|
+
this.emit(AgentEvent_1.AgentEvent.MAX_TOKENS_EXCEEDED, error);
|
|
166
|
+
this.emit(AgentEvent_1.AgentEvent.ERROR, error);
|
|
167
|
+
if (this.vizEventId) {
|
|
168
|
+
VizReporter_1.vizReporter.agentError(this.vizEventId, "MaxTokensExceededError", error.message, false);
|
|
169
|
+
this.vizEventId = undefined;
|
|
170
|
+
}
|
|
171
|
+
throw error;
|
|
172
|
+
}
|
|
173
|
+
const hasToolCalls = message.tool_calls && message.tool_calls.length > 0;
|
|
174
|
+
if (!hasToolCalls) {
|
|
175
|
+
const textContent = message.content || "";
|
|
176
|
+
const entry = transformers_1.chatCompletionsTransformer.fromProviderMessage(message);
|
|
177
|
+
this.addToHistory(entry);
|
|
178
|
+
this.emit(AgentEvent_1.AgentEvent.DONE, message, usage);
|
|
179
|
+
if (this.vizEventId) {
|
|
180
|
+
VizReporter_1.vizReporter.agentComplete(this.vizEventId, {
|
|
181
|
+
input: this.lastTokenUsage?.input_tokens || 0,
|
|
182
|
+
output: this.lastTokenUsage?.output_tokens || 0,
|
|
183
|
+
total: this.lastTokenUsage?.total_tokens || 0,
|
|
184
|
+
}, "end_turn", this.currentToolCallCount > 0, this.currentToolCallCount, textContent);
|
|
185
|
+
this.vizEventId = undefined;
|
|
186
|
+
}
|
|
187
|
+
return textContent;
|
|
188
|
+
}
|
|
189
|
+
const toolCalls = message.tool_calls;
|
|
190
|
+
this.emit(AgentEvent_1.AgentEvent.TOOL_USE, toolCalls);
|
|
191
|
+
this.currentToolCallCount += toolCalls.length;
|
|
192
|
+
const assistantEntry = transformers_1.chatCompletionsTransformer.fromProviderMessage(message);
|
|
193
|
+
this.addToHistory(assistantEntry);
|
|
194
|
+
const toolResults = await this.handleToolCalls(toolCalls);
|
|
195
|
+
for (const result of toolResults) {
|
|
196
|
+
const resultEntry = transformers_1.chatCompletionsTransformer.toolResultEntry(result.toolCallId, result.content);
|
|
197
|
+
this.addToHistory(resultEntry);
|
|
198
|
+
}
|
|
199
|
+
try {
|
|
200
|
+
const newResponse = await this.callProvider();
|
|
201
|
+
this.emit(AgentEvent_1.AgentEvent.AFTER_EXECUTE, newResponse);
|
|
202
|
+
return this.handleResponse(newResponse);
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
const executionError = new AgentError_1.ExecutionError(`${this.getVendorName()} error during tool response: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
206
|
+
this.emit(AgentEvent_1.AgentEvent.ERROR, executionError);
|
|
207
|
+
throw executionError;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
async handleToolCalls(toolCalls) {
|
|
211
|
+
return Promise.all(toolCalls.map(async (toolCall) => {
|
|
212
|
+
const toolName = toolCall.type === "function" ? toolCall.function.name : "";
|
|
213
|
+
const tool = this.tools.get(toolName);
|
|
214
|
+
const toolCallId = toolCall.id;
|
|
215
|
+
if (toolCall.type !== "function" || !tool) {
|
|
216
|
+
const errorMessage = `Tool '${toolName}' not found`;
|
|
217
|
+
const error = new AgentError_1.ToolExecutionError(errorMessage, toolName, toolCall.type === "function"
|
|
218
|
+
? toolCall.function.arguments
|
|
219
|
+
: undefined);
|
|
220
|
+
this.emit(AgentEvent_1.AgentEvent.TOOL_ERROR, error);
|
|
221
|
+
return { toolCallId, content: errorMessage };
|
|
222
|
+
}
|
|
223
|
+
try {
|
|
224
|
+
const args = JSON.parse(toolCall.function.arguments || "{}");
|
|
225
|
+
const result = await tool.execute(this.getId(), this.getName(), args, toolCallId, this.config.model, this.vendor);
|
|
226
|
+
return { toolCallId, content: JSON.stringify(result) };
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
const errorMessage = `Error executing tool '${toolName}': ${error instanceof Error ? error.message : "Unknown error"}`;
|
|
230
|
+
if (this.debug) {
|
|
231
|
+
console.error(errorMessage);
|
|
232
|
+
}
|
|
233
|
+
const toolError = new AgentError_1.ToolExecutionError(errorMessage, toolName, toolCall.function.arguments);
|
|
234
|
+
this.emit(AgentEvent_1.AgentEvent.TOOL_ERROR, toolError);
|
|
235
|
+
return { toolCallId, content: errorMessage };
|
|
236
|
+
}
|
|
237
|
+
}));
|
|
238
|
+
}
|
|
239
|
+
parseUsage(response) {
|
|
240
|
+
const usage = response.usage;
|
|
241
|
+
return {
|
|
242
|
+
input_tokens: usage?.prompt_tokens ?? 0,
|
|
243
|
+
output_tokens: usage?.completion_tokens ?? 0,
|
|
244
|
+
total_tokens: usage?.total_tokens ?? 0,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
exports.OpenAICompatibleAgent = OpenAICompatibleAgent;
|
|
249
|
+
//# sourceMappingURL=OpenAICompatibleAgent.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,8 @@ export { MistralAgent } from "./agents/mistral/MistralAgent";
|
|
|
5
5
|
export { GeminiAgent } from "./agents/google/GeminiAgent";
|
|
6
6
|
export { OllamaAgent } from "./agents/ollama/OllamaAgent";
|
|
7
7
|
export { LlamaCppAgent } from "./agents/llamacpp/LlamaCppAgent";
|
|
8
|
+
export { OpenAICompatibleAgent } from "./agents/openai-compatible/OpenAICompatibleAgent";
|
|
9
|
+
export type { OpenAICompatibleConfig } from "./agents/openai-compatible/OpenAICompatibleAgent";
|
|
8
10
|
export * from "./agents/model-types";
|
|
9
11
|
export * from "./agents/AgentConfig";
|
|
10
12
|
export * from "./agents/AgentEvent";
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
22
22
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
23
23
|
};
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.chatCompletionsTransformer = exports.ollamaTransformer = exports.geminiTransformer = exports.mistralTransformer = exports.openAiTransformer = exports.anthropicTransformer = exports.LlamaCppAgent = exports.OllamaAgent = exports.GeminiAgent = exports.MistralAgent = exports.OpenAiAgent = void 0;
|
|
25
|
+
exports.chatCompletionsTransformer = exports.ollamaTransformer = exports.geminiTransformer = exports.mistralTransformer = exports.openAiTransformer = exports.anthropicTransformer = exports.OpenAICompatibleAgent = exports.LlamaCppAgent = exports.OllamaAgent = exports.GeminiAgent = exports.MistralAgent = exports.OpenAiAgent = void 0;
|
|
26
26
|
// Agents
|
|
27
27
|
__exportStar(require("./agents/BaseAgent"), exports);
|
|
28
28
|
__exportStar(require("./agents/anthropic/ClaudeAgent"), exports);
|
|
@@ -36,6 +36,8 @@ var OllamaAgent_1 = require("./agents/ollama/OllamaAgent");
|
|
|
36
36
|
Object.defineProperty(exports, "OllamaAgent", { enumerable: true, get: function () { return OllamaAgent_1.OllamaAgent; } });
|
|
37
37
|
var LlamaCppAgent_1 = require("./agents/llamacpp/LlamaCppAgent");
|
|
38
38
|
Object.defineProperty(exports, "LlamaCppAgent", { enumerable: true, get: function () { return LlamaCppAgent_1.LlamaCppAgent; } });
|
|
39
|
+
var OpenAICompatibleAgent_1 = require("./agents/openai-compatible/OpenAICompatibleAgent");
|
|
40
|
+
Object.defineProperty(exports, "OpenAICompatibleAgent", { enumerable: true, get: function () { return OpenAICompatibleAgent_1.OpenAICompatibleAgent; } });
|
|
39
41
|
__exportStar(require("./agents/model-types"), exports);
|
|
40
42
|
__exportStar(require("./agents/AgentConfig"), exports);
|
|
41
43
|
__exportStar(require("./agents/AgentEvent"), exports);
|
package/dist/llamacpp.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export * from "./core";
|
|
2
2
|
export { LlamaCppAgent } from "./agents/llamacpp/LlamaCppAgent";
|
|
3
|
+
export { OpenAICompatibleAgent } from "./agents/openai-compatible/OpenAICompatibleAgent";
|
|
4
|
+
export type { OpenAICompatibleConfig } from "./agents/openai-compatible/OpenAICompatibleAgent";
|
|
3
5
|
export { chatCompletionsTransformer } from "./history/transformers";
|
|
4
6
|
//# sourceMappingURL=llamacpp.d.ts.map
|
package/dist/llamacpp.js
CHANGED
|
@@ -14,11 +14,13 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.chatCompletionsTransformer = exports.LlamaCppAgent = void 0;
|
|
18
|
-
// llama.cpp Agent Entry Point
|
|
17
|
+
exports.chatCompletionsTransformer = exports.OpenAICompatibleAgent = exports.LlamaCppAgent = void 0;
|
|
18
|
+
// llama.cpp / OpenAI-compatible Agent Entry Point
|
|
19
19
|
__exportStar(require("./core"), exports);
|
|
20
20
|
var LlamaCppAgent_1 = require("./agents/llamacpp/LlamaCppAgent");
|
|
21
21
|
Object.defineProperty(exports, "LlamaCppAgent", { enumerable: true, get: function () { return LlamaCppAgent_1.LlamaCppAgent; } });
|
|
22
|
+
var OpenAICompatibleAgent_1 = require("./agents/openai-compatible/OpenAICompatibleAgent");
|
|
23
|
+
Object.defineProperty(exports, "OpenAICompatibleAgent", { enumerable: true, get: function () { return OpenAICompatibleAgent_1.OpenAICompatibleAgent; } });
|
|
22
24
|
var transformers_1 = require("./history/transformers");
|
|
23
25
|
Object.defineProperty(exports, "chatCompletionsTransformer", { enumerable: true, get: function () { return transformers_1.chatCompletionsTransformer; } });
|
|
24
26
|
//# sourceMappingURL=llamacpp.js.map
|