@inkeep/agents-run-api 0.0.0-dev-20250910232631
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +49 -0
- package/README.md +117 -0
- package/dist/__tests__/setup.d.ts +4 -0
- package/dist/__tests__/setup.d.ts.map +1 -0
- package/dist/__tests__/setup.js +80 -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 +656 -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 +151 -0
- package/dist/agents/Agent.d.ts.map +1 -0
- package/dist/agents/Agent.js +1164 -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 +53 -0
- package/dist/agents/ToolSessionManager.d.ts.map +1 -0
- package/dist/agents/ToolSessionManager.js +106 -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 +35 -0
- package/dist/agents/relationTools.d.ts.map +1 -0
- package/dist/agents/relationTools.js +246 -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 +5 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +219 -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 +78 -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 +45 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +64 -0
- package/dist/handlers/executionHandler.d.ts +36 -0
- package/dist/handlers/executionHandler.d.ts.map +1 -0
- package/dist/handlers/executionHandler.js +415 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -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 +10 -0
- package/dist/routes/agents.d.ts.map +1 -0
- package/dist/routes/agents.js +158 -0
- package/dist/routes/chat.d.ts +10 -0
- package/dist/routes/chat.d.ts.map +1 -0
- package/dist/routes/chat.js +307 -0
- package/dist/routes/chatDataStream.d.ts +10 -0
- package/dist/routes/chatDataStream.d.ts.map +1 -0
- package/dist/routes/chatDataStream.js +185 -0
- package/dist/routes/mcp.d.ts +10 -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 +107 -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 +93 -0
- package/dist/utils/agent-operations.d.ts.map +1 -0
- package/dist/utils/agent-operations.js +78 -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 +253 -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 +230 -0
- package/dist/utils/graph-session.d.ts.map +1 -0
- package/dist/utils/graph-session.js +1199 -0
- package/dist/utils/incremental-stream-parser.d.ts +62 -0
- package/dist/utils/incremental-stream-parser.d.ts.map +1 -0
- package/dist/utils/incremental-stream-parser.js +330 -0
- package/dist/utils/response-formatter.d.ts +26 -0
- package/dist/utils/response-formatter.d.ts.map +1 -0
- package/dist/utils/response-formatter.js +158 -0
- package/dist/utils/stream-helpers.d.ts +186 -0
- package/dist/utils/stream-helpers.d.ts.map +1 -0
- package/dist/utils/stream-helpers.js +603 -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 +95 -0
- package/templates/v1/artifact.xml +7 -0
- package/templates/v1/data-component.xml +9 -0
- package/templates/v1/system-prompt.xml +52 -0
- package/templates/v1/thinking-preparation.xml +34 -0
- package/templates/v1/tool.xml +12 -0
|
@@ -0,0 +1,656 @@
|
|
|
1
|
+
import { createMessage, createTask, getRequestExecutionContext, TaskState, updateTask, } from '@inkeep/agents-core';
|
|
2
|
+
import { streamSSE } from 'hono/streaming';
|
|
3
|
+
import { nanoid } from 'nanoid';
|
|
4
|
+
import dbClient from '../data/db/dbClient';
|
|
5
|
+
import { getLogger } from '../logger';
|
|
6
|
+
const logger = getLogger('a2aHandler');
|
|
7
|
+
export async function a2aHandler(c, agent) {
|
|
8
|
+
try {
|
|
9
|
+
const rpcRequest = await c.req.json();
|
|
10
|
+
// Validate JSON-RPC format
|
|
11
|
+
if (rpcRequest.jsonrpc !== '2.0') {
|
|
12
|
+
return c.json({
|
|
13
|
+
jsonrpc: '2.0',
|
|
14
|
+
error: {
|
|
15
|
+
code: -32600,
|
|
16
|
+
message: 'Invalid Request - must be JSON-RPC 2.0',
|
|
17
|
+
},
|
|
18
|
+
id: rpcRequest.id,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
// Handle different A2A methods (including Google's protocol methods)
|
|
22
|
+
switch (rpcRequest.method) {
|
|
23
|
+
// Google A2A Protocol Methods
|
|
24
|
+
case 'message/send':
|
|
25
|
+
return await handleMessageSend(c, agent, rpcRequest);
|
|
26
|
+
case 'message/stream':
|
|
27
|
+
return await handleMessageStream(c, agent, rpcRequest);
|
|
28
|
+
case 'tasks/get':
|
|
29
|
+
return await handleTasksGet(c, agent, rpcRequest);
|
|
30
|
+
case 'tasks/cancel':
|
|
31
|
+
return await handleTasksCancel(c, agent, rpcRequest);
|
|
32
|
+
case 'tasks/resubscribe':
|
|
33
|
+
return await handleTasksResubscribe(c, agent, rpcRequest);
|
|
34
|
+
// Legacy/simplified methods
|
|
35
|
+
case 'agent.invoke':
|
|
36
|
+
return await handleAgentInvoke(c, agent, rpcRequest);
|
|
37
|
+
case 'agent.getCapabilities':
|
|
38
|
+
return await handleGetCapabilities(c, agent, rpcRequest);
|
|
39
|
+
case 'agent.getStatus':
|
|
40
|
+
return await handleGetStatus(c, agent, rpcRequest);
|
|
41
|
+
default:
|
|
42
|
+
return c.json({
|
|
43
|
+
jsonrpc: '2.0',
|
|
44
|
+
error: {
|
|
45
|
+
code: -32601,
|
|
46
|
+
message: `Method not found: ${rpcRequest.method}`,
|
|
47
|
+
},
|
|
48
|
+
id: rpcRequest.id,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
console.error('A2A Handler Error:', error);
|
|
54
|
+
return c.json({
|
|
55
|
+
jsonrpc: '2.0',
|
|
56
|
+
error: {
|
|
57
|
+
code: -32700,
|
|
58
|
+
message: 'Parse error',
|
|
59
|
+
},
|
|
60
|
+
id: null,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function handleMessageSend(c, agent, request) {
|
|
65
|
+
try {
|
|
66
|
+
const params = request.params;
|
|
67
|
+
const executionContext = getRequestExecutionContext(c);
|
|
68
|
+
const { graphId } = executionContext;
|
|
69
|
+
// Convert to our internal task format
|
|
70
|
+
const task = {
|
|
71
|
+
id: nanoid(),
|
|
72
|
+
input: {
|
|
73
|
+
parts: params.message.parts.map((part) => ({
|
|
74
|
+
kind: part.kind,
|
|
75
|
+
text: part.kind === 'text' ? part.text : undefined,
|
|
76
|
+
data: part.kind === 'data' ? part.data : undefined,
|
|
77
|
+
})),
|
|
78
|
+
},
|
|
79
|
+
context: {
|
|
80
|
+
conversationId: params.message.contextId,
|
|
81
|
+
metadata: {
|
|
82
|
+
blocking: params.configuration?.blocking ?? false,
|
|
83
|
+
custom: { graph_id: graphId || '' },
|
|
84
|
+
// Pass through streaming metadata from the original message
|
|
85
|
+
...params.message.metadata,
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
// Enhanced contextId resolution for delegation
|
|
90
|
+
let effectiveContextId = params.message?.contextId;
|
|
91
|
+
// If contextId is missing or 'default', try to get it from task.context
|
|
92
|
+
if (!effectiveContextId || effectiveContextId === 'default') {
|
|
93
|
+
effectiveContextId = task.context?.conversationId;
|
|
94
|
+
}
|
|
95
|
+
// If still missing, try to extract from metadata
|
|
96
|
+
if (!effectiveContextId || effectiveContextId === 'default') {
|
|
97
|
+
if (params.message?.metadata?.conversationId &&
|
|
98
|
+
params.message.metadata.conversationId !== 'default') {
|
|
99
|
+
effectiveContextId = params.message.metadata.conversationId;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Final fallback
|
|
103
|
+
if (!effectiveContextId || effectiveContextId === 'default') {
|
|
104
|
+
effectiveContextId = 'default';
|
|
105
|
+
}
|
|
106
|
+
// Enhanced message content handling
|
|
107
|
+
let _messageContent = '';
|
|
108
|
+
try {
|
|
109
|
+
if (params.message && Object.keys(params.message).length > 0) {
|
|
110
|
+
_messageContent = JSON.stringify(params.message);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
// Fallback: create a minimal message structure
|
|
114
|
+
_messageContent = JSON.stringify({
|
|
115
|
+
role: 'agent',
|
|
116
|
+
parts: [{ text: 'Delegation task', kind: 'text' }],
|
|
117
|
+
contextId: effectiveContextId,
|
|
118
|
+
messageId: task.id,
|
|
119
|
+
kind: 'message',
|
|
120
|
+
});
|
|
121
|
+
logger.warn({
|
|
122
|
+
taskId: task.id,
|
|
123
|
+
agentId: agent.agentId,
|
|
124
|
+
originalMessage: params.message,
|
|
125
|
+
}, 'Created fallback message content for empty delegation message');
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
logger.error({ error, taskId: task.id }, 'Failed to serialize message');
|
|
130
|
+
_messageContent = JSON.stringify({
|
|
131
|
+
error: 'Failed to serialize message',
|
|
132
|
+
taskId: task.id,
|
|
133
|
+
contextId: effectiveContextId,
|
|
134
|
+
parts: [{ text: 'Error in delegation', kind: 'text' }],
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
logger.info({
|
|
138
|
+
originalContextId: params.message.contextId,
|
|
139
|
+
taskContextId: task.context?.conversationId,
|
|
140
|
+
metadataContextId: params.message.metadata?.conversationId,
|
|
141
|
+
finalContextId: effectiveContextId,
|
|
142
|
+
agentId: agent.agentId,
|
|
143
|
+
}, 'A2A contextId resolution for delegation');
|
|
144
|
+
// --- Persist the task in the DB ---
|
|
145
|
+
await createTask(dbClient)({
|
|
146
|
+
id: task.id,
|
|
147
|
+
tenantId: agent.tenantId,
|
|
148
|
+
projectId: agent.projectId,
|
|
149
|
+
contextId: effectiveContextId,
|
|
150
|
+
status: 'working',
|
|
151
|
+
metadata: {
|
|
152
|
+
conversation_id: effectiveContextId,
|
|
153
|
+
message_id: params.message.messageId || '',
|
|
154
|
+
created_at: new Date().toISOString(),
|
|
155
|
+
updated_at: new Date().toISOString(),
|
|
156
|
+
agent_id: agent.agentId,
|
|
157
|
+
graph_id: graphId || '',
|
|
158
|
+
stream_request_id: params.message.metadata?.stream_request_id,
|
|
159
|
+
},
|
|
160
|
+
agentId: agent.agentId,
|
|
161
|
+
createdAt: new Date().toISOString(),
|
|
162
|
+
updatedAt: new Date().toISOString(),
|
|
163
|
+
});
|
|
164
|
+
logger.info({ metadata: params.message.metadata }, 'message metadata');
|
|
165
|
+
// --- Store A2A message in database if this is agent-to-agent communication ---
|
|
166
|
+
// TODO: we need to identify external agent requests through propoer auth headers
|
|
167
|
+
if (params.message.metadata?.fromAgentId || params.message.metadata?.fromExternalAgentId) {
|
|
168
|
+
const messageText = params.message.parts
|
|
169
|
+
.filter((part) => part.kind === 'text' && 'text' in part && part.text)
|
|
170
|
+
.map((part) => part.text)
|
|
171
|
+
.join(' ');
|
|
172
|
+
try {
|
|
173
|
+
const messageData = {
|
|
174
|
+
id: nanoid(),
|
|
175
|
+
tenantId: agent.tenantId,
|
|
176
|
+
projectId: agent.projectId,
|
|
177
|
+
conversationId: effectiveContextId,
|
|
178
|
+
role: 'agent',
|
|
179
|
+
content: {
|
|
180
|
+
text: messageText,
|
|
181
|
+
},
|
|
182
|
+
visibility: params.message.metadata?.fromExternalAgentId ? 'external' : 'internal',
|
|
183
|
+
messageType: 'a2a-request',
|
|
184
|
+
taskId: task.id,
|
|
185
|
+
};
|
|
186
|
+
// Set appropriate agent tracking fields
|
|
187
|
+
if (params.message.metadata?.fromAgentId) {
|
|
188
|
+
// Internal agent communication
|
|
189
|
+
messageData.fromAgentId = params.message.metadata.fromAgentId;
|
|
190
|
+
messageData.toAgentId = agent.agentId;
|
|
191
|
+
}
|
|
192
|
+
else if (params.message.metadata?.fromExternalAgentId) {
|
|
193
|
+
// External agent communication
|
|
194
|
+
messageData.fromExternalAgentId = params.message.metadata.fromExternalAgentId;
|
|
195
|
+
messageData.toAgentId = agent.agentId;
|
|
196
|
+
}
|
|
197
|
+
await createMessage(dbClient)(messageData);
|
|
198
|
+
logger.info({
|
|
199
|
+
fromAgentId: params.message.metadata.fromAgentId,
|
|
200
|
+
fromExternalAgentId: params.message.metadata.fromExternalAgentId,
|
|
201
|
+
toAgentId: agent.agentId,
|
|
202
|
+
conversationId: effectiveContextId,
|
|
203
|
+
messageType: 'a2a-request',
|
|
204
|
+
taskId: task.id,
|
|
205
|
+
}, 'A2A message stored in database');
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
logger.error({
|
|
209
|
+
error,
|
|
210
|
+
fromAgentId: params.message.metadata.fromAgentId,
|
|
211
|
+
fromExternalAgentId: params.message.metadata.fromExternalAgentId,
|
|
212
|
+
toAgentId: agent.agentId,
|
|
213
|
+
conversationId: effectiveContextId,
|
|
214
|
+
}, 'Failed to store A2A message in database');
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// Execute the task
|
|
218
|
+
const result = await agent.taskHandler(task);
|
|
219
|
+
// --- Update the task in the DB with result ---
|
|
220
|
+
await updateTask(dbClient)({
|
|
221
|
+
taskId: task.id,
|
|
222
|
+
data: {
|
|
223
|
+
status: result.status.state.toLowerCase(),
|
|
224
|
+
metadata: {
|
|
225
|
+
conversation_id: params.message.contextId || '',
|
|
226
|
+
message_id: params.message.messageId || '',
|
|
227
|
+
created_at: new Date().toISOString(),
|
|
228
|
+
updated_at: new Date().toISOString(),
|
|
229
|
+
agent_id: agent.agentId,
|
|
230
|
+
graph_id: graphId || '',
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
// Check if the result contains a transfer indication
|
|
235
|
+
const transferArtifact = result.artifacts?.find((artifact) => artifact.parts?.some((part) => part.kind === 'data' &&
|
|
236
|
+
part.data &&
|
|
237
|
+
typeof part.data === 'object' &&
|
|
238
|
+
part.data.type === 'transfer'));
|
|
239
|
+
if (transferArtifact) {
|
|
240
|
+
const transferPart = transferArtifact.parts?.find((part) => part.kind === 'data' &&
|
|
241
|
+
part.data &&
|
|
242
|
+
typeof part.data === 'object' &&
|
|
243
|
+
part.data.type === 'transfer');
|
|
244
|
+
if (transferPart && transferPart.kind === 'data' && transferPart.data) {
|
|
245
|
+
logger.info({ transferPart }, 'transferPart');
|
|
246
|
+
// Return a transfer response instead of normal task/message response
|
|
247
|
+
return c.json({
|
|
248
|
+
jsonrpc: '2.0',
|
|
249
|
+
result: {
|
|
250
|
+
kind: 'task',
|
|
251
|
+
contextId: params.message.contextId,
|
|
252
|
+
id: task.id,
|
|
253
|
+
status: {
|
|
254
|
+
state: TaskState.Completed,
|
|
255
|
+
timestamp: new Date().toISOString(),
|
|
256
|
+
},
|
|
257
|
+
artifacts: [
|
|
258
|
+
{
|
|
259
|
+
artifactId: nanoid(),
|
|
260
|
+
parts: [
|
|
261
|
+
{
|
|
262
|
+
kind: 'data',
|
|
263
|
+
data: {
|
|
264
|
+
type: 'transfer',
|
|
265
|
+
targetAgentId: transferPart.data.target,
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
kind: 'text',
|
|
270
|
+
text: transferPart.data.reason || 'Agent requested transfer',
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
},
|
|
274
|
+
],
|
|
275
|
+
},
|
|
276
|
+
id: request.id,
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
// Convert A2ATaskResult status to schema TaskStatus
|
|
281
|
+
const taskStatus = {
|
|
282
|
+
state: result.status.state,
|
|
283
|
+
timestamp: new Date().toISOString(),
|
|
284
|
+
// Don't include message field since it expects Message object, not string
|
|
285
|
+
};
|
|
286
|
+
// Convert back to Google A2A format
|
|
287
|
+
if (params.configuration?.blocking === false) {
|
|
288
|
+
// Return a Task for non-blocking requests
|
|
289
|
+
const taskResponse = {
|
|
290
|
+
id: task.id,
|
|
291
|
+
contextId: params.message.contextId || nanoid(),
|
|
292
|
+
status: taskStatus,
|
|
293
|
+
artifacts: result.artifacts,
|
|
294
|
+
kind: 'task',
|
|
295
|
+
};
|
|
296
|
+
return c.json({
|
|
297
|
+
jsonrpc: '2.0',
|
|
298
|
+
result: taskResponse,
|
|
299
|
+
id: request.id,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
// Return a Message for blocking requests
|
|
303
|
+
const messageResponse = {
|
|
304
|
+
messageId: nanoid(),
|
|
305
|
+
parts: result.artifacts?.[0]?.parts || [
|
|
306
|
+
{
|
|
307
|
+
kind: 'text',
|
|
308
|
+
text: 'Task completed successfully',
|
|
309
|
+
},
|
|
310
|
+
],
|
|
311
|
+
role: 'agent',
|
|
312
|
+
taskId: task.id,
|
|
313
|
+
contextId: params.message.contextId,
|
|
314
|
+
kind: 'message',
|
|
315
|
+
};
|
|
316
|
+
return c.json({
|
|
317
|
+
jsonrpc: '2.0',
|
|
318
|
+
result: messageResponse,
|
|
319
|
+
id: request.id,
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
catch (error) {
|
|
323
|
+
return c.json({
|
|
324
|
+
jsonrpc: '2.0',
|
|
325
|
+
error: {
|
|
326
|
+
code: -32603,
|
|
327
|
+
message: 'Internal error during message send',
|
|
328
|
+
data: error instanceof Error ? error.message : 'Unknown error',
|
|
329
|
+
},
|
|
330
|
+
id: request.id,
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
async function handleMessageStream(c, agent, request) {
|
|
335
|
+
try {
|
|
336
|
+
const params = request.params;
|
|
337
|
+
const executionContext = getRequestExecutionContext(c);
|
|
338
|
+
const { graphId } = executionContext;
|
|
339
|
+
// Check if agent supports streaming
|
|
340
|
+
if (!agent.agentCard.capabilities.streaming) {
|
|
341
|
+
return c.json({
|
|
342
|
+
jsonrpc: '2.0',
|
|
343
|
+
error: {
|
|
344
|
+
code: -32604,
|
|
345
|
+
message: 'Agent does not support streaming',
|
|
346
|
+
},
|
|
347
|
+
id: request.id,
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
// Convert to our internal task format
|
|
351
|
+
const task = {
|
|
352
|
+
id: nanoid(),
|
|
353
|
+
input: {
|
|
354
|
+
parts: params.message.parts.map((part) => ({
|
|
355
|
+
kind: part.kind,
|
|
356
|
+
text: part.kind === 'text' ? part.text : undefined,
|
|
357
|
+
data: part.kind === 'data' ? part.data : undefined,
|
|
358
|
+
})),
|
|
359
|
+
},
|
|
360
|
+
context: {
|
|
361
|
+
conversationId: params.message.contextId,
|
|
362
|
+
metadata: {
|
|
363
|
+
blocking: false, // Streaming is always non-blocking
|
|
364
|
+
custom: { graph_id: graphId || '' },
|
|
365
|
+
},
|
|
366
|
+
},
|
|
367
|
+
};
|
|
368
|
+
// Return SSE stream
|
|
369
|
+
return streamSSE(c, async (stream) => {
|
|
370
|
+
try {
|
|
371
|
+
// Initial task acknowledgment
|
|
372
|
+
const initialTask = {
|
|
373
|
+
id: task.id,
|
|
374
|
+
contextId: params.message.contextId || nanoid(),
|
|
375
|
+
status: {
|
|
376
|
+
state: TaskState.Working,
|
|
377
|
+
timestamp: new Date().toISOString(),
|
|
378
|
+
},
|
|
379
|
+
artifacts: [],
|
|
380
|
+
kind: 'task',
|
|
381
|
+
};
|
|
382
|
+
// Send initial task status
|
|
383
|
+
await stream.writeSSE({
|
|
384
|
+
data: JSON.stringify({
|
|
385
|
+
jsonrpc: '2.0',
|
|
386
|
+
result: initialTask,
|
|
387
|
+
id: request.id,
|
|
388
|
+
}),
|
|
389
|
+
});
|
|
390
|
+
// Execute the task with streaming
|
|
391
|
+
const result = await agent.taskHandler(task);
|
|
392
|
+
// Check for transfer first
|
|
393
|
+
const transferArtifact = result.artifacts?.find((artifact) => artifact.parts?.some((part) => part.kind === 'data' &&
|
|
394
|
+
part.data &&
|
|
395
|
+
typeof part.data === 'object' &&
|
|
396
|
+
part.data.type === 'transfer'));
|
|
397
|
+
if (transferArtifact) {
|
|
398
|
+
const transferPart = transferArtifact.parts?.find((part) => part.kind === 'data' &&
|
|
399
|
+
part.data &&
|
|
400
|
+
typeof part.data === 'object' &&
|
|
401
|
+
part.data.type === 'transfer');
|
|
402
|
+
if (transferPart && transferPart.kind === 'data' && transferPart.data) {
|
|
403
|
+
// Stream transfer response
|
|
404
|
+
await stream.writeSSE({
|
|
405
|
+
data: JSON.stringify({
|
|
406
|
+
jsonrpc: '2.0',
|
|
407
|
+
result: {
|
|
408
|
+
type: 'transfer',
|
|
409
|
+
target: transferPart.data.target,
|
|
410
|
+
task_id: task.id,
|
|
411
|
+
reason: transferPart.data.reason || 'Agent requested transfer',
|
|
412
|
+
original_message: transferPart.data.original_message,
|
|
413
|
+
context: {
|
|
414
|
+
conversationId: params.message.contextId,
|
|
415
|
+
tenantId: agent.tenantId,
|
|
416
|
+
transfer_context: result.artifacts,
|
|
417
|
+
},
|
|
418
|
+
},
|
|
419
|
+
id: request.id,
|
|
420
|
+
}),
|
|
421
|
+
});
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
// Stream regular message response
|
|
426
|
+
const messageResponse = {
|
|
427
|
+
messageId: nanoid(),
|
|
428
|
+
parts: result.artifacts?.[0]?.parts || [
|
|
429
|
+
{
|
|
430
|
+
kind: 'text',
|
|
431
|
+
text: 'Task completed successfully',
|
|
432
|
+
},
|
|
433
|
+
],
|
|
434
|
+
role: 'agent',
|
|
435
|
+
taskId: task.id,
|
|
436
|
+
contextId: params.message.contextId,
|
|
437
|
+
kind: 'message',
|
|
438
|
+
};
|
|
439
|
+
await stream.writeSSE({
|
|
440
|
+
data: JSON.stringify({
|
|
441
|
+
jsonrpc: '2.0',
|
|
442
|
+
result: messageResponse,
|
|
443
|
+
id: request.id,
|
|
444
|
+
}),
|
|
445
|
+
});
|
|
446
|
+
// Send final task completion status
|
|
447
|
+
const completedTask = {
|
|
448
|
+
...initialTask,
|
|
449
|
+
status: {
|
|
450
|
+
state: TaskState.Completed,
|
|
451
|
+
timestamp: new Date().toISOString(),
|
|
452
|
+
},
|
|
453
|
+
artifacts: result.artifacts,
|
|
454
|
+
};
|
|
455
|
+
await stream.writeSSE({
|
|
456
|
+
data: JSON.stringify({
|
|
457
|
+
jsonrpc: '2.0',
|
|
458
|
+
result: completedTask,
|
|
459
|
+
id: request.id,
|
|
460
|
+
}),
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
catch (error) {
|
|
464
|
+
console.error('Error in stream execution:', error);
|
|
465
|
+
// Send error as SSE event
|
|
466
|
+
await stream.writeSSE({
|
|
467
|
+
data: JSON.stringify({
|
|
468
|
+
jsonrpc: '2.0',
|
|
469
|
+
error: {
|
|
470
|
+
code: -32603,
|
|
471
|
+
message: 'Internal error during streaming execution',
|
|
472
|
+
data: error instanceof Error ? error.message : 'Unknown error',
|
|
473
|
+
},
|
|
474
|
+
id: request.id,
|
|
475
|
+
}),
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
catch (error) {
|
|
481
|
+
return c.json({
|
|
482
|
+
jsonrpc: '2.0',
|
|
483
|
+
error: {
|
|
484
|
+
code: -32603,
|
|
485
|
+
message: 'Internal error during message stream setup',
|
|
486
|
+
data: error instanceof Error ? error.message : 'Unknown error',
|
|
487
|
+
},
|
|
488
|
+
id: request.id,
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
async function handleTasksGet(c, _agent, request) {
|
|
493
|
+
try {
|
|
494
|
+
const params = request.params;
|
|
495
|
+
// For now, return a mock task since we don't have persistent storage
|
|
496
|
+
const task = {
|
|
497
|
+
id: params.id,
|
|
498
|
+
contextId: nanoid(),
|
|
499
|
+
status: {
|
|
500
|
+
state: TaskState.Completed,
|
|
501
|
+
timestamp: new Date().toISOString(),
|
|
502
|
+
},
|
|
503
|
+
artifacts: [
|
|
504
|
+
{
|
|
505
|
+
artifactId: nanoid(),
|
|
506
|
+
parts: [
|
|
507
|
+
{
|
|
508
|
+
kind: 'text',
|
|
509
|
+
text: `Task ${params.id} completed successfully`,
|
|
510
|
+
},
|
|
511
|
+
],
|
|
512
|
+
},
|
|
513
|
+
],
|
|
514
|
+
kind: 'task',
|
|
515
|
+
};
|
|
516
|
+
return c.json({
|
|
517
|
+
jsonrpc: '2.0',
|
|
518
|
+
result: task,
|
|
519
|
+
id: request.id,
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
catch (error) {
|
|
523
|
+
return c.json({
|
|
524
|
+
jsonrpc: '2.0',
|
|
525
|
+
error: {
|
|
526
|
+
code: -32603,
|
|
527
|
+
message: 'Internal error getting task',
|
|
528
|
+
data: error instanceof Error ? error.message : 'Unknown error',
|
|
529
|
+
},
|
|
530
|
+
id: request.id,
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
async function handleTasksCancel(c, _agent, request) {
|
|
535
|
+
try {
|
|
536
|
+
const _params = request.params;
|
|
537
|
+
// For now, just return success
|
|
538
|
+
return c.json({
|
|
539
|
+
jsonrpc: '2.0',
|
|
540
|
+
result: { success: true },
|
|
541
|
+
id: request.id,
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
catch (error) {
|
|
545
|
+
return c.json({
|
|
546
|
+
jsonrpc: '2.0',
|
|
547
|
+
error: {
|
|
548
|
+
code: -32603,
|
|
549
|
+
message: 'Internal error canceling task',
|
|
550
|
+
data: error instanceof Error ? error.message : 'Unknown error',
|
|
551
|
+
},
|
|
552
|
+
id: request.id,
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
async function handleAgentInvoke(c, agent, request) {
|
|
557
|
+
try {
|
|
558
|
+
const task = request.params;
|
|
559
|
+
const result = await agent.taskHandler(task);
|
|
560
|
+
return c.json({
|
|
561
|
+
jsonrpc: '2.0',
|
|
562
|
+
result,
|
|
563
|
+
id: request.id,
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
catch (error) {
|
|
567
|
+
return c.json({
|
|
568
|
+
jsonrpc: '2.0',
|
|
569
|
+
error: {
|
|
570
|
+
code: -32603,
|
|
571
|
+
message: 'Internal error during agent invocation',
|
|
572
|
+
data: error instanceof Error ? error.message : 'Unknown error',
|
|
573
|
+
},
|
|
574
|
+
id: request.id,
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
async function handleGetCapabilities(c, agent, request) {
|
|
579
|
+
return c.json({
|
|
580
|
+
jsonrpc: '2.0',
|
|
581
|
+
result: agent.agentCard.capabilities,
|
|
582
|
+
id: request.id,
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
async function handleGetStatus(c, agent, request) {
|
|
586
|
+
return c.json({
|
|
587
|
+
jsonrpc: '2.0',
|
|
588
|
+
result: { status: 'ready', agentId: agent.agentId },
|
|
589
|
+
id: request.id,
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
async function handleTasksResubscribe(c, agent, request) {
|
|
593
|
+
try {
|
|
594
|
+
const params = request.params;
|
|
595
|
+
// Check if agent supports streaming
|
|
596
|
+
if (!agent.agentCard.capabilities.streaming) {
|
|
597
|
+
return c.json({
|
|
598
|
+
jsonrpc: '2.0',
|
|
599
|
+
error: {
|
|
600
|
+
code: -32604,
|
|
601
|
+
message: 'Agent does not support streaming for resubscription',
|
|
602
|
+
},
|
|
603
|
+
id: request.id,
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
// For now, return SSE stream that immediately provides task status
|
|
607
|
+
// In a full implementation, this would reconnect to an existing task's stream
|
|
608
|
+
return streamSSE(c, async (stream) => {
|
|
609
|
+
try {
|
|
610
|
+
// Mock task status for resubscription
|
|
611
|
+
const task = {
|
|
612
|
+
id: params.taskId,
|
|
613
|
+
contextId: nanoid(),
|
|
614
|
+
status: {
|
|
615
|
+
state: TaskState.Completed,
|
|
616
|
+
timestamp: new Date().toISOString(),
|
|
617
|
+
},
|
|
618
|
+
artifacts: [],
|
|
619
|
+
kind: 'task',
|
|
620
|
+
};
|
|
621
|
+
await stream.writeSSE({
|
|
622
|
+
data: JSON.stringify({
|
|
623
|
+
jsonrpc: '2.0',
|
|
624
|
+
result: task,
|
|
625
|
+
id: request.id,
|
|
626
|
+
}),
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
catch (error) {
|
|
630
|
+
console.error('Error in task resubscription:', error);
|
|
631
|
+
await stream.writeSSE({
|
|
632
|
+
data: JSON.stringify({
|
|
633
|
+
jsonrpc: '2.0',
|
|
634
|
+
error: {
|
|
635
|
+
code: -32603,
|
|
636
|
+
message: 'Internal error during task resubscription',
|
|
637
|
+
data: error instanceof Error ? error.message : 'Unknown error',
|
|
638
|
+
},
|
|
639
|
+
id: request.id,
|
|
640
|
+
}),
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
catch (error) {
|
|
646
|
+
return c.json({
|
|
647
|
+
jsonrpc: '2.0',
|
|
648
|
+
error: {
|
|
649
|
+
code: -32603,
|
|
650
|
+
message: 'Internal error during task resubscription setup',
|
|
651
|
+
data: error instanceof Error ? error.message : 'Unknown error',
|
|
652
|
+
},
|
|
653
|
+
id: request.id,
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { TransferResponse } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Executes a transfer by sending the original message to the target agent
|
|
4
|
+
*/
|
|
5
|
+
export declare function executeTransfer({ tenantId, threadId, projectId, targetAgentId, }: {
|
|
6
|
+
tenantId: string;
|
|
7
|
+
threadId: string;
|
|
8
|
+
projectId: string;
|
|
9
|
+
targetAgentId: string;
|
|
10
|
+
}): Promise<{
|
|
11
|
+
success: boolean;
|
|
12
|
+
targetAgentId: string;
|
|
13
|
+
}>;
|
|
14
|
+
/**
|
|
15
|
+
* Checks if a response is a transfer response
|
|
16
|
+
*/
|
|
17
|
+
export declare function isTransferResponse(result: any): result is TransferResponse;
|
|
18
|
+
//# sourceMappingURL=transfer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transfer.d.ts","sourceRoot":"","sources":["../../src/a2a/transfer.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAGhD;;GAEG;AACH,wBAAsB,eAAe,CAAC,EACpC,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,aAAa,GACd,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC;IACV,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC,CAQD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,GAAG,GAAG,MAAM,IAAI,gBAAgB,CAI1E"}
|