@inkeep/agents-run-api 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +117 -0
- package/dist/AgentExecutionServer.d.ts +23 -0
- package/dist/AgentExecutionServer.d.ts.map +1 -0
- package/dist/AgentExecutionServer.js +32 -0
- package/dist/__tests__/setup.d.ts +4 -0
- package/dist/__tests__/setup.d.ts.map +1 -0
- package/dist/__tests__/setup.js +50 -0
- package/dist/__tests__/utils/testProject.d.ts +18 -0
- package/dist/__tests__/utils/testProject.d.ts.map +1 -0
- package/dist/__tests__/utils/testProject.js +26 -0
- package/dist/__tests__/utils/testRequest.d.ts +8 -0
- package/dist/__tests__/utils/testRequest.d.ts.map +1 -0
- package/dist/__tests__/utils/testRequest.js +32 -0
- package/dist/__tests__/utils/testTenant.d.ts +64 -0
- package/dist/__tests__/utils/testTenant.d.ts.map +1 -0
- package/dist/__tests__/utils/testTenant.js +71 -0
- package/dist/a2a/client.d.ts +182 -0
- package/dist/a2a/client.d.ts.map +1 -0
- package/dist/a2a/client.js +645 -0
- package/dist/a2a/handlers.d.ts +4 -0
- package/dist/a2a/handlers.d.ts.map +1 -0
- package/dist/a2a/handlers.js +657 -0
- package/dist/a2a/transfer.d.ts +18 -0
- package/dist/a2a/transfer.d.ts.map +1 -0
- package/dist/a2a/transfer.js +22 -0
- package/dist/a2a/types.d.ts +63 -0
- package/dist/a2a/types.d.ts.map +1 -0
- package/dist/a2a/types.js +1 -0
- package/dist/agents/Agent.d.ts +154 -0
- package/dist/agents/Agent.d.ts.map +1 -0
- package/dist/agents/Agent.js +1105 -0
- package/dist/agents/ModelFactory.d.ts +62 -0
- package/dist/agents/ModelFactory.d.ts.map +1 -0
- package/dist/agents/ModelFactory.js +208 -0
- package/dist/agents/SystemPromptBuilder.d.ts +14 -0
- package/dist/agents/SystemPromptBuilder.d.ts.map +1 -0
- package/dist/agents/SystemPromptBuilder.js +62 -0
- package/dist/agents/ToolSessionManager.d.ts +61 -0
- package/dist/agents/ToolSessionManager.d.ts.map +1 -0
- package/dist/agents/ToolSessionManager.js +143 -0
- package/dist/agents/artifactTools.d.ts +30 -0
- package/dist/agents/artifactTools.d.ts.map +1 -0
- package/dist/agents/artifactTools.js +463 -0
- package/dist/agents/generateTaskHandler.d.ts +41 -0
- package/dist/agents/generateTaskHandler.d.ts.map +1 -0
- package/dist/agents/generateTaskHandler.js +350 -0
- package/dist/agents/relationTools.d.ts +33 -0
- package/dist/agents/relationTools.d.ts.map +1 -0
- package/dist/agents/relationTools.js +245 -0
- package/dist/agents/types.d.ts +23 -0
- package/dist/agents/types.d.ts.map +1 -0
- package/dist/agents/types.js +1 -0
- package/dist/agents/versions/V1Config.d.ts +21 -0
- package/dist/agents/versions/V1Config.d.ts.map +1 -0
- package/dist/agents/versions/V1Config.js +285 -0
- package/dist/app.d.ts +4 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +194 -0
- package/dist/data/agentGraph.d.ts +4 -0
- package/dist/data/agentGraph.d.ts.map +1 -0
- package/dist/data/agentGraph.js +73 -0
- package/dist/data/agents.d.ts +4 -0
- package/dist/data/agents.d.ts.map +1 -0
- package/dist/data/agents.js +73 -0
- package/dist/data/conversations.d.ts +59 -0
- package/dist/data/conversations.d.ts.map +1 -0
- package/dist/data/conversations.js +216 -0
- package/dist/data/db/clean.d.ts +6 -0
- package/dist/data/db/clean.d.ts.map +1 -0
- package/dist/data/db/clean.js +77 -0
- package/dist/data/db/dbClient.d.ts +3 -0
- package/dist/data/db/dbClient.d.ts.map +1 -0
- package/dist/data/db/dbClient.js +13 -0
- package/dist/env.d.ts +43 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +63 -0
- package/dist/handlers/executionHandler.d.ts +36 -0
- package/dist/handlers/executionHandler.d.ts.map +1 -0
- package/dist/handlers/executionHandler.js +402 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/instrumentation.d.ts +13 -0
- package/dist/instrumentation.d.ts.map +1 -0
- package/dist/instrumentation.js +66 -0
- package/dist/logger.d.ts +4 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +32 -0
- package/dist/middleware/api-key-auth.d.ts +22 -0
- package/dist/middleware/api-key-auth.d.ts.map +1 -0
- package/dist/middleware/api-key-auth.js +139 -0
- package/dist/middleware/index.d.ts +2 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +1 -0
- package/dist/openapi.d.ts +2 -0
- package/dist/openapi.d.ts.map +1 -0
- package/dist/openapi.js +36 -0
- package/dist/routes/agents.d.ts +4 -0
- package/dist/routes/agents.d.ts.map +1 -0
- package/dist/routes/agents.js +155 -0
- package/dist/routes/chat.d.ts +4 -0
- package/dist/routes/chat.d.ts.map +1 -0
- package/dist/routes/chat.js +308 -0
- package/dist/routes/chatDataStream.d.ts +4 -0
- package/dist/routes/chatDataStream.d.ts.map +1 -0
- package/dist/routes/chatDataStream.js +179 -0
- package/dist/routes/mcp.d.ts +4 -0
- package/dist/routes/mcp.d.ts.map +1 -0
- package/dist/routes/mcp.js +500 -0
- package/dist/tracer.d.ts +24 -0
- package/dist/tracer.d.ts.map +1 -0
- package/dist/tracer.js +97 -0
- package/dist/types/chat.d.ts +25 -0
- package/dist/types/chat.d.ts.map +1 -0
- package/dist/types/chat.js +1 -0
- package/dist/types/execution-context.d.ts +14 -0
- package/dist/types/execution-context.d.ts.map +1 -0
- package/dist/types/execution-context.js +14 -0
- package/dist/utils/agent-operations.d.ts +79 -0
- package/dist/utils/agent-operations.d.ts.map +1 -0
- package/dist/utils/agent-operations.js +67 -0
- package/dist/utils/artifact-component-schema.d.ts +29 -0
- package/dist/utils/artifact-component-schema.d.ts.map +1 -0
- package/dist/utils/artifact-component-schema.js +119 -0
- package/dist/utils/artifact-parser.d.ts +71 -0
- package/dist/utils/artifact-parser.d.ts.map +1 -0
- package/dist/utils/artifact-parser.js +251 -0
- package/dist/utils/cleanup.d.ts +19 -0
- package/dist/utils/cleanup.d.ts.map +1 -0
- package/dist/utils/cleanup.js +66 -0
- package/dist/utils/data-component-schema.d.ts +6 -0
- package/dist/utils/data-component-schema.d.ts.map +1 -0
- package/dist/utils/data-component-schema.js +43 -0
- package/dist/utils/graph-session.d.ts +200 -0
- package/dist/utils/graph-session.d.ts.map +1 -0
- package/dist/utils/graph-session.js +1009 -0
- package/dist/utils/incremental-stream-parser.d.ts +57 -0
- package/dist/utils/incremental-stream-parser.d.ts.map +1 -0
- package/dist/utils/incremental-stream-parser.js +287 -0
- package/dist/utils/response-formatter.d.ts +27 -0
- package/dist/utils/response-formatter.d.ts.map +1 -0
- package/dist/utils/response-formatter.js +160 -0
- package/dist/utils/stream-helpers.d.ts +162 -0
- package/dist/utils/stream-helpers.d.ts.map +1 -0
- package/dist/utils/stream-helpers.js +385 -0
- package/dist/utils/stream-registry.d.ts +18 -0
- package/dist/utils/stream-registry.d.ts.map +1 -0
- package/dist/utils/stream-registry.js +33 -0
- package/package.json +88 -0
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import destr from 'destr'; // safe JSON.parse-if-JSON
|
|
2
|
+
import { nanoid } from 'nanoid';
|
|
3
|
+
import traverse from 'traverse'; // tiny object walker
|
|
4
|
+
import { TaskState, getAgentGraph, getRelatedAgentsForGraph, getToolsForAgent, getAgentById, getArtifactComponentsForAgent, getDataComponentsForAgent, } from '@inkeep/agents-core';
|
|
5
|
+
import { getLogger } from '../logger.js';
|
|
6
|
+
import { Agent } from './Agent.js';
|
|
7
|
+
import dbClient from '../data/db/dbClient.js';
|
|
8
|
+
/** Turn any string value that is valid JSON into an object/array (in place). */
|
|
9
|
+
export function parseEmbeddedJson(data) {
|
|
10
|
+
return traverse(data).map(function (x) {
|
|
11
|
+
if (typeof x === 'string') {
|
|
12
|
+
const v = destr(x); // returns original string if not JSON
|
|
13
|
+
if (v !== x && (Array.isArray(v) || (v && typeof v === 'object'))) {
|
|
14
|
+
this.update(v); // replace the string with the parsed value
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
const logger = getLogger('generateTaskHandler');
|
|
20
|
+
export const createTaskHandler = (config) => {
|
|
21
|
+
return async (task) => {
|
|
22
|
+
try {
|
|
23
|
+
// Extract the user message from the task
|
|
24
|
+
const userMessage = task.input.parts
|
|
25
|
+
.filter((part) => part.text)
|
|
26
|
+
.map((part) => part.text)
|
|
27
|
+
.join(' ');
|
|
28
|
+
if (!userMessage.trim()) {
|
|
29
|
+
return {
|
|
30
|
+
status: {
|
|
31
|
+
state: TaskState.Failed,
|
|
32
|
+
message: 'No text content found in task input',
|
|
33
|
+
},
|
|
34
|
+
artifacts: [],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const [{ internalRelations, externalRelations }, toolsForAgent, dataComponents, artifactComponents,] = await Promise.all([
|
|
38
|
+
getRelatedAgentsForGraph(dbClient)({
|
|
39
|
+
scopes: {
|
|
40
|
+
tenantId: config.tenantId,
|
|
41
|
+
projectId: config.projectId,
|
|
42
|
+
},
|
|
43
|
+
graphId: config.graphId,
|
|
44
|
+
agentId: config.agentId,
|
|
45
|
+
}),
|
|
46
|
+
getToolsForAgent(dbClient)({
|
|
47
|
+
scopes: {
|
|
48
|
+
tenantId: config.tenantId,
|
|
49
|
+
projectId: config.projectId,
|
|
50
|
+
},
|
|
51
|
+
agentId: config.agentId,
|
|
52
|
+
}),
|
|
53
|
+
getDataComponentsForAgent(dbClient)({
|
|
54
|
+
scopes: {
|
|
55
|
+
tenantId: config.tenantId,
|
|
56
|
+
projectId: config.projectId,
|
|
57
|
+
},
|
|
58
|
+
agentId: config.agentId,
|
|
59
|
+
}),
|
|
60
|
+
getArtifactComponentsForAgent(dbClient)({
|
|
61
|
+
scopes: {
|
|
62
|
+
tenantId: config.tenantId,
|
|
63
|
+
projectId: config.projectId,
|
|
64
|
+
},
|
|
65
|
+
agentId: config.agentId,
|
|
66
|
+
}),
|
|
67
|
+
]);
|
|
68
|
+
logger.info({ toolsForAgent, internalRelations, externalRelations }, 'agent stuff');
|
|
69
|
+
// Check if this is an internal agent (has prompt)
|
|
70
|
+
const agentPrompt = 'prompt' in config.agentSchema ? config.agentSchema.prompt : '';
|
|
71
|
+
const models = 'models' in config.agentSchema ? config.agentSchema.models : undefined;
|
|
72
|
+
const stopWhen = 'stopWhen' in config.agentSchema ? config.agentSchema.stopWhen : undefined;
|
|
73
|
+
const agent = new Agent({
|
|
74
|
+
id: config.agentId,
|
|
75
|
+
tenantId: config.tenantId,
|
|
76
|
+
projectId: config.projectId,
|
|
77
|
+
graphId: config.graphId,
|
|
78
|
+
baseUrl: config.baseUrl,
|
|
79
|
+
apiKey: config.apiKey,
|
|
80
|
+
name: config.name,
|
|
81
|
+
description: config.description || '',
|
|
82
|
+
agentPrompt,
|
|
83
|
+
models: models || undefined,
|
|
84
|
+
stopWhen: stopWhen || undefined,
|
|
85
|
+
agentRelations: internalRelations.map((relation) => ({
|
|
86
|
+
id: relation.id,
|
|
87
|
+
tenantId: config.tenantId,
|
|
88
|
+
projectId: config.projectId,
|
|
89
|
+
graphId: config.graphId,
|
|
90
|
+
baseUrl: config.baseUrl,
|
|
91
|
+
apiKey: config.apiKey,
|
|
92
|
+
name: relation.name,
|
|
93
|
+
description: relation.description,
|
|
94
|
+
agentPrompt: '',
|
|
95
|
+
delegateRelations: [],
|
|
96
|
+
agentRelations: [],
|
|
97
|
+
transferRelations: [],
|
|
98
|
+
})),
|
|
99
|
+
transferRelations: internalRelations
|
|
100
|
+
.filter((relation) => relation.relationType === 'transfer')
|
|
101
|
+
.map((relation) => ({
|
|
102
|
+
baseUrl: config.baseUrl,
|
|
103
|
+
apiKey: config.apiKey,
|
|
104
|
+
id: relation.id,
|
|
105
|
+
tenantId: config.tenantId,
|
|
106
|
+
projectId: config.projectId,
|
|
107
|
+
graphId: config.graphId,
|
|
108
|
+
name: relation.name,
|
|
109
|
+
description: relation.description,
|
|
110
|
+
agentPrompt: '',
|
|
111
|
+
delegateRelations: [],
|
|
112
|
+
agentRelations: [],
|
|
113
|
+
transferRelations: [],
|
|
114
|
+
})),
|
|
115
|
+
delegateRelations: [
|
|
116
|
+
// Internal delegate relations
|
|
117
|
+
...internalRelations
|
|
118
|
+
.filter((relation) => relation.relationType === 'delegate')
|
|
119
|
+
.map((relation) => ({
|
|
120
|
+
type: 'internal',
|
|
121
|
+
config: {
|
|
122
|
+
id: relation.id,
|
|
123
|
+
tenantId: config.tenantId,
|
|
124
|
+
projectId: config.projectId,
|
|
125
|
+
graphId: config.graphId,
|
|
126
|
+
baseUrl: config.baseUrl,
|
|
127
|
+
apiKey: config.apiKey,
|
|
128
|
+
name: relation.name,
|
|
129
|
+
description: relation.description,
|
|
130
|
+
agentPrompt: '',
|
|
131
|
+
delegateRelations: [],
|
|
132
|
+
agentRelations: [],
|
|
133
|
+
transferRelations: [],
|
|
134
|
+
},
|
|
135
|
+
})),
|
|
136
|
+
// External delegate relations
|
|
137
|
+
...externalRelations.map((relation) => ({
|
|
138
|
+
type: 'external',
|
|
139
|
+
config: {
|
|
140
|
+
id: relation.externalAgent.id,
|
|
141
|
+
name: relation.externalAgent.name,
|
|
142
|
+
description: relation.externalAgent.description || '',
|
|
143
|
+
baseUrl: relation.externalAgent.baseUrl,
|
|
144
|
+
relationType: relation.relationType || undefined,
|
|
145
|
+
},
|
|
146
|
+
})),
|
|
147
|
+
],
|
|
148
|
+
tools: toolsForAgent.data.map((item) => ({
|
|
149
|
+
...item.tool,
|
|
150
|
+
capabilities: item.tool.capabilities || undefined,
|
|
151
|
+
lastHealthCheck: item.tool.lastHealthCheck
|
|
152
|
+
? new Date(item.tool.lastHealthCheck)
|
|
153
|
+
: undefined,
|
|
154
|
+
lastToolsSync: item.tool.lastToolsSync
|
|
155
|
+
? new Date(item.tool.lastToolsSync)
|
|
156
|
+
: undefined,
|
|
157
|
+
createdAt: new Date(item.tool.createdAt),
|
|
158
|
+
updatedAt: new Date(item.tool.updatedAt),
|
|
159
|
+
})) ?? [],
|
|
160
|
+
functionTools: [], // All tools are now handled via MCP servers
|
|
161
|
+
dataComponents: dataComponents,
|
|
162
|
+
artifactComponents: artifactComponents,
|
|
163
|
+
contextConfigId: config.contextConfigId || undefined,
|
|
164
|
+
conversationHistoryConfig: config.conversationHistoryConfig,
|
|
165
|
+
});
|
|
166
|
+
// More robust contextId resolution for delegation scenarios
|
|
167
|
+
let contextId = task.context?.conversationId;
|
|
168
|
+
// If contextId is not set in task.context, try to extract it from the task.id
|
|
169
|
+
// Many tasks are created with IDs like "task_math-demo-123456-chatcmpl-789"
|
|
170
|
+
if (!contextId || contextId === 'default' || contextId === '') {
|
|
171
|
+
const taskIdMatch = task.id.match(/^task_([^-]+-[^-]+-\d+)-/);
|
|
172
|
+
if (taskIdMatch) {
|
|
173
|
+
contextId = taskIdMatch[1];
|
|
174
|
+
logger.info({
|
|
175
|
+
taskId: task.id,
|
|
176
|
+
extractedContextId: contextId,
|
|
177
|
+
agentId: config.agentId,
|
|
178
|
+
}, 'Extracted contextId from task ID for delegation');
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
contextId = 'default';
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Extract streaming context from task metadata and get streamHelper from registry
|
|
185
|
+
const streamRequestId = task.context?.metadata?.stream_request_id || task.context?.metadata?.streamRequestId;
|
|
186
|
+
// Check if this is a delegation - delegated agents should not stream to user
|
|
187
|
+
const isDelegation = task.context?.metadata?.isDelegation === true;
|
|
188
|
+
agent.setDelegationStatus(isDelegation);
|
|
189
|
+
if (isDelegation) {
|
|
190
|
+
logger.info({ agentId: config.agentId, taskId: task.id }, 'Delegated agent - streaming disabled');
|
|
191
|
+
}
|
|
192
|
+
const response = await agent.generate(userMessage, {
|
|
193
|
+
contextId,
|
|
194
|
+
metadata: {
|
|
195
|
+
conversationId: contextId,
|
|
196
|
+
taskId: task.id,
|
|
197
|
+
threadId: contextId, // using conversationId as threadId for now
|
|
198
|
+
streamRequestId: streamRequestId,
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
// Process steps to extract tool calls and results from content arrays
|
|
202
|
+
const stepContents = response.steps && Array.isArray(response.steps)
|
|
203
|
+
? response.steps.flatMap((step) => {
|
|
204
|
+
return step.content && Array.isArray(step.content) ? step.content : [];
|
|
205
|
+
})
|
|
206
|
+
: [];
|
|
207
|
+
const allToolCalls = stepContents.filter((content) => content.type === 'tool-call');
|
|
208
|
+
const allToolResults = stepContents.filter((content) => content.type === 'tool-result');
|
|
209
|
+
const allThoughts = stepContents.filter((content) => content.type === 'text');
|
|
210
|
+
if (allToolCalls.length > 0) {
|
|
211
|
+
for (const toolCall of allToolCalls) {
|
|
212
|
+
// Check for transfer tool calls (we support multiple patterns)
|
|
213
|
+
if (toolCall.toolName.includes('transfer') ||
|
|
214
|
+
toolCall.toolName.includes('transferToRefundAgent')) {
|
|
215
|
+
// Look for the tool result
|
|
216
|
+
const toolResult = allToolResults.find((result) => result.toolCallId === toolCall.toolCallId);
|
|
217
|
+
// Validate transfer result with proper type checking
|
|
218
|
+
const isValidTransferResult = (output) => {
|
|
219
|
+
return (typeof output === 'object' &&
|
|
220
|
+
output !== null &&
|
|
221
|
+
'type' in output &&
|
|
222
|
+
'target' in output &&
|
|
223
|
+
output.type === 'transfer' &&
|
|
224
|
+
typeof output.target === 'string' &&
|
|
225
|
+
(output.reason === undefined || typeof output.reason === 'string'));
|
|
226
|
+
};
|
|
227
|
+
//In the agent.generate response, response.text is not always populated. In that case, use allThoughts to get the last text part found in the steps array.
|
|
228
|
+
const responseText = response.text ||
|
|
229
|
+
(response.object ? JSON.stringify(response.object) : '');
|
|
230
|
+
const transferReason = responseText ||
|
|
231
|
+
allThoughts[allThoughts.length - 1]?.text ||
|
|
232
|
+
'Agent requested transfer. No reason provided.';
|
|
233
|
+
if (toolResult?.output && isValidTransferResult(toolResult.output)) {
|
|
234
|
+
const transferResult = toolResult.output;
|
|
235
|
+
// Return transfer indication in A2A format
|
|
236
|
+
return {
|
|
237
|
+
status: {
|
|
238
|
+
state: TaskState.Completed,
|
|
239
|
+
message: `Transfer requested to ${transferResult.target}`,
|
|
240
|
+
},
|
|
241
|
+
artifacts: [
|
|
242
|
+
{
|
|
243
|
+
artifactId: nanoid(),
|
|
244
|
+
parts: [
|
|
245
|
+
{
|
|
246
|
+
kind: 'data',
|
|
247
|
+
data: {
|
|
248
|
+
type: 'transfer',
|
|
249
|
+
target: transferResult.target,
|
|
250
|
+
task_id: task.id,
|
|
251
|
+
reason: transferReason,
|
|
252
|
+
original_message: userMessage,
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
],
|
|
256
|
+
},
|
|
257
|
+
],
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// Use formatted content parts if available, otherwise fall back to response.text
|
|
264
|
+
const parts = (response.formattedContent?.parts || []).map((part) => ({
|
|
265
|
+
kind: part.kind,
|
|
266
|
+
...(part.kind === 'text' && { text: part.text }),
|
|
267
|
+
...(part.kind === 'data' && { data: part.data }),
|
|
268
|
+
}));
|
|
269
|
+
return {
|
|
270
|
+
status: { state: TaskState.Completed },
|
|
271
|
+
artifacts: [
|
|
272
|
+
{
|
|
273
|
+
artifactId: nanoid(),
|
|
274
|
+
parts,
|
|
275
|
+
},
|
|
276
|
+
],
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
catch (error) {
|
|
280
|
+
console.error('Task handler error:', error);
|
|
281
|
+
return {
|
|
282
|
+
status: {
|
|
283
|
+
state: TaskState.Failed,
|
|
284
|
+
message: error instanceof Error ? error.message : 'Unknown error occurred',
|
|
285
|
+
},
|
|
286
|
+
artifacts: [],
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
};
|
|
291
|
+
/**
|
|
292
|
+
* Serializes a TaskHandlerConfig to JSON
|
|
293
|
+
*/
|
|
294
|
+
export const serializeTaskHandlerConfig = (config) => {
|
|
295
|
+
return JSON.stringify(config, null, 2);
|
|
296
|
+
};
|
|
297
|
+
/**
|
|
298
|
+
* Deserializes a TaskHandlerConfig from JSON
|
|
299
|
+
*/
|
|
300
|
+
export const deserializeTaskHandlerConfig = (configJson) => {
|
|
301
|
+
return JSON.parse(configJson);
|
|
302
|
+
};
|
|
303
|
+
/**
|
|
304
|
+
* Creates a task handler configuration from agent data
|
|
305
|
+
*/
|
|
306
|
+
export const createTaskHandlerConfig = async (params) => {
|
|
307
|
+
const agent = await getAgentById(dbClient)({
|
|
308
|
+
scopes: {
|
|
309
|
+
tenantId: params.tenantId,
|
|
310
|
+
projectId: params.projectId,
|
|
311
|
+
},
|
|
312
|
+
agentId: params.agentId,
|
|
313
|
+
});
|
|
314
|
+
const agentGraph = await getAgentGraph(dbClient)({
|
|
315
|
+
scopes: {
|
|
316
|
+
tenantId: params.tenantId,
|
|
317
|
+
projectId: params.projectId,
|
|
318
|
+
},
|
|
319
|
+
graphId: params.graphId,
|
|
320
|
+
});
|
|
321
|
+
if (!agent) {
|
|
322
|
+
throw new Error(`Agent not found: ${params.agentId}`);
|
|
323
|
+
}
|
|
324
|
+
// Inherit graph models if agent doesn't have one
|
|
325
|
+
const effectiveModels = agent.models || agentGraph?.models || undefined;
|
|
326
|
+
const effectiveConversationHistoryConfig = agent.conversationHistoryConfig || { mode: 'full' };
|
|
327
|
+
return {
|
|
328
|
+
tenantId: params.tenantId,
|
|
329
|
+
projectId: params.projectId,
|
|
330
|
+
graphId: params.graphId,
|
|
331
|
+
agentId: params.agentId,
|
|
332
|
+
agentSchema: {
|
|
333
|
+
id: agent.id,
|
|
334
|
+
name: agent.name,
|
|
335
|
+
description: agent.description,
|
|
336
|
+
prompt: agent.prompt,
|
|
337
|
+
models: effectiveModels || null,
|
|
338
|
+
conversationHistoryConfig: effectiveConversationHistoryConfig || null,
|
|
339
|
+
stopWhen: agent.stopWhen || null,
|
|
340
|
+
createdAt: agent.createdAt,
|
|
341
|
+
updatedAt: agent.updatedAt,
|
|
342
|
+
},
|
|
343
|
+
baseUrl: params.baseUrl,
|
|
344
|
+
apiKey: params.apiKey,
|
|
345
|
+
name: agent.name,
|
|
346
|
+
description: agent.description,
|
|
347
|
+
conversationHistoryConfig: effectiveConversationHistoryConfig,
|
|
348
|
+
contextConfigId: agentGraph?.contextConfigId || undefined,
|
|
349
|
+
};
|
|
350
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { AgentConfig, DelegateRelation } from './Agent.js';
|
|
2
|
+
export declare const createTransferToAgentTool: ({ transferConfig, callingAgentId, agent, streamRequestId, }: {
|
|
3
|
+
transferConfig: AgentConfig;
|
|
4
|
+
callingAgentId: string;
|
|
5
|
+
agent: any;
|
|
6
|
+
streamRequestId?: string;
|
|
7
|
+
}) => import("ai").Tool<Record<string, never>, {
|
|
8
|
+
type: string;
|
|
9
|
+
target: string;
|
|
10
|
+
fromAgentId: string;
|
|
11
|
+
}>;
|
|
12
|
+
export declare function createDelegateToAgentTool({ delegateConfig, callingAgentId, tenantId, projectId, graphId, contextId, metadata, sessionId, agent, }: {
|
|
13
|
+
delegateConfig: DelegateRelation;
|
|
14
|
+
callingAgentId: string;
|
|
15
|
+
tenantId: string;
|
|
16
|
+
projectId: string;
|
|
17
|
+
graphId: string;
|
|
18
|
+
contextId: string;
|
|
19
|
+
metadata: {
|
|
20
|
+
conversationId: string;
|
|
21
|
+
threadId: string;
|
|
22
|
+
streamRequestId?: string;
|
|
23
|
+
streamBaseUrl?: string;
|
|
24
|
+
};
|
|
25
|
+
sessionId?: string;
|
|
26
|
+
agent: any;
|
|
27
|
+
}): import("ai").Tool<{
|
|
28
|
+
message: string;
|
|
29
|
+
}, {
|
|
30
|
+
toolCallId: any;
|
|
31
|
+
result: import("@inkeep/agents-core").Message | import("@inkeep/agents-core").Task;
|
|
32
|
+
}>;
|
|
33
|
+
//# sourceMappingURL=relationTools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relationTools.d.ts","sourceRoot":"","sources":["../../src/agents/relationTools.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA2BhE,eAAO,MAAM,yBAAyB,GAAI,6DAKvC;IACD,cAAc,EAAE,WAAW,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,GAAG,CAAC;IACX,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;;;;EAsCA,CAAC;AAEF,wBAAgB,yBAAyB,CAAC,EACxC,cAAc,EACd,cAAc,EACd,QAAQ,EACR,SAAS,EACT,OAAO,EACP,SAAS,EACT,QAAQ,EACR,SAAS,EACT,KAAK,GACN,EAAE;IACD,cAAc,EAAE,gBAAgB,CAAC;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE;QACR,cAAc,EAAE,MAAM,CAAC;QACvB,QAAQ,EAAE,MAAM,CAAC;QACjB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,GAAG,CAAC;CACZ;;;;;GAkNA"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { trace } from '@opentelemetry/api';
|
|
2
|
+
import { tool } from 'ai';
|
|
3
|
+
import { nanoid } from 'nanoid';
|
|
4
|
+
import z from 'zod';
|
|
5
|
+
import { A2AClient } from '../a2a/client.js';
|
|
6
|
+
import { createMessage, getCredentialReference, getExternalAgent, CredentialStuffer, ContextResolver, } from '@inkeep/agents-core';
|
|
7
|
+
import { saveA2AMessageResponse } from '../data/conversations.js';
|
|
8
|
+
import dbClient from '../data/db/dbClient.js';
|
|
9
|
+
import { executionServer } from '../index.js';
|
|
10
|
+
import { getLogger } from '../logger.js';
|
|
11
|
+
import { graphSessionManager } from '../utils/graph-session.js';
|
|
12
|
+
import { toolSessionManager } from './ToolSessionManager.js';
|
|
13
|
+
const logger = getLogger('relationships Tools');
|
|
14
|
+
const generateTransferToolDescription = (config) => {
|
|
15
|
+
return `Hand off the conversation to agent ${config.id}.
|
|
16
|
+
|
|
17
|
+
Agent Information:
|
|
18
|
+
- ID: ${config.id}
|
|
19
|
+
- Name: ${config.name ?? 'No name provided'}
|
|
20
|
+
- Description: ${config.description ?? 'No description provided'}
|
|
21
|
+
|
|
22
|
+
Hand off the conversation to agent ${config.id} when the user's request would be better handled by this specialized agent.`;
|
|
23
|
+
};
|
|
24
|
+
const generateDelegateToolDescription = (config) => {
|
|
25
|
+
return `Delegate a specific task to another agent.
|
|
26
|
+
|
|
27
|
+
Agent Information:
|
|
28
|
+
- ID: ${config.id}
|
|
29
|
+
- Name: ${config.name}
|
|
30
|
+
- Description: ${config.description || 'No description provided'}
|
|
31
|
+
|
|
32
|
+
Delegate a specific task to agent ${config.id} when it seems like the agent can do relevant work.`;
|
|
33
|
+
};
|
|
34
|
+
export const createTransferToAgentTool = ({ transferConfig, callingAgentId, agent, streamRequestId, }) => {
|
|
35
|
+
return tool({
|
|
36
|
+
description: generateTransferToolDescription(transferConfig),
|
|
37
|
+
inputSchema: z.object({}),
|
|
38
|
+
execute: async () => {
|
|
39
|
+
// Add span attributes to indicate transfer source and target
|
|
40
|
+
const activeSpan = trace.getActiveSpan();
|
|
41
|
+
if (activeSpan) {
|
|
42
|
+
activeSpan.setAttributes({
|
|
43
|
+
'transfer.from_agent_id': callingAgentId,
|
|
44
|
+
'transfer.to_agent_id': transferConfig.id ?? 'unknown',
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
logger.info({
|
|
48
|
+
transferTo: transferConfig.id ?? 'unknown',
|
|
49
|
+
fromAgent: callingAgentId,
|
|
50
|
+
}, 'invoked transferToAgentTool');
|
|
51
|
+
// Record transfer event in GraphSession
|
|
52
|
+
if (streamRequestId) {
|
|
53
|
+
graphSessionManager.recordEvent(streamRequestId, 'transfer', callingAgentId, {
|
|
54
|
+
fromAgent: callingAgentId,
|
|
55
|
+
targetAgent: transferConfig.id ?? 'unknown',
|
|
56
|
+
reason: `Transfer to ${transferConfig.name || transferConfig.id}`,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
type: 'transfer',
|
|
61
|
+
target: transferConfig.id ?? 'unknown',
|
|
62
|
+
fromAgentId: callingAgentId, // Include the calling agent ID for tracking
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
export function createDelegateToAgentTool({ delegateConfig, callingAgentId, tenantId, projectId, graphId, contextId, metadata, sessionId, agent, }) {
|
|
68
|
+
return tool({
|
|
69
|
+
description: generateDelegateToolDescription(delegateConfig.config),
|
|
70
|
+
inputSchema: z.object({ message: z.string() }),
|
|
71
|
+
execute: async (input, context) => {
|
|
72
|
+
// Generate unique delegation ID for tracking
|
|
73
|
+
const delegationId = `del_${nanoid()}`;
|
|
74
|
+
// Add span attributes to indicate delegation source and target
|
|
75
|
+
const activeSpan = trace.getActiveSpan();
|
|
76
|
+
if (activeSpan) {
|
|
77
|
+
activeSpan.setAttributes({
|
|
78
|
+
'delegation.from_agent_id': callingAgentId,
|
|
79
|
+
'delegation.to_agent_id': delegateConfig.config.id ?? 'unknown',
|
|
80
|
+
'delegation.id': delegationId,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
// Record delegation sent event in GraphSession
|
|
84
|
+
if (metadata.streamRequestId) {
|
|
85
|
+
graphSessionManager.recordEvent(metadata.streamRequestId, 'delegation_sent', callingAgentId, {
|
|
86
|
+
delegationId,
|
|
87
|
+
fromAgent: callingAgentId,
|
|
88
|
+
targetAgent: delegateConfig.config.id,
|
|
89
|
+
taskDescription: input.message,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
const isInternal = delegateConfig.type === 'internal';
|
|
93
|
+
// Get the base URL for the agent
|
|
94
|
+
let agentBaseUrl;
|
|
95
|
+
let resolvedHeaders = {};
|
|
96
|
+
if (!isInternal) {
|
|
97
|
+
agentBaseUrl = delegateConfig.config.baseUrl;
|
|
98
|
+
// For external agents, fetch configuration
|
|
99
|
+
const externalAgent = await getExternalAgent(dbClient)({
|
|
100
|
+
scopes: {
|
|
101
|
+
tenantId,
|
|
102
|
+
projectId,
|
|
103
|
+
},
|
|
104
|
+
agentId: delegateConfig.config.id,
|
|
105
|
+
});
|
|
106
|
+
// If the external agent has a credential reference ID or headers, resolve them
|
|
107
|
+
if (externalAgent && (externalAgent.credentialReferenceId || externalAgent.headers)) {
|
|
108
|
+
const contextResolver = new ContextResolver(tenantId, projectId, dbClient, executionServer);
|
|
109
|
+
const credentialStuffer = new CredentialStuffer(executionServer, contextResolver);
|
|
110
|
+
const credentialContext = {
|
|
111
|
+
tenantId,
|
|
112
|
+
projectId,
|
|
113
|
+
conversationId: metadata.conversationId,
|
|
114
|
+
contextConfigId: contextId,
|
|
115
|
+
metadata: metadata,
|
|
116
|
+
};
|
|
117
|
+
let storeReference;
|
|
118
|
+
if (externalAgent.credentialReferenceId) {
|
|
119
|
+
// Get credential store configuration
|
|
120
|
+
const credentialReference = await getCredentialReference(dbClient)({
|
|
121
|
+
scopes: {
|
|
122
|
+
tenantId,
|
|
123
|
+
projectId,
|
|
124
|
+
},
|
|
125
|
+
id: externalAgent.credentialReferenceId,
|
|
126
|
+
});
|
|
127
|
+
if (credentialReference) {
|
|
128
|
+
storeReference = {
|
|
129
|
+
credentialStoreId: credentialReference.credentialStoreId,
|
|
130
|
+
retrievalParams: credentialReference.retrievalParams || {},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Resolve credentials using CredentialStuffer
|
|
135
|
+
resolvedHeaders = await credentialStuffer.getCredentialHeaders({
|
|
136
|
+
context: credentialContext,
|
|
137
|
+
storeReference,
|
|
138
|
+
headers: externalAgent.headers || undefined,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
resolvedHeaders = {
|
|
144
|
+
Authorization: `Bearer ${delegateConfig.config.apiKey}`,
|
|
145
|
+
'x-inkeep-tenant-id': tenantId,
|
|
146
|
+
'x-inkeep-project-id': projectId,
|
|
147
|
+
'x-inkeep-graph-id': graphId,
|
|
148
|
+
'x-inkeep-agent-id': delegateConfig.config.id,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
// Configure retry behavior for A2A client with custom settings and resolved headers
|
|
152
|
+
const a2aClient = new A2AClient(delegateConfig.config.baseUrl, {
|
|
153
|
+
headers: resolvedHeaders,
|
|
154
|
+
retryConfig: {
|
|
155
|
+
strategy: 'backoff',
|
|
156
|
+
retryConnectionErrors: true,
|
|
157
|
+
statusCodes: ['429', '500', '502', '503', '504'],
|
|
158
|
+
backoff: {
|
|
159
|
+
initialInterval: 100,
|
|
160
|
+
maxInterval: 10000,
|
|
161
|
+
exponent: 2,
|
|
162
|
+
maxElapsedTime: 20000, // 1 minute max retry time
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
// Create the message to send to the agent
|
|
167
|
+
// Keep streamRequestId for GraphSession access, add isDelegation flag to prevent streaming
|
|
168
|
+
const messageToSend = {
|
|
169
|
+
role: 'agent',
|
|
170
|
+
parts: [{ text: input.message, kind: 'text' }],
|
|
171
|
+
messageId: nanoid(),
|
|
172
|
+
kind: 'message',
|
|
173
|
+
contextId,
|
|
174
|
+
metadata: {
|
|
175
|
+
...metadata, // Keep all metadata including streamRequestId
|
|
176
|
+
isDelegation: true, // Flag to prevent streaming in delegated agents
|
|
177
|
+
delegationId, // Include delegation ID for tracking
|
|
178
|
+
...(isInternal
|
|
179
|
+
? { fromAgentId: callingAgentId }
|
|
180
|
+
: { fromExternalAgentId: callingAgentId }),
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
logger.info({ messageToSend }, 'messageToSend');
|
|
184
|
+
// Record the outgoing message to the agent
|
|
185
|
+
await createMessage(dbClient)({
|
|
186
|
+
id: nanoid(),
|
|
187
|
+
tenantId: tenantId,
|
|
188
|
+
projectId: projectId,
|
|
189
|
+
conversationId: contextId,
|
|
190
|
+
role: 'agent',
|
|
191
|
+
content: {
|
|
192
|
+
text: input.message,
|
|
193
|
+
},
|
|
194
|
+
visibility: isInternal ? 'internal' : 'external',
|
|
195
|
+
messageType: 'a2a-request',
|
|
196
|
+
fromAgentId: callingAgentId,
|
|
197
|
+
...(isInternal
|
|
198
|
+
? { toAgentId: delegateConfig.config.id }
|
|
199
|
+
: { toExternalAgentId: delegateConfig.config.id }),
|
|
200
|
+
});
|
|
201
|
+
const response = await a2aClient.sendMessage({
|
|
202
|
+
message: messageToSend,
|
|
203
|
+
});
|
|
204
|
+
if (response.error) {
|
|
205
|
+
throw new Error(response.error.message);
|
|
206
|
+
}
|
|
207
|
+
// Save the response using the reusable function
|
|
208
|
+
await saveA2AMessageResponse(response, {
|
|
209
|
+
tenantId,
|
|
210
|
+
projectId,
|
|
211
|
+
conversationId: contextId,
|
|
212
|
+
messageType: 'a2a-response',
|
|
213
|
+
visibility: isInternal ? 'internal' : 'external',
|
|
214
|
+
toAgentId: callingAgentId,
|
|
215
|
+
...(isInternal
|
|
216
|
+
? { fromAgentId: delegateConfig.config.id }
|
|
217
|
+
: { fromExternalAgentId: delegateConfig.config.id }),
|
|
218
|
+
});
|
|
219
|
+
// Record the delegation result as a tool result for the parent agent
|
|
220
|
+
if (sessionId && context?.toolCallId) {
|
|
221
|
+
const toolResult = {
|
|
222
|
+
toolCallId: context.toolCallId,
|
|
223
|
+
toolName: `delegate_to_${delegateConfig.config.id}`,
|
|
224
|
+
args: input,
|
|
225
|
+
result: response.result,
|
|
226
|
+
timestamp: Date.now(),
|
|
227
|
+
};
|
|
228
|
+
toolSessionManager.recordToolResult(sessionId, toolResult);
|
|
229
|
+
}
|
|
230
|
+
// Record delegation returned event in GraphSession
|
|
231
|
+
if (metadata.streamRequestId) {
|
|
232
|
+
graphSessionManager.recordEvent(metadata.streamRequestId, 'delegation_returned', callingAgentId, {
|
|
233
|
+
delegationId,
|
|
234
|
+
fromAgent: delegateConfig.config.id,
|
|
235
|
+
targetAgent: callingAgentId,
|
|
236
|
+
result: response.result,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
return {
|
|
240
|
+
toolCallId: context?.toolCallId,
|
|
241
|
+
result: response.result,
|
|
242
|
+
};
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DataComponentApiInsert, ArtifactComponentApiInsert, Artifact } from '@inkeep/agents-core';
|
|
2
|
+
export interface VersionConfig<TConfig> {
|
|
3
|
+
templateFiles: string[];
|
|
4
|
+
assemble(templates: Map<string, string>, config: TConfig): string;
|
|
5
|
+
}
|
|
6
|
+
export interface SystemPromptV1 {
|
|
7
|
+
corePrompt: string;
|
|
8
|
+
graphPrompt?: string;
|
|
9
|
+
artifacts: Artifact[];
|
|
10
|
+
tools: ToolData[];
|
|
11
|
+
dataComponents: DataComponentApiInsert[];
|
|
12
|
+
artifactComponents?: ArtifactComponentApiInsert[];
|
|
13
|
+
isThinkingPreparation?: boolean;
|
|
14
|
+
hasTransferRelations?: boolean;
|
|
15
|
+
hasDelegateRelations?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface ToolData {
|
|
18
|
+
name: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
inputSchema?: Record<string, unknown>;
|
|
21
|
+
usageGuidelines?: string;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/agents/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGxG,MAAM,WAAW,aAAa,CAAC,OAAO;IACpC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;CACnE;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,cAAc,EAAE,sBAAsB,EAAE,CAAC;IACzC,kBAAkB,CAAC,EAAE,0BAA0B,EAAE,CAAC;IAClD,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|