@inkeep/agents-sdk 0.1.1 → 0.1.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/SUPPLEMENTAL_TERMS.md +40 -0
- package/dist/index.cjs +2863 -0
- package/dist/index.d.cts +919 -0
- package/dist/index.d.ts +919 -11
- package/dist/index.js +2840 -10
- package/package.json +7 -6
- package/dist/__tests__/utils/testTenant.d.ts +0 -7
- package/dist/__tests__/utils/testTenant.d.ts.map +0 -1
- package/dist/__tests__/utils/testTenant.js +0 -10
- package/dist/__tests__/utils/testTenant.js.map +0 -1
- package/dist/agent.d.ts +0 -47
- package/dist/agent.d.ts.map +0 -1
- package/dist/agent.js +0 -601
- package/dist/agent.js.map +0 -1
- package/dist/artifact-component.d.ts +0 -27
- package/dist/artifact-component.d.ts.map +0 -1
- package/dist/artifact-component.js +0 -116
- package/dist/artifact-component.js.map +0 -1
- package/dist/builders.d.ts +0 -211
- package/dist/builders.d.ts.map +0 -1
- package/dist/builders.js +0 -244
- package/dist/builders.js.map +0 -1
- package/dist/data-component.d.ts +0 -25
- package/dist/data-component.d.ts.map +0 -1
- package/dist/data-component.js +0 -112
- package/dist/data-component.js.map +0 -1
- package/dist/environment-settings.d.ts +0 -28
- package/dist/environment-settings.d.ts.map +0 -1
- package/dist/environment-settings.js +0 -78
- package/dist/environment-settings.js.map +0 -1
- package/dist/externalAgent.d.ts +0 -58
- package/dist/externalAgent.d.ts.map +0 -1
- package/dist/externalAgent.js +0 -161
- package/dist/externalAgent.js.map +0 -1
- package/dist/graph.d.ts +0 -200
- package/dist/graph.d.ts.map +0 -1
- package/dist/graph.js +0 -1294
- package/dist/graph.js.map +0 -1
- package/dist/graphFullClient.d.ts +0 -22
- package/dist/graphFullClient.d.ts.map +0 -1
- package/dist/graphFullClient.js +0 -189
- package/dist/graphFullClient.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/module-hosted-tool-manager.d.ts +0 -37
- package/dist/module-hosted-tool-manager.d.ts.map +0 -1
- package/dist/module-hosted-tool-manager.js +0 -375
- package/dist/module-hosted-tool-manager.js.map +0 -1
- package/dist/runner.d.ts +0 -38
- package/dist/runner.d.ts.map +0 -1
- package/dist/runner.js +0 -164
- package/dist/runner.js.map +0 -1
- package/dist/tool.d.ts +0 -29
- package/dist/tool.d.ts.map +0 -1
- package/dist/tool.js +0 -122
- package/dist/tool.js.map +0 -1
- package/dist/types.d.ts +0 -285
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -37
- package/dist/types.js.map +0 -1
package/dist/graph.js
DELETED
|
@@ -1,1294 +0,0 @@
|
|
|
1
|
-
import { createDatabaseClient, getLogger, getProject } from '@inkeep/agents-core';
|
|
2
|
-
import { ExternalAgent } from './externalAgent';
|
|
3
|
-
import { updateFullGraphViaAPI } from './graphFullClient';
|
|
4
|
-
const logger = getLogger('graph');
|
|
5
|
-
// Helper function to resolve getter functions
|
|
6
|
-
function resolveGetter(value) {
|
|
7
|
-
if (typeof value === 'function') {
|
|
8
|
-
return value();
|
|
9
|
-
}
|
|
10
|
-
return value;
|
|
11
|
-
}
|
|
12
|
-
export class AgentGraph {
|
|
13
|
-
agents = [];
|
|
14
|
-
agentMap = new Map();
|
|
15
|
-
defaultAgent;
|
|
16
|
-
baseURL;
|
|
17
|
-
tenantId;
|
|
18
|
-
projectId;
|
|
19
|
-
graphId;
|
|
20
|
-
graphName;
|
|
21
|
-
graphDescription;
|
|
22
|
-
initialized = false;
|
|
23
|
-
contextConfig; // ContextConfigBuilder
|
|
24
|
-
credentials;
|
|
25
|
-
models;
|
|
26
|
-
statusUpdateSettings;
|
|
27
|
-
graphPrompt;
|
|
28
|
-
stopWhen;
|
|
29
|
-
dbClient;
|
|
30
|
-
constructor(config) {
|
|
31
|
-
this.defaultAgent = config.defaultAgent;
|
|
32
|
-
this.tenantId = config.tenantId || 'default';
|
|
33
|
-
this.projectId = 'default'; // Default project ID, will be overridden by setConfig
|
|
34
|
-
this.graphId = config.id;
|
|
35
|
-
this.graphName = config.name || this.graphId;
|
|
36
|
-
this.graphDescription = config.description;
|
|
37
|
-
this.baseURL = process.env.INKEEP_API_URL || 'http://localhost:3002';
|
|
38
|
-
this.contextConfig = config.contextConfig;
|
|
39
|
-
this.credentials = resolveGetter(config.credentials);
|
|
40
|
-
this.models = config.models;
|
|
41
|
-
// Initialize database client
|
|
42
|
-
// In test environment, always use in-memory database
|
|
43
|
-
const dbUrl = process.env.ENVIRONMENT === 'test'
|
|
44
|
-
? ':memory:'
|
|
45
|
-
: process.env.DB_FILE_NAME || process.env.DATABASE_URL || ':memory:';
|
|
46
|
-
this.dbClient = createDatabaseClient({
|
|
47
|
-
url: dbUrl,
|
|
48
|
-
});
|
|
49
|
-
this.statusUpdateSettings = config.statusUpdates;
|
|
50
|
-
this.graphPrompt = config.graphPrompt;
|
|
51
|
-
// Set stopWhen - preserve original config or set default during inheritance
|
|
52
|
-
this.stopWhen = config.stopWhen
|
|
53
|
-
? {
|
|
54
|
-
transferCountIs: config.stopWhen.transferCountIs,
|
|
55
|
-
}
|
|
56
|
-
: undefined;
|
|
57
|
-
this.agents = resolveGetter(config.agents) || [];
|
|
58
|
-
this.agentMap = new Map(this.agents.map((agent) => [agent.getId(), agent]));
|
|
59
|
-
// Add default agent to map
|
|
60
|
-
if (this.defaultAgent) {
|
|
61
|
-
this.agents.push(this.defaultAgent);
|
|
62
|
-
this.agentMap.set(this.defaultAgent.getId(), this.defaultAgent);
|
|
63
|
-
}
|
|
64
|
-
// Propagate graph-level models to agents immediately (if graph has models)
|
|
65
|
-
if (this.models) {
|
|
66
|
-
this.propagateImmediateModelSettings();
|
|
67
|
-
}
|
|
68
|
-
logger.info({
|
|
69
|
-
graphId: this.graphId,
|
|
70
|
-
tenantId: this.tenantId,
|
|
71
|
-
agentCount: this.agents.length,
|
|
72
|
-
defaultAgent: this.defaultAgent?.getName(),
|
|
73
|
-
}, 'AgentGraph created');
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Set or update the configuration (tenantId, projectId and apiUrl)
|
|
77
|
-
* This is used by the CLI to inject configuration from inkeep.config.ts
|
|
78
|
-
*/
|
|
79
|
-
setConfig(tenantId, projectId, apiUrl) {
|
|
80
|
-
if (this.initialized) {
|
|
81
|
-
throw new Error('Cannot set config after graph has been initialized');
|
|
82
|
-
}
|
|
83
|
-
this.tenantId = tenantId;
|
|
84
|
-
this.projectId = projectId;
|
|
85
|
-
this.baseURL = apiUrl;
|
|
86
|
-
// Propagate tenantId to all agents and their tools
|
|
87
|
-
for (const agent of this.agents) {
|
|
88
|
-
if (this.isInternalAgent(agent)) {
|
|
89
|
-
const internalAgent = agent;
|
|
90
|
-
if (!internalAgent.config.tenantId) {
|
|
91
|
-
internalAgent.config.tenantId = tenantId;
|
|
92
|
-
}
|
|
93
|
-
// Also update tools in this agent
|
|
94
|
-
const tools = internalAgent.getTools();
|
|
95
|
-
for (const [_, toolInstance] of Object.entries(tools)) {
|
|
96
|
-
if (toolInstance && typeof toolInstance === 'object' && toolInstance.config) {
|
|
97
|
-
if (!toolInstance.config.tenantId) {
|
|
98
|
-
toolInstance.config.tenantId = tenantId;
|
|
99
|
-
}
|
|
100
|
-
// Also update baseURL for tools if they have one
|
|
101
|
-
if ('baseURL' in toolInstance && !toolInstance.baseURL) {
|
|
102
|
-
toolInstance.baseURL = apiUrl;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
// Update context config tenant ID if present
|
|
109
|
-
if (this.contextConfig && !this.contextConfig.tenantId) {
|
|
110
|
-
this.contextConfig.tenantId = tenantId;
|
|
111
|
-
}
|
|
112
|
-
logger.info({
|
|
113
|
-
graphId: this.graphId,
|
|
114
|
-
tenantId: this.tenantId,
|
|
115
|
-
projectId: this.projectId,
|
|
116
|
-
apiUrl: this.baseURL,
|
|
117
|
-
}, 'Graph configuration updated');
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Convert the AgentGraph to FullGraphDefinition format for the new graph endpoint
|
|
121
|
-
*/
|
|
122
|
-
async toFullGraphDefinition() {
|
|
123
|
-
const agentsObject = {};
|
|
124
|
-
for (const agent of this.agents) {
|
|
125
|
-
if (this.isInternalAgent(agent)) {
|
|
126
|
-
// Handle internal agents
|
|
127
|
-
const internalAgent = agent;
|
|
128
|
-
// Get agent relationships
|
|
129
|
-
const transfers = internalAgent.getTransfers();
|
|
130
|
-
const delegates = internalAgent.getDelegates();
|
|
131
|
-
// Convert tools to the expected format (agent.tools should be an array of tool IDs)
|
|
132
|
-
const tools = [];
|
|
133
|
-
const agentTools = internalAgent.getTools();
|
|
134
|
-
for (const [toolName, toolInstance] of Object.entries(agentTools)) {
|
|
135
|
-
if (toolInstance && typeof toolInstance === 'object') {
|
|
136
|
-
const toolId = toolInstance.getId?.() || toolInstance.id || toolName;
|
|
137
|
-
tools.push(toolId);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
// Convert dataComponents to the expected format (agent.dataComponents should be an array of dataComponent IDs)
|
|
141
|
-
const dataComponents = [];
|
|
142
|
-
const agentDataComponents = internalAgent.getDataComponents();
|
|
143
|
-
if (agentDataComponents) {
|
|
144
|
-
for (const dataComponent of agentDataComponents) {
|
|
145
|
-
const dataComponentId = dataComponent.id || dataComponent.name.toLowerCase().replace(/\s+/g, '-');
|
|
146
|
-
dataComponents.push(dataComponentId);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
// Convert artifactComponents to the expected format (agent.artifactComponents should be an array of artifactComponent IDs)
|
|
150
|
-
const artifactComponents = [];
|
|
151
|
-
const agentArtifactComponents = internalAgent.getArtifactComponents();
|
|
152
|
-
if (agentArtifactComponents) {
|
|
153
|
-
for (const artifactComponent of agentArtifactComponents) {
|
|
154
|
-
const artifactComponentId = artifactComponent.id || artifactComponent.name.toLowerCase().replace(/\s+/g, '-');
|
|
155
|
-
artifactComponents.push(artifactComponentId);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
agentsObject[internalAgent.getId()] = {
|
|
159
|
-
id: internalAgent.getId(),
|
|
160
|
-
name: internalAgent.getName(),
|
|
161
|
-
description: internalAgent.config.description || `Agent ${internalAgent.getName()}`,
|
|
162
|
-
prompt: internalAgent.getInstructions(),
|
|
163
|
-
models: internalAgent.config.models,
|
|
164
|
-
canTransferTo: transfers.map((h) => h.getId()),
|
|
165
|
-
canDelegateTo: delegates.map((d) => d.getId()),
|
|
166
|
-
tools,
|
|
167
|
-
dataComponents: dataComponents.length > 0 ? dataComponents : undefined,
|
|
168
|
-
artifactComponents: artifactComponents.length > 0 ? artifactComponents : undefined,
|
|
169
|
-
type: 'internal',
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
// Handle external agents
|
|
174
|
-
const externalAgent = agent;
|
|
175
|
-
agentsObject[externalAgent.getId()] = {
|
|
176
|
-
id: externalAgent.getId(),
|
|
177
|
-
name: externalAgent.getName(),
|
|
178
|
-
description: externalAgent.getDescription(),
|
|
179
|
-
baseUrl: externalAgent.getBaseUrl(),
|
|
180
|
-
credentialReferenceId: externalAgent.getCredentialReferenceId(),
|
|
181
|
-
headers: externalAgent.getHeaders(),
|
|
182
|
-
tools: [], // External agents don't have tools in this context
|
|
183
|
-
type: 'external',
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
// Collect all tools from all agents
|
|
188
|
-
const toolsObject = {};
|
|
189
|
-
for (const agent of this.agents) {
|
|
190
|
-
if (!agent.getTransfers) {
|
|
191
|
-
continue; // Skip external agents
|
|
192
|
-
}
|
|
193
|
-
const internalAgent = agent;
|
|
194
|
-
const agentTools = internalAgent.getTools();
|
|
195
|
-
for (const [toolName, toolInstance] of Object.entries(agentTools)) {
|
|
196
|
-
if (toolInstance && typeof toolInstance === 'object') {
|
|
197
|
-
const toolId = toolInstance.getId?.() || toolInstance.id || toolName;
|
|
198
|
-
// Only add if not already added (avoid duplicates across agents)
|
|
199
|
-
if (!toolsObject[toolId]) {
|
|
200
|
-
let toolConfig;
|
|
201
|
-
// Check if it's an IPCTool with MCP server configuration
|
|
202
|
-
if (toolInstance.config?.serverUrl) {
|
|
203
|
-
toolConfig = {
|
|
204
|
-
type: 'mcp',
|
|
205
|
-
mcp: {
|
|
206
|
-
server: {
|
|
207
|
-
url: toolInstance.config.serverUrl,
|
|
208
|
-
},
|
|
209
|
-
},
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
else if (toolInstance.config?.type === 'mcp') {
|
|
213
|
-
// Already has proper MCP config
|
|
214
|
-
toolConfig = toolInstance.config;
|
|
215
|
-
}
|
|
216
|
-
else {
|
|
217
|
-
// Fallback for function tools or uninitialized tools
|
|
218
|
-
toolConfig = {
|
|
219
|
-
type: 'function',
|
|
220
|
-
parameters: toolInstance.parameters || {},
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
const toolData = {
|
|
224
|
-
id: toolId,
|
|
225
|
-
name: toolInstance.config?.name || toolInstance.name || toolName,
|
|
226
|
-
config: toolConfig,
|
|
227
|
-
status: toolInstance.getStatus?.() || toolInstance.status || 'unknown',
|
|
228
|
-
};
|
|
229
|
-
// Add additional fields if available
|
|
230
|
-
if (toolInstance.config?.imageUrl) {
|
|
231
|
-
toolData.imageUrl = toolInstance.config.imageUrl;
|
|
232
|
-
}
|
|
233
|
-
if (toolInstance.config?.headers) {
|
|
234
|
-
toolData.headers = toolInstance.config.headers;
|
|
235
|
-
}
|
|
236
|
-
if (toolInstance.capabilities) {
|
|
237
|
-
toolData.capabilities = toolInstance.capabilities;
|
|
238
|
-
}
|
|
239
|
-
if (toolInstance.lastHealthCheck) {
|
|
240
|
-
toolData.lastHealthCheck = toolInstance.lastHealthCheck;
|
|
241
|
-
}
|
|
242
|
-
if (toolInstance.availableTools) {
|
|
243
|
-
toolData.availableTools = toolInstance.availableTools;
|
|
244
|
-
}
|
|
245
|
-
if (toolInstance.lastError) {
|
|
246
|
-
toolData.lastError = toolInstance.lastError;
|
|
247
|
-
}
|
|
248
|
-
if (toolInstance.lastToolsSync) {
|
|
249
|
-
toolData.lastToolsSync = toolInstance.lastToolsSync;
|
|
250
|
-
}
|
|
251
|
-
// Add credential reference ID if available
|
|
252
|
-
if (toolInstance.getCredentialReferenceId?.()) {
|
|
253
|
-
toolData.credentialReferenceId = toolInstance.getCredentialReferenceId();
|
|
254
|
-
}
|
|
255
|
-
toolsObject[toolId] = toolData;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
// Collect all dataComponents from all agents
|
|
261
|
-
const dataComponentsObject = {};
|
|
262
|
-
for (const agent of this.agents) {
|
|
263
|
-
if (!this.isInternalAgent(agent)) {
|
|
264
|
-
continue; // Skip external agents
|
|
265
|
-
}
|
|
266
|
-
const internalAgent = agent;
|
|
267
|
-
const agentDataComponents = internalAgent.getDataComponents();
|
|
268
|
-
if (agentDataComponents) {
|
|
269
|
-
for (const dataComponent of agentDataComponents) {
|
|
270
|
-
const dataComponentId = dataComponent.id || dataComponent.name.toLowerCase().replace(/\s+/g, '-');
|
|
271
|
-
// Only add if not already added (avoid duplicates across agents)
|
|
272
|
-
if (!dataComponentsObject[dataComponentId]) {
|
|
273
|
-
dataComponentsObject[dataComponentId] = {
|
|
274
|
-
id: dataComponentId,
|
|
275
|
-
name: dataComponent.name,
|
|
276
|
-
description: dataComponent.description || '',
|
|
277
|
-
props: dataComponent.props || {},
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
// Collect all artifactComponents from all agents
|
|
284
|
-
const artifactComponentsObject = {};
|
|
285
|
-
for (const agent of this.agents) {
|
|
286
|
-
if (!this.isInternalAgent(agent)) {
|
|
287
|
-
continue; // Skip external agents
|
|
288
|
-
}
|
|
289
|
-
const internalAgent = agent;
|
|
290
|
-
const agentArtifactComponents = internalAgent.getArtifactComponents();
|
|
291
|
-
if (agentArtifactComponents) {
|
|
292
|
-
for (const artifactComponent of agentArtifactComponents) {
|
|
293
|
-
const artifactComponentId = artifactComponent.id || artifactComponent.name.toLowerCase().replace(/\s+/g, '-');
|
|
294
|
-
// Only add if not already added (avoid duplicates across agents)
|
|
295
|
-
if (!artifactComponentsObject[artifactComponentId]) {
|
|
296
|
-
artifactComponentsObject[artifactComponentId] = {
|
|
297
|
-
id: artifactComponentId,
|
|
298
|
-
name: artifactComponent.name,
|
|
299
|
-
description: artifactComponent.description || '',
|
|
300
|
-
summaryProps: artifactComponent.summaryProps || {},
|
|
301
|
-
fullProps: artifactComponent.fullProps || {},
|
|
302
|
-
};
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
return {
|
|
308
|
-
id: this.graphId,
|
|
309
|
-
name: this.graphName,
|
|
310
|
-
description: this.graphDescription,
|
|
311
|
-
defaultAgentId: this.defaultAgent?.getId() || '',
|
|
312
|
-
agents: agentsObject,
|
|
313
|
-
tools: toolsObject,
|
|
314
|
-
contextConfig: this.contextConfig?.toObject(),
|
|
315
|
-
credentialReferences: this.credentials?.map((credentialReference) => ({
|
|
316
|
-
type: credentialReference.type,
|
|
317
|
-
id: credentialReference.id,
|
|
318
|
-
credentialStoreId: credentialReference.credentialStoreId,
|
|
319
|
-
retrievalParams: credentialReference.retrievalParams || {},
|
|
320
|
-
})),
|
|
321
|
-
models: this.models,
|
|
322
|
-
statusUpdates: this.statusUpdateSettings,
|
|
323
|
-
graphPrompt: this.graphPrompt,
|
|
324
|
-
dataComponents: Object.keys(dataComponentsObject).length > 0 ? dataComponentsObject : undefined,
|
|
325
|
-
artifactComponents: Object.keys(artifactComponentsObject).length > 0 ? artifactComponentsObject : undefined,
|
|
326
|
-
createdAt: new Date().toISOString(),
|
|
327
|
-
updatedAt: new Date().toISOString(),
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
/**
|
|
331
|
-
* Initialize all tools in all agents (especially IPCTools that need MCP server URLs)
|
|
332
|
-
*/
|
|
333
|
-
async initializeAllTools() {
|
|
334
|
-
logger.info({ graphId: this.graphId }, 'Initializing all tools in graph');
|
|
335
|
-
const toolInitPromises = [];
|
|
336
|
-
for (const agent of this.agents) {
|
|
337
|
-
// Skip external agents as they don't have getTools method
|
|
338
|
-
if (!agent.getTools) {
|
|
339
|
-
continue;
|
|
340
|
-
}
|
|
341
|
-
const internalAgent = agent;
|
|
342
|
-
const agentTools = internalAgent.getTools();
|
|
343
|
-
for (const [toolName, toolInstance] of Object.entries(agentTools)) {
|
|
344
|
-
if (toolInstance && typeof toolInstance === 'object') {
|
|
345
|
-
// Check if this is a tool that needs initialization
|
|
346
|
-
if (typeof toolInstance.init === 'function') {
|
|
347
|
-
toolInitPromises.push((async () => {
|
|
348
|
-
try {
|
|
349
|
-
// Skip database registration for all tools since graphFull will handle it
|
|
350
|
-
const skipDbRegistration = toolInstance.constructor.name === 'IPCTool' ||
|
|
351
|
-
toolInstance.constructor.name === 'HostedTool' ||
|
|
352
|
-
toolInstance.constructor.name === 'Tool';
|
|
353
|
-
if (typeof toolInstance.init === 'function') {
|
|
354
|
-
if (skipDbRegistration) {
|
|
355
|
-
await toolInstance.init({
|
|
356
|
-
skipDatabaseRegistration: true,
|
|
357
|
-
});
|
|
358
|
-
}
|
|
359
|
-
else {
|
|
360
|
-
await toolInstance.init();
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
logger.debug({
|
|
364
|
-
agentId: agent.getId(),
|
|
365
|
-
toolName,
|
|
366
|
-
toolType: toolInstance.constructor.name,
|
|
367
|
-
skipDbRegistration,
|
|
368
|
-
}, 'Tool initialized successfully');
|
|
369
|
-
}
|
|
370
|
-
catch (error) {
|
|
371
|
-
logger.error({
|
|
372
|
-
agentId: agent.getId(),
|
|
373
|
-
toolName,
|
|
374
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
375
|
-
}, 'Failed to initialize tool');
|
|
376
|
-
throw error;
|
|
377
|
-
}
|
|
378
|
-
})());
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
await Promise.all(toolInitPromises);
|
|
384
|
-
logger.info({ graphId: this.graphId, toolCount: toolInitPromises.length }, 'All tools initialized successfully');
|
|
385
|
-
}
|
|
386
|
-
/**
|
|
387
|
-
* Initialize the graph and all agents in the backend using the new graph endpoint
|
|
388
|
-
*/
|
|
389
|
-
async init() {
|
|
390
|
-
if (this.initialized) {
|
|
391
|
-
logger.info({ graphId: this.graphId }, 'Graph already initialized');
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
logger.info({
|
|
395
|
-
graphId: this.graphId,
|
|
396
|
-
agentCount: this.agents.length,
|
|
397
|
-
}, 'Initializing agent graph using new graph endpoint');
|
|
398
|
-
try {
|
|
399
|
-
// Initialize all tools first (especially IPCTools that need MCP server URLs)
|
|
400
|
-
await this.initializeAllTools();
|
|
401
|
-
// Apply model inheritance hierarchy (Project -> Graph -> Agent)
|
|
402
|
-
await this.applyModelInheritance();
|
|
403
|
-
// Convert to FullGraphDefinition format
|
|
404
|
-
const graphDefinition = await this.toFullGraphDefinition();
|
|
405
|
-
// Always use API mode (baseURL is always set)
|
|
406
|
-
logger.info({
|
|
407
|
-
graphId: this.graphId,
|
|
408
|
-
mode: 'api-client',
|
|
409
|
-
apiUrl: this.baseURL,
|
|
410
|
-
}, 'Using API client to create/update graph');
|
|
411
|
-
// Try update first (upsert behavior)
|
|
412
|
-
const createdGraph = await updateFullGraphViaAPI(this.tenantId, this.projectId, this.baseURL, this.graphId, graphDefinition);
|
|
413
|
-
logger.info({
|
|
414
|
-
graphId: this.graphId,
|
|
415
|
-
agentCount: Object.keys(createdGraph.agents || {}).length,
|
|
416
|
-
}, 'Agent graph initialized successfully using graph endpoint');
|
|
417
|
-
this.initialized = true;
|
|
418
|
-
}
|
|
419
|
-
catch (error) {
|
|
420
|
-
logger.error({
|
|
421
|
-
graphId: this.graphId,
|
|
422
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
423
|
-
}, 'Failed to initialize agent graph using graph endpoint');
|
|
424
|
-
throw error;
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
/**
|
|
428
|
-
* Legacy initialization method - kept for backward compatibility
|
|
429
|
-
* Initialize the graph and all agents in the backend using individual endpoints
|
|
430
|
-
*/
|
|
431
|
-
async initLegacy() {
|
|
432
|
-
if (this.initialized) {
|
|
433
|
-
logger.info({ graphId: this.graphId }, 'Graph already initialized');
|
|
434
|
-
return;
|
|
435
|
-
}
|
|
436
|
-
logger.info({
|
|
437
|
-
graphId: this.graphId,
|
|
438
|
-
agentCount: this.agents.length,
|
|
439
|
-
}, 'Initializing agent graph');
|
|
440
|
-
try {
|
|
441
|
-
// Component mode has been removed
|
|
442
|
-
// Step 2: Initialize context configuration if provided
|
|
443
|
-
if (this.contextConfig) {
|
|
444
|
-
await this.contextConfig.init();
|
|
445
|
-
logger.info({
|
|
446
|
-
graphId: this.graphId,
|
|
447
|
-
contextConfigId: this.contextConfig.getId(),
|
|
448
|
-
}, 'Context configuration initialized for graph');
|
|
449
|
-
}
|
|
450
|
-
// Step 3: Initialize all agents
|
|
451
|
-
const initPromises = this.agents.map(async (agent) => {
|
|
452
|
-
try {
|
|
453
|
-
// Set the graphId on the agent config before initialization
|
|
454
|
-
agent.config.graphId = this.graphId;
|
|
455
|
-
await agent.init();
|
|
456
|
-
logger.debug({
|
|
457
|
-
agentId: agent.getId(),
|
|
458
|
-
graphId: this.graphId,
|
|
459
|
-
}, 'Agent initialized in graph');
|
|
460
|
-
}
|
|
461
|
-
catch (error) {
|
|
462
|
-
logger.error({
|
|
463
|
-
agentId: agent.getId(),
|
|
464
|
-
graphId: this.graphId,
|
|
465
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
466
|
-
}, 'Failed to initialize agent in graph');
|
|
467
|
-
throw error;
|
|
468
|
-
}
|
|
469
|
-
});
|
|
470
|
-
await Promise.all(initPromises);
|
|
471
|
-
// Step 2: Create agent graph in database (now that agents exist)
|
|
472
|
-
await this.saveToDatabase();
|
|
473
|
-
// Step 3: Create external agents in database
|
|
474
|
-
await this.createExternalAgents();
|
|
475
|
-
// Step 4: Create agent relations (transfer and delegation) using the graph's graphId
|
|
476
|
-
await this.createAgentRelations();
|
|
477
|
-
// Step 5: Set up graph-level relationships
|
|
478
|
-
await this.saveRelations();
|
|
479
|
-
this.initialized = true;
|
|
480
|
-
logger.info({
|
|
481
|
-
graphId: this.graphId,
|
|
482
|
-
agentCount: this.agents.length,
|
|
483
|
-
}, 'Agent graph initialized successfully');
|
|
484
|
-
}
|
|
485
|
-
catch (error) {
|
|
486
|
-
logger.error({
|
|
487
|
-
graphId: this.graphId,
|
|
488
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
489
|
-
}, 'Failed to initialize agent graph');
|
|
490
|
-
throw error;
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
/**
|
|
494
|
-
* Generate a response using the default agent
|
|
495
|
-
*/
|
|
496
|
-
async generate(input, options) {
|
|
497
|
-
await this._init();
|
|
498
|
-
if (!this.defaultAgent) {
|
|
499
|
-
throw new Error('No default agent configured for this graph');
|
|
500
|
-
}
|
|
501
|
-
logger.info({
|
|
502
|
-
graphId: this.graphId,
|
|
503
|
-
defaultAgent: this.defaultAgent.getName(),
|
|
504
|
-
conversationId: options?.conversationId,
|
|
505
|
-
}, 'Generating response with default agent');
|
|
506
|
-
// Use the proper backend execution instead of the local runner
|
|
507
|
-
const response = await this.executeWithBackend(input, options);
|
|
508
|
-
return response;
|
|
509
|
-
}
|
|
510
|
-
/**
|
|
511
|
-
* Stream a response using the default agent
|
|
512
|
-
*/
|
|
513
|
-
async stream(input, options) {
|
|
514
|
-
await this._init();
|
|
515
|
-
if (!this.defaultAgent) {
|
|
516
|
-
throw new Error('No default agent configured for this graph');
|
|
517
|
-
}
|
|
518
|
-
logger.info({
|
|
519
|
-
graphId: this.graphId,
|
|
520
|
-
defaultAgent: this.defaultAgent.getName(),
|
|
521
|
-
conversationId: options?.conversationId,
|
|
522
|
-
}, 'Streaming response with default agent');
|
|
523
|
-
// Delegate to the graph's stream method with backend
|
|
524
|
-
// For now, create a simple async generator that yields the response
|
|
525
|
-
const textStream = async function* (graph) {
|
|
526
|
-
const response = await graph.executeWithBackend(input, options);
|
|
527
|
-
// Simulate streaming by yielding chunks
|
|
528
|
-
const words = response.split(' ');
|
|
529
|
-
for (const word of words) {
|
|
530
|
-
yield `${word} `;
|
|
531
|
-
}
|
|
532
|
-
};
|
|
533
|
-
return {
|
|
534
|
-
textStream: textStream(this),
|
|
535
|
-
};
|
|
536
|
-
}
|
|
537
|
-
/**
|
|
538
|
-
* Alias for stream() method for consistency with naming patterns
|
|
539
|
-
*/
|
|
540
|
-
async generateStream(input, options) {
|
|
541
|
-
return await this.stream(input, options);
|
|
542
|
-
}
|
|
543
|
-
/**
|
|
544
|
-
* Run with a specific agent from the graph
|
|
545
|
-
*/
|
|
546
|
-
async runWith(agentId, input, options) {
|
|
547
|
-
await this._init();
|
|
548
|
-
const agent = this.getAgent(agentId);
|
|
549
|
-
if (!agent) {
|
|
550
|
-
throw new Error(`Agent '${agentId}' not found in graph`);
|
|
551
|
-
}
|
|
552
|
-
// Only internal agents can be run directly via this method
|
|
553
|
-
if (!this.isInternalAgent(agent)) {
|
|
554
|
-
throw new Error(`Agent '${agentId}' is an external agent and cannot be run directly. External agents are only accessible via delegation.`);
|
|
555
|
-
}
|
|
556
|
-
logger.info({
|
|
557
|
-
graphId: this.graphId,
|
|
558
|
-
agentId,
|
|
559
|
-
conversationId: options?.conversationId,
|
|
560
|
-
}, 'Running with specific agent');
|
|
561
|
-
// Use backend execution and wrap result in RunResult format
|
|
562
|
-
const response = await this.executeWithBackend(input, options);
|
|
563
|
-
return {
|
|
564
|
-
finalOutput: response,
|
|
565
|
-
agent: agent,
|
|
566
|
-
turnCount: 1,
|
|
567
|
-
usage: { inputTokens: 0, outputTokens: 0 },
|
|
568
|
-
metadata: {
|
|
569
|
-
toolCalls: [],
|
|
570
|
-
transfers: [],
|
|
571
|
-
},
|
|
572
|
-
};
|
|
573
|
-
}
|
|
574
|
-
/**
|
|
575
|
-
* Get an agent by name (unified method for all agent types)
|
|
576
|
-
*/
|
|
577
|
-
getAgent(name) {
|
|
578
|
-
return this.agentMap.get(name);
|
|
579
|
-
}
|
|
580
|
-
/**
|
|
581
|
-
* Add an agent to the graph
|
|
582
|
-
*/
|
|
583
|
-
addAgent(agent) {
|
|
584
|
-
this.agents.push(agent);
|
|
585
|
-
this.agentMap.set(agent.getId(), agent);
|
|
586
|
-
// Apply immediate model inheritance if graph has models
|
|
587
|
-
if (this.models && this.isInternalAgent(agent)) {
|
|
588
|
-
this.propagateModelSettingsToAgent(agent);
|
|
589
|
-
}
|
|
590
|
-
logger.info({
|
|
591
|
-
graphId: this.graphId,
|
|
592
|
-
agentId: agent.getId(),
|
|
593
|
-
agentType: this.isInternalAgent(agent) ? 'internal' : 'external',
|
|
594
|
-
}, 'Agent added to graph');
|
|
595
|
-
}
|
|
596
|
-
/**
|
|
597
|
-
* Remove an agent from the graph
|
|
598
|
-
*/
|
|
599
|
-
removeAgent(id) {
|
|
600
|
-
const agentToRemove = this.agentMap.get(id);
|
|
601
|
-
if (agentToRemove) {
|
|
602
|
-
this.agentMap.delete(agentToRemove.getId());
|
|
603
|
-
this.agents = this.agents.filter((agent) => agent.getId() !== agentToRemove.getId());
|
|
604
|
-
logger.info({
|
|
605
|
-
graphId: this.graphId,
|
|
606
|
-
agentId: agentToRemove.getId(),
|
|
607
|
-
}, 'Agent removed from graph');
|
|
608
|
-
return true;
|
|
609
|
-
}
|
|
610
|
-
return false;
|
|
611
|
-
}
|
|
612
|
-
/**
|
|
613
|
-
* Get all agents in the graph
|
|
614
|
-
*/
|
|
615
|
-
getAgents() {
|
|
616
|
-
return this.agents;
|
|
617
|
-
}
|
|
618
|
-
/**
|
|
619
|
-
* Get all agent ids (unified method for all agent types)
|
|
620
|
-
*/
|
|
621
|
-
getAgentIds() {
|
|
622
|
-
return Array.from(this.agentMap.keys());
|
|
623
|
-
}
|
|
624
|
-
/**
|
|
625
|
-
* Set the default agent
|
|
626
|
-
*/
|
|
627
|
-
setDefaultAgent(agent) {
|
|
628
|
-
this.defaultAgent = agent;
|
|
629
|
-
this.addAgent(agent); // Ensure it's in the graph
|
|
630
|
-
logger.info({
|
|
631
|
-
graphId: this.graphId,
|
|
632
|
-
defaultAgent: agent.getId(),
|
|
633
|
-
}, 'Default agent updated');
|
|
634
|
-
}
|
|
635
|
-
/**
|
|
636
|
-
* Get the default agent
|
|
637
|
-
*/
|
|
638
|
-
getDefaultAgent() {
|
|
639
|
-
return this.defaultAgent;
|
|
640
|
-
}
|
|
641
|
-
/**
|
|
642
|
-
* Get the graph ID
|
|
643
|
-
*/
|
|
644
|
-
getId() {
|
|
645
|
-
return this.graphId;
|
|
646
|
-
}
|
|
647
|
-
getName() {
|
|
648
|
-
return this.graphName;
|
|
649
|
-
}
|
|
650
|
-
getDescription() {
|
|
651
|
-
return this.graphDescription;
|
|
652
|
-
}
|
|
653
|
-
getTenantId() {
|
|
654
|
-
return this.tenantId;
|
|
655
|
-
}
|
|
656
|
-
/**
|
|
657
|
-
* Get the graph's model settingsuration
|
|
658
|
-
*/
|
|
659
|
-
getModels() {
|
|
660
|
-
return this.models;
|
|
661
|
-
}
|
|
662
|
-
/**
|
|
663
|
-
* Set the graph's model settingsuration
|
|
664
|
-
*/
|
|
665
|
-
setModels(models) {
|
|
666
|
-
this.models = models;
|
|
667
|
-
}
|
|
668
|
-
/**
|
|
669
|
-
* Get the graph's prompt configuration
|
|
670
|
-
*/
|
|
671
|
-
getGraphPrompt() {
|
|
672
|
-
return this.graphPrompt;
|
|
673
|
-
}
|
|
674
|
-
/**
|
|
675
|
-
* Get the graph's stopWhen configuration
|
|
676
|
-
*/
|
|
677
|
-
getStopWhen() {
|
|
678
|
-
return this.stopWhen || { transferCountIs: 10 };
|
|
679
|
-
}
|
|
680
|
-
/**
|
|
681
|
-
* Get the graph's status updates configuration
|
|
682
|
-
*/
|
|
683
|
-
getStatusUpdateSettings() {
|
|
684
|
-
return this.statusUpdateSettings;
|
|
685
|
-
}
|
|
686
|
-
/**
|
|
687
|
-
* Get the summarizer model from the graph's model settings
|
|
688
|
-
*/
|
|
689
|
-
getSummarizerModel() {
|
|
690
|
-
return this.models?.summarizer;
|
|
691
|
-
}
|
|
692
|
-
/**
|
|
693
|
-
* Get graph statistics
|
|
694
|
-
*/
|
|
695
|
-
getStats() {
|
|
696
|
-
return {
|
|
697
|
-
agentCount: this.agents.length,
|
|
698
|
-
defaultAgent: this.defaultAgent?.getName() || null,
|
|
699
|
-
initialized: this.initialized,
|
|
700
|
-
graphId: this.graphId,
|
|
701
|
-
tenantId: this.tenantId,
|
|
702
|
-
};
|
|
703
|
-
}
|
|
704
|
-
/**
|
|
705
|
-
* Validate the graph configuration
|
|
706
|
-
*/
|
|
707
|
-
validate() {
|
|
708
|
-
const errors = [];
|
|
709
|
-
if (this.agents.length === 0) {
|
|
710
|
-
errors.push('Graph must contain at least one agent');
|
|
711
|
-
}
|
|
712
|
-
if (!this.defaultAgent) {
|
|
713
|
-
errors.push('Graph must have a default agent');
|
|
714
|
-
}
|
|
715
|
-
// Validate agent names are unique
|
|
716
|
-
const names = new Set();
|
|
717
|
-
for (const agent of this.agents) {
|
|
718
|
-
const name = agent.getName();
|
|
719
|
-
if (names.has(name)) {
|
|
720
|
-
errors.push(`Duplicate agent name: ${name}`);
|
|
721
|
-
}
|
|
722
|
-
names.add(name);
|
|
723
|
-
}
|
|
724
|
-
// Validate agent relationships (transfer and delegation) for internal agents only
|
|
725
|
-
for (const agent of this.agents) {
|
|
726
|
-
if (!this.isInternalAgent(agent))
|
|
727
|
-
continue; // Skip external agents for relationship validation
|
|
728
|
-
// Validate transfer relationships
|
|
729
|
-
const transfers = agent.getTransfers();
|
|
730
|
-
for (const transferAgent of transfers) {
|
|
731
|
-
if (!this.agentMap.has(transferAgent.getName())) {
|
|
732
|
-
errors.push(`Agent '${agent.getName()}' has transfer to '${transferAgent.getName()}' which is not in the graph`);
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
// Validate delegation relationships
|
|
736
|
-
const delegates = agent.getDelegates();
|
|
737
|
-
for (const delegateAgent of delegates) {
|
|
738
|
-
if (!this.agentMap.has(delegateAgent.getName())) {
|
|
739
|
-
errors.push(`Agent '${agent.getName()}' has delegation to '${delegateAgent.getName()}' which is not in the graph`);
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
return {
|
|
744
|
-
valid: errors.length === 0,
|
|
745
|
-
errors,
|
|
746
|
-
};
|
|
747
|
-
}
|
|
748
|
-
// Private helper methods
|
|
749
|
-
async _init() {
|
|
750
|
-
if (!this.initialized) {
|
|
751
|
-
await this.init();
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
/**
|
|
755
|
-
* Type guard to check if an agent is an internal AgentInterface
|
|
756
|
-
*/
|
|
757
|
-
isInternalAgent(agent) {
|
|
758
|
-
// Internal agents have getTransfers, getDelegates, and other AgentInterface methods
|
|
759
|
-
// External agents only have basic identification methods
|
|
760
|
-
return 'getTransfers' in agent && typeof agent.getTransfers === 'function';
|
|
761
|
-
}
|
|
762
|
-
/**
|
|
763
|
-
* Get project-level model settingsuration defaults
|
|
764
|
-
*/
|
|
765
|
-
async getProjectModelDefaults() {
|
|
766
|
-
try {
|
|
767
|
-
const project = await getProject(this.dbClient)({
|
|
768
|
-
scopes: { tenantId: this.tenantId, projectId: this.projectId },
|
|
769
|
-
});
|
|
770
|
-
return project?.models;
|
|
771
|
-
}
|
|
772
|
-
catch (error) {
|
|
773
|
-
logger.warn({
|
|
774
|
-
tenantId: this.tenantId,
|
|
775
|
-
projectId: this.projectId,
|
|
776
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
777
|
-
}, 'Failed to get project model defaults');
|
|
778
|
-
return undefined;
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
/**
|
|
782
|
-
* Get project-level stopWhen configuration defaults
|
|
783
|
-
*/
|
|
784
|
-
async getProjectStopWhenDefaults() {
|
|
785
|
-
try {
|
|
786
|
-
const project = await getProject(this.dbClient)({
|
|
787
|
-
scopes: { tenantId: this.tenantId, projectId: this.projectId },
|
|
788
|
-
});
|
|
789
|
-
return project?.stopWhen;
|
|
790
|
-
}
|
|
791
|
-
catch (error) {
|
|
792
|
-
logger.warn({
|
|
793
|
-
tenantId: this.tenantId,
|
|
794
|
-
projectId: this.projectId,
|
|
795
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
796
|
-
}, 'Failed to get project stopWhen defaults');
|
|
797
|
-
return undefined;
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
/**
|
|
801
|
-
* Apply model inheritance hierarchy: Project -> Graph -> Agent
|
|
802
|
-
*/
|
|
803
|
-
async applyModelInheritance() {
|
|
804
|
-
// Always get project defaults to check for partial inheritance
|
|
805
|
-
const projectModels = await this.getProjectModelDefaults();
|
|
806
|
-
if (projectModels) {
|
|
807
|
-
// Initialize models object if it doesn't exist
|
|
808
|
-
if (!this.models) {
|
|
809
|
-
this.models = {};
|
|
810
|
-
}
|
|
811
|
-
// Inherit individual model types from project if not set at graph level
|
|
812
|
-
if (!this.models.base && projectModels.base) {
|
|
813
|
-
this.models.base = projectModels.base;
|
|
814
|
-
}
|
|
815
|
-
if (!this.models.structuredOutput && projectModels.structuredOutput) {
|
|
816
|
-
this.models.structuredOutput = projectModels.structuredOutput;
|
|
817
|
-
}
|
|
818
|
-
if (!this.models.summarizer && projectModels.summarizer) {
|
|
819
|
-
this.models.summarizer = projectModels.summarizer;
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
// Apply stopWhen inheritance: Project -> Graph -> Agent
|
|
823
|
-
await this.applyStopWhenInheritance();
|
|
824
|
-
// Propagate to agents
|
|
825
|
-
for (const agent of this.agents) {
|
|
826
|
-
if (this.isInternalAgent(agent)) {
|
|
827
|
-
this.propagateModelSettingsToAgent(agent);
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
/**
|
|
832
|
-
* Apply stopWhen inheritance hierarchy: Project -> Graph -> Agent
|
|
833
|
-
*/
|
|
834
|
-
async applyStopWhenInheritance() {
|
|
835
|
-
// Get project stopWhen defaults
|
|
836
|
-
const projectStopWhen = await this.getProjectStopWhenDefaults();
|
|
837
|
-
// Initialize stopWhen if it doesn't exist (graph had no stopWhen config)
|
|
838
|
-
if (!this.stopWhen) {
|
|
839
|
-
this.stopWhen = {};
|
|
840
|
-
}
|
|
841
|
-
// Inherit transferCountIs from project if graph doesn't have it explicitly set
|
|
842
|
-
if (this.stopWhen.transferCountIs === undefined &&
|
|
843
|
-
projectStopWhen?.transferCountIs !== undefined) {
|
|
844
|
-
this.stopWhen.transferCountIs = projectStopWhen.transferCountIs;
|
|
845
|
-
}
|
|
846
|
-
// Set default transferCountIs if still not set
|
|
847
|
-
if (this.stopWhen.transferCountIs === undefined) {
|
|
848
|
-
this.stopWhen.transferCountIs = 10;
|
|
849
|
-
}
|
|
850
|
-
// Propagate stepCountIs from project to agents
|
|
851
|
-
if (projectStopWhen?.stepCountIs !== undefined) {
|
|
852
|
-
for (const agent of this.agents) {
|
|
853
|
-
if (this.isInternalAgent(agent)) {
|
|
854
|
-
const internalAgent = agent;
|
|
855
|
-
// Initialize agent stopWhen if it doesn't exist
|
|
856
|
-
if (!internalAgent.config.stopWhen) {
|
|
857
|
-
internalAgent.config.stopWhen = {};
|
|
858
|
-
}
|
|
859
|
-
// Inherit stepCountIs from project if not set at agent level
|
|
860
|
-
if (internalAgent.config.stopWhen.stepCountIs === undefined) {
|
|
861
|
-
internalAgent.config.stopWhen.stepCountIs = projectStopWhen.stepCountIs;
|
|
862
|
-
}
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
logger.debug({
|
|
867
|
-
graphId: this.graphId,
|
|
868
|
-
graphStopWhen: this.stopWhen,
|
|
869
|
-
projectStopWhen,
|
|
870
|
-
}, 'Applied stopWhen inheritance from project to graph');
|
|
871
|
-
}
|
|
872
|
-
/**
|
|
873
|
-
* Propagate graph-level model settings to agents (supporting partial inheritance)
|
|
874
|
-
*/
|
|
875
|
-
propagateModelSettingsToAgent(agent) {
|
|
876
|
-
if (this.models) {
|
|
877
|
-
// Initialize agent models if they don't exist
|
|
878
|
-
if (!agent.config.models) {
|
|
879
|
-
agent.config.models = {};
|
|
880
|
-
}
|
|
881
|
-
// Inherit individual model types from graph if not set at agent level
|
|
882
|
-
if (!agent.config.models.base && this.models.base) {
|
|
883
|
-
agent.config.models.base = this.models.base;
|
|
884
|
-
}
|
|
885
|
-
if (!agent.config.models.structuredOutput && this.models.structuredOutput) {
|
|
886
|
-
agent.config.models.structuredOutput = this.models.structuredOutput;
|
|
887
|
-
}
|
|
888
|
-
if (!agent.config.models.summarizer && this.models.summarizer) {
|
|
889
|
-
agent.config.models.summarizer = this.models.summarizer;
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
/**
|
|
894
|
-
* Immediately propagate graph-level models to all agents during construction
|
|
895
|
-
*/
|
|
896
|
-
propagateImmediateModelSettings() {
|
|
897
|
-
for (const agent of this.agents) {
|
|
898
|
-
if (this.isInternalAgent(agent)) {
|
|
899
|
-
this.propagateModelSettingsToAgent(agent);
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
/**
|
|
904
|
-
* Type guard to check if an agent is an external AgentInterface
|
|
905
|
-
*/
|
|
906
|
-
isExternalAgent(agent) {
|
|
907
|
-
return !this.isInternalAgent(agent);
|
|
908
|
-
}
|
|
909
|
-
/**
|
|
910
|
-
* Execute agent using the backend system instead of local runner
|
|
911
|
-
*/
|
|
912
|
-
async executeWithBackend(input, options) {
|
|
913
|
-
const normalizedMessages = this.normalizeMessages(input);
|
|
914
|
-
const url = `${this.baseURL}/tenants/${this.tenantId}/graphs/${this.graphId}/v1/chat/completions`;
|
|
915
|
-
logger.info({ url }, 'Executing with backend');
|
|
916
|
-
const requestBody = {
|
|
917
|
-
model: 'gpt-4o-mini',
|
|
918
|
-
messages: normalizedMessages.map((msg) => ({
|
|
919
|
-
role: msg.role,
|
|
920
|
-
content: msg.content,
|
|
921
|
-
})),
|
|
922
|
-
...options,
|
|
923
|
-
// Include conversationId for multi-turn support
|
|
924
|
-
...(options?.conversationId && { conversationId: options.conversationId }),
|
|
925
|
-
// Include context data if available
|
|
926
|
-
...(options?.customBodyParams && { ...options.customBodyParams }),
|
|
927
|
-
stream: false, // Explicitly disable streaming - must come after options to override
|
|
928
|
-
};
|
|
929
|
-
try {
|
|
930
|
-
const response = await fetch(url, {
|
|
931
|
-
method: 'POST',
|
|
932
|
-
headers: {
|
|
933
|
-
'Content-Type': 'application/json',
|
|
934
|
-
Accept: 'application/json',
|
|
935
|
-
},
|
|
936
|
-
body: JSON.stringify(requestBody),
|
|
937
|
-
});
|
|
938
|
-
if (!response.ok) {
|
|
939
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
940
|
-
}
|
|
941
|
-
const responseText = await response.text();
|
|
942
|
-
// Check if response is SSE format (starts with "data:")
|
|
943
|
-
if (responseText.startsWith('data:')) {
|
|
944
|
-
// Parse SSE response
|
|
945
|
-
return this.parseStreamingResponse(responseText);
|
|
946
|
-
}
|
|
947
|
-
// Parse regular JSON response
|
|
948
|
-
const data = JSON.parse(responseText);
|
|
949
|
-
return data.result || data.choices?.[0]?.message?.content || '';
|
|
950
|
-
}
|
|
951
|
-
catch (error) {
|
|
952
|
-
throw new Error(`Graph execution failed: ${error.message || 'Unknown error'}`);
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
/**
|
|
956
|
-
* Parse streaming response in SSE format
|
|
957
|
-
*/
|
|
958
|
-
parseStreamingResponse(text) {
|
|
959
|
-
const lines = text.split('\n');
|
|
960
|
-
let content = '';
|
|
961
|
-
for (const line of lines) {
|
|
962
|
-
if (line.startsWith('data: ')) {
|
|
963
|
-
const dataStr = line.slice(6); // Remove 'data: ' prefix
|
|
964
|
-
if (dataStr === '[DONE]')
|
|
965
|
-
break;
|
|
966
|
-
try {
|
|
967
|
-
const data = JSON.parse(dataStr);
|
|
968
|
-
const delta = data.choices?.[0]?.delta?.content;
|
|
969
|
-
if (delta) {
|
|
970
|
-
content += delta;
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
catch (e) {
|
|
974
|
-
// Skip invalid JSON lines
|
|
975
|
-
}
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
return content;
|
|
979
|
-
}
|
|
980
|
-
/**
|
|
981
|
-
* Normalize input messages to the expected format
|
|
982
|
-
*/
|
|
983
|
-
normalizeMessages(input) {
|
|
984
|
-
if (typeof input === 'string') {
|
|
985
|
-
return [{ role: 'user', content: input }];
|
|
986
|
-
}
|
|
987
|
-
if (Array.isArray(input)) {
|
|
988
|
-
return input.map((msg) => (typeof msg === 'string' ? { role: 'user', content: msg } : msg));
|
|
989
|
-
}
|
|
990
|
-
return [input];
|
|
991
|
-
}
|
|
992
|
-
async saveToDatabase() {
|
|
993
|
-
try {
|
|
994
|
-
// Check if graph already exists
|
|
995
|
-
const getUrl = `${this.baseURL}/tenants/${this.tenantId}/crud/agent-graphs/${this.graphId}`;
|
|
996
|
-
try {
|
|
997
|
-
const getResponse = await fetch(getUrl, {
|
|
998
|
-
method: 'GET',
|
|
999
|
-
headers: {
|
|
1000
|
-
'Content-Type': 'application/json',
|
|
1001
|
-
},
|
|
1002
|
-
});
|
|
1003
|
-
if (getResponse.ok) {
|
|
1004
|
-
logger.info({ graphId: this.graphId }, 'Graph already exists in backend');
|
|
1005
|
-
return;
|
|
1006
|
-
}
|
|
1007
|
-
if (getResponse.status !== 404) {
|
|
1008
|
-
throw new Error(`HTTP ${getResponse.status}: ${getResponse.statusText}`);
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
catch (error) {
|
|
1012
|
-
if (!error.message.includes('404')) {
|
|
1013
|
-
throw error;
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
// Graph doesn't exist, create it
|
|
1017
|
-
logger.info({ graphId: this.graphId }, 'Creating graph in backend');
|
|
1018
|
-
const createUrl = `${this.baseURL}/tenants/${this.tenantId}/crud/agent-graphs`;
|
|
1019
|
-
const createResponse = await fetch(createUrl, {
|
|
1020
|
-
method: 'POST',
|
|
1021
|
-
headers: {
|
|
1022
|
-
'Content-Type': 'application/json',
|
|
1023
|
-
},
|
|
1024
|
-
body: JSON.stringify({
|
|
1025
|
-
id: this.graphId,
|
|
1026
|
-
name: this.graphName,
|
|
1027
|
-
defaultAgentId: this.defaultAgent?.getId() || '',
|
|
1028
|
-
contextConfigId: this.contextConfig?.getId(),
|
|
1029
|
-
models: this.models,
|
|
1030
|
-
}),
|
|
1031
|
-
});
|
|
1032
|
-
if (!createResponse.ok) {
|
|
1033
|
-
throw new Error(`HTTP ${createResponse.status}: ${createResponse.statusText}`);
|
|
1034
|
-
}
|
|
1035
|
-
const createData = (await createResponse.json());
|
|
1036
|
-
this.graphId = createData.data.id;
|
|
1037
|
-
logger.info({ graph: createData.data }, 'Graph created in backend');
|
|
1038
|
-
}
|
|
1039
|
-
catch (error) {
|
|
1040
|
-
throw new Error(`Failed to save graph to database: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
1041
|
-
}
|
|
1042
|
-
}
|
|
1043
|
-
async saveRelations() {
|
|
1044
|
-
if (this.defaultAgent) {
|
|
1045
|
-
try {
|
|
1046
|
-
const updateUrl = `${this.baseURL}/tenants/${this.tenantId}/crud/agent-graphs/${this.graphId}`;
|
|
1047
|
-
const updateResponse = await fetch(updateUrl, {
|
|
1048
|
-
method: 'PUT',
|
|
1049
|
-
headers: {
|
|
1050
|
-
'Content-Type': 'application/json',
|
|
1051
|
-
},
|
|
1052
|
-
body: JSON.stringify({
|
|
1053
|
-
id: this.graphId,
|
|
1054
|
-
defaultAgentId: this.defaultAgent.getId(),
|
|
1055
|
-
contextConfigId: this.contextConfig?.getId(),
|
|
1056
|
-
}),
|
|
1057
|
-
});
|
|
1058
|
-
if (!updateResponse.ok) {
|
|
1059
|
-
throw new Error(`HTTP ${updateResponse.status}: ${updateResponse.statusText}`);
|
|
1060
|
-
}
|
|
1061
|
-
logger.debug({
|
|
1062
|
-
graphId: this.graphId,
|
|
1063
|
-
defaultAgent: this.defaultAgent.getName(),
|
|
1064
|
-
}, 'Graph relationships configured');
|
|
1065
|
-
}
|
|
1066
|
-
catch (error) {
|
|
1067
|
-
logger.error({
|
|
1068
|
-
graphId: this.graphId,
|
|
1069
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
1070
|
-
}, 'Failed to update graph relationships');
|
|
1071
|
-
throw error;
|
|
1072
|
-
}
|
|
1073
|
-
}
|
|
1074
|
-
}
|
|
1075
|
-
async createAgentRelations() {
|
|
1076
|
-
// Create both transfer and delegation relations for all agents now that they have graphId
|
|
1077
|
-
const allRelationPromises = [];
|
|
1078
|
-
// Collect all relation creation promises from all agents
|
|
1079
|
-
for (const agent of this.agents) {
|
|
1080
|
-
if (this.isInternalAgent(agent)) {
|
|
1081
|
-
// Create internal transfer relations
|
|
1082
|
-
const transfers = agent.getTransfers();
|
|
1083
|
-
for (const transferAgent of transfers) {
|
|
1084
|
-
allRelationPromises.push(this.createInternalAgentRelation(agent, transferAgent, 'transfer'));
|
|
1085
|
-
}
|
|
1086
|
-
// Create internal delegation relations
|
|
1087
|
-
const delegates = agent.getDelegates();
|
|
1088
|
-
for (const delegate of delegates) {
|
|
1089
|
-
// Check if delegate is an ExternalAgent instance
|
|
1090
|
-
if (delegate instanceof ExternalAgent) {
|
|
1091
|
-
allRelationPromises.push(this.createExternalAgentRelation(agent, delegate, 'delegate'));
|
|
1092
|
-
}
|
|
1093
|
-
else {
|
|
1094
|
-
// Must be an internal agent (AgentInterface)
|
|
1095
|
-
allRelationPromises.push(this.createInternalAgentRelation(agent, delegate, 'delegate'));
|
|
1096
|
-
}
|
|
1097
|
-
}
|
|
1098
|
-
}
|
|
1099
|
-
}
|
|
1100
|
-
// Use Promise.allSettled for better error handling - allows all operations to complete
|
|
1101
|
-
const results = await Promise.allSettled(allRelationPromises);
|
|
1102
|
-
// Log and collect errors without failing the entire operation
|
|
1103
|
-
const errors = [];
|
|
1104
|
-
let successCount = 0;
|
|
1105
|
-
for (const result of results) {
|
|
1106
|
-
if (result.status === 'fulfilled') {
|
|
1107
|
-
successCount++;
|
|
1108
|
-
}
|
|
1109
|
-
else {
|
|
1110
|
-
errors.push(result.reason);
|
|
1111
|
-
logger.error({
|
|
1112
|
-
error: result.reason instanceof Error ? result.reason.message : 'Unknown error',
|
|
1113
|
-
graphId: this.graphId,
|
|
1114
|
-
}, 'Failed to create agent relation');
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
logger.info({
|
|
1118
|
-
graphId: this.graphId,
|
|
1119
|
-
totalRelations: allRelationPromises.length,
|
|
1120
|
-
successCount,
|
|
1121
|
-
errorCount: errors.length,
|
|
1122
|
-
}, 'Completed agent relation creation batch');
|
|
1123
|
-
// Only throw if ALL relations failed, allowing partial success
|
|
1124
|
-
if (errors.length > 0 && successCount === 0) {
|
|
1125
|
-
throw new Error(`All ${errors.length} agent relation creations failed`);
|
|
1126
|
-
}
|
|
1127
|
-
}
|
|
1128
|
-
async createInternalAgentRelation(sourceAgent, targetAgent, relationType) {
|
|
1129
|
-
try {
|
|
1130
|
-
const response = await fetch(`${this.baseURL}/tenants/${this.tenantId}/crud/agent-relations`, {
|
|
1131
|
-
method: 'POST',
|
|
1132
|
-
headers: {
|
|
1133
|
-
'Content-Type': 'application/json',
|
|
1134
|
-
},
|
|
1135
|
-
body: JSON.stringify({
|
|
1136
|
-
graphId: this.graphId,
|
|
1137
|
-
sourceAgentId: sourceAgent.getId(),
|
|
1138
|
-
targetAgentId: targetAgent.getId(),
|
|
1139
|
-
relationType,
|
|
1140
|
-
}),
|
|
1141
|
-
});
|
|
1142
|
-
if (!response.ok) {
|
|
1143
|
-
const errorText = await response.text().catch(() => 'Unknown error');
|
|
1144
|
-
// Check if this is a duplicate relation (which is acceptable)
|
|
1145
|
-
if (response.status === 422 && errorText.includes('already exists')) {
|
|
1146
|
-
logger.info({
|
|
1147
|
-
sourceAgentId: sourceAgent.getId(),
|
|
1148
|
-
targetAgentId: targetAgent.getId(),
|
|
1149
|
-
graphId: this.graphId,
|
|
1150
|
-
relationType,
|
|
1151
|
-
}, `${relationType} relation already exists, skipping creation`);
|
|
1152
|
-
return;
|
|
1153
|
-
}
|
|
1154
|
-
throw new Error(`Failed to create agent relation: ${response.status} - ${errorText}`);
|
|
1155
|
-
}
|
|
1156
|
-
logger.info({
|
|
1157
|
-
sourceAgentId: sourceAgent.getId(),
|
|
1158
|
-
targetAgentId: targetAgent.getId(),
|
|
1159
|
-
graphId: this.graphId,
|
|
1160
|
-
relationType,
|
|
1161
|
-
}, `${relationType} relation created successfully`);
|
|
1162
|
-
}
|
|
1163
|
-
catch (error) {
|
|
1164
|
-
logger.error({
|
|
1165
|
-
sourceAgentId: sourceAgent.getId(),
|
|
1166
|
-
targetAgentId: targetAgent.getId(),
|
|
1167
|
-
graphId: this.graphId,
|
|
1168
|
-
relationType,
|
|
1169
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
1170
|
-
}, `Failed to create ${relationType} relation`);
|
|
1171
|
-
throw error;
|
|
1172
|
-
}
|
|
1173
|
-
}
|
|
1174
|
-
// enableComponentMode removed – feature deprecated
|
|
1175
|
-
async createExternalAgentRelation(sourceAgent, externalAgent, relationType) {
|
|
1176
|
-
try {
|
|
1177
|
-
const response = await fetch(`${this.baseURL}/tenants/${this.tenantId}/crud/agent-relations`, {
|
|
1178
|
-
method: 'POST',
|
|
1179
|
-
headers: {
|
|
1180
|
-
'Content-Type': 'application/json',
|
|
1181
|
-
},
|
|
1182
|
-
body: JSON.stringify({
|
|
1183
|
-
graphId: this.graphId,
|
|
1184
|
-
sourceAgentId: sourceAgent.getId(),
|
|
1185
|
-
externalAgentId: externalAgent.getId(),
|
|
1186
|
-
relationType,
|
|
1187
|
-
}),
|
|
1188
|
-
});
|
|
1189
|
-
if (!response.ok) {
|
|
1190
|
-
const errorText = await response.text().catch(() => 'Unknown error');
|
|
1191
|
-
// Check if this is a duplicate relation (which is acceptable)
|
|
1192
|
-
if (response.status === 422 && errorText.includes('already exists')) {
|
|
1193
|
-
logger.info({
|
|
1194
|
-
sourceAgentId: sourceAgent.getId(),
|
|
1195
|
-
externalAgentId: externalAgent.getId(),
|
|
1196
|
-
graphId: this.graphId,
|
|
1197
|
-
relationType,
|
|
1198
|
-
}, `${relationType} relation already exists, skipping creation`);
|
|
1199
|
-
return;
|
|
1200
|
-
}
|
|
1201
|
-
throw new Error(`Failed to create external agent relation: ${response.status} - ${errorText}`);
|
|
1202
|
-
}
|
|
1203
|
-
logger.info({
|
|
1204
|
-
sourceAgentId: sourceAgent.getId(),
|
|
1205
|
-
externalAgentId: externalAgent.getId(),
|
|
1206
|
-
graphId: this.graphId,
|
|
1207
|
-
relationType,
|
|
1208
|
-
}, `${relationType} relation created successfully`);
|
|
1209
|
-
}
|
|
1210
|
-
catch (error) {
|
|
1211
|
-
logger.error({
|
|
1212
|
-
sourceAgentId: sourceAgent.getId(),
|
|
1213
|
-
externalAgentId: externalAgent.getId(),
|
|
1214
|
-
graphId: this.graphId,
|
|
1215
|
-
relationType,
|
|
1216
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
1217
|
-
}, `Failed to create ${relationType} relation`);
|
|
1218
|
-
throw error;
|
|
1219
|
-
}
|
|
1220
|
-
}
|
|
1221
|
-
/**
|
|
1222
|
-
* Create external agents in the database
|
|
1223
|
-
*/
|
|
1224
|
-
async createExternalAgents() {
|
|
1225
|
-
const externalAgents = this.agents.filter((agent) => this.isExternalAgent(agent));
|
|
1226
|
-
logger.info({
|
|
1227
|
-
graphId: this.graphId,
|
|
1228
|
-
externalAgentCount: externalAgents.length,
|
|
1229
|
-
}, 'Creating external agents in database');
|
|
1230
|
-
const initPromises = externalAgents.map(async (externalAgent) => {
|
|
1231
|
-
try {
|
|
1232
|
-
await externalAgent.init();
|
|
1233
|
-
logger.debug({
|
|
1234
|
-
externalAgentId: externalAgent.getId(),
|
|
1235
|
-
graphId: this.graphId,
|
|
1236
|
-
}, 'External agent created in database');
|
|
1237
|
-
}
|
|
1238
|
-
catch (error) {
|
|
1239
|
-
logger.error({
|
|
1240
|
-
externalAgentId: externalAgent.getId(),
|
|
1241
|
-
graphId: this.graphId,
|
|
1242
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
1243
|
-
}, 'Failed to create external agent in database');
|
|
1244
|
-
throw error;
|
|
1245
|
-
}
|
|
1246
|
-
});
|
|
1247
|
-
try {
|
|
1248
|
-
await Promise.all(initPromises);
|
|
1249
|
-
logger.info({
|
|
1250
|
-
graphId: this.graphId,
|
|
1251
|
-
externalAgentCount: externalAgents.length,
|
|
1252
|
-
}, 'All external agents created successfully');
|
|
1253
|
-
}
|
|
1254
|
-
catch (error) {
|
|
1255
|
-
logger.error({
|
|
1256
|
-
graphId: this.graphId,
|
|
1257
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
1258
|
-
}, 'Failed to create some external agents');
|
|
1259
|
-
throw error;
|
|
1260
|
-
}
|
|
1261
|
-
}
|
|
1262
|
-
}
|
|
1263
|
-
/**
|
|
1264
|
-
* Helper function to create graphs - OpenAI style
|
|
1265
|
-
*/
|
|
1266
|
-
export function agentGraph(config) {
|
|
1267
|
-
return new AgentGraph(config);
|
|
1268
|
-
}
|
|
1269
|
-
/**
|
|
1270
|
-
* Factory function to create graph from configuration file
|
|
1271
|
-
*/
|
|
1272
|
-
export async function generateGraph(configPath) {
|
|
1273
|
-
logger.info({ configPath }, 'Loading graph configuration');
|
|
1274
|
-
try {
|
|
1275
|
-
const config = await import(configPath);
|
|
1276
|
-
const graphConfig = config.default || config;
|
|
1277
|
-
const graph = agentGraph(graphConfig);
|
|
1278
|
-
await graph.init();
|
|
1279
|
-
logger.info({
|
|
1280
|
-
configPath,
|
|
1281
|
-
graphId: graph.getStats().graphId,
|
|
1282
|
-
agentCount: graph.getStats().agentCount,
|
|
1283
|
-
}, 'Graph generated successfully');
|
|
1284
|
-
return graph;
|
|
1285
|
-
}
|
|
1286
|
-
catch (error) {
|
|
1287
|
-
logger.error({
|
|
1288
|
-
configPath,
|
|
1289
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
1290
|
-
}, 'Failed to generate graph from configuration');
|
|
1291
|
-
throw error;
|
|
1292
|
-
}
|
|
1293
|
-
}
|
|
1294
|
-
//# sourceMappingURL=graph.js.map
|