@inkeep/agents-sdk 0.1.1 → 0.1.7
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 +3334 -0
- package/dist/index.d.cts +1131 -0
- package/dist/index.d.ts +1131 -11
- package/dist/index.js +3305 -10
- package/package.json +8 -7
- 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/index.js
CHANGED
|
@@ -1,10 +1,3305 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
import { getLogger, generateIdFromName, CredentialReferenceApiInsertSchema, MCPToolConfigSchema, createDatabaseClient, getProject } from '@inkeep/agents-core';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
7
|
+
var logger = getLogger("artifactComponent");
|
|
8
|
+
var ArtifactComponent = class {
|
|
9
|
+
constructor(config) {
|
|
10
|
+
__publicField(this, "config");
|
|
11
|
+
__publicField(this, "baseURL");
|
|
12
|
+
__publicField(this, "tenantId");
|
|
13
|
+
__publicField(this, "projectId");
|
|
14
|
+
__publicField(this, "initialized", false);
|
|
15
|
+
__publicField(this, "id");
|
|
16
|
+
this.id = generateIdFromName(config.name);
|
|
17
|
+
this.config = {
|
|
18
|
+
...config,
|
|
19
|
+
id: this.id,
|
|
20
|
+
tenantId: config.tenantId || "default",
|
|
21
|
+
projectId: config.projectId || "default"
|
|
22
|
+
};
|
|
23
|
+
this.baseURL = process.env.INKEEP_API_URL || "http://localhost:3002";
|
|
24
|
+
this.tenantId = this.config.tenantId;
|
|
25
|
+
this.projectId = this.config.projectId;
|
|
26
|
+
logger.info(
|
|
27
|
+
{
|
|
28
|
+
artifactComponentId: this.getId(),
|
|
29
|
+
artifactComponentName: config.name
|
|
30
|
+
},
|
|
31
|
+
"ArtifactComponent constructor initialized"
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
// Compute ID from name using same slug transformation as agents
|
|
35
|
+
getId() {
|
|
36
|
+
return this.id;
|
|
37
|
+
}
|
|
38
|
+
getName() {
|
|
39
|
+
return this.config.name;
|
|
40
|
+
}
|
|
41
|
+
getDescription() {
|
|
42
|
+
return this.config.description;
|
|
43
|
+
}
|
|
44
|
+
getSummaryProps() {
|
|
45
|
+
return this.config.summaryProps;
|
|
46
|
+
}
|
|
47
|
+
getFullProps() {
|
|
48
|
+
return this.config.fullProps;
|
|
49
|
+
}
|
|
50
|
+
// Public method to ensure artifact component exists in backend (with upsert behavior)
|
|
51
|
+
async init() {
|
|
52
|
+
if (this.initialized) return;
|
|
53
|
+
try {
|
|
54
|
+
await this.upsertArtifactComponent();
|
|
55
|
+
logger.info(
|
|
56
|
+
{
|
|
57
|
+
artifactComponentId: this.getId()
|
|
58
|
+
},
|
|
59
|
+
"ArtifactComponent initialized successfully"
|
|
60
|
+
);
|
|
61
|
+
this.initialized = true;
|
|
62
|
+
} catch (error) {
|
|
63
|
+
logger.error(
|
|
64
|
+
{
|
|
65
|
+
artifactComponentId: this.getId(),
|
|
66
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
67
|
+
},
|
|
68
|
+
"Failed to initialize artifact component"
|
|
69
|
+
);
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Private method to upsert artifact component (create or update)
|
|
74
|
+
async upsertArtifactComponent() {
|
|
75
|
+
const artifactComponentData = {
|
|
76
|
+
id: this.getId(),
|
|
77
|
+
name: this.config.name,
|
|
78
|
+
description: this.config.description,
|
|
79
|
+
summaryProps: this.config.summaryProps,
|
|
80
|
+
fullProps: this.config.fullProps
|
|
81
|
+
};
|
|
82
|
+
logger.info({ artifactComponentData }, "artifactComponentData for create/update");
|
|
83
|
+
const updateResponse = await fetch(
|
|
84
|
+
`${this.baseURL}/tenants/${this.tenantId}/crud/artifact-components/${this.getId()}`,
|
|
85
|
+
{
|
|
86
|
+
method: "PUT",
|
|
87
|
+
headers: {
|
|
88
|
+
"Content-Type": "application/json"
|
|
89
|
+
},
|
|
90
|
+
body: JSON.stringify(artifactComponentData)
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
logger.info(
|
|
94
|
+
{
|
|
95
|
+
status: updateResponse.status,
|
|
96
|
+
artifactComponentId: this.getId()
|
|
97
|
+
},
|
|
98
|
+
"artifact component updateResponse"
|
|
99
|
+
);
|
|
100
|
+
if (updateResponse.ok) {
|
|
101
|
+
logger.info(
|
|
102
|
+
{
|
|
103
|
+
artifactComponentId: this.getId()
|
|
104
|
+
},
|
|
105
|
+
"ArtifactComponent updated successfully"
|
|
106
|
+
);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (updateResponse.status === 404) {
|
|
110
|
+
logger.info(
|
|
111
|
+
{
|
|
112
|
+
artifactComponentId: this.getId()
|
|
113
|
+
},
|
|
114
|
+
"ArtifactComponent not found, creating new artifact component"
|
|
115
|
+
);
|
|
116
|
+
const createResponse = await fetch(
|
|
117
|
+
`${this.baseURL}/tenants/${this.tenantId}/crud/artifact-components`,
|
|
118
|
+
{
|
|
119
|
+
method: "POST",
|
|
120
|
+
headers: {
|
|
121
|
+
"Content-Type": "application/json"
|
|
122
|
+
},
|
|
123
|
+
body: JSON.stringify(artifactComponentData)
|
|
124
|
+
}
|
|
125
|
+
);
|
|
126
|
+
if (!createResponse.ok) {
|
|
127
|
+
const errorText2 = await createResponse.text().catch(() => "Unknown error");
|
|
128
|
+
throw new Error(
|
|
129
|
+
`Failed to create artifact component: ${createResponse.status} ${createResponse.statusText} - ${errorText2}`
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
logger.info(
|
|
133
|
+
{
|
|
134
|
+
artifactComponentId: this.getId()
|
|
135
|
+
},
|
|
136
|
+
"ArtifactComponent created successfully"
|
|
137
|
+
);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const errorText = await updateResponse.text().catch(() => "Unknown error");
|
|
141
|
+
throw new Error(
|
|
142
|
+
`Failed to update artifact component: ${updateResponse.status} ${updateResponse.statusText} - ${errorText}`
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
var logger2 = getLogger("dataComponent");
|
|
147
|
+
var DataComponent = class {
|
|
148
|
+
constructor(config) {
|
|
149
|
+
__publicField(this, "config");
|
|
150
|
+
__publicField(this, "baseURL");
|
|
151
|
+
__publicField(this, "tenantId");
|
|
152
|
+
__publicField(this, "projectId");
|
|
153
|
+
__publicField(this, "initialized", false);
|
|
154
|
+
__publicField(this, "id");
|
|
155
|
+
this.id = generateIdFromName(config.name);
|
|
156
|
+
this.config = {
|
|
157
|
+
...config,
|
|
158
|
+
id: this.id,
|
|
159
|
+
tenantId: config.tenantId || "default",
|
|
160
|
+
projectId: config.projectId || "default"
|
|
161
|
+
};
|
|
162
|
+
this.baseURL = process.env.INKEEP_API_URL || "http://localhost:3002";
|
|
163
|
+
this.tenantId = this.config.tenantId;
|
|
164
|
+
this.projectId = this.config.projectId;
|
|
165
|
+
logger2.info(
|
|
166
|
+
{
|
|
167
|
+
dataComponentId: this.getId(),
|
|
168
|
+
dataComponentName: config.name
|
|
169
|
+
},
|
|
170
|
+
"DataComponent constructor initialized"
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
// Compute ID from name using same slug transformation as agents
|
|
174
|
+
getId() {
|
|
175
|
+
return this.id;
|
|
176
|
+
}
|
|
177
|
+
getName() {
|
|
178
|
+
return this.config.name;
|
|
179
|
+
}
|
|
180
|
+
getDescription() {
|
|
181
|
+
return this.config.description;
|
|
182
|
+
}
|
|
183
|
+
getProps() {
|
|
184
|
+
return this.config.props;
|
|
185
|
+
}
|
|
186
|
+
// Public method to ensure data component exists in backend (with upsert behavior)
|
|
187
|
+
async init() {
|
|
188
|
+
if (this.initialized) return;
|
|
189
|
+
try {
|
|
190
|
+
await this.upsertDataComponent();
|
|
191
|
+
logger2.info(
|
|
192
|
+
{
|
|
193
|
+
dataComponentId: this.getId()
|
|
194
|
+
},
|
|
195
|
+
"DataComponent initialized successfully"
|
|
196
|
+
);
|
|
197
|
+
this.initialized = true;
|
|
198
|
+
} catch (error) {
|
|
199
|
+
logger2.error(
|
|
200
|
+
{
|
|
201
|
+
dataComponentId: this.getId(),
|
|
202
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
203
|
+
},
|
|
204
|
+
"Failed to initialize data component"
|
|
205
|
+
);
|
|
206
|
+
throw error;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
// Private method to upsert data component (create or update)
|
|
210
|
+
async upsertDataComponent() {
|
|
211
|
+
const dataComponentData = {
|
|
212
|
+
id: this.getId(),
|
|
213
|
+
name: this.config.name,
|
|
214
|
+
description: this.config.description,
|
|
215
|
+
props: this.config.props
|
|
216
|
+
};
|
|
217
|
+
logger2.info({ dataComponentData }, "dataComponentData for create/update");
|
|
218
|
+
const updateResponse = await fetch(
|
|
219
|
+
`${this.baseURL}/tenants/${this.tenantId}/crud/data-components/${this.getId()}`,
|
|
220
|
+
{
|
|
221
|
+
method: "PUT",
|
|
222
|
+
headers: {
|
|
223
|
+
"Content-Type": "application/json"
|
|
224
|
+
},
|
|
225
|
+
body: JSON.stringify(dataComponentData)
|
|
226
|
+
}
|
|
227
|
+
);
|
|
228
|
+
logger2.info(
|
|
229
|
+
{
|
|
230
|
+
status: updateResponse.status,
|
|
231
|
+
dataComponentId: this.getId()
|
|
232
|
+
},
|
|
233
|
+
"data component updateResponse"
|
|
234
|
+
);
|
|
235
|
+
if (updateResponse.ok) {
|
|
236
|
+
logger2.info(
|
|
237
|
+
{
|
|
238
|
+
dataComponentId: this.getId()
|
|
239
|
+
},
|
|
240
|
+
"DataComponent updated successfully"
|
|
241
|
+
);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (updateResponse.status === 404) {
|
|
245
|
+
logger2.info(
|
|
246
|
+
{
|
|
247
|
+
dataComponentId: this.getId()
|
|
248
|
+
},
|
|
249
|
+
"DataComponent not found, creating new data component"
|
|
250
|
+
);
|
|
251
|
+
const createResponse = await fetch(
|
|
252
|
+
`${this.baseURL}/tenants/${this.tenantId}/crud/data-components`,
|
|
253
|
+
{
|
|
254
|
+
method: "POST",
|
|
255
|
+
headers: {
|
|
256
|
+
"Content-Type": "application/json"
|
|
257
|
+
},
|
|
258
|
+
body: JSON.stringify(dataComponentData)
|
|
259
|
+
}
|
|
260
|
+
);
|
|
261
|
+
if (!createResponse.ok) {
|
|
262
|
+
const errorText2 = await createResponse.text().catch(() => "Unknown error");
|
|
263
|
+
throw new Error(
|
|
264
|
+
`Failed to create data component: ${createResponse.status} ${createResponse.statusText} - ${errorText2}`
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
logger2.info(
|
|
268
|
+
{
|
|
269
|
+
dataComponentId: this.getId()
|
|
270
|
+
},
|
|
271
|
+
"DataComponent created successfully"
|
|
272
|
+
);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
const errorText = await updateResponse.text().catch(() => "Unknown error");
|
|
276
|
+
throw new Error(
|
|
277
|
+
`Failed to update data component: ${updateResponse.status} ${updateResponse.statusText} - ${errorText}`
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
var logger3 = getLogger("tool");
|
|
282
|
+
var Tool = class {
|
|
283
|
+
constructor(config) {
|
|
284
|
+
__publicField(this, "config");
|
|
285
|
+
__publicField(this, "baseURL");
|
|
286
|
+
__publicField(this, "tenantId");
|
|
287
|
+
__publicField(this, "initialized", false);
|
|
288
|
+
__publicField(this, "projectId");
|
|
289
|
+
this.config = config;
|
|
290
|
+
this.baseURL = process.env.INKEEP_API_URL || "http://localhost:3002";
|
|
291
|
+
this.tenantId = config.tenantId || "default";
|
|
292
|
+
this.projectId = config.projectId || "default";
|
|
293
|
+
logger3.info(
|
|
294
|
+
{
|
|
295
|
+
Id: this.getId(),
|
|
296
|
+
Name: config.name
|
|
297
|
+
},
|
|
298
|
+
"Tool constructor initialized"
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
// Compute ID from name using same slug transformation as agents
|
|
302
|
+
getId() {
|
|
303
|
+
return this.config.id;
|
|
304
|
+
}
|
|
305
|
+
getName() {
|
|
306
|
+
return this.config.name;
|
|
307
|
+
}
|
|
308
|
+
getDescription() {
|
|
309
|
+
return this.config.description || "";
|
|
310
|
+
}
|
|
311
|
+
getServerUrl() {
|
|
312
|
+
return this.config.serverUrl;
|
|
313
|
+
}
|
|
314
|
+
getActiveTools() {
|
|
315
|
+
return this.config.activeTools;
|
|
316
|
+
}
|
|
317
|
+
getCredentialReferenceId() {
|
|
318
|
+
return this.config.credential?.id;
|
|
319
|
+
}
|
|
320
|
+
// Public method to ensure tool exists in backend (with upsert behavior)
|
|
321
|
+
async init(options) {
|
|
322
|
+
if (this.initialized) return;
|
|
323
|
+
try {
|
|
324
|
+
if (!options?.skipDatabaseRegistration) {
|
|
325
|
+
await this.upsertTool();
|
|
326
|
+
}
|
|
327
|
+
logger3.info(
|
|
328
|
+
{
|
|
329
|
+
toolId: this.getId()
|
|
330
|
+
},
|
|
331
|
+
"Tool initialized successfully"
|
|
332
|
+
);
|
|
333
|
+
this.initialized = true;
|
|
334
|
+
} catch (error) {
|
|
335
|
+
logger3.error(
|
|
336
|
+
{
|
|
337
|
+
toolId: this.getId(),
|
|
338
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
339
|
+
},
|
|
340
|
+
"Failed to initialize tool"
|
|
341
|
+
);
|
|
342
|
+
throw error;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
// Private method to upsert tool (create or update)
|
|
346
|
+
async upsertTool() {
|
|
347
|
+
const toolDataForUpdate = {
|
|
348
|
+
id: this.getId(),
|
|
349
|
+
name: this.config.name,
|
|
350
|
+
credentialReferenceId: this.config.credential?.id ?? null,
|
|
351
|
+
headers: this.config.headers ?? null,
|
|
352
|
+
imageUrl: this.config.imageUrl,
|
|
353
|
+
config: {
|
|
354
|
+
type: "mcp",
|
|
355
|
+
mcp: {
|
|
356
|
+
server: {
|
|
357
|
+
url: this.config.serverUrl
|
|
358
|
+
},
|
|
359
|
+
transport: this.config.transport,
|
|
360
|
+
activeTools: this.config.activeTools
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
const toolDataForCreate = {
|
|
365
|
+
...toolDataForUpdate
|
|
366
|
+
};
|
|
367
|
+
logger3.info({ toolDataForCreate }, "toolDataForCreate");
|
|
368
|
+
const updateResponse = await fetch(
|
|
369
|
+
`${this.baseURL}/tenants/${this.tenantId}/crud/projects/${this.projectId}/tools/${this.getId()}`,
|
|
370
|
+
{
|
|
371
|
+
method: "PUT",
|
|
372
|
+
headers: {
|
|
373
|
+
"Content-Type": "application/json"
|
|
374
|
+
},
|
|
375
|
+
body: JSON.stringify(toolDataForUpdate)
|
|
376
|
+
}
|
|
377
|
+
);
|
|
378
|
+
logger3.info({ updateResponse }, "tool updateResponse");
|
|
379
|
+
if (updateResponse.ok) {
|
|
380
|
+
logger3.info(
|
|
381
|
+
{
|
|
382
|
+
toolId: this.getId()
|
|
383
|
+
},
|
|
384
|
+
"Tool updated successfully"
|
|
385
|
+
);
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
if (updateResponse.status === 404) {
|
|
389
|
+
logger3.info(
|
|
390
|
+
{
|
|
391
|
+
toolId: this.getId()
|
|
392
|
+
},
|
|
393
|
+
"Tool not found, creating new tool"
|
|
394
|
+
);
|
|
395
|
+
const createResponse = await fetch(
|
|
396
|
+
`${this.baseURL}/tenants/${this.tenantId}/crud/projects/${this.projectId}/tools`,
|
|
397
|
+
{
|
|
398
|
+
method: "POST",
|
|
399
|
+
headers: {
|
|
400
|
+
"Content-Type": "application/json"
|
|
401
|
+
},
|
|
402
|
+
body: JSON.stringify(toolDataForCreate)
|
|
403
|
+
}
|
|
404
|
+
);
|
|
405
|
+
if (!createResponse.ok) {
|
|
406
|
+
throw new Error(`Failed to create tool: ${createResponse.status}`);
|
|
407
|
+
}
|
|
408
|
+
logger3.info(
|
|
409
|
+
{
|
|
410
|
+
toolId: this.getId()
|
|
411
|
+
},
|
|
412
|
+
"Tool created successfully"
|
|
413
|
+
);
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
throw new Error(`Failed to update tool: ${updateResponse.status}`);
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
// src/agent.ts
|
|
421
|
+
var logger4 = getLogger("agent");
|
|
422
|
+
function resolveGetter(value) {
|
|
423
|
+
if (typeof value === "function") {
|
|
424
|
+
return value();
|
|
425
|
+
}
|
|
426
|
+
return value;
|
|
427
|
+
}
|
|
428
|
+
var Agent = class {
|
|
429
|
+
constructor(config) {
|
|
430
|
+
__publicField(this, "config");
|
|
431
|
+
__publicField(this, "type", "internal");
|
|
432
|
+
__publicField(this, "baseURL");
|
|
433
|
+
__publicField(this, "tenantId");
|
|
434
|
+
__publicField(this, "projectId");
|
|
435
|
+
__publicField(this, "initialized", false);
|
|
436
|
+
this.config = { ...config, type: "internal" };
|
|
437
|
+
this.baseURL = process.env.INKEEP_API_URL || "http://localhost:3002";
|
|
438
|
+
this.tenantId = config.tenantId || "default";
|
|
439
|
+
this.projectId = config.projectId || "default";
|
|
440
|
+
logger4.info(
|
|
441
|
+
{
|
|
442
|
+
tenantId: this.tenantId,
|
|
443
|
+
agentId: this.config.id,
|
|
444
|
+
agentName: config.name
|
|
445
|
+
},
|
|
446
|
+
"Agent constructor initialized"
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
// Return the configured ID
|
|
450
|
+
getId() {
|
|
451
|
+
return this.config.id;
|
|
452
|
+
}
|
|
453
|
+
// Agent introspection methods
|
|
454
|
+
getName() {
|
|
455
|
+
return this.config.name;
|
|
456
|
+
}
|
|
457
|
+
getInstructions() {
|
|
458
|
+
return this.config.prompt;
|
|
459
|
+
}
|
|
460
|
+
// adjust
|
|
461
|
+
getTools() {
|
|
462
|
+
const tools = resolveGetter(this.config.canUse);
|
|
463
|
+
if (!tools) {
|
|
464
|
+
return {};
|
|
465
|
+
}
|
|
466
|
+
if (!Array.isArray(tools)) {
|
|
467
|
+
throw new Error("tools getter must return an array");
|
|
468
|
+
}
|
|
469
|
+
const toolRecord = {};
|
|
470
|
+
for (const tool of tools) {
|
|
471
|
+
if (tool && typeof tool === "object") {
|
|
472
|
+
let id;
|
|
473
|
+
let toolInstance;
|
|
474
|
+
if ("server" in tool && "selectedTools" in tool) {
|
|
475
|
+
const agentMcpConfig = tool;
|
|
476
|
+
id = agentMcpConfig.server.getId();
|
|
477
|
+
toolInstance = agentMcpConfig.server;
|
|
478
|
+
toolInstance.selectedTools = agentMcpConfig.selectedTools;
|
|
479
|
+
} else {
|
|
480
|
+
id = tool.id || tool.getId?.() || tool.name;
|
|
481
|
+
toolInstance = tool;
|
|
482
|
+
}
|
|
483
|
+
if (id) {
|
|
484
|
+
toolRecord[id] = toolInstance;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return toolRecord;
|
|
489
|
+
}
|
|
490
|
+
getModels() {
|
|
491
|
+
return this.config.models;
|
|
492
|
+
}
|
|
493
|
+
setModels(models) {
|
|
494
|
+
this.config.models = models;
|
|
495
|
+
}
|
|
496
|
+
getTransfers() {
|
|
497
|
+
return typeof this.config.canTransferTo === "function" ? this.config.canTransferTo() : [];
|
|
498
|
+
}
|
|
499
|
+
getDelegates() {
|
|
500
|
+
return typeof this.config.canDelegateTo === "function" ? this.config.canDelegateTo() : [];
|
|
501
|
+
}
|
|
502
|
+
getDataComponents() {
|
|
503
|
+
return resolveGetter(this.config.dataComponents) || [];
|
|
504
|
+
}
|
|
505
|
+
getArtifactComponents() {
|
|
506
|
+
return resolveGetter(this.config.artifactComponents) || [];
|
|
507
|
+
}
|
|
508
|
+
// adjust
|
|
509
|
+
addTool(_name, tool) {
|
|
510
|
+
const existingTools = this.config.canUse ? this.config.canUse() : [];
|
|
511
|
+
this.config.canUse = () => [...existingTools, tool];
|
|
512
|
+
}
|
|
513
|
+
addTransfer(...agents) {
|
|
514
|
+
if (typeof this.config.canTransferTo === "function") {
|
|
515
|
+
const existingTransfers = this.config.canTransferTo;
|
|
516
|
+
this.config.canTransferTo = () => [...existingTransfers(), ...agents];
|
|
517
|
+
} else {
|
|
518
|
+
this.config.canTransferTo = () => agents;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
addDelegate(...agents) {
|
|
522
|
+
if (typeof this.config.canDelegateTo === "function") {
|
|
523
|
+
const existingDelegates = this.config.canDelegateTo;
|
|
524
|
+
this.config.canDelegateTo = () => [...existingDelegates(), ...agents];
|
|
525
|
+
} else {
|
|
526
|
+
this.config.canDelegateTo = () => agents;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
// Public method to ensure agent exists in backend (with upsert behavior)
|
|
530
|
+
async init() {
|
|
531
|
+
if (this.initialized) return;
|
|
532
|
+
try {
|
|
533
|
+
await this.upsertAgent();
|
|
534
|
+
await this.loadDataComponents();
|
|
535
|
+
await this.loadArtifactComponents();
|
|
536
|
+
await this.saveToolsAndRelations();
|
|
537
|
+
await this.saveDataComponents();
|
|
538
|
+
await this.saveArtifactComponents();
|
|
539
|
+
logger4.info(
|
|
540
|
+
{
|
|
541
|
+
agentId: this.getId()
|
|
542
|
+
},
|
|
543
|
+
"Agent initialized successfully"
|
|
544
|
+
);
|
|
545
|
+
this.initialized = true;
|
|
546
|
+
} catch (error) {
|
|
547
|
+
logger4.error(
|
|
548
|
+
{
|
|
549
|
+
agentId: this.getId(),
|
|
550
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
551
|
+
},
|
|
552
|
+
"Failed to initialize agent"
|
|
553
|
+
);
|
|
554
|
+
throw error;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
// Private method to upsert agent (create or update)
|
|
558
|
+
async upsertAgent() {
|
|
559
|
+
const agentData = {
|
|
560
|
+
id: this.getId(),
|
|
561
|
+
name: this.config.name,
|
|
562
|
+
description: this.config.description || "",
|
|
563
|
+
prompt: this.config.prompt,
|
|
564
|
+
conversationHistoryConfig: this.config.conversationHistoryConfig,
|
|
565
|
+
models: this.config.models,
|
|
566
|
+
stopWhen: this.config.stopWhen
|
|
567
|
+
};
|
|
568
|
+
const updateResponse = await fetch(
|
|
569
|
+
`${this.baseURL}/tenants/${this.tenantId}/crud/agents/${this.getId()}`,
|
|
570
|
+
{
|
|
571
|
+
method: "PUT",
|
|
572
|
+
headers: {
|
|
573
|
+
"Content-Type": "application/json"
|
|
574
|
+
},
|
|
575
|
+
body: JSON.stringify(agentData)
|
|
576
|
+
}
|
|
577
|
+
);
|
|
578
|
+
if (updateResponse.ok) {
|
|
579
|
+
logger4.info(
|
|
580
|
+
{
|
|
581
|
+
agentId: this.getId()
|
|
582
|
+
},
|
|
583
|
+
"Agent updated successfully"
|
|
584
|
+
);
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
if (updateResponse.status === 404) {
|
|
588
|
+
logger4.info(
|
|
589
|
+
{
|
|
590
|
+
agentId: this.getId()
|
|
591
|
+
},
|
|
592
|
+
"Agent not found, creating new agent"
|
|
593
|
+
);
|
|
594
|
+
const createResponse = await fetch(`${this.baseURL}/tenants/${this.tenantId}/crud/agents`, {
|
|
595
|
+
method: "POST",
|
|
596
|
+
headers: {
|
|
597
|
+
"Content-Type": "application/json"
|
|
598
|
+
},
|
|
599
|
+
body: JSON.stringify(agentData)
|
|
600
|
+
});
|
|
601
|
+
if (!createResponse.ok) {
|
|
602
|
+
const errorText2 = await createResponse.text().catch(() => "Unknown error");
|
|
603
|
+
throw new Error(
|
|
604
|
+
`Failed to create agent: ${createResponse.status} ${createResponse.statusText} - ${errorText2}`
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
logger4.info(
|
|
608
|
+
{
|
|
609
|
+
agentId: this.getId()
|
|
610
|
+
},
|
|
611
|
+
"Agent created successfully"
|
|
612
|
+
);
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
const errorText = await updateResponse.text().catch(() => "Unknown error");
|
|
616
|
+
throw new Error(
|
|
617
|
+
`Failed to update agent: ${updateResponse.status} ${updateResponse.statusText} - ${errorText}`
|
|
618
|
+
);
|
|
619
|
+
}
|
|
620
|
+
async saveToolsAndRelations() {
|
|
621
|
+
if (this.config.canUse) {
|
|
622
|
+
const tools = resolveGetter(this.config.canUse);
|
|
623
|
+
if (tools && Array.isArray(tools)) {
|
|
624
|
+
for (let i = 0; i < tools.length; i++) {
|
|
625
|
+
const toolConfig = tools[i];
|
|
626
|
+
let toolId;
|
|
627
|
+
if (toolConfig instanceof Tool) {
|
|
628
|
+
toolId = toolConfig.getId();
|
|
629
|
+
} else if (toolConfig && typeof toolConfig === "object" && "server" in toolConfig) {
|
|
630
|
+
toolId = toolConfig.server.getId();
|
|
631
|
+
} else {
|
|
632
|
+
toolId = `tool-${i}`;
|
|
633
|
+
}
|
|
634
|
+
try {
|
|
635
|
+
await this.createTool(toolId, toolConfig);
|
|
636
|
+
} catch (error) {
|
|
637
|
+
logger4.error(
|
|
638
|
+
{
|
|
639
|
+
toolId,
|
|
640
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
641
|
+
},
|
|
642
|
+
"Tool creation failed"
|
|
643
|
+
);
|
|
644
|
+
throw error;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
async saveDataComponents() {
|
|
651
|
+
logger4.info({ dataComponents: this.config.dataComponents }, "dataComponents and config");
|
|
652
|
+
const components = resolveGetter(this.config.dataComponents);
|
|
653
|
+
if (components) {
|
|
654
|
+
for (const dataComponent2 of components) {
|
|
655
|
+
await this.createDataComponent(dataComponent2);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
async saveArtifactComponents() {
|
|
660
|
+
logger4.info(
|
|
661
|
+
{ artifactComponents: this.config.artifactComponents },
|
|
662
|
+
"artifactComponents and config"
|
|
663
|
+
);
|
|
664
|
+
const components = resolveGetter(this.config.artifactComponents);
|
|
665
|
+
if (components) {
|
|
666
|
+
for (const artifactComponent2 of components) {
|
|
667
|
+
await this.createArtifactComponent(artifactComponent2);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
async loadDataComponents() {
|
|
672
|
+
try {
|
|
673
|
+
const existingComponents = [];
|
|
674
|
+
const dbDataComponents = existingComponents.map((component) => ({
|
|
675
|
+
id: component.id,
|
|
676
|
+
tenantId: component.tenantId || this.tenantId,
|
|
677
|
+
projectId: component.projectId || this.projectId,
|
|
678
|
+
name: component.name,
|
|
679
|
+
description: component.description,
|
|
680
|
+
props: component.props,
|
|
681
|
+
createdAt: component.createdAt,
|
|
682
|
+
updatedAt: component.updatedAt
|
|
683
|
+
}));
|
|
684
|
+
const configComponents = resolveGetter(this.config.dataComponents) || [];
|
|
685
|
+
const allComponents = [...dbDataComponents, ...configComponents];
|
|
686
|
+
const uniqueComponents = allComponents.reduce((acc, component) => {
|
|
687
|
+
const existingIndex = acc.findIndex((c) => c.id === component.id);
|
|
688
|
+
if (existingIndex >= 0) {
|
|
689
|
+
acc[existingIndex] = component;
|
|
690
|
+
} else {
|
|
691
|
+
acc.push(component);
|
|
692
|
+
}
|
|
693
|
+
return acc;
|
|
694
|
+
}, []);
|
|
695
|
+
this.config.dataComponents = uniqueComponents;
|
|
696
|
+
logger4.info(
|
|
697
|
+
{
|
|
698
|
+
agentId: this.getId(),
|
|
699
|
+
dbComponentCount: dbDataComponents.length,
|
|
700
|
+
configComponentCount: configComponents.length,
|
|
701
|
+
totalComponentCount: uniqueComponents.length
|
|
702
|
+
},
|
|
703
|
+
"Loaded and merged data components"
|
|
704
|
+
);
|
|
705
|
+
} catch (error) {
|
|
706
|
+
logger4.error(
|
|
707
|
+
{
|
|
708
|
+
agentId: this.getId(),
|
|
709
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
710
|
+
},
|
|
711
|
+
"Failed to load data components from database"
|
|
712
|
+
);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
async loadArtifactComponents() {
|
|
716
|
+
try {
|
|
717
|
+
const existingComponents = [];
|
|
718
|
+
const dbArtifactComponents = existingComponents.map((component) => ({
|
|
719
|
+
id: component.id,
|
|
720
|
+
tenantId: component.tenantId || this.tenantId,
|
|
721
|
+
projectId: component.projectId || this.projectId,
|
|
722
|
+
name: component.name,
|
|
723
|
+
description: component.description,
|
|
724
|
+
summaryProps: component.summaryProps,
|
|
725
|
+
fullProps: component.fullProps,
|
|
726
|
+
createdAt: component.createdAt,
|
|
727
|
+
updatedAt: component.updatedAt
|
|
728
|
+
}));
|
|
729
|
+
const configComponents = resolveGetter(this.config.artifactComponents) || [];
|
|
730
|
+
const allComponents = [...dbArtifactComponents, ...configComponents];
|
|
731
|
+
const uniqueComponents = allComponents.reduce((acc, component) => {
|
|
732
|
+
const existingIndex = acc.findIndex((c) => c.id === component.id);
|
|
733
|
+
if (existingIndex >= 0) {
|
|
734
|
+
acc[existingIndex] = component;
|
|
735
|
+
} else {
|
|
736
|
+
acc.push(component);
|
|
737
|
+
}
|
|
738
|
+
return acc;
|
|
739
|
+
}, []);
|
|
740
|
+
this.config.artifactComponents = uniqueComponents;
|
|
741
|
+
logger4.info(
|
|
742
|
+
{
|
|
743
|
+
agentId: this.getId(),
|
|
744
|
+
dbComponentCount: dbArtifactComponents.length,
|
|
745
|
+
configComponentCount: configComponents.length,
|
|
746
|
+
totalComponentCount: uniqueComponents.length
|
|
747
|
+
},
|
|
748
|
+
"Loaded and merged artifact components"
|
|
749
|
+
);
|
|
750
|
+
} catch (error) {
|
|
751
|
+
logger4.error(
|
|
752
|
+
{
|
|
753
|
+
agentId: this.getId(),
|
|
754
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
755
|
+
},
|
|
756
|
+
"Failed to load artifact components from database"
|
|
757
|
+
);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
async createTool(toolId, toolConfig) {
|
|
761
|
+
try {
|
|
762
|
+
if (toolConfig.type === "function") {
|
|
763
|
+
logger4.info(
|
|
764
|
+
{
|
|
765
|
+
agentId: this.getId(),
|
|
766
|
+
toolId
|
|
767
|
+
},
|
|
768
|
+
"Skipping function tool creation - will be handled at runtime"
|
|
769
|
+
);
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
let tool;
|
|
773
|
+
let selectedTools;
|
|
774
|
+
if (toolConfig && typeof toolConfig === "object" && "server" in toolConfig && "selectedTools" in toolConfig) {
|
|
775
|
+
const mcpConfig = toolConfig;
|
|
776
|
+
tool = mcpConfig.server;
|
|
777
|
+
selectedTools = mcpConfig.selectedTools;
|
|
778
|
+
await tool.init();
|
|
779
|
+
} else if (toolConfig instanceof Tool) {
|
|
780
|
+
tool = toolConfig;
|
|
781
|
+
await tool.init();
|
|
782
|
+
} else {
|
|
783
|
+
tool = new Tool({
|
|
784
|
+
id: toolId,
|
|
785
|
+
tenantId: this.tenantId,
|
|
786
|
+
name: toolConfig.name || toolId,
|
|
787
|
+
description: toolConfig.description || `MCP tool: ${toolId}`,
|
|
788
|
+
serverUrl: toolConfig.config?.serverUrl || toolConfig.serverUrl || "http://localhost:3000",
|
|
789
|
+
activeTools: toolConfig.config?.mcp?.activeTools,
|
|
790
|
+
credential: toolConfig.credential
|
|
791
|
+
});
|
|
792
|
+
await tool.init();
|
|
793
|
+
}
|
|
794
|
+
await this.createAgentToolRelation(tool.getId(), selectedTools);
|
|
795
|
+
logger4.info(
|
|
796
|
+
{
|
|
797
|
+
agentId: this.getId(),
|
|
798
|
+
toolId: tool.getId()
|
|
799
|
+
},
|
|
800
|
+
"Tool created and linked to agent"
|
|
801
|
+
);
|
|
802
|
+
} catch (error) {
|
|
803
|
+
logger4.error(
|
|
804
|
+
{
|
|
805
|
+
agentId: this.getId(),
|
|
806
|
+
toolId,
|
|
807
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
808
|
+
},
|
|
809
|
+
"Failed to create tool"
|
|
810
|
+
);
|
|
811
|
+
throw error;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
async createDataComponent(dataComponent2) {
|
|
815
|
+
try {
|
|
816
|
+
const dc = new DataComponent({
|
|
817
|
+
tenantId: this.tenantId,
|
|
818
|
+
projectId: this.projectId,
|
|
819
|
+
name: dataComponent2.name,
|
|
820
|
+
description: dataComponent2.description,
|
|
821
|
+
props: dataComponent2.props
|
|
822
|
+
});
|
|
823
|
+
await dc.init();
|
|
824
|
+
await this.createAgentDataComponentRelation(dc.getId());
|
|
825
|
+
logger4.info(
|
|
826
|
+
{
|
|
827
|
+
agentId: this.getId(),
|
|
828
|
+
dataComponentId: dc.getId()
|
|
829
|
+
},
|
|
830
|
+
"DataComponent created and linked to agent"
|
|
831
|
+
);
|
|
832
|
+
} catch (error) {
|
|
833
|
+
logger4.error(
|
|
834
|
+
{
|
|
835
|
+
agentId: this.getId(),
|
|
836
|
+
dataComponentName: dataComponent2.name,
|
|
837
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
838
|
+
},
|
|
839
|
+
"Failed to create data component"
|
|
840
|
+
);
|
|
841
|
+
throw error;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
async createArtifactComponent(artifactComponent2) {
|
|
845
|
+
try {
|
|
846
|
+
const ac = new ArtifactComponent({
|
|
847
|
+
tenantId: this.tenantId,
|
|
848
|
+
projectId: this.projectId,
|
|
849
|
+
name: artifactComponent2.name,
|
|
850
|
+
description: artifactComponent2.description,
|
|
851
|
+
summaryProps: artifactComponent2.summaryProps,
|
|
852
|
+
fullProps: artifactComponent2.fullProps
|
|
853
|
+
});
|
|
854
|
+
await ac.init();
|
|
855
|
+
await this.createAgentArtifactComponentRelation(ac.getId());
|
|
856
|
+
logger4.info(
|
|
857
|
+
{
|
|
858
|
+
agentId: this.getId(),
|
|
859
|
+
artifactComponentId: ac.getId()
|
|
860
|
+
},
|
|
861
|
+
"ArtifactComponent created and linked to agent"
|
|
862
|
+
);
|
|
863
|
+
} catch (error) {
|
|
864
|
+
logger4.error(
|
|
865
|
+
{
|
|
866
|
+
agentId: this.getId(),
|
|
867
|
+
artifactComponentName: artifactComponent2.name,
|
|
868
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
869
|
+
},
|
|
870
|
+
"Failed to create artifact component"
|
|
871
|
+
);
|
|
872
|
+
throw error;
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
async createAgentDataComponentRelation(dataComponentId) {
|
|
876
|
+
const relationResponse = await fetch(
|
|
877
|
+
`${this.baseURL}/tenants/${this.tenantId}/crud/agent-data-components`,
|
|
878
|
+
{
|
|
879
|
+
method: "POST",
|
|
880
|
+
headers: {
|
|
881
|
+
"Content-Type": "application/json"
|
|
882
|
+
},
|
|
883
|
+
body: JSON.stringify({
|
|
884
|
+
id: `${this.getId()}-dc-${dataComponentId}`,
|
|
885
|
+
tenantId: this.tenantId,
|
|
886
|
+
agentId: this.getId(),
|
|
887
|
+
dataComponentId
|
|
888
|
+
})
|
|
889
|
+
}
|
|
890
|
+
);
|
|
891
|
+
if (!relationResponse.ok) {
|
|
892
|
+
throw new Error(
|
|
893
|
+
`Failed to create agent-dataComponent relation: ${relationResponse.status} ${relationResponse.statusText}`
|
|
894
|
+
);
|
|
895
|
+
}
|
|
896
|
+
logger4.info(
|
|
897
|
+
{
|
|
898
|
+
agentId: this.getId(),
|
|
899
|
+
dataComponentId
|
|
900
|
+
},
|
|
901
|
+
"Created agent-dataComponent relation"
|
|
902
|
+
);
|
|
903
|
+
}
|
|
904
|
+
async createAgentArtifactComponentRelation(artifactComponentId) {
|
|
905
|
+
const relationResponse = await fetch(
|
|
906
|
+
`${this.baseURL}/tenants/${this.tenantId}/crud/agent-artifact-components`,
|
|
907
|
+
{
|
|
908
|
+
method: "POST",
|
|
909
|
+
headers: {
|
|
910
|
+
"Content-Type": "application/json"
|
|
911
|
+
},
|
|
912
|
+
body: JSON.stringify({
|
|
913
|
+
id: crypto.randomUUID(),
|
|
914
|
+
tenantId: this.tenantId,
|
|
915
|
+
agentId: this.getId(),
|
|
916
|
+
artifactComponentId
|
|
917
|
+
})
|
|
918
|
+
}
|
|
919
|
+
);
|
|
920
|
+
if (!relationResponse.ok) {
|
|
921
|
+
throw new Error(
|
|
922
|
+
`Failed to create agent-artifactComponent relation: ${relationResponse.status} ${relationResponse.statusText}`
|
|
923
|
+
);
|
|
924
|
+
}
|
|
925
|
+
logger4.info(
|
|
926
|
+
{
|
|
927
|
+
agentId: this.getId(),
|
|
928
|
+
artifactComponentId
|
|
929
|
+
},
|
|
930
|
+
"Created agent-artifactComponent relation"
|
|
931
|
+
);
|
|
932
|
+
}
|
|
933
|
+
async createAgentToolRelation(toolId, selectedTools) {
|
|
934
|
+
const relationData = {
|
|
935
|
+
id: `${this.getId()}-tool-${toolId}`,
|
|
936
|
+
tenantId: this.tenantId,
|
|
937
|
+
projectId: this.projectId,
|
|
938
|
+
agentId: this.getId(),
|
|
939
|
+
toolId
|
|
940
|
+
};
|
|
941
|
+
if (selectedTools !== void 0) {
|
|
942
|
+
relationData.selectedTools = selectedTools;
|
|
943
|
+
}
|
|
944
|
+
const relationResponse = await fetch(
|
|
945
|
+
`${this.baseURL}/tenants/${this.tenantId}/crud/projects/${this.projectId}/agent-tool-relations`,
|
|
946
|
+
{
|
|
947
|
+
method: "POST",
|
|
948
|
+
headers: {
|
|
949
|
+
"Content-Type": "application/json"
|
|
950
|
+
},
|
|
951
|
+
body: JSON.stringify(relationData)
|
|
952
|
+
}
|
|
953
|
+
);
|
|
954
|
+
if (!relationResponse.ok) {
|
|
955
|
+
const errorBody = await relationResponse.text().catch(() => "Unknown error");
|
|
956
|
+
throw new Error(
|
|
957
|
+
`Failed to create agent-tool relation: ${relationResponse.status} - ${errorBody}`
|
|
958
|
+
);
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
};
|
|
962
|
+
var logger5 = getLogger("external-agent-builder");
|
|
963
|
+
var ExternalAgent = class {
|
|
964
|
+
constructor(config) {
|
|
965
|
+
__publicField(this, "config");
|
|
966
|
+
__publicField(this, "type", "external");
|
|
967
|
+
__publicField(this, "initialized", false);
|
|
968
|
+
__publicField(this, "tenantId");
|
|
969
|
+
__publicField(this, "baseURL");
|
|
970
|
+
this.config = { ...config, type: "external" };
|
|
971
|
+
this.tenantId = config.tenantId || "default";
|
|
972
|
+
this.baseURL = process.env.INKEEP_API_URL || "http://localhost:3002";
|
|
973
|
+
logger5.debug(
|
|
974
|
+
{
|
|
975
|
+
externalAgentName: this.config.name,
|
|
976
|
+
baseUrl: this.config.baseUrl,
|
|
977
|
+
tenantId: this.config.tenantId
|
|
978
|
+
},
|
|
979
|
+
"External Agent constructor initialized"
|
|
980
|
+
);
|
|
981
|
+
}
|
|
982
|
+
/**
|
|
983
|
+
* Initialize the external agent by upserting it in the database
|
|
984
|
+
*/
|
|
985
|
+
async init() {
|
|
986
|
+
if (this.initialized) return;
|
|
987
|
+
try {
|
|
988
|
+
await this.upsertExternalAgent();
|
|
989
|
+
logger5.info(
|
|
990
|
+
{
|
|
991
|
+
externalAgentId: this.getId()
|
|
992
|
+
},
|
|
993
|
+
"External agent initialized successfully"
|
|
994
|
+
);
|
|
995
|
+
this.initialized = true;
|
|
996
|
+
} catch (error) {
|
|
997
|
+
logger5.error(
|
|
998
|
+
{
|
|
999
|
+
externalAgentId: this.getId(),
|
|
1000
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
1001
|
+
},
|
|
1002
|
+
"Failed to initialize external agent"
|
|
1003
|
+
);
|
|
1004
|
+
throw error;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
// Compute ID from name using a simple slug transformation
|
|
1008
|
+
getId() {
|
|
1009
|
+
return this.config.id;
|
|
1010
|
+
}
|
|
1011
|
+
// Private method to upsert external agent (create or update)
|
|
1012
|
+
async upsertExternalAgent() {
|
|
1013
|
+
const externalAgentData = {
|
|
1014
|
+
id: this.getId(),
|
|
1015
|
+
name: this.config.name,
|
|
1016
|
+
description: this.config.description,
|
|
1017
|
+
baseUrl: this.config.baseUrl,
|
|
1018
|
+
credentialReferenceId: this.config.credentialReference?.id || void 0,
|
|
1019
|
+
headers: this.config.headers || void 0
|
|
1020
|
+
};
|
|
1021
|
+
const updateResponse = await fetch(
|
|
1022
|
+
`${this.baseURL}/tenants/${this.tenantId}/crud/external-agents/${this.getId()}`,
|
|
1023
|
+
{
|
|
1024
|
+
method: "PUT",
|
|
1025
|
+
headers: {
|
|
1026
|
+
"Content-Type": "application/json"
|
|
1027
|
+
},
|
|
1028
|
+
body: JSON.stringify(externalAgentData)
|
|
1029
|
+
}
|
|
1030
|
+
);
|
|
1031
|
+
if (updateResponse.ok) {
|
|
1032
|
+
logger5.info(
|
|
1033
|
+
{
|
|
1034
|
+
externalAgentId: this.getId()
|
|
1035
|
+
},
|
|
1036
|
+
"External agent updated successfully"
|
|
1037
|
+
);
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
if (updateResponse.status === 404) {
|
|
1041
|
+
logger5.info(
|
|
1042
|
+
{
|
|
1043
|
+
externalAgentId: this.getId()
|
|
1044
|
+
},
|
|
1045
|
+
"External agent not found, creating new external agent"
|
|
1046
|
+
);
|
|
1047
|
+
const createResponse = await fetch(
|
|
1048
|
+
`${this.baseURL}/tenants/${this.tenantId}/crud/external-agents`,
|
|
1049
|
+
{
|
|
1050
|
+
method: "POST",
|
|
1051
|
+
headers: {
|
|
1052
|
+
"Content-Type": "application/json"
|
|
1053
|
+
},
|
|
1054
|
+
body: JSON.stringify(externalAgentData)
|
|
1055
|
+
}
|
|
1056
|
+
);
|
|
1057
|
+
if (!createResponse.ok) {
|
|
1058
|
+
const errorText2 = await createResponse.text().catch(() => "Unknown error");
|
|
1059
|
+
throw new Error(
|
|
1060
|
+
`Failed to create external agent: ${createResponse.status} ${createResponse.statusText} - ${errorText2}`
|
|
1061
|
+
);
|
|
1062
|
+
}
|
|
1063
|
+
logger5.info(
|
|
1064
|
+
{
|
|
1065
|
+
externalAgentId: this.getId()
|
|
1066
|
+
},
|
|
1067
|
+
"External agent created successfully"
|
|
1068
|
+
);
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
1071
|
+
const errorText = await updateResponse.text().catch(() => "Unknown error");
|
|
1072
|
+
throw new Error(
|
|
1073
|
+
`Failed to update external agent: ${updateResponse.status} ${updateResponse.statusText} - ${errorText}`
|
|
1074
|
+
);
|
|
1075
|
+
}
|
|
1076
|
+
/**
|
|
1077
|
+
* Get the external agent configuration
|
|
1078
|
+
*/
|
|
1079
|
+
getConfig() {
|
|
1080
|
+
return { ...this.config };
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Get the external agent name
|
|
1084
|
+
*/
|
|
1085
|
+
getName() {
|
|
1086
|
+
return this.config.name;
|
|
1087
|
+
}
|
|
1088
|
+
/**
|
|
1089
|
+
* Get the external agent base URL
|
|
1090
|
+
*/
|
|
1091
|
+
getBaseUrl() {
|
|
1092
|
+
return this.config.baseUrl;
|
|
1093
|
+
}
|
|
1094
|
+
/**
|
|
1095
|
+
* Get the tenant ID
|
|
1096
|
+
*/
|
|
1097
|
+
getTenantId() {
|
|
1098
|
+
return this.tenantId;
|
|
1099
|
+
}
|
|
1100
|
+
getDescription() {
|
|
1101
|
+
return this.config.description || "";
|
|
1102
|
+
}
|
|
1103
|
+
getCredentialReferenceId() {
|
|
1104
|
+
return this.config.credentialReference?.id || void 0;
|
|
1105
|
+
}
|
|
1106
|
+
getHeaders() {
|
|
1107
|
+
return this.config.headers;
|
|
1108
|
+
}
|
|
1109
|
+
};
|
|
1110
|
+
function externalAgent(config) {
|
|
1111
|
+
return new ExternalAgent(config);
|
|
1112
|
+
}
|
|
1113
|
+
function externalAgents(configs) {
|
|
1114
|
+
const builders = {};
|
|
1115
|
+
for (const [name, config] of Object.entries(configs)) {
|
|
1116
|
+
builders[name] = externalAgent(config);
|
|
1117
|
+
}
|
|
1118
|
+
return builders;
|
|
1119
|
+
}
|
|
1120
|
+
var logger6 = getLogger("graphFullClient");
|
|
1121
|
+
async function updateFullGraphViaAPI(tenantId, projectId, apiUrl, graphId, graphData) {
|
|
1122
|
+
logger6.info(
|
|
1123
|
+
{
|
|
1124
|
+
tenantId,
|
|
1125
|
+
projectId,
|
|
1126
|
+
graphId,
|
|
1127
|
+
apiUrl
|
|
1128
|
+
},
|
|
1129
|
+
"Updating full graph via API"
|
|
1130
|
+
);
|
|
1131
|
+
const url = `${apiUrl}/tenants/${tenantId}/crud/projects/${projectId}/graph/${graphId}`;
|
|
1132
|
+
const response = await fetch(url, {
|
|
1133
|
+
method: "PUT",
|
|
1134
|
+
headers: {
|
|
1135
|
+
"Content-Type": "application/json"
|
|
1136
|
+
},
|
|
1137
|
+
body: JSON.stringify(graphData)
|
|
1138
|
+
});
|
|
1139
|
+
if (!response.ok) {
|
|
1140
|
+
const errorText = await response.text();
|
|
1141
|
+
let errorMessage = `Failed to update graph: ${response.status} ${response.statusText}`;
|
|
1142
|
+
try {
|
|
1143
|
+
const errorJson = JSON.parse(errorText);
|
|
1144
|
+
if (errorJson.error) {
|
|
1145
|
+
errorMessage = errorJson.error;
|
|
1146
|
+
}
|
|
1147
|
+
} catch {
|
|
1148
|
+
if (errorText) {
|
|
1149
|
+
errorMessage = errorText;
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
logger6.error(
|
|
1153
|
+
{
|
|
1154
|
+
status: response.status,
|
|
1155
|
+
error: errorMessage
|
|
1156
|
+
},
|
|
1157
|
+
"Failed to update graph via API"
|
|
1158
|
+
);
|
|
1159
|
+
throw new Error(errorMessage);
|
|
1160
|
+
}
|
|
1161
|
+
const result = await response.json();
|
|
1162
|
+
logger6.info(
|
|
1163
|
+
{
|
|
1164
|
+
graphId
|
|
1165
|
+
},
|
|
1166
|
+
"Successfully updated graph via API"
|
|
1167
|
+
);
|
|
1168
|
+
return result.data;
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
// src/graph.ts
|
|
1172
|
+
var logger7 = getLogger("graph");
|
|
1173
|
+
function resolveGetter2(value) {
|
|
1174
|
+
if (typeof value === "function") {
|
|
1175
|
+
return value();
|
|
1176
|
+
}
|
|
1177
|
+
return value;
|
|
1178
|
+
}
|
|
1179
|
+
var AgentGraph = class {
|
|
1180
|
+
constructor(config) {
|
|
1181
|
+
__publicField(this, "agents", []);
|
|
1182
|
+
__publicField(this, "agentMap", /* @__PURE__ */ new Map());
|
|
1183
|
+
__publicField(this, "defaultAgent");
|
|
1184
|
+
__publicField(this, "baseURL");
|
|
1185
|
+
__publicField(this, "tenantId");
|
|
1186
|
+
__publicField(this, "projectId");
|
|
1187
|
+
__publicField(this, "graphId");
|
|
1188
|
+
__publicField(this, "graphName");
|
|
1189
|
+
__publicField(this, "graphDescription");
|
|
1190
|
+
__publicField(this, "initialized", false);
|
|
1191
|
+
__publicField(this, "contextConfig");
|
|
1192
|
+
// ContextConfigBuilder
|
|
1193
|
+
__publicField(this, "credentials");
|
|
1194
|
+
__publicField(this, "models");
|
|
1195
|
+
__publicField(this, "statusUpdateSettings");
|
|
1196
|
+
__publicField(this, "graphPrompt");
|
|
1197
|
+
__publicField(this, "stopWhen");
|
|
1198
|
+
__publicField(this, "dbClient");
|
|
1199
|
+
this.defaultAgent = config.defaultAgent;
|
|
1200
|
+
this.tenantId = config.tenantId || "default";
|
|
1201
|
+
this.projectId = "default";
|
|
1202
|
+
this.graphId = config.id;
|
|
1203
|
+
this.graphName = config.name || this.graphId;
|
|
1204
|
+
this.graphDescription = config.description;
|
|
1205
|
+
this.baseURL = process.env.INKEEP_API_URL || "http://localhost:3002";
|
|
1206
|
+
this.contextConfig = config.contextConfig;
|
|
1207
|
+
this.credentials = resolveGetter2(config.credentials);
|
|
1208
|
+
this.models = config.models;
|
|
1209
|
+
const dbUrl = process.env.ENVIRONMENT === "test" ? ":memory:" : process.env.DB_FILE_NAME || process.env.DATABASE_URL || ":memory:";
|
|
1210
|
+
this.dbClient = createDatabaseClient({
|
|
1211
|
+
url: dbUrl
|
|
1212
|
+
});
|
|
1213
|
+
this.statusUpdateSettings = config.statusUpdates;
|
|
1214
|
+
this.graphPrompt = config.graphPrompt;
|
|
1215
|
+
this.stopWhen = config.stopWhen ? {
|
|
1216
|
+
transferCountIs: config.stopWhen.transferCountIs
|
|
1217
|
+
} : void 0;
|
|
1218
|
+
this.agents = resolveGetter2(config.agents) || [];
|
|
1219
|
+
this.agentMap = new Map(this.agents.map((agent2) => [agent2.getId(), agent2]));
|
|
1220
|
+
if (this.defaultAgent) {
|
|
1221
|
+
this.agents.push(this.defaultAgent);
|
|
1222
|
+
this.agentMap.set(this.defaultAgent.getId(), this.defaultAgent);
|
|
1223
|
+
}
|
|
1224
|
+
if (this.models) {
|
|
1225
|
+
this.propagateImmediateModelSettings();
|
|
1226
|
+
}
|
|
1227
|
+
logger7.info(
|
|
1228
|
+
{
|
|
1229
|
+
graphId: this.graphId,
|
|
1230
|
+
tenantId: this.tenantId,
|
|
1231
|
+
agentCount: this.agents.length,
|
|
1232
|
+
defaultAgent: this.defaultAgent?.getName()
|
|
1233
|
+
},
|
|
1234
|
+
"AgentGraph created"
|
|
1235
|
+
);
|
|
1236
|
+
}
|
|
1237
|
+
/**
|
|
1238
|
+
* Set or update the configuration (tenantId, projectId and apiUrl)
|
|
1239
|
+
* This is used by the CLI to inject configuration from inkeep.config.ts
|
|
1240
|
+
*/
|
|
1241
|
+
setConfig(tenantId, projectId, apiUrl) {
|
|
1242
|
+
if (this.initialized) {
|
|
1243
|
+
throw new Error("Cannot set config after graph has been initialized");
|
|
1244
|
+
}
|
|
1245
|
+
this.tenantId = tenantId;
|
|
1246
|
+
this.projectId = projectId;
|
|
1247
|
+
this.baseURL = apiUrl;
|
|
1248
|
+
for (const agent2 of this.agents) {
|
|
1249
|
+
if (this.isInternalAgent(agent2)) {
|
|
1250
|
+
const internalAgent = agent2;
|
|
1251
|
+
if (!internalAgent.config.tenantId) {
|
|
1252
|
+
internalAgent.config.tenantId = tenantId;
|
|
1253
|
+
}
|
|
1254
|
+
const tools = internalAgent.getTools();
|
|
1255
|
+
for (const [_, toolInstance] of Object.entries(tools)) {
|
|
1256
|
+
if (toolInstance && typeof toolInstance === "object" && toolInstance.config) {
|
|
1257
|
+
if (!toolInstance.config.tenantId) {
|
|
1258
|
+
toolInstance.config.tenantId = tenantId;
|
|
1259
|
+
}
|
|
1260
|
+
if ("baseURL" in toolInstance && !toolInstance.baseURL) {
|
|
1261
|
+
toolInstance.baseURL = apiUrl;
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
if (this.contextConfig && !this.contextConfig.tenantId) {
|
|
1268
|
+
this.contextConfig.tenantId = tenantId;
|
|
1269
|
+
}
|
|
1270
|
+
logger7.info(
|
|
1271
|
+
{
|
|
1272
|
+
graphId: this.graphId,
|
|
1273
|
+
tenantId: this.tenantId,
|
|
1274
|
+
projectId: this.projectId,
|
|
1275
|
+
apiUrl: this.baseURL
|
|
1276
|
+
},
|
|
1277
|
+
"Graph configuration updated"
|
|
1278
|
+
);
|
|
1279
|
+
}
|
|
1280
|
+
/**
|
|
1281
|
+
* Convert the AgentGraph to FullGraphDefinition format for the new graph endpoint
|
|
1282
|
+
*/
|
|
1283
|
+
async toFullGraphDefinition() {
|
|
1284
|
+
const agentsObject = {};
|
|
1285
|
+
for (const agent2 of this.agents) {
|
|
1286
|
+
if (this.isInternalAgent(agent2)) {
|
|
1287
|
+
const internalAgent = agent2;
|
|
1288
|
+
const transfers = internalAgent.getTransfers();
|
|
1289
|
+
const delegates = internalAgent.getDelegates();
|
|
1290
|
+
const tools = [];
|
|
1291
|
+
const selectedToolsMapping = {};
|
|
1292
|
+
const agentTools = internalAgent.getTools();
|
|
1293
|
+
for (const [toolName, toolInstance] of Object.entries(agentTools)) {
|
|
1294
|
+
if (toolInstance && typeof toolInstance === "object") {
|
|
1295
|
+
let toolId;
|
|
1296
|
+
toolId = toolInstance.getId?.() || toolInstance.id;
|
|
1297
|
+
if ("selectedTools" in toolInstance && toolInstance.selectedTools !== void 0) {
|
|
1298
|
+
logger7.info({ toolId, selectedTools: toolInstance.selectedTools }, "Selected tools");
|
|
1299
|
+
selectedToolsMapping[toolId] = toolInstance.selectedTools;
|
|
1300
|
+
}
|
|
1301
|
+
tools.push(toolId);
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
const dataComponents = [];
|
|
1305
|
+
const agentDataComponents = internalAgent.getDataComponents();
|
|
1306
|
+
if (agentDataComponents) {
|
|
1307
|
+
for (const dataComponent2 of agentDataComponents) {
|
|
1308
|
+
const dataComponentId = dataComponent2.id || dataComponent2.name.toLowerCase().replace(/\s+/g, "-");
|
|
1309
|
+
dataComponents.push(dataComponentId);
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
const artifactComponents = [];
|
|
1313
|
+
const agentArtifactComponents = internalAgent.getArtifactComponents();
|
|
1314
|
+
if (agentArtifactComponents) {
|
|
1315
|
+
for (const artifactComponent2 of agentArtifactComponents) {
|
|
1316
|
+
const artifactComponentId = artifactComponent2.id || artifactComponent2.name.toLowerCase().replace(/\s+/g, "-");
|
|
1317
|
+
artifactComponents.push(artifactComponentId);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
agentsObject[internalAgent.getId()] = {
|
|
1321
|
+
id: internalAgent.getId(),
|
|
1322
|
+
name: internalAgent.getName(),
|
|
1323
|
+
description: internalAgent.config.description || `Agent ${internalAgent.getName()}`,
|
|
1324
|
+
prompt: internalAgent.getInstructions(),
|
|
1325
|
+
models: internalAgent.config.models,
|
|
1326
|
+
canTransferTo: transfers.map((h) => h.getId()),
|
|
1327
|
+
canDelegateTo: delegates.map((d) => d.getId()),
|
|
1328
|
+
tools,
|
|
1329
|
+
selectedTools: Object.keys(selectedToolsMapping).length > 0 ? selectedToolsMapping : void 0,
|
|
1330
|
+
dataComponents: dataComponents.length > 0 ? dataComponents : void 0,
|
|
1331
|
+
artifactComponents: artifactComponents.length > 0 ? artifactComponents : void 0,
|
|
1332
|
+
type: "internal"
|
|
1333
|
+
};
|
|
1334
|
+
} else {
|
|
1335
|
+
const externalAgent2 = agent2;
|
|
1336
|
+
agentsObject[externalAgent2.getId()] = {
|
|
1337
|
+
id: externalAgent2.getId(),
|
|
1338
|
+
name: externalAgent2.getName(),
|
|
1339
|
+
description: externalAgent2.getDescription(),
|
|
1340
|
+
baseUrl: externalAgent2.getBaseUrl(),
|
|
1341
|
+
credentialReferenceId: externalAgent2.getCredentialReferenceId(),
|
|
1342
|
+
headers: externalAgent2.getHeaders(),
|
|
1343
|
+
tools: [],
|
|
1344
|
+
// External agents don't have tools in this context
|
|
1345
|
+
type: "external"
|
|
1346
|
+
};
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
const toolsObject = {};
|
|
1350
|
+
for (const agent2 of this.agents) {
|
|
1351
|
+
if (!agent2.getTransfers) {
|
|
1352
|
+
continue;
|
|
1353
|
+
}
|
|
1354
|
+
const internalAgent = agent2;
|
|
1355
|
+
const agentTools = internalAgent.getTools();
|
|
1356
|
+
for (const [toolName, toolInstance] of Object.entries(agentTools)) {
|
|
1357
|
+
if (toolInstance && typeof toolInstance === "object") {
|
|
1358
|
+
let actualTool;
|
|
1359
|
+
let toolId;
|
|
1360
|
+
if ("server" in toolInstance && "selectedTools" in toolInstance) {
|
|
1361
|
+
const mcpConfig = toolInstance;
|
|
1362
|
+
actualTool = mcpConfig.server;
|
|
1363
|
+
toolId = actualTool.getId();
|
|
1364
|
+
} else {
|
|
1365
|
+
actualTool = toolInstance;
|
|
1366
|
+
toolId = actualTool.getId?.() || actualTool.id || toolName;
|
|
1367
|
+
}
|
|
1368
|
+
if (!toolsObject[toolId]) {
|
|
1369
|
+
let toolConfig;
|
|
1370
|
+
if (actualTool.config?.serverUrl) {
|
|
1371
|
+
toolConfig = {
|
|
1372
|
+
type: "mcp",
|
|
1373
|
+
mcp: {
|
|
1374
|
+
server: {
|
|
1375
|
+
url: actualTool.config.serverUrl
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
};
|
|
1379
|
+
} else if (actualTool.config?.type === "mcp") {
|
|
1380
|
+
toolConfig = actualTool.config;
|
|
1381
|
+
} else {
|
|
1382
|
+
toolConfig = {
|
|
1383
|
+
type: "function",
|
|
1384
|
+
parameters: actualTool.parameters || {}
|
|
1385
|
+
};
|
|
1386
|
+
}
|
|
1387
|
+
const toolData = {
|
|
1388
|
+
id: toolId,
|
|
1389
|
+
name: actualTool.config?.name || actualTool.name || toolName,
|
|
1390
|
+
config: toolConfig,
|
|
1391
|
+
status: actualTool.getStatus?.() || actualTool.status || "unknown"
|
|
1392
|
+
};
|
|
1393
|
+
if (actualTool.config?.imageUrl) {
|
|
1394
|
+
toolData.imageUrl = actualTool.config.imageUrl;
|
|
1395
|
+
}
|
|
1396
|
+
if (actualTool.config?.headers) {
|
|
1397
|
+
toolData.headers = actualTool.config.headers;
|
|
1398
|
+
}
|
|
1399
|
+
if (actualTool.capabilities) {
|
|
1400
|
+
toolData.capabilities = actualTool.capabilities;
|
|
1401
|
+
}
|
|
1402
|
+
if (actualTool.lastHealthCheck) {
|
|
1403
|
+
toolData.lastHealthCheck = actualTool.lastHealthCheck;
|
|
1404
|
+
}
|
|
1405
|
+
if (actualTool.availableTools) {
|
|
1406
|
+
toolData.availableTools = actualTool.availableTools;
|
|
1407
|
+
}
|
|
1408
|
+
if (actualTool.lastError) {
|
|
1409
|
+
toolData.lastError = actualTool.lastError;
|
|
1410
|
+
}
|
|
1411
|
+
if (actualTool.lastToolsSync) {
|
|
1412
|
+
toolData.lastToolsSync = actualTool.lastToolsSync;
|
|
1413
|
+
}
|
|
1414
|
+
if (actualTool.getCredentialReferenceId?.()) {
|
|
1415
|
+
toolData.credentialReferenceId = actualTool.getCredentialReferenceId();
|
|
1416
|
+
}
|
|
1417
|
+
toolsObject[toolId] = toolData;
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
const dataComponentsObject = {};
|
|
1423
|
+
for (const agent2 of this.agents) {
|
|
1424
|
+
if (!this.isInternalAgent(agent2)) {
|
|
1425
|
+
continue;
|
|
1426
|
+
}
|
|
1427
|
+
const internalAgent = agent2;
|
|
1428
|
+
const agentDataComponents = internalAgent.getDataComponents();
|
|
1429
|
+
if (agentDataComponents) {
|
|
1430
|
+
for (const dataComponent2 of agentDataComponents) {
|
|
1431
|
+
const dataComponentId = dataComponent2.id || dataComponent2.name.toLowerCase().replace(/\s+/g, "-");
|
|
1432
|
+
if (!dataComponentsObject[dataComponentId]) {
|
|
1433
|
+
dataComponentsObject[dataComponentId] = {
|
|
1434
|
+
id: dataComponentId,
|
|
1435
|
+
name: dataComponent2.name,
|
|
1436
|
+
description: dataComponent2.description || "",
|
|
1437
|
+
props: dataComponent2.props || {}
|
|
1438
|
+
};
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
const artifactComponentsObject = {};
|
|
1444
|
+
for (const agent2 of this.agents) {
|
|
1445
|
+
if (!this.isInternalAgent(agent2)) {
|
|
1446
|
+
continue;
|
|
1447
|
+
}
|
|
1448
|
+
const internalAgent = agent2;
|
|
1449
|
+
const agentArtifactComponents = internalAgent.getArtifactComponents();
|
|
1450
|
+
if (agentArtifactComponents) {
|
|
1451
|
+
for (const artifactComponent2 of agentArtifactComponents) {
|
|
1452
|
+
const artifactComponentId = artifactComponent2.id || artifactComponent2.name.toLowerCase().replace(/\s+/g, "-");
|
|
1453
|
+
if (!artifactComponentsObject[artifactComponentId]) {
|
|
1454
|
+
artifactComponentsObject[artifactComponentId] = {
|
|
1455
|
+
id: artifactComponentId,
|
|
1456
|
+
name: artifactComponent2.name,
|
|
1457
|
+
description: artifactComponent2.description || "",
|
|
1458
|
+
summaryProps: artifactComponent2.summaryProps || {},
|
|
1459
|
+
fullProps: artifactComponent2.fullProps || {}
|
|
1460
|
+
};
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
return {
|
|
1466
|
+
id: this.graphId,
|
|
1467
|
+
name: this.graphName,
|
|
1468
|
+
description: this.graphDescription,
|
|
1469
|
+
defaultAgentId: this.defaultAgent?.getId() || "",
|
|
1470
|
+
agents: agentsObject,
|
|
1471
|
+
tools: toolsObject,
|
|
1472
|
+
contextConfig: this.contextConfig?.toObject(),
|
|
1473
|
+
credentialReferences: this.credentials?.map((credentialReference) => ({
|
|
1474
|
+
type: credentialReference.type,
|
|
1475
|
+
id: credentialReference.id,
|
|
1476
|
+
credentialStoreId: credentialReference.credentialStoreId,
|
|
1477
|
+
retrievalParams: credentialReference.retrievalParams || {}
|
|
1478
|
+
})),
|
|
1479
|
+
models: this.models,
|
|
1480
|
+
statusUpdates: this.statusUpdateSettings,
|
|
1481
|
+
graphPrompt: this.graphPrompt,
|
|
1482
|
+
dataComponents: Object.keys(dataComponentsObject).length > 0 ? dataComponentsObject : void 0,
|
|
1483
|
+
artifactComponents: Object.keys(artifactComponentsObject).length > 0 ? artifactComponentsObject : void 0,
|
|
1484
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1485
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1486
|
+
};
|
|
1487
|
+
}
|
|
1488
|
+
/**
|
|
1489
|
+
* Initialize all tools in all agents (especially IPCTools that need MCP server URLs)
|
|
1490
|
+
*/
|
|
1491
|
+
async initializeAllTools() {
|
|
1492
|
+
logger7.info({ graphId: this.graphId }, "Initializing all tools in graph");
|
|
1493
|
+
const toolInitPromises = [];
|
|
1494
|
+
for (const agent2 of this.agents) {
|
|
1495
|
+
if (!agent2.getTools) {
|
|
1496
|
+
continue;
|
|
1497
|
+
}
|
|
1498
|
+
const internalAgent = agent2;
|
|
1499
|
+
const agentTools = internalAgent.getTools();
|
|
1500
|
+
for (const [toolName, toolInstance] of Object.entries(agentTools)) {
|
|
1501
|
+
if (toolInstance && typeof toolInstance === "object") {
|
|
1502
|
+
if (typeof toolInstance.init === "function") {
|
|
1503
|
+
toolInitPromises.push(
|
|
1504
|
+
(async () => {
|
|
1505
|
+
try {
|
|
1506
|
+
const skipDbRegistration = toolInstance.constructor.name === "IPCTool" || toolInstance.constructor.name === "HostedTool" || toolInstance.constructor.name === "Tool";
|
|
1507
|
+
if (typeof toolInstance.init === "function") {
|
|
1508
|
+
if (skipDbRegistration) {
|
|
1509
|
+
await toolInstance.init({
|
|
1510
|
+
skipDatabaseRegistration: true
|
|
1511
|
+
});
|
|
1512
|
+
} else {
|
|
1513
|
+
await toolInstance.init();
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
logger7.debug(
|
|
1517
|
+
{
|
|
1518
|
+
agentId: agent2.getId(),
|
|
1519
|
+
toolName,
|
|
1520
|
+
toolType: toolInstance.constructor.name,
|
|
1521
|
+
skipDbRegistration
|
|
1522
|
+
},
|
|
1523
|
+
"Tool initialized successfully"
|
|
1524
|
+
);
|
|
1525
|
+
} catch (error) {
|
|
1526
|
+
logger7.error(
|
|
1527
|
+
{
|
|
1528
|
+
agentId: agent2.getId(),
|
|
1529
|
+
toolName,
|
|
1530
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
1531
|
+
},
|
|
1532
|
+
"Failed to initialize tool"
|
|
1533
|
+
);
|
|
1534
|
+
throw error;
|
|
1535
|
+
}
|
|
1536
|
+
})()
|
|
1537
|
+
);
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
await Promise.all(toolInitPromises);
|
|
1543
|
+
logger7.info(
|
|
1544
|
+
{ graphId: this.graphId, toolCount: toolInitPromises.length },
|
|
1545
|
+
"All tools initialized successfully"
|
|
1546
|
+
);
|
|
1547
|
+
}
|
|
1548
|
+
/**
|
|
1549
|
+
* Initialize the graph and all agents in the backend using the new graph endpoint
|
|
1550
|
+
*/
|
|
1551
|
+
async init() {
|
|
1552
|
+
if (this.initialized) {
|
|
1553
|
+
logger7.info({ graphId: this.graphId }, "Graph already initialized");
|
|
1554
|
+
return;
|
|
1555
|
+
}
|
|
1556
|
+
logger7.info(
|
|
1557
|
+
{
|
|
1558
|
+
graphId: this.graphId,
|
|
1559
|
+
agentCount: this.agents.length
|
|
1560
|
+
},
|
|
1561
|
+
"Initializing agent graph using new graph endpoint"
|
|
1562
|
+
);
|
|
1563
|
+
try {
|
|
1564
|
+
await this.initializeAllTools();
|
|
1565
|
+
await this.applyModelInheritance();
|
|
1566
|
+
const graphDefinition = await this.toFullGraphDefinition();
|
|
1567
|
+
logger7.info(
|
|
1568
|
+
{
|
|
1569
|
+
graphId: this.graphId,
|
|
1570
|
+
mode: "api-client",
|
|
1571
|
+
apiUrl: this.baseURL
|
|
1572
|
+
},
|
|
1573
|
+
"Using API client to create/update graph"
|
|
1574
|
+
);
|
|
1575
|
+
const createdGraph = await updateFullGraphViaAPI(
|
|
1576
|
+
this.tenantId,
|
|
1577
|
+
this.projectId,
|
|
1578
|
+
this.baseURL,
|
|
1579
|
+
this.graphId,
|
|
1580
|
+
graphDefinition
|
|
1581
|
+
);
|
|
1582
|
+
logger7.info(
|
|
1583
|
+
{
|
|
1584
|
+
graphId: this.graphId,
|
|
1585
|
+
agentCount: Object.keys(createdGraph.agents || {}).length
|
|
1586
|
+
},
|
|
1587
|
+
"Agent graph initialized successfully using graph endpoint"
|
|
1588
|
+
);
|
|
1589
|
+
this.initialized = true;
|
|
1590
|
+
} catch (error) {
|
|
1591
|
+
logger7.error(
|
|
1592
|
+
{
|
|
1593
|
+
graphId: this.graphId,
|
|
1594
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
1595
|
+
},
|
|
1596
|
+
"Failed to initialize agent graph using graph endpoint"
|
|
1597
|
+
);
|
|
1598
|
+
throw error;
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
/**
|
|
1602
|
+
* Legacy initialization method - kept for backward compatibility
|
|
1603
|
+
* Initialize the graph and all agents in the backend using individual endpoints
|
|
1604
|
+
*/
|
|
1605
|
+
async initLegacy() {
|
|
1606
|
+
if (this.initialized) {
|
|
1607
|
+
logger7.info({ graphId: this.graphId }, "Graph already initialized");
|
|
1608
|
+
return;
|
|
1609
|
+
}
|
|
1610
|
+
logger7.info(
|
|
1611
|
+
{
|
|
1612
|
+
graphId: this.graphId,
|
|
1613
|
+
agentCount: this.agents.length
|
|
1614
|
+
},
|
|
1615
|
+
"Initializing agent graph"
|
|
1616
|
+
);
|
|
1617
|
+
try {
|
|
1618
|
+
if (this.contextConfig) {
|
|
1619
|
+
await this.contextConfig.init();
|
|
1620
|
+
logger7.info(
|
|
1621
|
+
{
|
|
1622
|
+
graphId: this.graphId,
|
|
1623
|
+
contextConfigId: this.contextConfig.getId()
|
|
1624
|
+
},
|
|
1625
|
+
"Context configuration initialized for graph"
|
|
1626
|
+
);
|
|
1627
|
+
}
|
|
1628
|
+
const initPromises = this.agents.map(async (agent2) => {
|
|
1629
|
+
try {
|
|
1630
|
+
agent2.config.graphId = this.graphId;
|
|
1631
|
+
await agent2.init();
|
|
1632
|
+
logger7.debug(
|
|
1633
|
+
{
|
|
1634
|
+
agentId: agent2.getId(),
|
|
1635
|
+
graphId: this.graphId
|
|
1636
|
+
},
|
|
1637
|
+
"Agent initialized in graph"
|
|
1638
|
+
);
|
|
1639
|
+
} catch (error) {
|
|
1640
|
+
logger7.error(
|
|
1641
|
+
{
|
|
1642
|
+
agentId: agent2.getId(),
|
|
1643
|
+
graphId: this.graphId,
|
|
1644
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
1645
|
+
},
|
|
1646
|
+
"Failed to initialize agent in graph"
|
|
1647
|
+
);
|
|
1648
|
+
throw error;
|
|
1649
|
+
}
|
|
1650
|
+
});
|
|
1651
|
+
await Promise.all(initPromises);
|
|
1652
|
+
await this.saveToDatabase();
|
|
1653
|
+
await this.createExternalAgents();
|
|
1654
|
+
await this.createAgentRelations();
|
|
1655
|
+
await this.saveRelations();
|
|
1656
|
+
this.initialized = true;
|
|
1657
|
+
logger7.info(
|
|
1658
|
+
{
|
|
1659
|
+
graphId: this.graphId,
|
|
1660
|
+
agentCount: this.agents.length
|
|
1661
|
+
},
|
|
1662
|
+
"Agent graph initialized successfully"
|
|
1663
|
+
);
|
|
1664
|
+
} catch (error) {
|
|
1665
|
+
logger7.error(
|
|
1666
|
+
{
|
|
1667
|
+
graphId: this.graphId,
|
|
1668
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
1669
|
+
},
|
|
1670
|
+
"Failed to initialize agent graph"
|
|
1671
|
+
);
|
|
1672
|
+
throw error;
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
/**
|
|
1676
|
+
* Generate a response using the default agent
|
|
1677
|
+
*/
|
|
1678
|
+
async generate(input, options) {
|
|
1679
|
+
await this._init();
|
|
1680
|
+
if (!this.defaultAgent) {
|
|
1681
|
+
throw new Error("No default agent configured for this graph");
|
|
1682
|
+
}
|
|
1683
|
+
logger7.info(
|
|
1684
|
+
{
|
|
1685
|
+
graphId: this.graphId,
|
|
1686
|
+
defaultAgent: this.defaultAgent.getName(),
|
|
1687
|
+
conversationId: options?.conversationId
|
|
1688
|
+
},
|
|
1689
|
+
"Generating response with default agent"
|
|
1690
|
+
);
|
|
1691
|
+
const response = await this.executeWithBackend(input, options);
|
|
1692
|
+
return response;
|
|
1693
|
+
}
|
|
1694
|
+
/**
|
|
1695
|
+
* Stream a response using the default agent
|
|
1696
|
+
*/
|
|
1697
|
+
async stream(input, options) {
|
|
1698
|
+
await this._init();
|
|
1699
|
+
if (!this.defaultAgent) {
|
|
1700
|
+
throw new Error("No default agent configured for this graph");
|
|
1701
|
+
}
|
|
1702
|
+
logger7.info(
|
|
1703
|
+
{
|
|
1704
|
+
graphId: this.graphId,
|
|
1705
|
+
defaultAgent: this.defaultAgent.getName(),
|
|
1706
|
+
conversationId: options?.conversationId
|
|
1707
|
+
},
|
|
1708
|
+
"Streaming response with default agent"
|
|
1709
|
+
);
|
|
1710
|
+
const textStream = async function* (graph) {
|
|
1711
|
+
const response = await graph.executeWithBackend(input, options);
|
|
1712
|
+
const words = response.split(" ");
|
|
1713
|
+
for (const word of words) {
|
|
1714
|
+
yield `${word} `;
|
|
1715
|
+
}
|
|
1716
|
+
};
|
|
1717
|
+
return {
|
|
1718
|
+
textStream: textStream(this)
|
|
1719
|
+
};
|
|
1720
|
+
}
|
|
1721
|
+
/**
|
|
1722
|
+
* Alias for stream() method for consistency with naming patterns
|
|
1723
|
+
*/
|
|
1724
|
+
async generateStream(input, options) {
|
|
1725
|
+
return await this.stream(input, options);
|
|
1726
|
+
}
|
|
1727
|
+
/**
|
|
1728
|
+
* Run with a specific agent from the graph
|
|
1729
|
+
*/
|
|
1730
|
+
async runWith(agentId, input, options) {
|
|
1731
|
+
await this._init();
|
|
1732
|
+
const agent2 = this.getAgent(agentId);
|
|
1733
|
+
if (!agent2) {
|
|
1734
|
+
throw new Error(`Agent '${agentId}' not found in graph`);
|
|
1735
|
+
}
|
|
1736
|
+
if (!this.isInternalAgent(agent2)) {
|
|
1737
|
+
throw new Error(
|
|
1738
|
+
`Agent '${agentId}' is an external agent and cannot be run directly. External agents are only accessible via delegation.`
|
|
1739
|
+
);
|
|
1740
|
+
}
|
|
1741
|
+
logger7.info(
|
|
1742
|
+
{
|
|
1743
|
+
graphId: this.graphId,
|
|
1744
|
+
agentId,
|
|
1745
|
+
conversationId: options?.conversationId
|
|
1746
|
+
},
|
|
1747
|
+
"Running with specific agent"
|
|
1748
|
+
);
|
|
1749
|
+
const response = await this.executeWithBackend(input, options);
|
|
1750
|
+
return {
|
|
1751
|
+
finalOutput: response,
|
|
1752
|
+
agent: agent2,
|
|
1753
|
+
turnCount: 1,
|
|
1754
|
+
usage: { inputTokens: 0, outputTokens: 0 },
|
|
1755
|
+
metadata: {
|
|
1756
|
+
toolCalls: [],
|
|
1757
|
+
transfers: []
|
|
1758
|
+
}
|
|
1759
|
+
};
|
|
1760
|
+
}
|
|
1761
|
+
/**
|
|
1762
|
+
* Get an agent by name (unified method for all agent types)
|
|
1763
|
+
*/
|
|
1764
|
+
getAgent(name) {
|
|
1765
|
+
return this.agentMap.get(name);
|
|
1766
|
+
}
|
|
1767
|
+
/**
|
|
1768
|
+
* Add an agent to the graph
|
|
1769
|
+
*/
|
|
1770
|
+
addAgent(agent2) {
|
|
1771
|
+
this.agents.push(agent2);
|
|
1772
|
+
this.agentMap.set(agent2.getId(), agent2);
|
|
1773
|
+
if (this.models && this.isInternalAgent(agent2)) {
|
|
1774
|
+
this.propagateModelSettingsToAgent(agent2);
|
|
1775
|
+
}
|
|
1776
|
+
logger7.info(
|
|
1777
|
+
{
|
|
1778
|
+
graphId: this.graphId,
|
|
1779
|
+
agentId: agent2.getId(),
|
|
1780
|
+
agentType: this.isInternalAgent(agent2) ? "internal" : "external"
|
|
1781
|
+
},
|
|
1782
|
+
"Agent added to graph"
|
|
1783
|
+
);
|
|
1784
|
+
}
|
|
1785
|
+
/**
|
|
1786
|
+
* Remove an agent from the graph
|
|
1787
|
+
*/
|
|
1788
|
+
removeAgent(id) {
|
|
1789
|
+
const agentToRemove = this.agentMap.get(id);
|
|
1790
|
+
if (agentToRemove) {
|
|
1791
|
+
this.agentMap.delete(agentToRemove.getId());
|
|
1792
|
+
this.agents = this.agents.filter((agent2) => agent2.getId() !== agentToRemove.getId());
|
|
1793
|
+
logger7.info(
|
|
1794
|
+
{
|
|
1795
|
+
graphId: this.graphId,
|
|
1796
|
+
agentId: agentToRemove.getId()
|
|
1797
|
+
},
|
|
1798
|
+
"Agent removed from graph"
|
|
1799
|
+
);
|
|
1800
|
+
return true;
|
|
1801
|
+
}
|
|
1802
|
+
return false;
|
|
1803
|
+
}
|
|
1804
|
+
/**
|
|
1805
|
+
* Get all agents in the graph
|
|
1806
|
+
*/
|
|
1807
|
+
getAgents() {
|
|
1808
|
+
return this.agents;
|
|
1809
|
+
}
|
|
1810
|
+
/**
|
|
1811
|
+
* Get all agent ids (unified method for all agent types)
|
|
1812
|
+
*/
|
|
1813
|
+
getAgentIds() {
|
|
1814
|
+
return Array.from(this.agentMap.keys());
|
|
1815
|
+
}
|
|
1816
|
+
/**
|
|
1817
|
+
* Set the default agent
|
|
1818
|
+
*/
|
|
1819
|
+
setDefaultAgent(agent2) {
|
|
1820
|
+
this.defaultAgent = agent2;
|
|
1821
|
+
this.addAgent(agent2);
|
|
1822
|
+
logger7.info(
|
|
1823
|
+
{
|
|
1824
|
+
graphId: this.graphId,
|
|
1825
|
+
defaultAgent: agent2.getId()
|
|
1826
|
+
},
|
|
1827
|
+
"Default agent updated"
|
|
1828
|
+
);
|
|
1829
|
+
}
|
|
1830
|
+
/**
|
|
1831
|
+
* Get the default agent
|
|
1832
|
+
*/
|
|
1833
|
+
getDefaultAgent() {
|
|
1834
|
+
return this.defaultAgent;
|
|
1835
|
+
}
|
|
1836
|
+
/**
|
|
1837
|
+
* Get the graph ID
|
|
1838
|
+
*/
|
|
1839
|
+
getId() {
|
|
1840
|
+
return this.graphId;
|
|
1841
|
+
}
|
|
1842
|
+
getName() {
|
|
1843
|
+
return this.graphName;
|
|
1844
|
+
}
|
|
1845
|
+
getDescription() {
|
|
1846
|
+
return this.graphDescription;
|
|
1847
|
+
}
|
|
1848
|
+
getTenantId() {
|
|
1849
|
+
return this.tenantId;
|
|
1850
|
+
}
|
|
1851
|
+
/**
|
|
1852
|
+
* Get the graph's model settingsuration
|
|
1853
|
+
*/
|
|
1854
|
+
getModels() {
|
|
1855
|
+
return this.models;
|
|
1856
|
+
}
|
|
1857
|
+
/**
|
|
1858
|
+
* Set the graph's model settingsuration
|
|
1859
|
+
*/
|
|
1860
|
+
setModels(models) {
|
|
1861
|
+
this.models = models;
|
|
1862
|
+
}
|
|
1863
|
+
/**
|
|
1864
|
+
* Get the graph's prompt configuration
|
|
1865
|
+
*/
|
|
1866
|
+
getGraphPrompt() {
|
|
1867
|
+
return this.graphPrompt;
|
|
1868
|
+
}
|
|
1869
|
+
/**
|
|
1870
|
+
* Get the graph's stopWhen configuration
|
|
1871
|
+
*/
|
|
1872
|
+
getStopWhen() {
|
|
1873
|
+
return this.stopWhen || { transferCountIs: 10 };
|
|
1874
|
+
}
|
|
1875
|
+
/**
|
|
1876
|
+
* Get the graph's status updates configuration
|
|
1877
|
+
*/
|
|
1878
|
+
getStatusUpdateSettings() {
|
|
1879
|
+
return this.statusUpdateSettings;
|
|
1880
|
+
}
|
|
1881
|
+
/**
|
|
1882
|
+
* Get the summarizer model from the graph's model settings
|
|
1883
|
+
*/
|
|
1884
|
+
getSummarizerModel() {
|
|
1885
|
+
return this.models?.summarizer;
|
|
1886
|
+
}
|
|
1887
|
+
/**
|
|
1888
|
+
* Get graph statistics
|
|
1889
|
+
*/
|
|
1890
|
+
getStats() {
|
|
1891
|
+
return {
|
|
1892
|
+
agentCount: this.agents.length,
|
|
1893
|
+
defaultAgent: this.defaultAgent?.getName() || null,
|
|
1894
|
+
initialized: this.initialized,
|
|
1895
|
+
graphId: this.graphId,
|
|
1896
|
+
tenantId: this.tenantId
|
|
1897
|
+
};
|
|
1898
|
+
}
|
|
1899
|
+
/**
|
|
1900
|
+
* Validate the graph configuration
|
|
1901
|
+
*/
|
|
1902
|
+
validate() {
|
|
1903
|
+
const errors = [];
|
|
1904
|
+
if (this.agents.length === 0) {
|
|
1905
|
+
errors.push("Graph must contain at least one agent");
|
|
1906
|
+
}
|
|
1907
|
+
if (!this.defaultAgent) {
|
|
1908
|
+
errors.push("Graph must have a default agent");
|
|
1909
|
+
}
|
|
1910
|
+
const names = /* @__PURE__ */ new Set();
|
|
1911
|
+
for (const agent2 of this.agents) {
|
|
1912
|
+
const name = agent2.getName();
|
|
1913
|
+
if (names.has(name)) {
|
|
1914
|
+
errors.push(`Duplicate agent name: ${name}`);
|
|
1915
|
+
}
|
|
1916
|
+
names.add(name);
|
|
1917
|
+
}
|
|
1918
|
+
for (const agent2 of this.agents) {
|
|
1919
|
+
if (!this.isInternalAgent(agent2)) continue;
|
|
1920
|
+
const transfers = agent2.getTransfers();
|
|
1921
|
+
for (const transferAgent of transfers) {
|
|
1922
|
+
if (!this.agentMap.has(transferAgent.getName())) {
|
|
1923
|
+
errors.push(
|
|
1924
|
+
`Agent '${agent2.getName()}' has transfer to '${transferAgent.getName()}' which is not in the graph`
|
|
1925
|
+
);
|
|
1926
|
+
}
|
|
1927
|
+
}
|
|
1928
|
+
const delegates = agent2.getDelegates();
|
|
1929
|
+
for (const delegateAgent of delegates) {
|
|
1930
|
+
if (!this.agentMap.has(delegateAgent.getName())) {
|
|
1931
|
+
errors.push(
|
|
1932
|
+
`Agent '${agent2.getName()}' has delegation to '${delegateAgent.getName()}' which is not in the graph`
|
|
1933
|
+
);
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
return {
|
|
1938
|
+
valid: errors.length === 0,
|
|
1939
|
+
errors
|
|
1940
|
+
};
|
|
1941
|
+
}
|
|
1942
|
+
// Private helper methods
|
|
1943
|
+
async _init() {
|
|
1944
|
+
if (!this.initialized) {
|
|
1945
|
+
await this.init();
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
/**
|
|
1949
|
+
* Type guard to check if an agent is an internal AgentInterface
|
|
1950
|
+
*/
|
|
1951
|
+
isInternalAgent(agent2) {
|
|
1952
|
+
return "getTransfers" in agent2 && typeof agent2.getTransfers === "function";
|
|
1953
|
+
}
|
|
1954
|
+
/**
|
|
1955
|
+
* Get project-level model settingsuration defaults
|
|
1956
|
+
*/
|
|
1957
|
+
async getProjectModelDefaults() {
|
|
1958
|
+
try {
|
|
1959
|
+
const project2 = await getProject(this.dbClient)({
|
|
1960
|
+
scopes: { tenantId: this.tenantId, projectId: this.projectId }
|
|
1961
|
+
});
|
|
1962
|
+
return project2?.models;
|
|
1963
|
+
} catch (error) {
|
|
1964
|
+
logger7.warn(
|
|
1965
|
+
{
|
|
1966
|
+
tenantId: this.tenantId,
|
|
1967
|
+
projectId: this.projectId,
|
|
1968
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
1969
|
+
},
|
|
1970
|
+
"Failed to get project model defaults"
|
|
1971
|
+
);
|
|
1972
|
+
return void 0;
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
/**
|
|
1976
|
+
* Get project-level stopWhen configuration defaults
|
|
1977
|
+
*/
|
|
1978
|
+
async getProjectStopWhenDefaults() {
|
|
1979
|
+
try {
|
|
1980
|
+
const project2 = await getProject(this.dbClient)({
|
|
1981
|
+
scopes: { tenantId: this.tenantId, projectId: this.projectId }
|
|
1982
|
+
});
|
|
1983
|
+
return project2?.stopWhen;
|
|
1984
|
+
} catch (error) {
|
|
1985
|
+
logger7.warn(
|
|
1986
|
+
{
|
|
1987
|
+
tenantId: this.tenantId,
|
|
1988
|
+
projectId: this.projectId,
|
|
1989
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
1990
|
+
},
|
|
1991
|
+
"Failed to get project stopWhen defaults"
|
|
1992
|
+
);
|
|
1993
|
+
return void 0;
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
/**
|
|
1997
|
+
* Apply model inheritance hierarchy: Project -> Graph -> Agent
|
|
1998
|
+
*/
|
|
1999
|
+
async applyModelInheritance() {
|
|
2000
|
+
const projectModels = await this.getProjectModelDefaults();
|
|
2001
|
+
if (projectModels) {
|
|
2002
|
+
if (!this.models) {
|
|
2003
|
+
this.models = {};
|
|
2004
|
+
}
|
|
2005
|
+
if (!this.models.base && projectModels.base) {
|
|
2006
|
+
this.models.base = projectModels.base;
|
|
2007
|
+
}
|
|
2008
|
+
if (!this.models.structuredOutput && projectModels.structuredOutput) {
|
|
2009
|
+
this.models.structuredOutput = projectModels.structuredOutput;
|
|
2010
|
+
}
|
|
2011
|
+
if (!this.models.summarizer && projectModels.summarizer) {
|
|
2012
|
+
this.models.summarizer = projectModels.summarizer;
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
await this.applyStopWhenInheritance();
|
|
2016
|
+
for (const agent2 of this.agents) {
|
|
2017
|
+
if (this.isInternalAgent(agent2)) {
|
|
2018
|
+
this.propagateModelSettingsToAgent(agent2);
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
/**
|
|
2023
|
+
* Apply stopWhen inheritance hierarchy: Project -> Graph -> Agent
|
|
2024
|
+
*/
|
|
2025
|
+
async applyStopWhenInheritance() {
|
|
2026
|
+
const projectStopWhen = await this.getProjectStopWhenDefaults();
|
|
2027
|
+
if (!this.stopWhen) {
|
|
2028
|
+
this.stopWhen = {};
|
|
2029
|
+
}
|
|
2030
|
+
if (this.stopWhen.transferCountIs === void 0 && projectStopWhen?.transferCountIs !== void 0) {
|
|
2031
|
+
this.stopWhen.transferCountIs = projectStopWhen.transferCountIs;
|
|
2032
|
+
}
|
|
2033
|
+
if (this.stopWhen.transferCountIs === void 0) {
|
|
2034
|
+
this.stopWhen.transferCountIs = 10;
|
|
2035
|
+
}
|
|
2036
|
+
if (projectStopWhen?.stepCountIs !== void 0) {
|
|
2037
|
+
for (const agent2 of this.agents) {
|
|
2038
|
+
if (this.isInternalAgent(agent2)) {
|
|
2039
|
+
const internalAgent = agent2;
|
|
2040
|
+
if (!internalAgent.config.stopWhen) {
|
|
2041
|
+
internalAgent.config.stopWhen = {};
|
|
2042
|
+
}
|
|
2043
|
+
if (internalAgent.config.stopWhen.stepCountIs === void 0) {
|
|
2044
|
+
internalAgent.config.stopWhen.stepCountIs = projectStopWhen.stepCountIs;
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
logger7.debug(
|
|
2050
|
+
{
|
|
2051
|
+
graphId: this.graphId,
|
|
2052
|
+
graphStopWhen: this.stopWhen,
|
|
2053
|
+
projectStopWhen
|
|
2054
|
+
},
|
|
2055
|
+
"Applied stopWhen inheritance from project to graph"
|
|
2056
|
+
);
|
|
2057
|
+
}
|
|
2058
|
+
/**
|
|
2059
|
+
* Propagate graph-level model settings to agents (supporting partial inheritance)
|
|
2060
|
+
*/
|
|
2061
|
+
propagateModelSettingsToAgent(agent2) {
|
|
2062
|
+
if (this.models) {
|
|
2063
|
+
if (!agent2.config.models) {
|
|
2064
|
+
agent2.config.models = {};
|
|
2065
|
+
}
|
|
2066
|
+
if (!agent2.config.models.base && this.models.base) {
|
|
2067
|
+
agent2.config.models.base = this.models.base;
|
|
2068
|
+
}
|
|
2069
|
+
if (!agent2.config.models.structuredOutput && this.models.structuredOutput) {
|
|
2070
|
+
agent2.config.models.structuredOutput = this.models.structuredOutput;
|
|
2071
|
+
}
|
|
2072
|
+
if (!agent2.config.models.summarizer && this.models.summarizer) {
|
|
2073
|
+
agent2.config.models.summarizer = this.models.summarizer;
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
/**
|
|
2078
|
+
* Immediately propagate graph-level models to all agents during construction
|
|
2079
|
+
*/
|
|
2080
|
+
propagateImmediateModelSettings() {
|
|
2081
|
+
for (const agent2 of this.agents) {
|
|
2082
|
+
if (this.isInternalAgent(agent2)) {
|
|
2083
|
+
this.propagateModelSettingsToAgent(agent2);
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
/**
|
|
2088
|
+
* Type guard to check if an agent is an external AgentInterface
|
|
2089
|
+
*/
|
|
2090
|
+
isExternalAgent(agent2) {
|
|
2091
|
+
return !this.isInternalAgent(agent2);
|
|
2092
|
+
}
|
|
2093
|
+
/**
|
|
2094
|
+
* Execute agent using the backend system instead of local runner
|
|
2095
|
+
*/
|
|
2096
|
+
async executeWithBackend(input, options) {
|
|
2097
|
+
const normalizedMessages = this.normalizeMessages(input);
|
|
2098
|
+
const url = `${this.baseURL}/tenants/${this.tenantId}/graphs/${this.graphId}/v1/chat/completions`;
|
|
2099
|
+
logger7.info({ url }, "Executing with backend");
|
|
2100
|
+
const requestBody = {
|
|
2101
|
+
model: "gpt-4o-mini",
|
|
2102
|
+
messages: normalizedMessages.map((msg) => ({
|
|
2103
|
+
role: msg.role,
|
|
2104
|
+
content: msg.content
|
|
2105
|
+
})),
|
|
2106
|
+
...options,
|
|
2107
|
+
// Include conversationId for multi-turn support
|
|
2108
|
+
...options?.conversationId && {
|
|
2109
|
+
conversationId: options.conversationId
|
|
2110
|
+
},
|
|
2111
|
+
// Include context data if available
|
|
2112
|
+
...options?.customBodyParams && { ...options.customBodyParams },
|
|
2113
|
+
stream: false
|
|
2114
|
+
// Explicitly disable streaming - must come after options to override
|
|
2115
|
+
};
|
|
2116
|
+
try {
|
|
2117
|
+
const response = await fetch(url, {
|
|
2118
|
+
method: "POST",
|
|
2119
|
+
headers: {
|
|
2120
|
+
"Content-Type": "application/json",
|
|
2121
|
+
Accept: "application/json"
|
|
2122
|
+
},
|
|
2123
|
+
body: JSON.stringify(requestBody)
|
|
2124
|
+
});
|
|
2125
|
+
if (!response.ok) {
|
|
2126
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
2127
|
+
}
|
|
2128
|
+
const responseText = await response.text();
|
|
2129
|
+
if (responseText.startsWith("data:")) {
|
|
2130
|
+
return this.parseStreamingResponse(responseText);
|
|
2131
|
+
}
|
|
2132
|
+
const data = JSON.parse(responseText);
|
|
2133
|
+
return data.result || data.choices?.[0]?.message?.content || "";
|
|
2134
|
+
} catch (error) {
|
|
2135
|
+
throw new Error(`Graph execution failed: ${error.message || "Unknown error"}`);
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
/**
|
|
2139
|
+
* Parse streaming response in SSE format
|
|
2140
|
+
*/
|
|
2141
|
+
parseStreamingResponse(text) {
|
|
2142
|
+
const lines = text.split("\n");
|
|
2143
|
+
let content = "";
|
|
2144
|
+
for (const line of lines) {
|
|
2145
|
+
if (line.startsWith("data: ")) {
|
|
2146
|
+
const dataStr = line.slice(6);
|
|
2147
|
+
if (dataStr === "[DONE]") break;
|
|
2148
|
+
try {
|
|
2149
|
+
const data = JSON.parse(dataStr);
|
|
2150
|
+
const delta = data.choices?.[0]?.delta?.content;
|
|
2151
|
+
if (delta) {
|
|
2152
|
+
content += delta;
|
|
2153
|
+
}
|
|
2154
|
+
} catch (_e) {
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
return content;
|
|
2159
|
+
}
|
|
2160
|
+
/**
|
|
2161
|
+
* Normalize input messages to the expected format
|
|
2162
|
+
*/
|
|
2163
|
+
normalizeMessages(input) {
|
|
2164
|
+
if (typeof input === "string") {
|
|
2165
|
+
return [{ role: "user", content: input }];
|
|
2166
|
+
}
|
|
2167
|
+
if (Array.isArray(input)) {
|
|
2168
|
+
return input.map((msg) => typeof msg === "string" ? { role: "user", content: msg } : msg);
|
|
2169
|
+
}
|
|
2170
|
+
return [input];
|
|
2171
|
+
}
|
|
2172
|
+
async saveToDatabase() {
|
|
2173
|
+
try {
|
|
2174
|
+
const getUrl = `${this.baseURL}/tenants/${this.tenantId}/crud/agent-graphs/${this.graphId}`;
|
|
2175
|
+
try {
|
|
2176
|
+
const getResponse = await fetch(getUrl, {
|
|
2177
|
+
method: "GET",
|
|
2178
|
+
headers: {
|
|
2179
|
+
"Content-Type": "application/json"
|
|
2180
|
+
}
|
|
2181
|
+
});
|
|
2182
|
+
if (getResponse.ok) {
|
|
2183
|
+
logger7.info({ graphId: this.graphId }, "Graph already exists in backend");
|
|
2184
|
+
return;
|
|
2185
|
+
}
|
|
2186
|
+
if (getResponse.status !== 404) {
|
|
2187
|
+
throw new Error(`HTTP ${getResponse.status}: ${getResponse.statusText}`);
|
|
2188
|
+
}
|
|
2189
|
+
} catch (error) {
|
|
2190
|
+
if (!error.message.includes("404")) {
|
|
2191
|
+
throw error;
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
logger7.info({ graphId: this.graphId }, "Creating graph in backend");
|
|
2195
|
+
const createUrl = `${this.baseURL}/tenants/${this.tenantId}/crud/agent-graphs`;
|
|
2196
|
+
const createResponse = await fetch(createUrl, {
|
|
2197
|
+
method: "POST",
|
|
2198
|
+
headers: {
|
|
2199
|
+
"Content-Type": "application/json"
|
|
2200
|
+
},
|
|
2201
|
+
body: JSON.stringify({
|
|
2202
|
+
id: this.graphId,
|
|
2203
|
+
name: this.graphName,
|
|
2204
|
+
defaultAgentId: this.defaultAgent?.getId() || "",
|
|
2205
|
+
contextConfigId: this.contextConfig?.getId(),
|
|
2206
|
+
models: this.models
|
|
2207
|
+
})
|
|
2208
|
+
});
|
|
2209
|
+
if (!createResponse.ok) {
|
|
2210
|
+
throw new Error(`HTTP ${createResponse.status}: ${createResponse.statusText}`);
|
|
2211
|
+
}
|
|
2212
|
+
const createData = await createResponse.json();
|
|
2213
|
+
this.graphId = createData.data.id;
|
|
2214
|
+
logger7.info({ graph: createData.data }, "Graph created in backend");
|
|
2215
|
+
} catch (error) {
|
|
2216
|
+
throw new Error(
|
|
2217
|
+
`Failed to save graph to database: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
2218
|
+
);
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
async saveRelations() {
|
|
2222
|
+
if (this.defaultAgent) {
|
|
2223
|
+
try {
|
|
2224
|
+
const updateUrl = `${this.baseURL}/tenants/${this.tenantId}/crud/agent-graphs/${this.graphId}`;
|
|
2225
|
+
const updateResponse = await fetch(updateUrl, {
|
|
2226
|
+
method: "PUT",
|
|
2227
|
+
headers: {
|
|
2228
|
+
"Content-Type": "application/json"
|
|
2229
|
+
},
|
|
2230
|
+
body: JSON.stringify({
|
|
2231
|
+
id: this.graphId,
|
|
2232
|
+
defaultAgentId: this.defaultAgent.getId(),
|
|
2233
|
+
contextConfigId: this.contextConfig?.getId()
|
|
2234
|
+
})
|
|
2235
|
+
});
|
|
2236
|
+
if (!updateResponse.ok) {
|
|
2237
|
+
throw new Error(`HTTP ${updateResponse.status}: ${updateResponse.statusText}`);
|
|
2238
|
+
}
|
|
2239
|
+
logger7.debug(
|
|
2240
|
+
{
|
|
2241
|
+
graphId: this.graphId,
|
|
2242
|
+
defaultAgent: this.defaultAgent.getName()
|
|
2243
|
+
},
|
|
2244
|
+
"Graph relationships configured"
|
|
2245
|
+
);
|
|
2246
|
+
} catch (error) {
|
|
2247
|
+
logger7.error(
|
|
2248
|
+
{
|
|
2249
|
+
graphId: this.graphId,
|
|
2250
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
2251
|
+
},
|
|
2252
|
+
"Failed to update graph relationships"
|
|
2253
|
+
);
|
|
2254
|
+
throw error;
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
}
|
|
2258
|
+
async createAgentRelations() {
|
|
2259
|
+
const allRelationPromises = [];
|
|
2260
|
+
for (const agent2 of this.agents) {
|
|
2261
|
+
if (this.isInternalAgent(agent2)) {
|
|
2262
|
+
const transfers = agent2.getTransfers();
|
|
2263
|
+
for (const transferAgent of transfers) {
|
|
2264
|
+
allRelationPromises.push(
|
|
2265
|
+
this.createInternalAgentRelation(agent2, transferAgent, "transfer")
|
|
2266
|
+
);
|
|
2267
|
+
}
|
|
2268
|
+
const delegates = agent2.getDelegates();
|
|
2269
|
+
for (const delegate of delegates) {
|
|
2270
|
+
if (delegate instanceof ExternalAgent) {
|
|
2271
|
+
allRelationPromises.push(this.createExternalAgentRelation(agent2, delegate, "delegate"));
|
|
2272
|
+
} else {
|
|
2273
|
+
allRelationPromises.push(
|
|
2274
|
+
this.createInternalAgentRelation(agent2, delegate, "delegate")
|
|
2275
|
+
);
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
const results = await Promise.allSettled(allRelationPromises);
|
|
2281
|
+
const errors = [];
|
|
2282
|
+
let successCount = 0;
|
|
2283
|
+
for (const result of results) {
|
|
2284
|
+
if (result.status === "fulfilled") {
|
|
2285
|
+
successCount++;
|
|
2286
|
+
} else {
|
|
2287
|
+
errors.push(result.reason);
|
|
2288
|
+
logger7.error(
|
|
2289
|
+
{
|
|
2290
|
+
error: result.reason instanceof Error ? result.reason.message : "Unknown error",
|
|
2291
|
+
graphId: this.graphId
|
|
2292
|
+
},
|
|
2293
|
+
"Failed to create agent relation"
|
|
2294
|
+
);
|
|
2295
|
+
}
|
|
2296
|
+
}
|
|
2297
|
+
logger7.info(
|
|
2298
|
+
{
|
|
2299
|
+
graphId: this.graphId,
|
|
2300
|
+
totalRelations: allRelationPromises.length,
|
|
2301
|
+
successCount,
|
|
2302
|
+
errorCount: errors.length
|
|
2303
|
+
},
|
|
2304
|
+
"Completed agent relation creation batch"
|
|
2305
|
+
);
|
|
2306
|
+
if (errors.length > 0 && successCount === 0) {
|
|
2307
|
+
throw new Error(`All ${errors.length} agent relation creations failed`);
|
|
2308
|
+
}
|
|
2309
|
+
}
|
|
2310
|
+
async createInternalAgentRelation(sourceAgent, targetAgent, relationType) {
|
|
2311
|
+
try {
|
|
2312
|
+
const response = await fetch(
|
|
2313
|
+
`${this.baseURL}/tenants/${this.tenantId}/crud/agent-relations`,
|
|
2314
|
+
{
|
|
2315
|
+
method: "POST",
|
|
2316
|
+
headers: {
|
|
2317
|
+
"Content-Type": "application/json"
|
|
2318
|
+
},
|
|
2319
|
+
body: JSON.stringify({
|
|
2320
|
+
graphId: this.graphId,
|
|
2321
|
+
sourceAgentId: sourceAgent.getId(),
|
|
2322
|
+
targetAgentId: targetAgent.getId(),
|
|
2323
|
+
relationType
|
|
2324
|
+
})
|
|
2325
|
+
}
|
|
2326
|
+
);
|
|
2327
|
+
if (!response.ok) {
|
|
2328
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
2329
|
+
if (response.status === 422 && errorText.includes("already exists")) {
|
|
2330
|
+
logger7.info(
|
|
2331
|
+
{
|
|
2332
|
+
sourceAgentId: sourceAgent.getId(),
|
|
2333
|
+
targetAgentId: targetAgent.getId(),
|
|
2334
|
+
graphId: this.graphId,
|
|
2335
|
+
relationType
|
|
2336
|
+
},
|
|
2337
|
+
`${relationType} relation already exists, skipping creation`
|
|
2338
|
+
);
|
|
2339
|
+
return;
|
|
2340
|
+
}
|
|
2341
|
+
throw new Error(`Failed to create agent relation: ${response.status} - ${errorText}`);
|
|
2342
|
+
}
|
|
2343
|
+
logger7.info(
|
|
2344
|
+
{
|
|
2345
|
+
sourceAgentId: sourceAgent.getId(),
|
|
2346
|
+
targetAgentId: targetAgent.getId(),
|
|
2347
|
+
graphId: this.graphId,
|
|
2348
|
+
relationType
|
|
2349
|
+
},
|
|
2350
|
+
`${relationType} relation created successfully`
|
|
2351
|
+
);
|
|
2352
|
+
} catch (error) {
|
|
2353
|
+
logger7.error(
|
|
2354
|
+
{
|
|
2355
|
+
sourceAgentId: sourceAgent.getId(),
|
|
2356
|
+
targetAgentId: targetAgent.getId(),
|
|
2357
|
+
graphId: this.graphId,
|
|
2358
|
+
relationType,
|
|
2359
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
2360
|
+
},
|
|
2361
|
+
`Failed to create ${relationType} relation`
|
|
2362
|
+
);
|
|
2363
|
+
throw error;
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
// enableComponentMode removed – feature deprecated
|
|
2367
|
+
async createExternalAgentRelation(sourceAgent, externalAgent2, relationType) {
|
|
2368
|
+
try {
|
|
2369
|
+
const response = await fetch(
|
|
2370
|
+
`${this.baseURL}/tenants/${this.tenantId}/crud/agent-relations`,
|
|
2371
|
+
{
|
|
2372
|
+
method: "POST",
|
|
2373
|
+
headers: {
|
|
2374
|
+
"Content-Type": "application/json"
|
|
2375
|
+
},
|
|
2376
|
+
body: JSON.stringify({
|
|
2377
|
+
graphId: this.graphId,
|
|
2378
|
+
sourceAgentId: sourceAgent.getId(),
|
|
2379
|
+
externalAgentId: externalAgent2.getId(),
|
|
2380
|
+
relationType
|
|
2381
|
+
})
|
|
2382
|
+
}
|
|
2383
|
+
);
|
|
2384
|
+
if (!response.ok) {
|
|
2385
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
2386
|
+
if (response.status === 422 && errorText.includes("already exists")) {
|
|
2387
|
+
logger7.info(
|
|
2388
|
+
{
|
|
2389
|
+
sourceAgentId: sourceAgent.getId(),
|
|
2390
|
+
externalAgentId: externalAgent2.getId(),
|
|
2391
|
+
graphId: this.graphId,
|
|
2392
|
+
relationType
|
|
2393
|
+
},
|
|
2394
|
+
`${relationType} relation already exists, skipping creation`
|
|
2395
|
+
);
|
|
2396
|
+
return;
|
|
2397
|
+
}
|
|
2398
|
+
throw new Error(
|
|
2399
|
+
`Failed to create external agent relation: ${response.status} - ${errorText}`
|
|
2400
|
+
);
|
|
2401
|
+
}
|
|
2402
|
+
logger7.info(
|
|
2403
|
+
{
|
|
2404
|
+
sourceAgentId: sourceAgent.getId(),
|
|
2405
|
+
externalAgentId: externalAgent2.getId(),
|
|
2406
|
+
graphId: this.graphId,
|
|
2407
|
+
relationType
|
|
2408
|
+
},
|
|
2409
|
+
`${relationType} relation created successfully`
|
|
2410
|
+
);
|
|
2411
|
+
} catch (error) {
|
|
2412
|
+
logger7.error(
|
|
2413
|
+
{
|
|
2414
|
+
sourceAgentId: sourceAgent.getId(),
|
|
2415
|
+
externalAgentId: externalAgent2.getId(),
|
|
2416
|
+
graphId: this.graphId,
|
|
2417
|
+
relationType,
|
|
2418
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
2419
|
+
},
|
|
2420
|
+
`Failed to create ${relationType} relation`
|
|
2421
|
+
);
|
|
2422
|
+
throw error;
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
/**
|
|
2426
|
+
* Create external agents in the database
|
|
2427
|
+
*/
|
|
2428
|
+
async createExternalAgents() {
|
|
2429
|
+
const externalAgents2 = this.agents.filter((agent2) => this.isExternalAgent(agent2));
|
|
2430
|
+
logger7.info(
|
|
2431
|
+
{
|
|
2432
|
+
graphId: this.graphId,
|
|
2433
|
+
externalAgentCount: externalAgents2.length
|
|
2434
|
+
},
|
|
2435
|
+
"Creating external agents in database"
|
|
2436
|
+
);
|
|
2437
|
+
const initPromises = externalAgents2.map(async (externalAgent2) => {
|
|
2438
|
+
try {
|
|
2439
|
+
await externalAgent2.init();
|
|
2440
|
+
logger7.debug(
|
|
2441
|
+
{
|
|
2442
|
+
externalAgentId: externalAgent2.getId(),
|
|
2443
|
+
graphId: this.graphId
|
|
2444
|
+
},
|
|
2445
|
+
"External agent created in database"
|
|
2446
|
+
);
|
|
2447
|
+
} catch (error) {
|
|
2448
|
+
logger7.error(
|
|
2449
|
+
{
|
|
2450
|
+
externalAgentId: externalAgent2.getId(),
|
|
2451
|
+
graphId: this.graphId,
|
|
2452
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
2453
|
+
},
|
|
2454
|
+
"Failed to create external agent in database"
|
|
2455
|
+
);
|
|
2456
|
+
throw error;
|
|
2457
|
+
}
|
|
2458
|
+
});
|
|
2459
|
+
try {
|
|
2460
|
+
await Promise.all(initPromises);
|
|
2461
|
+
logger7.info(
|
|
2462
|
+
{
|
|
2463
|
+
graphId: this.graphId,
|
|
2464
|
+
externalAgentCount: externalAgents2.length
|
|
2465
|
+
},
|
|
2466
|
+
"All external agents created successfully"
|
|
2467
|
+
);
|
|
2468
|
+
} catch (error) {
|
|
2469
|
+
logger7.error(
|
|
2470
|
+
{
|
|
2471
|
+
graphId: this.graphId,
|
|
2472
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
2473
|
+
},
|
|
2474
|
+
"Failed to create some external agents"
|
|
2475
|
+
);
|
|
2476
|
+
throw error;
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
2479
|
+
};
|
|
2480
|
+
var logger8 = getLogger("projectFullClient");
|
|
2481
|
+
async function createFullProjectViaAPI(tenantId, apiUrl, projectData) {
|
|
2482
|
+
logger8.info(
|
|
2483
|
+
{
|
|
2484
|
+
tenantId,
|
|
2485
|
+
projectId: projectData.id,
|
|
2486
|
+
apiUrl
|
|
2487
|
+
},
|
|
2488
|
+
"Creating full project via API"
|
|
2489
|
+
);
|
|
2490
|
+
const url = `${apiUrl}/tenants/${tenantId}/project-full`;
|
|
2491
|
+
const response = await fetch(url, {
|
|
2492
|
+
method: "POST",
|
|
2493
|
+
headers: {
|
|
2494
|
+
"Content-Type": "application/json"
|
|
2495
|
+
},
|
|
2496
|
+
body: JSON.stringify(projectData)
|
|
2497
|
+
});
|
|
2498
|
+
if (!response.ok) {
|
|
2499
|
+
const errorText = await response.text();
|
|
2500
|
+
let errorMessage = `Failed to create project: ${response.status} ${response.statusText}`;
|
|
2501
|
+
try {
|
|
2502
|
+
const errorJson = JSON.parse(errorText);
|
|
2503
|
+
if (errorJson.error) {
|
|
2504
|
+
errorMessage = errorJson.error;
|
|
2505
|
+
}
|
|
2506
|
+
} catch {
|
|
2507
|
+
if (errorText) {
|
|
2508
|
+
errorMessage = errorText;
|
|
2509
|
+
}
|
|
2510
|
+
}
|
|
2511
|
+
logger8.error(
|
|
2512
|
+
{
|
|
2513
|
+
status: response.status,
|
|
2514
|
+
error: errorMessage
|
|
2515
|
+
},
|
|
2516
|
+
"Failed to create project via API"
|
|
2517
|
+
);
|
|
2518
|
+
throw new Error(errorMessage);
|
|
2519
|
+
}
|
|
2520
|
+
const result = await response.json();
|
|
2521
|
+
logger8.info(
|
|
2522
|
+
{
|
|
2523
|
+
projectId: projectData.id
|
|
2524
|
+
},
|
|
2525
|
+
"Successfully created project via API"
|
|
2526
|
+
);
|
|
2527
|
+
return result.data;
|
|
2528
|
+
}
|
|
2529
|
+
async function updateFullProjectViaAPI(tenantId, apiUrl, projectId, projectData) {
|
|
2530
|
+
logger8.info(
|
|
2531
|
+
{
|
|
2532
|
+
tenantId,
|
|
2533
|
+
projectId,
|
|
2534
|
+
apiUrl
|
|
2535
|
+
},
|
|
2536
|
+
"Updating full project via API"
|
|
2537
|
+
);
|
|
2538
|
+
const url = `${apiUrl}/tenants/${tenantId}/project-full/${projectId}`;
|
|
2539
|
+
const response = await fetch(url, {
|
|
2540
|
+
method: "PUT",
|
|
2541
|
+
headers: {
|
|
2542
|
+
"Content-Type": "application/json"
|
|
2543
|
+
},
|
|
2544
|
+
body: JSON.stringify(projectData)
|
|
2545
|
+
});
|
|
2546
|
+
if (!response.ok) {
|
|
2547
|
+
const errorText = await response.text();
|
|
2548
|
+
let errorMessage = `Failed to update project: ${response.status} ${response.statusText}`;
|
|
2549
|
+
try {
|
|
2550
|
+
const errorJson = JSON.parse(errorText);
|
|
2551
|
+
if (errorJson.error) {
|
|
2552
|
+
errorMessage = errorJson.error;
|
|
2553
|
+
}
|
|
2554
|
+
} catch {
|
|
2555
|
+
if (errorText) {
|
|
2556
|
+
errorMessage = errorText;
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
logger8.error(
|
|
2560
|
+
{
|
|
2561
|
+
status: response.status,
|
|
2562
|
+
error: errorMessage
|
|
2563
|
+
},
|
|
2564
|
+
"Failed to update project via API"
|
|
2565
|
+
);
|
|
2566
|
+
throw new Error(errorMessage);
|
|
2567
|
+
}
|
|
2568
|
+
const result = await response.json();
|
|
2569
|
+
logger8.info(
|
|
2570
|
+
{
|
|
2571
|
+
projectId
|
|
2572
|
+
},
|
|
2573
|
+
"Successfully updated project via API"
|
|
2574
|
+
);
|
|
2575
|
+
return result.data;
|
|
2576
|
+
}
|
|
2577
|
+
async function getFullProjectViaAPI(tenantId, apiUrl, projectId) {
|
|
2578
|
+
logger8.info(
|
|
2579
|
+
{
|
|
2580
|
+
tenantId,
|
|
2581
|
+
projectId,
|
|
2582
|
+
apiUrl
|
|
2583
|
+
},
|
|
2584
|
+
"Getting full project via API"
|
|
2585
|
+
);
|
|
2586
|
+
const url = `${apiUrl}/tenants/${tenantId}/project-full/${projectId}`;
|
|
2587
|
+
const response = await fetch(url, {
|
|
2588
|
+
method: "GET",
|
|
2589
|
+
headers: {
|
|
2590
|
+
"Content-Type": "application/json"
|
|
2591
|
+
}
|
|
2592
|
+
});
|
|
2593
|
+
if (!response.ok) {
|
|
2594
|
+
if (response.status === 404) {
|
|
2595
|
+
logger8.info(
|
|
2596
|
+
{
|
|
2597
|
+
projectId
|
|
2598
|
+
},
|
|
2599
|
+
"Project not found"
|
|
2600
|
+
);
|
|
2601
|
+
return null;
|
|
2602
|
+
}
|
|
2603
|
+
const errorText = await response.text();
|
|
2604
|
+
let errorMessage = `Failed to get project: ${response.status} ${response.statusText}`;
|
|
2605
|
+
try {
|
|
2606
|
+
const errorJson = JSON.parse(errorText);
|
|
2607
|
+
if (errorJson.error) {
|
|
2608
|
+
errorMessage = errorJson.error;
|
|
2609
|
+
}
|
|
2610
|
+
} catch {
|
|
2611
|
+
if (errorText) {
|
|
2612
|
+
errorMessage = errorText;
|
|
2613
|
+
}
|
|
2614
|
+
}
|
|
2615
|
+
logger8.error(
|
|
2616
|
+
{
|
|
2617
|
+
status: response.status,
|
|
2618
|
+
error: errorMessage
|
|
2619
|
+
},
|
|
2620
|
+
"Failed to get project via API"
|
|
2621
|
+
);
|
|
2622
|
+
throw new Error(errorMessage);
|
|
2623
|
+
}
|
|
2624
|
+
const result = await response.json();
|
|
2625
|
+
logger8.info(
|
|
2626
|
+
{
|
|
2627
|
+
projectId
|
|
2628
|
+
},
|
|
2629
|
+
"Successfully retrieved project via API"
|
|
2630
|
+
);
|
|
2631
|
+
return result.data;
|
|
2632
|
+
}
|
|
2633
|
+
async function deleteFullProjectViaAPI(tenantId, apiUrl, projectId) {
|
|
2634
|
+
logger8.info(
|
|
2635
|
+
{
|
|
2636
|
+
tenantId,
|
|
2637
|
+
projectId,
|
|
2638
|
+
apiUrl
|
|
2639
|
+
},
|
|
2640
|
+
"Deleting full project via API"
|
|
2641
|
+
);
|
|
2642
|
+
const url = `${apiUrl}/tenants/${tenantId}/project-full/${projectId}`;
|
|
2643
|
+
const response = await fetch(url, {
|
|
2644
|
+
method: "DELETE",
|
|
2645
|
+
headers: {
|
|
2646
|
+
"Content-Type": "application/json"
|
|
2647
|
+
}
|
|
2648
|
+
});
|
|
2649
|
+
if (!response.ok) {
|
|
2650
|
+
const errorText = await response.text();
|
|
2651
|
+
let errorMessage = `Failed to delete project: ${response.status} ${response.statusText}`;
|
|
2652
|
+
try {
|
|
2653
|
+
const errorJson = JSON.parse(errorText);
|
|
2654
|
+
if (errorJson.error) {
|
|
2655
|
+
errorMessage = errorJson.error;
|
|
2656
|
+
}
|
|
2657
|
+
} catch {
|
|
2658
|
+
if (errorText) {
|
|
2659
|
+
errorMessage = errorText;
|
|
2660
|
+
}
|
|
2661
|
+
}
|
|
2662
|
+
logger8.error(
|
|
2663
|
+
{
|
|
2664
|
+
status: response.status,
|
|
2665
|
+
error: errorMessage
|
|
2666
|
+
},
|
|
2667
|
+
"Failed to delete project via API"
|
|
2668
|
+
);
|
|
2669
|
+
throw new Error(errorMessage);
|
|
2670
|
+
}
|
|
2671
|
+
logger8.info(
|
|
2672
|
+
{
|
|
2673
|
+
projectId
|
|
2674
|
+
},
|
|
2675
|
+
"Successfully deleted project via API"
|
|
2676
|
+
);
|
|
2677
|
+
}
|
|
2678
|
+
|
|
2679
|
+
// src/project.ts
|
|
2680
|
+
var logger9 = getLogger("project");
|
|
2681
|
+
var Project = class {
|
|
2682
|
+
constructor(config) {
|
|
2683
|
+
__publicField(this, "projectId");
|
|
2684
|
+
__publicField(this, "projectName");
|
|
2685
|
+
__publicField(this, "projectDescription");
|
|
2686
|
+
__publicField(this, "tenantId");
|
|
2687
|
+
__publicField(this, "baseURL");
|
|
2688
|
+
__publicField(this, "initialized", false);
|
|
2689
|
+
__publicField(this, "models");
|
|
2690
|
+
__publicField(this, "stopWhen");
|
|
2691
|
+
__publicField(this, "graphs", []);
|
|
2692
|
+
__publicField(this, "graphMap", /* @__PURE__ */ new Map());
|
|
2693
|
+
this.projectId = config.id;
|
|
2694
|
+
this.projectName = config.name;
|
|
2695
|
+
this.projectDescription = config.description;
|
|
2696
|
+
this.tenantId = config.tenantId || "default";
|
|
2697
|
+
this.baseURL = process.env.INKEEP_API_URL || "http://localhost:3002";
|
|
2698
|
+
this.models = config.models;
|
|
2699
|
+
this.stopWhen = config.stopWhen;
|
|
2700
|
+
if (config.graphs) {
|
|
2701
|
+
this.graphs = config.graphs();
|
|
2702
|
+
this.graphMap = new Map(this.graphs.map((graph) => [graph.getId(), graph]));
|
|
2703
|
+
for (const graph of this.graphs) {
|
|
2704
|
+
graph.setConfig(this.tenantId, this.projectId, this.baseURL);
|
|
2705
|
+
}
|
|
2706
|
+
}
|
|
2707
|
+
logger9.info(
|
|
2708
|
+
{
|
|
2709
|
+
projectId: this.projectId,
|
|
2710
|
+
tenantId: this.tenantId,
|
|
2711
|
+
graphCount: this.graphs.length
|
|
2712
|
+
},
|
|
2713
|
+
"Project created"
|
|
2714
|
+
);
|
|
2715
|
+
}
|
|
2716
|
+
/**
|
|
2717
|
+
* Set or update the configuration (tenantId and apiUrl)
|
|
2718
|
+
* This is used by the CLI to inject configuration from inkeep.config.ts
|
|
2719
|
+
*/
|
|
2720
|
+
setConfig(tenantId, apiUrl) {
|
|
2721
|
+
if (this.initialized) {
|
|
2722
|
+
throw new Error("Cannot set config after project has been initialized");
|
|
2723
|
+
}
|
|
2724
|
+
this.tenantId = tenantId;
|
|
2725
|
+
this.baseURL = apiUrl;
|
|
2726
|
+
for (const graph of this.graphs) {
|
|
2727
|
+
graph.setConfig(tenantId, this.projectId, apiUrl);
|
|
2728
|
+
}
|
|
2729
|
+
logger9.info(
|
|
2730
|
+
{
|
|
2731
|
+
projectId: this.projectId,
|
|
2732
|
+
tenantId: this.tenantId,
|
|
2733
|
+
apiUrl: this.baseURL
|
|
2734
|
+
},
|
|
2735
|
+
"Project configuration updated"
|
|
2736
|
+
);
|
|
2737
|
+
}
|
|
2738
|
+
/**
|
|
2739
|
+
* Initialize the project and create/update it in the backend using full project approach
|
|
2740
|
+
*/
|
|
2741
|
+
async init() {
|
|
2742
|
+
if (this.initialized) {
|
|
2743
|
+
logger9.info({ projectId: this.projectId }, "Project already initialized");
|
|
2744
|
+
return;
|
|
2745
|
+
}
|
|
2746
|
+
logger9.info(
|
|
2747
|
+
{
|
|
2748
|
+
projectId: this.projectId,
|
|
2749
|
+
tenantId: this.tenantId,
|
|
2750
|
+
graphCount: this.graphs.length
|
|
2751
|
+
},
|
|
2752
|
+
"Initializing project using full project endpoint"
|
|
2753
|
+
);
|
|
2754
|
+
try {
|
|
2755
|
+
const initPromises = this.graphs.map(async (graph) => {
|
|
2756
|
+
try {
|
|
2757
|
+
await graph.init();
|
|
2758
|
+
logger9.debug(
|
|
2759
|
+
{
|
|
2760
|
+
projectId: this.projectId,
|
|
2761
|
+
graphId: graph.getId()
|
|
2762
|
+
},
|
|
2763
|
+
"Graph initialized in project"
|
|
2764
|
+
);
|
|
2765
|
+
} catch (error) {
|
|
2766
|
+
logger9.error(
|
|
2767
|
+
{
|
|
2768
|
+
projectId: this.projectId,
|
|
2769
|
+
graphId: graph.getId(),
|
|
2770
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
2771
|
+
},
|
|
2772
|
+
"Failed to initialize graph in project"
|
|
2773
|
+
);
|
|
2774
|
+
throw error;
|
|
2775
|
+
}
|
|
2776
|
+
});
|
|
2777
|
+
await Promise.all(initPromises);
|
|
2778
|
+
const projectDefinition = await this.toFullProjectDefinition();
|
|
2779
|
+
logger9.info(
|
|
2780
|
+
{
|
|
2781
|
+
projectId: this.projectId,
|
|
2782
|
+
mode: "api-client",
|
|
2783
|
+
apiUrl: this.baseURL
|
|
2784
|
+
},
|
|
2785
|
+
"Using API client to create/update full project"
|
|
2786
|
+
);
|
|
2787
|
+
const createdProject = await updateFullProjectViaAPI(
|
|
2788
|
+
this.tenantId,
|
|
2789
|
+
this.baseURL,
|
|
2790
|
+
this.projectId,
|
|
2791
|
+
projectDefinition
|
|
2792
|
+
);
|
|
2793
|
+
this.initialized = true;
|
|
2794
|
+
logger9.info(
|
|
2795
|
+
{
|
|
2796
|
+
projectId: this.projectId,
|
|
2797
|
+
tenantId: this.tenantId,
|
|
2798
|
+
graphCount: Object.keys(createdProject.graphs || {}).length
|
|
2799
|
+
},
|
|
2800
|
+
"Project initialized successfully using full project endpoint"
|
|
2801
|
+
);
|
|
2802
|
+
} catch (error) {
|
|
2803
|
+
logger9.error(
|
|
2804
|
+
{
|
|
2805
|
+
projectId: this.projectId,
|
|
2806
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
2807
|
+
},
|
|
2808
|
+
"Failed to initialize project using full project endpoint"
|
|
2809
|
+
);
|
|
2810
|
+
throw error;
|
|
2811
|
+
}
|
|
2812
|
+
}
|
|
2813
|
+
/**
|
|
2814
|
+
* Get the project ID
|
|
2815
|
+
*/
|
|
2816
|
+
getId() {
|
|
2817
|
+
return this.projectId;
|
|
2818
|
+
}
|
|
2819
|
+
/**
|
|
2820
|
+
* Get the project name
|
|
2821
|
+
*/
|
|
2822
|
+
getName() {
|
|
2823
|
+
return this.projectName;
|
|
2824
|
+
}
|
|
2825
|
+
/**
|
|
2826
|
+
* Get the project description
|
|
2827
|
+
*/
|
|
2828
|
+
getDescription() {
|
|
2829
|
+
return this.projectDescription;
|
|
2830
|
+
}
|
|
2831
|
+
/**
|
|
2832
|
+
* Get the tenant ID
|
|
2833
|
+
*/
|
|
2834
|
+
getTenantId() {
|
|
2835
|
+
return this.tenantId;
|
|
2836
|
+
}
|
|
2837
|
+
/**
|
|
2838
|
+
* Get the project's model configuration
|
|
2839
|
+
*/
|
|
2840
|
+
getModels() {
|
|
2841
|
+
return this.models;
|
|
2842
|
+
}
|
|
2843
|
+
/**
|
|
2844
|
+
* Set the project's model configuration
|
|
2845
|
+
*/
|
|
2846
|
+
setModels(models) {
|
|
2847
|
+
this.models = models;
|
|
2848
|
+
}
|
|
2849
|
+
/**
|
|
2850
|
+
* Get the project's stopWhen configuration
|
|
2851
|
+
*/
|
|
2852
|
+
getStopWhen() {
|
|
2853
|
+
return this.stopWhen;
|
|
2854
|
+
}
|
|
2855
|
+
/**
|
|
2856
|
+
* Set the project's stopWhen configuration
|
|
2857
|
+
*/
|
|
2858
|
+
setStopWhen(stopWhen) {
|
|
2859
|
+
this.stopWhen = stopWhen;
|
|
2860
|
+
}
|
|
2861
|
+
/**
|
|
2862
|
+
* Get all graphs in the project
|
|
2863
|
+
*/
|
|
2864
|
+
getGraphs() {
|
|
2865
|
+
return this.graphs;
|
|
2866
|
+
}
|
|
2867
|
+
/**
|
|
2868
|
+
* Get a graph by ID
|
|
2869
|
+
*/
|
|
2870
|
+
getGraph(id) {
|
|
2871
|
+
return this.graphMap.get(id);
|
|
2872
|
+
}
|
|
2873
|
+
/**
|
|
2874
|
+
* Add a graph to the project
|
|
2875
|
+
*/
|
|
2876
|
+
addGraph(graph) {
|
|
2877
|
+
this.graphs.push(graph);
|
|
2878
|
+
this.graphMap.set(graph.getId(), graph);
|
|
2879
|
+
graph.setConfig(this.tenantId, this.projectId, this.baseURL);
|
|
2880
|
+
logger9.info(
|
|
2881
|
+
{
|
|
2882
|
+
projectId: this.projectId,
|
|
2883
|
+
graphId: graph.getId()
|
|
2884
|
+
},
|
|
2885
|
+
"Graph added to project"
|
|
2886
|
+
);
|
|
2887
|
+
}
|
|
2888
|
+
/**
|
|
2889
|
+
* Remove a graph from the project
|
|
2890
|
+
*/
|
|
2891
|
+
removeGraph(id) {
|
|
2892
|
+
const graphToRemove = this.graphMap.get(id);
|
|
2893
|
+
if (graphToRemove) {
|
|
2894
|
+
this.graphMap.delete(id);
|
|
2895
|
+
this.graphs = this.graphs.filter((graph) => graph.getId() !== id);
|
|
2896
|
+
logger9.info(
|
|
2897
|
+
{
|
|
2898
|
+
projectId: this.projectId,
|
|
2899
|
+
graphId: id
|
|
2900
|
+
},
|
|
2901
|
+
"Graph removed from project"
|
|
2902
|
+
);
|
|
2903
|
+
return true;
|
|
2904
|
+
}
|
|
2905
|
+
return false;
|
|
2906
|
+
}
|
|
2907
|
+
/**
|
|
2908
|
+
* Get project statistics
|
|
2909
|
+
*/
|
|
2910
|
+
getStats() {
|
|
2911
|
+
return {
|
|
2912
|
+
projectId: this.projectId,
|
|
2913
|
+
tenantId: this.tenantId,
|
|
2914
|
+
graphCount: this.graphs.length,
|
|
2915
|
+
initialized: this.initialized
|
|
2916
|
+
};
|
|
2917
|
+
}
|
|
2918
|
+
/**
|
|
2919
|
+
* Validate the project configuration
|
|
2920
|
+
*/
|
|
2921
|
+
validate() {
|
|
2922
|
+
const errors = [];
|
|
2923
|
+
if (!this.projectId) {
|
|
2924
|
+
errors.push("Project must have an ID");
|
|
2925
|
+
}
|
|
2926
|
+
if (!this.projectName) {
|
|
2927
|
+
errors.push("Project must have a name");
|
|
2928
|
+
}
|
|
2929
|
+
const graphIds = /* @__PURE__ */ new Set();
|
|
2930
|
+
for (const graph of this.graphs) {
|
|
2931
|
+
const id = graph.getId();
|
|
2932
|
+
if (graphIds.has(id)) {
|
|
2933
|
+
errors.push(`Duplicate graph ID: ${id}`);
|
|
2934
|
+
}
|
|
2935
|
+
graphIds.add(id);
|
|
2936
|
+
}
|
|
2937
|
+
for (const graph of this.graphs) {
|
|
2938
|
+
const graphValidation = graph.validate();
|
|
2939
|
+
if (!graphValidation.valid) {
|
|
2940
|
+
errors.push(...graphValidation.errors.map((error) => `Graph '${graph.getId()}': ${error}`));
|
|
2941
|
+
}
|
|
2942
|
+
}
|
|
2943
|
+
return {
|
|
2944
|
+
valid: errors.length === 0,
|
|
2945
|
+
errors
|
|
2946
|
+
};
|
|
2947
|
+
}
|
|
2948
|
+
/**
|
|
2949
|
+
* Convert the Project to FullProjectDefinition format
|
|
2950
|
+
*/
|
|
2951
|
+
async toFullProjectDefinition() {
|
|
2952
|
+
const graphsObject = {};
|
|
2953
|
+
for (const graph of this.graphs) {
|
|
2954
|
+
const graphDefinition = await graph.toFullGraphDefinition();
|
|
2955
|
+
graphsObject[graph.getId()] = graphDefinition;
|
|
2956
|
+
}
|
|
2957
|
+
return {
|
|
2958
|
+
id: this.projectId,
|
|
2959
|
+
name: this.projectName,
|
|
2960
|
+
description: this.projectDescription || "",
|
|
2961
|
+
models: this.models,
|
|
2962
|
+
stopWhen: this.stopWhen,
|
|
2963
|
+
graphs: graphsObject,
|
|
2964
|
+
tools: {},
|
|
2965
|
+
// Empty tools object as SDK doesn't manage tools directly yet
|
|
2966
|
+
credentialReferences: void 0,
|
|
2967
|
+
// Projects don't directly hold credentials yet
|
|
2968
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2969
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2970
|
+
};
|
|
2971
|
+
}
|
|
2972
|
+
/**
|
|
2973
|
+
* Convert project configuration to API format
|
|
2974
|
+
*/
|
|
2975
|
+
toApiFormat() {
|
|
2976
|
+
return {
|
|
2977
|
+
id: this.projectId,
|
|
2978
|
+
name: this.projectName,
|
|
2979
|
+
description: this.projectDescription || "",
|
|
2980
|
+
models: this.models,
|
|
2981
|
+
stopWhen: this.stopWhen
|
|
2982
|
+
};
|
|
2983
|
+
}
|
|
2984
|
+
};
|
|
2985
|
+
|
|
2986
|
+
// src/utils/generateIdFromName.ts
|
|
2987
|
+
function generateIdFromName3(name) {
|
|
2988
|
+
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
2989
|
+
}
|
|
2990
|
+
|
|
2991
|
+
// src/builderFunctions.ts
|
|
2992
|
+
function agentGraph(config) {
|
|
2993
|
+
return new AgentGraph(config);
|
|
2994
|
+
}
|
|
2995
|
+
function project(config) {
|
|
2996
|
+
return new Project(config);
|
|
2997
|
+
}
|
|
2998
|
+
function agent(config) {
|
|
2999
|
+
if (!config.id) {
|
|
3000
|
+
throw new Error(
|
|
3001
|
+
"Agent ID is required. Agents must have stable IDs for consistency across deployments."
|
|
3002
|
+
);
|
|
3003
|
+
}
|
|
3004
|
+
return new Agent(config);
|
|
3005
|
+
}
|
|
3006
|
+
function credential(config) {
|
|
3007
|
+
return CredentialReferenceApiInsertSchema.parse(config);
|
|
3008
|
+
}
|
|
3009
|
+
function mcpServer(config) {
|
|
3010
|
+
if (!config.serverUrl) {
|
|
3011
|
+
throw new Error("MCP server requires a serverUrl");
|
|
3012
|
+
}
|
|
3013
|
+
const id = config.id || generateIdFromName3(config.name);
|
|
3014
|
+
return new Tool({
|
|
3015
|
+
id,
|
|
3016
|
+
name: config.name,
|
|
3017
|
+
description: config.description,
|
|
3018
|
+
serverUrl: config.serverUrl,
|
|
3019
|
+
tenantId: config.tenantId,
|
|
3020
|
+
credential: config.credential,
|
|
3021
|
+
activeTools: config.activeTools,
|
|
3022
|
+
headers: config.headers,
|
|
3023
|
+
imageUrl: config.imageUrl,
|
|
3024
|
+
transport: config.transport ? { type: config.transport } : void 0
|
|
3025
|
+
});
|
|
3026
|
+
}
|
|
3027
|
+
function mcpTool(config) {
|
|
3028
|
+
const configWithId = {
|
|
3029
|
+
...config,
|
|
3030
|
+
id: config.id || generateIdFromName3(config.name)
|
|
3031
|
+
};
|
|
3032
|
+
const validatedConfig = MCPToolConfigSchema.parse(configWithId);
|
|
3033
|
+
return new Tool(validatedConfig);
|
|
3034
|
+
}
|
|
3035
|
+
function artifactComponent(config) {
|
|
3036
|
+
return new ArtifactComponent({
|
|
3037
|
+
...config,
|
|
3038
|
+
tenantId: config.tenantId || "default",
|
|
3039
|
+
projectId: config.projectId || "default"
|
|
3040
|
+
});
|
|
3041
|
+
}
|
|
3042
|
+
function dataComponent(config) {
|
|
3043
|
+
return new DataComponent({
|
|
3044
|
+
...config,
|
|
3045
|
+
tenantId: config.tenantId || "default",
|
|
3046
|
+
projectId: config.projectId || "default"
|
|
3047
|
+
});
|
|
3048
|
+
}
|
|
3049
|
+
function agentMcp(config) {
|
|
3050
|
+
return {
|
|
3051
|
+
server: config.server,
|
|
3052
|
+
selectedTools: config.selectedTools
|
|
3053
|
+
};
|
|
3054
|
+
}
|
|
3055
|
+
|
|
3056
|
+
// src/utils/validateFunction.ts
|
|
3057
|
+
function validateFunction(value, name) {
|
|
3058
|
+
if (typeof value !== "function") {
|
|
3059
|
+
throw new Error(`${name} must be a function`);
|
|
3060
|
+
}
|
|
3061
|
+
}
|
|
3062
|
+
|
|
3063
|
+
// src/builders.ts
|
|
3064
|
+
var TransferConfigSchema = z.object({
|
|
3065
|
+
agent: z.instanceof(Agent),
|
|
3066
|
+
description: z.string().optional()
|
|
3067
|
+
});
|
|
3068
|
+
function transfer(targetAgent, description, condition) {
|
|
3069
|
+
if (condition !== void 0) {
|
|
3070
|
+
validateFunction(condition, "condition");
|
|
3071
|
+
}
|
|
3072
|
+
const config = {
|
|
3073
|
+
agent: targetAgent,
|
|
3074
|
+
description: description || `Hand off to ${targetAgent.getName()}`,
|
|
3075
|
+
condition
|
|
3076
|
+
};
|
|
3077
|
+
TransferConfigSchema.parse({
|
|
3078
|
+
agent: config.agent,
|
|
3079
|
+
description: config.description
|
|
3080
|
+
});
|
|
3081
|
+
return config;
|
|
3082
|
+
}
|
|
3083
|
+
|
|
3084
|
+
// src/environment-settings.ts
|
|
3085
|
+
function createEnvironmentSettings(environments) {
|
|
3086
|
+
return {
|
|
3087
|
+
getEnvironmentSetting: async (key) => {
|
|
3088
|
+
const currentEnv = process.env.INKEEP_ENV || "development";
|
|
3089
|
+
const env = environments[currentEnv];
|
|
3090
|
+
if (!env) {
|
|
3091
|
+
throw new Error(
|
|
3092
|
+
`Environment '${currentEnv}' not found. Available: ${Object.keys(environments).join(", ")}`
|
|
3093
|
+
);
|
|
3094
|
+
}
|
|
3095
|
+
const credential2 = env.credentials?.[key];
|
|
3096
|
+
if (!credential2) {
|
|
3097
|
+
throw new Error(`Credential '${String(key)}' not found in environment '${currentEnv}'`);
|
|
3098
|
+
}
|
|
3099
|
+
return credential2;
|
|
3100
|
+
}
|
|
3101
|
+
};
|
|
3102
|
+
}
|
|
3103
|
+
function registerEnvironmentSettings(config) {
|
|
3104
|
+
return config;
|
|
3105
|
+
}
|
|
3106
|
+
z.object({
|
|
3107
|
+
model: z.string().optional(),
|
|
3108
|
+
providerOptions: z.record(z.string(), z.record(z.string(), z.unknown())).optional()
|
|
3109
|
+
});
|
|
3110
|
+
var AgentError = class extends Error {
|
|
3111
|
+
constructor(message, code, details) {
|
|
3112
|
+
super(message);
|
|
3113
|
+
this.code = code;
|
|
3114
|
+
this.details = details;
|
|
3115
|
+
this.name = "AgentError";
|
|
3116
|
+
}
|
|
3117
|
+
};
|
|
3118
|
+
var MaxTurnsExceededError = class extends AgentError {
|
|
3119
|
+
constructor(maxTurns) {
|
|
3120
|
+
super(`Maximum turns (${maxTurns}) exceeded`);
|
|
3121
|
+
this.code = "MAX_TURNS_EXCEEDED";
|
|
3122
|
+
}
|
|
3123
|
+
};
|
|
3124
|
+
|
|
3125
|
+
// src/runner.ts
|
|
3126
|
+
var logger10 = getLogger("runner");
|
|
3127
|
+
var Runner = class _Runner {
|
|
3128
|
+
/**
|
|
3129
|
+
* Run a graph until completion, handling transfers and tool calls
|
|
3130
|
+
* Similar to OpenAI's Runner.run() pattern
|
|
3131
|
+
* NOTE: This now requires a graph instead of an agent
|
|
3132
|
+
*/
|
|
3133
|
+
static async run(graph, messages, options) {
|
|
3134
|
+
const maxTurns = options?.maxTurns || 10;
|
|
3135
|
+
let turnCount = 0;
|
|
3136
|
+
const messageHistory = _Runner.normalizeToMessageHistory(messages);
|
|
3137
|
+
const allToolCalls = [];
|
|
3138
|
+
logger10.info(
|
|
3139
|
+
{
|
|
3140
|
+
graphId: graph.getId(),
|
|
3141
|
+
defaultAgent: graph.getDefaultAgent()?.getName(),
|
|
3142
|
+
maxTurns,
|
|
3143
|
+
initialMessageCount: messageHistory.length
|
|
3144
|
+
},
|
|
3145
|
+
"Starting graph run"
|
|
3146
|
+
);
|
|
3147
|
+
while (turnCount < maxTurns) {
|
|
3148
|
+
logger10.debug(
|
|
3149
|
+
{
|
|
3150
|
+
graphId: graph.getId(),
|
|
3151
|
+
turnCount,
|
|
3152
|
+
messageHistoryLength: messageHistory.length
|
|
3153
|
+
},
|
|
3154
|
+
"Starting turn"
|
|
3155
|
+
);
|
|
3156
|
+
const response = await graph.generate(messageHistory, options);
|
|
3157
|
+
turnCount++;
|
|
3158
|
+
logger10.info(
|
|
3159
|
+
{
|
|
3160
|
+
graphId: graph.getId(),
|
|
3161
|
+
turnCount,
|
|
3162
|
+
responseLength: response.length
|
|
3163
|
+
},
|
|
3164
|
+
"Graph generation completed"
|
|
3165
|
+
);
|
|
3166
|
+
return {
|
|
3167
|
+
finalOutput: response,
|
|
3168
|
+
agent: graph.getDefaultAgent() || {},
|
|
3169
|
+
turnCount,
|
|
3170
|
+
usage: { inputTokens: 0, outputTokens: 0 },
|
|
3171
|
+
metadata: {
|
|
3172
|
+
toolCalls: allToolCalls,
|
|
3173
|
+
transfers: []
|
|
3174
|
+
// Graph handles transfers internally
|
|
3175
|
+
}
|
|
3176
|
+
};
|
|
3177
|
+
}
|
|
3178
|
+
logger10.error(
|
|
3179
|
+
{
|
|
3180
|
+
graphId: graph.getId(),
|
|
3181
|
+
maxTurns,
|
|
3182
|
+
finalTurnCount: turnCount
|
|
3183
|
+
},
|
|
3184
|
+
"Maximum turns exceeded"
|
|
3185
|
+
);
|
|
3186
|
+
throw new MaxTurnsExceededError(maxTurns);
|
|
3187
|
+
}
|
|
3188
|
+
/**
|
|
3189
|
+
* Stream a graph's response
|
|
3190
|
+
*/
|
|
3191
|
+
static async stream(graph, messages, options) {
|
|
3192
|
+
logger10.info(
|
|
3193
|
+
{
|
|
3194
|
+
graphId: graph.getId(),
|
|
3195
|
+
defaultAgent: graph.getDefaultAgent()?.getName()
|
|
3196
|
+
},
|
|
3197
|
+
"Starting graph stream"
|
|
3198
|
+
);
|
|
3199
|
+
return graph.stream(messages, options);
|
|
3200
|
+
}
|
|
3201
|
+
/**
|
|
3202
|
+
* Execute multiple graphs in parallel and return the first successful result
|
|
3203
|
+
*/
|
|
3204
|
+
static async raceGraphs(graphs, messages, options) {
|
|
3205
|
+
if (graphs.length === 0) {
|
|
3206
|
+
throw new Error("No graphs provided for race");
|
|
3207
|
+
}
|
|
3208
|
+
logger10.info(
|
|
3209
|
+
{
|
|
3210
|
+
graphCount: graphs.length,
|
|
3211
|
+
graphIds: graphs.map((g) => g.getId())
|
|
3212
|
+
},
|
|
3213
|
+
"Starting graph race"
|
|
3214
|
+
);
|
|
3215
|
+
const promises = graphs.map(async (graph, index) => {
|
|
3216
|
+
try {
|
|
3217
|
+
const result2 = await _Runner.run(graph, messages, options);
|
|
3218
|
+
return { ...result2, raceIndex: index };
|
|
3219
|
+
} catch (error) {
|
|
3220
|
+
logger10.error(
|
|
3221
|
+
{
|
|
3222
|
+
graphId: graph.getId(),
|
|
3223
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
3224
|
+
},
|
|
3225
|
+
"Graph failed in race"
|
|
3226
|
+
);
|
|
3227
|
+
throw error;
|
|
3228
|
+
}
|
|
3229
|
+
});
|
|
3230
|
+
const result = await Promise.race(promises);
|
|
3231
|
+
logger10.info(
|
|
3232
|
+
{
|
|
3233
|
+
winningGraphId: result.graphId || "unknown",
|
|
3234
|
+
raceIndex: result.raceIndex
|
|
3235
|
+
},
|
|
3236
|
+
"Graph race completed"
|
|
3237
|
+
);
|
|
3238
|
+
return result;
|
|
3239
|
+
}
|
|
3240
|
+
// Private helper methods
|
|
3241
|
+
static normalizeToMessageHistory(messages) {
|
|
3242
|
+
if (typeof messages === "string") {
|
|
3243
|
+
return [{ role: "user", content: messages }];
|
|
3244
|
+
}
|
|
3245
|
+
if (Array.isArray(messages)) {
|
|
3246
|
+
return messages.map(
|
|
3247
|
+
(msg) => typeof msg === "string" ? { role: "user", content: msg } : msg
|
|
3248
|
+
);
|
|
3249
|
+
}
|
|
3250
|
+
return [messages];
|
|
3251
|
+
}
|
|
3252
|
+
/**
|
|
3253
|
+
* Validate graph configuration before running
|
|
3254
|
+
*/
|
|
3255
|
+
static validateGraph(graph) {
|
|
3256
|
+
const errors = [];
|
|
3257
|
+
if (!graph.getId()) {
|
|
3258
|
+
errors.push("Graph ID is required");
|
|
3259
|
+
}
|
|
3260
|
+
const defaultAgent = graph.getDefaultAgent();
|
|
3261
|
+
if (!defaultAgent) {
|
|
3262
|
+
errors.push("Default agent is required");
|
|
3263
|
+
} else {
|
|
3264
|
+
if (!defaultAgent.getName()) {
|
|
3265
|
+
errors.push("Default agent name is required");
|
|
3266
|
+
}
|
|
3267
|
+
if (!defaultAgent.getInstructions()) {
|
|
3268
|
+
errors.push("Default agent instructions are required");
|
|
3269
|
+
}
|
|
3270
|
+
}
|
|
3271
|
+
const agents = graph.getAgents();
|
|
3272
|
+
if (agents.length === 0) {
|
|
3273
|
+
errors.push("Graph must contain at least one agent");
|
|
3274
|
+
}
|
|
3275
|
+
for (const agent2 of agents) {
|
|
3276
|
+
if (!agent2.getName()) {
|
|
3277
|
+
errors.push(`Agent missing name`);
|
|
3278
|
+
}
|
|
3279
|
+
}
|
|
3280
|
+
return {
|
|
3281
|
+
valid: errors.length === 0,
|
|
3282
|
+
errors
|
|
3283
|
+
};
|
|
3284
|
+
}
|
|
3285
|
+
/**
|
|
3286
|
+
* Get execution statistics for a graph
|
|
3287
|
+
*/
|
|
3288
|
+
static async getExecutionStats(graph, messages, options) {
|
|
3289
|
+
const agents = graph.getAgents();
|
|
3290
|
+
const defaultAgent = graph.getDefaultAgent();
|
|
3291
|
+
const messageCount = Array.isArray(messages) ? messages.length : 1;
|
|
3292
|
+
return {
|
|
3293
|
+
estimatedTurns: Math.min(Math.max(messageCount, 1), options?.maxTurns || 10),
|
|
3294
|
+
estimatedTokens: messageCount * 100,
|
|
3295
|
+
// Rough estimate
|
|
3296
|
+
agentCount: agents.length,
|
|
3297
|
+
defaultAgent: defaultAgent?.getName()
|
|
3298
|
+
};
|
|
3299
|
+
}
|
|
3300
|
+
};
|
|
3301
|
+
var run = Runner.run.bind(Runner);
|
|
3302
|
+
var stream = Runner.stream.bind(Runner);
|
|
3303
|
+
var raceGraphs = Runner.raceGraphs.bind(Runner);
|
|
3304
|
+
|
|
3305
|
+
export { Agent, ArtifactComponent, DataComponent, ExternalAgent, Project, Runner, Tool, agent, agentGraph, agentMcp, artifactComponent, createEnvironmentSettings, createFullProjectViaAPI, credential, dataComponent, deleteFullProjectViaAPI, externalAgent, externalAgents, getFullProjectViaAPI, mcpServer, mcpTool, project, raceGraphs, registerEnvironmentSettings, run, stream, transfer, updateFullProjectViaAPI };
|