agentnet 0.0.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/LICENSE.txt +202 -0
- package/README.md +488 -0
- package/package.json +23 -0
- package/src/agent/agent-loader.js +274 -0
- package/src/agent/agent.js +416 -0
- package/src/agent/client.js +14 -0
- package/src/agent/executor.js +320 -0
- package/src/agent/runtime.js +142 -0
- package/src/agent/runtimes/nats.js +379 -0
- package/src/errors/index.js +195 -0
- package/src/examples/agents-smartness.yaml +308 -0
- package/src/examples/agents.yaml +394 -0
- package/src/examples/def.js +74 -0
- package/src/examples/def2.js +65 -0
- package/src/examples/def3.js +67 -0
- package/src/examples/simple.js +103 -0
- package/src/index.js +115 -0
- package/src/llm/gemini.js +155 -0
- package/src/llm/gpt.js +155 -0
- package/src/store/store.js +167 -0
- package/src/utils/logger.js +209 -0
- package/src/utils/store.js +212 -0
- package/src/utils/validation.js +287 -0
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agentnet",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Agent library used by Smartness",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
9
|
+
},
|
|
10
|
+
"author": "",
|
|
11
|
+
"license": "ISC",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@google/genai": "^0.12.0",
|
|
14
|
+
"@nats-io/nats-core": "^3.0.2",
|
|
15
|
+
"@nats-io/transport-node": "^3.0.2",
|
|
16
|
+
"colors": "^1.4.0",
|
|
17
|
+
"openai": "^4.97.0",
|
|
18
|
+
"pg": "^8.15.6",
|
|
19
|
+
"redis": "^5.0.1",
|
|
20
|
+
"uuid": "^11.1.0",
|
|
21
|
+
"yaml": "^2.7.1"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import { parse } from 'yaml'
|
|
3
|
+
import { Gemini } from "../index.js"
|
|
4
|
+
import { Agent } from "./agent.js"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Loads agent definitions from a YAML file
|
|
8
|
+
* @param {string} path - Path to the YAML file
|
|
9
|
+
* @param {object} config - Configuration options
|
|
10
|
+
* @returns {Promise<object>} Map of loaded agents
|
|
11
|
+
*/
|
|
12
|
+
export async function AgentLoaderFile(path, config) {
|
|
13
|
+
try {
|
|
14
|
+
const yamlFileContent = fs.readFileSync(path, 'utf8');
|
|
15
|
+
const agentDefinitions = parseAgentDefinitionsFromYaml(yamlFileContent);
|
|
16
|
+
return await AgentLoader(agentDefinitions, config);
|
|
17
|
+
} catch (error) {
|
|
18
|
+
throw new Error(`Failed to load agents from file ${path}: ${error.message}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Loads agent definitions from JSON
|
|
24
|
+
* @param {object} json - JSON definition
|
|
25
|
+
* @param {object} config - Configuration options
|
|
26
|
+
* @returns {Promise<object>} Map of loaded agents
|
|
27
|
+
*/
|
|
28
|
+
export async function AgentLoaderJSON(json, config) {
|
|
29
|
+
return await AgentLoader([json], config);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Parses agent definitions from YAML content
|
|
34
|
+
* @param {string} yamlContent - YAML content to parse
|
|
35
|
+
* @returns {Array} Array of agent definitions
|
|
36
|
+
*/
|
|
37
|
+
function parseAgentDefinitionsFromYaml(yamlContent) {
|
|
38
|
+
const agentDefsYaml = yamlContent.split(/^---$/m)
|
|
39
|
+
.map(s => s.trim())
|
|
40
|
+
.filter(s => s);
|
|
41
|
+
|
|
42
|
+
const agentDefinitions = [];
|
|
43
|
+
|
|
44
|
+
for (const agentDef of agentDefsYaml) {
|
|
45
|
+
try {
|
|
46
|
+
const definition = parse(agentDef);
|
|
47
|
+
if (isValidAgentDefinition(definition)) {
|
|
48
|
+
agentDefinitions.push(definition);
|
|
49
|
+
} else {
|
|
50
|
+
console.warn("Skipping invalid or non-AgentDefinition document in YAML.");
|
|
51
|
+
}
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.warn(`Failed to parse YAML document: ${error.message}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return agentDefinitions;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Checks if a definition is a valid agent definition
|
|
62
|
+
* @param {object} definition - Definition to validate
|
|
63
|
+
* @returns {boolean} Whether definition is valid
|
|
64
|
+
*/
|
|
65
|
+
function isValidAgentDefinition(definition) {
|
|
66
|
+
return definition && definition.kind === 'AgentDefinition' && definition.spec;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Loads an LLM provider instance
|
|
71
|
+
* @param {string} providerName - Name of the provider
|
|
72
|
+
* @returns {object} LLM provider instance
|
|
73
|
+
*/
|
|
74
|
+
async function loadLlmProvider(providerName) {
|
|
75
|
+
if (providerName === 'Gemini') {
|
|
76
|
+
return Gemini;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
return global[providerName] || await import(providerName);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
throw new Error(`LLM Provider "${providerName}" could not be loaded: ${error.message}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Configures IO for an agent
|
|
88
|
+
* @param {object} agentBuilder - Agent builder instance
|
|
89
|
+
* @param {Array} ioDefinitions - IO definitions
|
|
90
|
+
* @param {object} bindings - IO bindings
|
|
91
|
+
* @returns {object} Updated agent builder
|
|
92
|
+
*/
|
|
93
|
+
function configureIO(agentBuilder, ioDefinitions, bindings) {
|
|
94
|
+
if (!ioDefinitions || !Array.isArray(ioDefinitions)) {
|
|
95
|
+
return agentBuilder;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
for (const ioDef of ioDefinitions) {
|
|
99
|
+
if (!bindings[ioDef.type]) {
|
|
100
|
+
throw new Error(`Missing binding for IO type: ${ioDef.type}`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (ioDef.type === 'NatsIO') {
|
|
104
|
+
agentBuilder = agentBuilder.addIO(bindings[ioDef.type], ioDef);
|
|
105
|
+
} else {
|
|
106
|
+
throw new Error(`Unsupported IO type: ${ioDef.type}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return agentBuilder;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Configures store for an agent
|
|
115
|
+
* @param {object} agentBuilder - Agent builder instance
|
|
116
|
+
* @param {object} storeSpec - Store specification
|
|
117
|
+
* @param {object} bindings - Store bindings
|
|
118
|
+
* @returns {object} Updated agent builder
|
|
119
|
+
*/
|
|
120
|
+
function configureStore(agentBuilder, storeSpec, bindings) {
|
|
121
|
+
if (!storeSpec) {
|
|
122
|
+
return agentBuilder;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const storeType = storeSpec.type;
|
|
126
|
+
|
|
127
|
+
if (!bindings[storeType]) {
|
|
128
|
+
throw new Error(`Missing binding for store type: ${storeType}`);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Add store to agent builder
|
|
132
|
+
return agentBuilder.withStore(bindings[storeType], storeSpec);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Configures LLM for an agent
|
|
137
|
+
* @param {object} agentBuilder - Agent builder instance
|
|
138
|
+
* @param {object} llmSpec - LLM specification
|
|
139
|
+
* @returns {Promise<object>} Updated agent builder
|
|
140
|
+
*/
|
|
141
|
+
async function configureLLM(agentBuilder, llmSpec) {
|
|
142
|
+
if (!llmSpec) {
|
|
143
|
+
return agentBuilder;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const llmProviderInstance = await loadLlmProvider(llmSpec.provider);
|
|
147
|
+
|
|
148
|
+
return agentBuilder.withLLM(llmProviderInstance, {
|
|
149
|
+
model: llmSpec.model,
|
|
150
|
+
systemInstruction: llmSpec.systemInstruction,
|
|
151
|
+
config: llmSpec.config
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Configures discovery schemas for an agent
|
|
157
|
+
* @param {object} agentBuilder - Agent builder instance
|
|
158
|
+
* @param {Array} schemas - Discovery schemas
|
|
159
|
+
* @returns {object} Updated agent builder
|
|
160
|
+
*/
|
|
161
|
+
function configureDiscoverySchemas(agentBuilder, schemas) {
|
|
162
|
+
if (!schemas || !Array.isArray(schemas)) {
|
|
163
|
+
return agentBuilder;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
for (const schema of schemas) {
|
|
167
|
+
agentBuilder = agentBuilder.addDiscoverySchema(schema);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return agentBuilder;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Configures tools for an agent
|
|
175
|
+
* @param {object} agentBuilder - Agent builder instance
|
|
176
|
+
* @param {Array} toolsSpec - Tools specification
|
|
177
|
+
* @returns {object} Tool map
|
|
178
|
+
*/
|
|
179
|
+
function configureTools(agentBuilder, toolsSpec) {
|
|
180
|
+
const toolMap = {};
|
|
181
|
+
|
|
182
|
+
if (!toolsSpec || !Array.isArray(toolsSpec)) {
|
|
183
|
+
return toolMap;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
for (const toolDef of toolsSpec) {
|
|
187
|
+
agentBuilder._config.toolsSchemas[toolDef.name] = {
|
|
188
|
+
name: toolDef.name,
|
|
189
|
+
schema: toolDef,
|
|
190
|
+
function: null
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
toolMap[toolDef.name] = {
|
|
194
|
+
bind: (handlerFunction) => {
|
|
195
|
+
agentBuilder._config.toolsSchemas[toolDef.name].function = handlerFunction;
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return toolMap;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Creates an agent interface
|
|
205
|
+
* @param {object} agentBuilder - Agent builder instance
|
|
206
|
+
* @param {object} toolMap - Tool map
|
|
207
|
+
* @returns {object} Agent interface
|
|
208
|
+
*/
|
|
209
|
+
function createAgentInterface(agentBuilder, toolMap) {
|
|
210
|
+
return {
|
|
211
|
+
tools: toolMap,
|
|
212
|
+
prompt: (callback) => {
|
|
213
|
+
agentBuilder._config.on.prompt = callback;
|
|
214
|
+
},
|
|
215
|
+
response: (callback) => {
|
|
216
|
+
agentBuilder._config.on.response = callback;
|
|
217
|
+
},
|
|
218
|
+
compile: async () => {
|
|
219
|
+
return await agentBuilder.compile();
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Main agent loading function
|
|
226
|
+
* @param {Array} agentsDefinitions - Array of agent definitions
|
|
227
|
+
* @param {object} config - Configuration options
|
|
228
|
+
* @returns {Promise<object>} Map of loaded agents
|
|
229
|
+
*/
|
|
230
|
+
async function AgentLoader(agentsDefinitions, config = {}) {
|
|
231
|
+
const bindings = config.bindings || {};
|
|
232
|
+
const loadedAgents = {};
|
|
233
|
+
|
|
234
|
+
for (const definition of agentsDefinitions) {
|
|
235
|
+
try {
|
|
236
|
+
if (!definition.spec) {
|
|
237
|
+
throw new Error(`Invalid agent definition: missing spec`);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const spec = definition.spec;
|
|
241
|
+
const metadata = definition.metadata || {
|
|
242
|
+
name: "default",
|
|
243
|
+
description: "Agent from definition"
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
if (!metadata.name) {
|
|
247
|
+
throw new Error("Agent definition is missing metadata.name");
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Initialize agent builder with metadata
|
|
251
|
+
let agentBuilder = Agent().setMetadata(metadata);
|
|
252
|
+
|
|
253
|
+
// Configure different aspects of the agent
|
|
254
|
+
agentBuilder = configureIO(agentBuilder, spec.io, bindings);
|
|
255
|
+
agentBuilder = configureStore(agentBuilder, spec.store, bindings);
|
|
256
|
+
agentBuilder = await configureLLM(agentBuilder, spec.llm);
|
|
257
|
+
agentBuilder = configureDiscoverySchemas(agentBuilder, spec.discoverySchemas);
|
|
258
|
+
|
|
259
|
+
// Set up tools
|
|
260
|
+
const toolMap = configureTools(agentBuilder, spec.tools);
|
|
261
|
+
|
|
262
|
+
// Create the agent interface
|
|
263
|
+
loadedAgents[metadata.name] = createAgentInterface(agentBuilder, toolMap);
|
|
264
|
+
|
|
265
|
+
} catch (error) {
|
|
266
|
+
const agentName = definition.metadata?.name || 'Unnamed Agent';
|
|
267
|
+
console.error(`Failed to load agent "${agentName}": ${error.message}`);
|
|
268
|
+
// Optional: decide whether to throw or just log and continue
|
|
269
|
+
// throw error;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return loadedAgents;
|
|
274
|
+
}
|
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
import { AgentRuntime } from "./runtime.js"
|
|
2
|
+
import {
|
|
3
|
+
validateRequired,
|
|
4
|
+
validateType,
|
|
5
|
+
validateObject,
|
|
6
|
+
validateEnum
|
|
7
|
+
} from "../utils/validation.js"
|
|
8
|
+
import { CompilationError, ConfigurationError } from "../errors/index.js"
|
|
9
|
+
import { logger } from "../utils/logger.js"
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Default hooks for agent events
|
|
13
|
+
*/
|
|
14
|
+
const DEFAULT_HOOKS = {
|
|
15
|
+
prompt: async (state, formattedInput) => formattedInput,
|
|
16
|
+
response: async (state, conversation, result) => result
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Default agent configuration
|
|
21
|
+
*/
|
|
22
|
+
const DEFAULT_CONFIG = {
|
|
23
|
+
metadata: {
|
|
24
|
+
name: "default",
|
|
25
|
+
description: "A default agent"
|
|
26
|
+
},
|
|
27
|
+
runner: {
|
|
28
|
+
maxRuns: 10
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Schema for agent configuration validation
|
|
34
|
+
*/
|
|
35
|
+
const AGENT_CONFIG_SCHEMA = {
|
|
36
|
+
type: 'object',
|
|
37
|
+
properties: {
|
|
38
|
+
metadata: {
|
|
39
|
+
type: 'object',
|
|
40
|
+
properties: {
|
|
41
|
+
name: { type: 'string' },
|
|
42
|
+
description: { type: 'string' }
|
|
43
|
+
},
|
|
44
|
+
required: ['name']
|
|
45
|
+
},
|
|
46
|
+
llm: {
|
|
47
|
+
type: 'object',
|
|
48
|
+
properties: {
|
|
49
|
+
api: { type: 'object' },
|
|
50
|
+
config: { type: 'object' }
|
|
51
|
+
},
|
|
52
|
+
required: ['api']
|
|
53
|
+
},
|
|
54
|
+
store: {
|
|
55
|
+
type: 'object',
|
|
56
|
+
properties: {
|
|
57
|
+
instance: { type: 'object' },
|
|
58
|
+
config: { type: 'object' }
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
io: { type: 'array' },
|
|
62
|
+
handoffs: { type: 'array' },
|
|
63
|
+
discoverySchemas: { type: 'array' },
|
|
64
|
+
toolsAndHandoffsMap: {
|
|
65
|
+
type: 'object',
|
|
66
|
+
properties: {
|
|
67
|
+
tools: { type: 'array' }
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
toolsSchemas: { type: 'object' },
|
|
71
|
+
runner: {
|
|
72
|
+
type: 'object',
|
|
73
|
+
properties: {
|
|
74
|
+
maxRuns: { type: 'number' }
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
on: { type: 'object' }
|
|
78
|
+
},
|
|
79
|
+
required: ['metadata', 'llm']
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Creates a new Agent builder
|
|
84
|
+
* @returns {Object} Agent builder interface
|
|
85
|
+
*/
|
|
86
|
+
export function Agent() {
|
|
87
|
+
// Initialize agent configuration
|
|
88
|
+
const config = {
|
|
89
|
+
metadata: { ...DEFAULT_CONFIG.metadata },
|
|
90
|
+
llm: {},
|
|
91
|
+
store: null,
|
|
92
|
+
io: [],
|
|
93
|
+
handoffs: [],
|
|
94
|
+
discoverySchemas: [],
|
|
95
|
+
hooks: null,
|
|
96
|
+
toolsAndHandoffsMap: {
|
|
97
|
+
tools: []
|
|
98
|
+
},
|
|
99
|
+
toolsSchemas: {},
|
|
100
|
+
runner: { ...DEFAULT_CONFIG.runner },
|
|
101
|
+
on: { ...DEFAULT_HOOKS }
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Validates that required configuration is present and well-formed
|
|
106
|
+
* @throws {ConfigurationError} If configuration is invalid
|
|
107
|
+
*/
|
|
108
|
+
function validateConfiguration() {
|
|
109
|
+
try {
|
|
110
|
+
// Validate overall structure against schema
|
|
111
|
+
validateObject(config, AGENT_CONFIG_SCHEMA, 'agent_config');
|
|
112
|
+
|
|
113
|
+
// Additional specific validations
|
|
114
|
+
|
|
115
|
+
// Metadata validation
|
|
116
|
+
if (!config.metadata.name.trim()) {
|
|
117
|
+
throw new ConfigurationError("Agent name cannot be empty", {
|
|
118
|
+
metadata: config.metadata
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// LLM API validation
|
|
123
|
+
if (typeof config.llm.api !== 'object' || config.llm.api === null) {
|
|
124
|
+
throw new ConfigurationError("LLM API must be a valid object", {
|
|
125
|
+
api: config.llm.api
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (!config.llm.api.getClient || typeof config.llm.api.getClient !== 'function') {
|
|
130
|
+
throw new ConfigurationError("LLM API must have a getClient method", {
|
|
131
|
+
apiMethods: Object.keys(config.llm.api)
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (!config.llm.api.callModel || typeof config.llm.api.callModel !== 'function') {
|
|
136
|
+
throw new ConfigurationError("LLM API must have a callModel method", {
|
|
137
|
+
apiMethods: Object.keys(config.llm.api)
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Store validation if present
|
|
142
|
+
if (config.store) {
|
|
143
|
+
if (typeof config.store.instance !== 'object' || config.store.instance === null) {
|
|
144
|
+
throw new ConfigurationError("Store instance must be a valid object", {
|
|
145
|
+
store: config.store
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (!config.store.instance.connect || typeof config.store.instance.connect !== 'function') {
|
|
150
|
+
throw new ConfigurationError("Store instance must have a connect method", {
|
|
151
|
+
storeInstanceMethods: Object.keys(config.store.instance)
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// IO validation
|
|
157
|
+
if (config.io.length > 0) {
|
|
158
|
+
config.io.forEach((io, index) => {
|
|
159
|
+
if (!io.type) {
|
|
160
|
+
throw new ConfigurationError(`IO interface at index ${index} has no type`, {
|
|
161
|
+
io
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (!io.instance) {
|
|
166
|
+
throw new ConfigurationError(`IO interface ${io.type} at index ${index} has no instance`, {
|
|
167
|
+
io
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (!io.config) {
|
|
172
|
+
throw new ConfigurationError(`IO interface ${io.type} at index ${index} has no configuration`, {
|
|
173
|
+
io
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Tool schemas validation
|
|
180
|
+
const toolSchemas = Object.values(config.toolsSchemas);
|
|
181
|
+
toolSchemas.forEach(schema => {
|
|
182
|
+
if (!schema.name) {
|
|
183
|
+
throw new ConfigurationError("Tool schema must have a name", {
|
|
184
|
+
schema
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// Event handlers validation
|
|
190
|
+
Object.entries(config.on).forEach(([eventName, handler]) => {
|
|
191
|
+
if (typeof handler !== 'function') {
|
|
192
|
+
throw new ConfigurationError(`Event handler for '${eventName}' must be a function`, {
|
|
193
|
+
eventName,
|
|
194
|
+
handlerType: typeof handler
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// Runner validation
|
|
200
|
+
validateType(config.runner.maxRuns, 'number', 'runner.maxRuns', 'agent_config');
|
|
201
|
+
if (config.runner.maxRuns <= 0) {
|
|
202
|
+
throw new ConfigurationError("runner.maxRuns must be greater than 0", {
|
|
203
|
+
maxRuns: config.runner.maxRuns
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
logger.debug(`Agent ${config.metadata.name} configuration validated successfully`);
|
|
208
|
+
|
|
209
|
+
} catch (error) {
|
|
210
|
+
if (error instanceof ConfigurationError) {
|
|
211
|
+
logger.error(`Agent configuration validation failed: ${error.message}`, {
|
|
212
|
+
configContext: error.configContext,
|
|
213
|
+
agentName: config.metadata?.name || 'unknown'
|
|
214
|
+
});
|
|
215
|
+
throw error;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Wrap other errors
|
|
219
|
+
logger.error(`Agent configuration validation failed with unexpected error`, {
|
|
220
|
+
error,
|
|
221
|
+
agentName: config.metadata?.name || 'unknown'
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
throw new ConfigurationError(
|
|
225
|
+
`Agent configuration validation failed: ${error.message}`,
|
|
226
|
+
{ cause: error }
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Adds an IO interface to the agent
|
|
233
|
+
* @param {Object} instance - IO provider instance
|
|
234
|
+
* @param {Object} ioConfig - IO configuration
|
|
235
|
+
* @returns {Object} Agent builder for chaining
|
|
236
|
+
*/
|
|
237
|
+
function addIO(instance, ioConfig) {
|
|
238
|
+
if (!instance || !instance.type) {
|
|
239
|
+
throw new ConfigurationError("IO instance must have a type", {
|
|
240
|
+
instance: instance ? Object.keys(instance) : null
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
config.io.push({
|
|
245
|
+
type: instance.type,
|
|
246
|
+
instance: instance,
|
|
247
|
+
config: ioConfig || {}
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
return this;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Configures the LLM for the agent
|
|
255
|
+
* @param {Object} llmApi - LLM API provider
|
|
256
|
+
* @param {Object} llmConfig - LLM configuration
|
|
257
|
+
* @returns {Object} Agent builder for chaining
|
|
258
|
+
*/
|
|
259
|
+
function withLLM(llmApi, llmConfig) {
|
|
260
|
+
if (!llmApi) {
|
|
261
|
+
throw new ConfigurationError("LLM API is required", {
|
|
262
|
+
provided: llmApi
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
config.llm = {
|
|
267
|
+
api: llmApi,
|
|
268
|
+
config: llmConfig || {}
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
return this;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Configures the store for the agent
|
|
276
|
+
* @param {Object} storeInstance - Store instance
|
|
277
|
+
* @param {Object} storeConfig - Store configuration
|
|
278
|
+
* @returns {Object} Agent builder for chaining
|
|
279
|
+
*/
|
|
280
|
+
function withStore(storeInstance, storeConfig) {
|
|
281
|
+
if (!storeInstance) {
|
|
282
|
+
throw new ConfigurationError("Store instance is required", {
|
|
283
|
+
provided: storeInstance
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
config.store = {
|
|
288
|
+
instance: storeInstance,
|
|
289
|
+
config: storeConfig || {}
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
return this;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Registers an event handler
|
|
297
|
+
* @param {String} eventName - Event name
|
|
298
|
+
* @param {Function} handler - Event handler function
|
|
299
|
+
* @returns {Object} Agent builder for chaining
|
|
300
|
+
*/
|
|
301
|
+
function on(eventName, handler) {
|
|
302
|
+
if (typeof handler !== 'function') {
|
|
303
|
+
throw new ConfigurationError(`Event handler for ${eventName} must be a function`, {
|
|
304
|
+
provided: typeof handler
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
config.on[eventName] = handler;
|
|
309
|
+
return this;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Adds a discovery schema
|
|
314
|
+
* @param {Object} schema - Discovery schema
|
|
315
|
+
* @returns {Object} Agent builder for chaining
|
|
316
|
+
*/
|
|
317
|
+
function addDiscoverySchema(schema) {
|
|
318
|
+
if (!schema) {
|
|
319
|
+
throw new ConfigurationError("Discovery schema is required", {
|
|
320
|
+
provided: schema
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
config.discoverySchemas.push(schema);
|
|
325
|
+
return this;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Adds a tool schema
|
|
330
|
+
* @param {Object} schema - Tool schema
|
|
331
|
+
* @returns {Object} Agent builder for chaining
|
|
332
|
+
*/
|
|
333
|
+
function addToolSchema(schema) {
|
|
334
|
+
if (!schema || !schema.name) {
|
|
335
|
+
throw new ConfigurationError("Tool schema must have a name", {
|
|
336
|
+
schema: schema
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
config.toolsSchemas[schema.name] = schema;
|
|
341
|
+
return this;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Sets agent metadata
|
|
346
|
+
* @param {Object} metadata - Agent metadata
|
|
347
|
+
* @returns {Object} Agent builder for chaining
|
|
348
|
+
*/
|
|
349
|
+
function setMetadata(metadata) {
|
|
350
|
+
if (!metadata) {
|
|
351
|
+
throw new ConfigurationError("Metadata is required", {
|
|
352
|
+
provided: metadata
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
config.metadata = {
|
|
357
|
+
...config.metadata,
|
|
358
|
+
...metadata
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
return this;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Gets all registered tool schemas
|
|
366
|
+
* @returns {Object} Map of tool schemas
|
|
367
|
+
*/
|
|
368
|
+
function getToolsSchemas() {
|
|
369
|
+
return { ...config.toolsSchemas };
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Compiles the agent configuration into a runnable agent
|
|
374
|
+
* @returns {Promise<Object>} Compiled agent interface
|
|
375
|
+
*/
|
|
376
|
+
async function compile() {
|
|
377
|
+
// Validate configuration before compiling
|
|
378
|
+
validateConfiguration();
|
|
379
|
+
|
|
380
|
+
try {
|
|
381
|
+
logger.info(`Compiling agent ${config.metadata.name}`);
|
|
382
|
+
const runtime = await AgentRuntime(config);
|
|
383
|
+
|
|
384
|
+
return {
|
|
385
|
+
query: runtime
|
|
386
|
+
};
|
|
387
|
+
} catch (error) {
|
|
388
|
+
logger.error(`Agent compilation error: ${error.message}`, {
|
|
389
|
+
agentName: config.metadata.name,
|
|
390
|
+
error
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
throw new CompilationError(
|
|
394
|
+
`Failed to compile agent ${config.metadata.name}: ${error.message}`,
|
|
395
|
+
config.metadata.name,
|
|
396
|
+
error
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Return the agent builder interface
|
|
402
|
+
return {
|
|
403
|
+
addIO,
|
|
404
|
+
withLLM,
|
|
405
|
+
withStore,
|
|
406
|
+
on,
|
|
407
|
+
addDiscoverySchema,
|
|
408
|
+
addToolSchema,
|
|
409
|
+
compile,
|
|
410
|
+
setMetadata,
|
|
411
|
+
getToolsSchemas,
|
|
412
|
+
|
|
413
|
+
// Expose config for backward compatibility
|
|
414
|
+
_config: config
|
|
415
|
+
};
|
|
416
|
+
}
|