@inkeep/agents-sdk 0.0.0-dev-20250910233133

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