opc-agent 2.0.0 → 2.0.1
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/dist/channels/email.d.ts +32 -26
- package/dist/channels/email.js +239 -62
- package/dist/channels/feishu.d.ts +21 -6
- package/dist/channels/feishu.js +225 -126
- package/dist/channels/websocket.d.ts +46 -3
- package/dist/channels/websocket.js +306 -37
- package/dist/channels/wechat.d.ts +33 -13
- package/dist/channels/wechat.js +229 -42
- package/dist/cli.js +712 -11
- package/dist/core/a2a.d.ts +17 -0
- package/dist/core/a2a.js +43 -1
- package/dist/core/agent.d.ts +16 -0
- package/dist/core/agent.js +108 -0
- package/dist/core/runtime.d.ts +6 -0
- package/dist/core/runtime.js +161 -2
- package/dist/core/sandbox.d.ts +26 -0
- package/dist/core/sandbox.js +117 -0
- package/dist/core/workflow-graph.d.ts +93 -0
- package/dist/core/workflow-graph.js +247 -0
- package/dist/doctor.d.ts +15 -0
- package/dist/doctor.js +183 -0
- package/dist/eval/index.d.ts +65 -0
- package/dist/eval/index.js +191 -0
- package/dist/index.d.ts +30 -6
- package/dist/index.js +60 -4
- package/dist/plugins/content-filter.d.ts +7 -0
- package/dist/plugins/content-filter.js +25 -0
- package/dist/plugins/index.d.ts +42 -0
- package/dist/plugins/index.js +108 -2
- package/dist/plugins/logger.d.ts +6 -0
- package/dist/plugins/logger.js +20 -0
- package/dist/plugins/rate-limiter.d.ts +7 -0
- package/dist/plugins/rate-limiter.js +35 -0
- package/dist/protocols/a2a/client.d.ts +25 -0
- package/dist/protocols/a2a/client.js +115 -0
- package/dist/protocols/a2a/index.d.ts +6 -0
- package/dist/protocols/a2a/index.js +12 -0
- package/dist/protocols/a2a/server.d.ts +41 -0
- package/dist/protocols/a2a/server.js +295 -0
- package/dist/protocols/a2a/types.d.ts +91 -0
- package/dist/protocols/a2a/types.js +15 -0
- package/dist/protocols/a2a/utils.d.ts +6 -0
- package/dist/protocols/a2a/utils.js +47 -0
- package/dist/protocols/agui/client.d.ts +10 -0
- package/dist/protocols/agui/client.js +75 -0
- package/dist/protocols/agui/index.d.ts +4 -0
- package/dist/protocols/agui/index.js +25 -0
- package/dist/protocols/agui/server.d.ts +37 -0
- package/dist/protocols/agui/server.js +191 -0
- package/dist/protocols/agui/types.d.ts +107 -0
- package/dist/protocols/agui/types.js +17 -0
- package/dist/protocols/index.d.ts +2 -0
- package/dist/protocols/index.js +19 -0
- package/dist/protocols/mcp/agent-tools.d.ts +11 -0
- package/dist/protocols/mcp/agent-tools.js +129 -0
- package/dist/protocols/mcp/index.d.ts +5 -0
- package/dist/protocols/mcp/index.js +11 -0
- package/dist/protocols/mcp/server.d.ts +31 -0
- package/dist/protocols/mcp/server.js +248 -0
- package/dist/protocols/mcp/types.d.ts +92 -0
- package/dist/protocols/mcp/types.js +17 -0
- package/dist/publish/index.d.ts +45 -0
- package/dist/publish/index.js +350 -0
- package/dist/schema/oad.d.ts +682 -65
- package/dist/schema/oad.js +36 -3
- package/dist/security/approval.d.ts +36 -0
- package/dist/security/approval.js +113 -0
- package/dist/security/index.d.ts +4 -0
- package/dist/security/index.js +8 -0
- package/dist/security/keys.d.ts +16 -0
- package/dist/security/keys.js +117 -0
- package/dist/studio/server.d.ts +63 -0
- package/dist/studio/server.js +625 -0
- package/dist/studio-ui/index.html +662 -0
- package/dist/telemetry/index.d.ts +93 -0
- package/dist/telemetry/index.js +285 -0
- package/package.json +5 -3
- package/scripts/install.ps1 +31 -0
- package/scripts/install.sh +40 -0
- package/src/channels/email.ts +351 -177
- package/src/channels/feishu.ts +349 -236
- package/src/channels/websocket.ts +399 -87
- package/src/channels/wechat.ts +329 -149
- package/src/cli.ts +783 -12
- package/src/core/a2a.ts +60 -0
- package/src/core/agent.ts +125 -0
- package/src/core/runtime.ts +127 -0
- package/src/core/sandbox.ts +143 -0
- package/src/core/workflow-graph.ts +365 -0
- package/src/doctor.ts +156 -0
- package/src/eval/index.ts +211 -0
- package/src/eval/suites/basic.json +16 -0
- package/src/eval/suites/memory.json +12 -0
- package/src/eval/suites/safety.json +14 -0
- package/src/index.ts +54 -6
- package/src/plugins/content-filter.ts +23 -0
- package/src/plugins/index.ts +133 -2
- package/src/plugins/logger.ts +18 -0
- package/src/plugins/rate-limiter.ts +38 -0
- package/src/protocols/a2a/client.ts +132 -0
- package/src/protocols/a2a/index.ts +8 -0
- package/src/protocols/a2a/server.ts +333 -0
- package/src/protocols/a2a/types.ts +88 -0
- package/src/protocols/a2a/utils.ts +50 -0
- package/src/protocols/agui/client.ts +83 -0
- package/src/protocols/agui/index.ts +4 -0
- package/src/protocols/agui/server.ts +218 -0
- package/src/protocols/agui/types.ts +153 -0
- package/src/protocols/index.ts +2 -0
- package/src/protocols/mcp/agent-tools.ts +134 -0
- package/src/protocols/mcp/index.ts +8 -0
- package/src/protocols/mcp/server.ts +262 -0
- package/src/protocols/mcp/types.ts +69 -0
- package/src/publish/index.ts +376 -0
- package/src/schema/oad.ts +39 -2
- package/src/security/approval.ts +131 -0
- package/src/security/index.ts +3 -0
- package/src/security/keys.ts +87 -0
- package/src/studio/server.ts +629 -0
- package/src/studio-ui/index.html +662 -0
- package/src/telemetry/index.ts +324 -0
- package/src/types/agent-workstation.d.ts +2 -0
- package/tests/a2a-protocol.test.ts +285 -0
- package/tests/agui-protocol.test.ts +246 -0
- package/tests/channels/discord.test.ts +79 -0
- package/tests/channels/email.test.ts +148 -0
- package/tests/channels/feishu.test.ts +123 -0
- package/tests/channels/telegram.test.ts +129 -0
- package/tests/channels/websocket.test.ts +53 -0
- package/tests/channels/wechat.test.ts +170 -0
- package/tests/chat-cli.test.ts +160 -0
- package/tests/daemon.test.ts +135 -0
- package/tests/deepbrain-wire.test.ts +234 -0
- package/tests/doctor.test.ts +38 -0
- package/tests/eval.test.ts +173 -0
- package/tests/init-role.test.ts +124 -0
- package/tests/mcp-client.test.ts +92 -0
- package/tests/mcp-server.test.ts +178 -0
- package/tests/plugin-a2a-enhanced.test.ts +230 -0
- package/tests/publish.test.ts +231 -0
- package/tests/scheduler.test.ts +200 -0
- package/tests/security-enhanced.test.ts +233 -0
- package/tests/skill-learner.test.ts +161 -0
- package/tests/studio.test.ts +229 -0
- package/tests/subagent.test.ts +63 -0
- package/tests/telemetry.test.ts +186 -0
- package/tests/tools/builtin-extended.test.ts +138 -0
- package/tests/workflow-graph.test.ts +279 -0
- package/tutorial/customer-service-agent/README.md +612 -0
- package/tutorial/customer-service-agent/SOUL.md +26 -0
- package/tutorial/customer-service-agent/agent.yaml +63 -0
- package/tutorial/customer-service-agent/package.json +19 -0
- package/tutorial/customer-service-agent/src/index.ts +69 -0
- package/tutorial/customer-service-agent/src/skills/faq.ts +27 -0
- package/tutorial/customer-service-agent/src/skills/ticket.ts +22 -0
- package/tutorial/customer-service-agent/tsconfig.json +14 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.A2AServer = void 0;
|
|
4
|
+
const http_1 = require("http");
|
|
5
|
+
const types_1 = require("./types");
|
|
6
|
+
const utils_1 = require("./utils");
|
|
7
|
+
class A2AServer {
|
|
8
|
+
tasks = new Map();
|
|
9
|
+
agent;
|
|
10
|
+
card;
|
|
11
|
+
server;
|
|
12
|
+
taskHandler;
|
|
13
|
+
constructor(agent, config) {
|
|
14
|
+
this.agent = agent;
|
|
15
|
+
// Build card from OAD if available, then overlay explicit config
|
|
16
|
+
const baseCard = config?.oad
|
|
17
|
+
? (0, utils_1.oadToAgentCard)(config.oad, config?.card?.url || `http://localhost:${config?.port || 3001}`)
|
|
18
|
+
: {
|
|
19
|
+
name: agent?.name || 'opc-agent',
|
|
20
|
+
description: agent?.config?.systemPrompt?.slice(0, 200) || 'OPC Agent',
|
|
21
|
+
url: `http://localhost:${config?.port || 3001}`,
|
|
22
|
+
version: '1.0.0',
|
|
23
|
+
capabilities: { streaming: true, pushNotifications: false, stateTransitionHistory: true },
|
|
24
|
+
skills: [],
|
|
25
|
+
defaultInputModes: ['text'],
|
|
26
|
+
defaultOutputModes: ['text'],
|
|
27
|
+
};
|
|
28
|
+
this.card = { ...baseCard, ...config?.card };
|
|
29
|
+
}
|
|
30
|
+
/** Set custom handler for processing tasks */
|
|
31
|
+
onTask(handler) {
|
|
32
|
+
this.taskHandler = handler;
|
|
33
|
+
}
|
|
34
|
+
getAgentCard() {
|
|
35
|
+
return this.card;
|
|
36
|
+
}
|
|
37
|
+
getTasks() {
|
|
38
|
+
return Array.from(this.tasks.values());
|
|
39
|
+
}
|
|
40
|
+
/** Mount A2A routes on an existing HTTP server handler */
|
|
41
|
+
mount(handleRequest) {
|
|
42
|
+
return (req, res) => {
|
|
43
|
+
const url = new URL(req.url || '/', `http://${req.headers.host || 'localhost'}`);
|
|
44
|
+
// /.well-known/agent.json
|
|
45
|
+
if (url.pathname === '/.well-known/agent.json' && req.method === 'GET') {
|
|
46
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
47
|
+
res.end(JSON.stringify(this.card, null, 2));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
// JSON-RPC endpoint
|
|
51
|
+
if (url.pathname === '/' && req.method === 'POST') {
|
|
52
|
+
this.handleHTTP(req, res);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
// Fall through to original handler
|
|
56
|
+
handleRequest(req, res);
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
async start(port) {
|
|
60
|
+
this.card.url = `http://localhost:${port}`;
|
|
61
|
+
return new Promise((resolve) => {
|
|
62
|
+
this.server = (0, http_1.createServer)((req, res) => {
|
|
63
|
+
const url = new URL(req.url || '/', `http://${req.headers.host || 'localhost'}`);
|
|
64
|
+
if (url.pathname === '/.well-known/agent.json' && req.method === 'GET') {
|
|
65
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
66
|
+
res.end(JSON.stringify(this.card, null, 2));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (url.pathname === '/' && req.method === 'POST') {
|
|
70
|
+
this.handleHTTP(req, res);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
res.writeHead(404);
|
|
74
|
+
res.end('Not Found');
|
|
75
|
+
});
|
|
76
|
+
this.server.listen(port, () => resolve());
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
async stop() {
|
|
80
|
+
return new Promise((resolve) => {
|
|
81
|
+
if (this.server) {
|
|
82
|
+
this.server.close(() => resolve());
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
resolve();
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
async handleHTTP(req, res) {
|
|
90
|
+
const body = await this.readBody(req);
|
|
91
|
+
let rpcReq;
|
|
92
|
+
try {
|
|
93
|
+
rpcReq = JSON.parse(body);
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
97
|
+
res.end(JSON.stringify(this.rpcError(null, types_1.JSON_RPC_ERRORS.PARSE_ERROR, 'Parse error')));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (!rpcReq.jsonrpc || rpcReq.jsonrpc !== '2.0' || !rpcReq.method) {
|
|
101
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
102
|
+
res.end(JSON.stringify(this.rpcError(rpcReq?.id ?? null, types_1.JSON_RPC_ERRORS.INVALID_REQUEST, 'Invalid Request')));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
// SSE for streaming
|
|
106
|
+
if (rpcReq.method === 'tasks/sendSubscribe') {
|
|
107
|
+
res.writeHead(200, {
|
|
108
|
+
'Content-Type': 'text/event-stream',
|
|
109
|
+
'Cache-Control': 'no-cache',
|
|
110
|
+
'Connection': 'keep-alive',
|
|
111
|
+
});
|
|
112
|
+
try {
|
|
113
|
+
await this.tasksSendSubscribe(rpcReq.params, (event) => {
|
|
114
|
+
res.write(`data: ${JSON.stringify(event)}\n\n`);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
res.write(`data: ${JSON.stringify({ error: err.message })}\n\n`);
|
|
119
|
+
}
|
|
120
|
+
res.end();
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const result = await this.handleRPC(rpcReq.method, rpcReq.params, rpcReq.id);
|
|
124
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
125
|
+
res.end(JSON.stringify(result));
|
|
126
|
+
}
|
|
127
|
+
async handleRPC(method, params, id) {
|
|
128
|
+
try {
|
|
129
|
+
let result;
|
|
130
|
+
switch (method) {
|
|
131
|
+
case 'tasks/send':
|
|
132
|
+
result = await this.tasksSend(params);
|
|
133
|
+
break;
|
|
134
|
+
case 'tasks/get':
|
|
135
|
+
result = await this.tasksGet(params);
|
|
136
|
+
break;
|
|
137
|
+
case 'tasks/cancel':
|
|
138
|
+
result = await this.tasksCancel(params);
|
|
139
|
+
break;
|
|
140
|
+
default:
|
|
141
|
+
return this.rpcError(id, types_1.JSON_RPC_ERRORS.METHOD_NOT_FOUND, `Method not found: ${method}`);
|
|
142
|
+
}
|
|
143
|
+
return { jsonrpc: '2.0', id: id, result };
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
if (err.code) {
|
|
147
|
+
return this.rpcError(id, err.code, err.message);
|
|
148
|
+
}
|
|
149
|
+
return this.rpcError(id, types_1.JSON_RPC_ERRORS.INTERNAL_ERROR, err.message);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async tasksSend(params) {
|
|
153
|
+
const taskId = params.id;
|
|
154
|
+
const sessionId = params.sessionId || `session_${Date.now()}`;
|
|
155
|
+
let task = this.tasks.get(taskId);
|
|
156
|
+
if (!task) {
|
|
157
|
+
task = {
|
|
158
|
+
id: taskId,
|
|
159
|
+
sessionId,
|
|
160
|
+
status: { state: 'submitted', timestamp: new Date().toISOString() },
|
|
161
|
+
history: [],
|
|
162
|
+
artifacts: [],
|
|
163
|
+
metadata: params.metadata,
|
|
164
|
+
};
|
|
165
|
+
this.tasks.set(taskId, task);
|
|
166
|
+
}
|
|
167
|
+
// Add user message to history
|
|
168
|
+
task.history.push(params.message);
|
|
169
|
+
task.status = { state: 'working', timestamp: new Date().toISOString() };
|
|
170
|
+
// Process with custom handler or agent
|
|
171
|
+
if (this.taskHandler) {
|
|
172
|
+
task = await this.taskHandler(task);
|
|
173
|
+
this.tasks.set(taskId, task);
|
|
174
|
+
return task;
|
|
175
|
+
}
|
|
176
|
+
// Default: use agent.handleMessage if available
|
|
177
|
+
if (this.agent?.handleMessage) {
|
|
178
|
+
try {
|
|
179
|
+
const textContent = params.message.parts
|
|
180
|
+
.filter((p) => p.type === 'text')
|
|
181
|
+
.map((p) => p.text)
|
|
182
|
+
.join('\n');
|
|
183
|
+
const response = await this.agent.handleMessage({
|
|
184
|
+
id: taskId,
|
|
185
|
+
role: 'user',
|
|
186
|
+
content: textContent,
|
|
187
|
+
timestamp: Date.now(),
|
|
188
|
+
});
|
|
189
|
+
const agentMessage = {
|
|
190
|
+
role: 'agent',
|
|
191
|
+
parts: [{ type: 'text', text: response.content }],
|
|
192
|
+
};
|
|
193
|
+
task.history.push(agentMessage);
|
|
194
|
+
task.status = { state: 'completed', message: agentMessage, timestamp: new Date().toISOString() };
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
task.status = {
|
|
198
|
+
state: 'failed',
|
|
199
|
+
message: { role: 'agent', parts: [{ type: 'text', text: err.message }] },
|
|
200
|
+
timestamp: new Date().toISOString(),
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
// No agent — just mark completed with echo
|
|
206
|
+
const agentMessage = {
|
|
207
|
+
role: 'agent',
|
|
208
|
+
parts: [{ type: 'text', text: 'No agent handler configured' }],
|
|
209
|
+
};
|
|
210
|
+
task.history.push(agentMessage);
|
|
211
|
+
task.status = { state: 'completed', message: agentMessage, timestamp: new Date().toISOString() };
|
|
212
|
+
}
|
|
213
|
+
this.tasks.set(taskId, task);
|
|
214
|
+
return task;
|
|
215
|
+
}
|
|
216
|
+
async tasksSendSubscribe(params, onEvent) {
|
|
217
|
+
const taskId = params.id;
|
|
218
|
+
const sessionId = params.sessionId || `session_${Date.now()}`;
|
|
219
|
+
let task = {
|
|
220
|
+
id: taskId,
|
|
221
|
+
sessionId,
|
|
222
|
+
status: { state: 'submitted', timestamp: new Date().toISOString() },
|
|
223
|
+
history: [],
|
|
224
|
+
artifacts: [],
|
|
225
|
+
metadata: params.metadata,
|
|
226
|
+
};
|
|
227
|
+
this.tasks.set(taskId, task);
|
|
228
|
+
task.history.push(params.message);
|
|
229
|
+
// Emit submitted
|
|
230
|
+
onEvent({ jsonrpc: '2.0', result: { id: taskId, status: task.status } });
|
|
231
|
+
task.status = { state: 'working', timestamp: new Date().toISOString() };
|
|
232
|
+
onEvent({ jsonrpc: '2.0', result: { id: taskId, status: task.status } });
|
|
233
|
+
// Process
|
|
234
|
+
if (this.agent?.handleMessage) {
|
|
235
|
+
const textContent = params.message.parts
|
|
236
|
+
.filter((p) => p.type === 'text')
|
|
237
|
+
.map((p) => p.text)
|
|
238
|
+
.join('\n');
|
|
239
|
+
try {
|
|
240
|
+
const response = await this.agent.handleMessage({
|
|
241
|
+
id: taskId, role: 'user', content: textContent, timestamp: Date.now(),
|
|
242
|
+
});
|
|
243
|
+
const agentMessage = { role: 'agent', parts: [{ type: 'text', text: response.content }] };
|
|
244
|
+
task.history.push(agentMessage);
|
|
245
|
+
task.status = { state: 'completed', message: agentMessage, timestamp: new Date().toISOString() };
|
|
246
|
+
}
|
|
247
|
+
catch (err) {
|
|
248
|
+
task.status = { state: 'failed', message: { role: 'agent', parts: [{ type: 'text', text: err.message }] }, timestamp: new Date().toISOString() };
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
const msg = { role: 'agent', parts: [{ type: 'text', text: 'No agent handler' }] };
|
|
253
|
+
task.history.push(msg);
|
|
254
|
+
task.status = { state: 'completed', message: msg, timestamp: new Date().toISOString() };
|
|
255
|
+
}
|
|
256
|
+
this.tasks.set(taskId, task);
|
|
257
|
+
onEvent({ jsonrpc: '2.0', result: { id: taskId, status: task.status, history: task.history } });
|
|
258
|
+
}
|
|
259
|
+
async tasksGet(params) {
|
|
260
|
+
const task = this.tasks.get(params.id);
|
|
261
|
+
if (!task) {
|
|
262
|
+
const err = new Error(`Task not found: ${params.id}`);
|
|
263
|
+
err.code = types_1.JSON_RPC_ERRORS.TASK_NOT_FOUND;
|
|
264
|
+
throw err;
|
|
265
|
+
}
|
|
266
|
+
if (params.historyLength !== undefined) {
|
|
267
|
+
return { ...task, history: task.history.slice(-params.historyLength) };
|
|
268
|
+
}
|
|
269
|
+
return task;
|
|
270
|
+
}
|
|
271
|
+
async tasksCancel(params) {
|
|
272
|
+
const task = this.tasks.get(params.id);
|
|
273
|
+
if (!task) {
|
|
274
|
+
const err = new Error(`Task not found: ${params.id}`);
|
|
275
|
+
err.code = types_1.JSON_RPC_ERRORS.TASK_NOT_FOUND;
|
|
276
|
+
throw err;
|
|
277
|
+
}
|
|
278
|
+
task.status = { state: 'canceled', timestamp: new Date().toISOString() };
|
|
279
|
+
this.tasks.set(params.id, task);
|
|
280
|
+
return task;
|
|
281
|
+
}
|
|
282
|
+
rpcError(id, code, message) {
|
|
283
|
+
return { jsonrpc: '2.0', id, error: { code, message } };
|
|
284
|
+
}
|
|
285
|
+
readBody(req) {
|
|
286
|
+
return new Promise((resolve, reject) => {
|
|
287
|
+
const chunks = [];
|
|
288
|
+
req.on('data', (chunk) => chunks.push(chunk));
|
|
289
|
+
req.on('end', () => resolve(Buffer.concat(chunks).toString()));
|
|
290
|
+
req.on('error', reject);
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
exports.A2AServer = A2AServer;
|
|
295
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export interface A2AAgentCard {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
url: string;
|
|
5
|
+
version: string;
|
|
6
|
+
capabilities: {
|
|
7
|
+
streaming: boolean;
|
|
8
|
+
pushNotifications: boolean;
|
|
9
|
+
stateTransitionHistory: boolean;
|
|
10
|
+
};
|
|
11
|
+
skills: A2AAgentSkill[];
|
|
12
|
+
defaultInputModes: string[];
|
|
13
|
+
defaultOutputModes: string[];
|
|
14
|
+
authentication?: {
|
|
15
|
+
schemes: string[];
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export interface A2AAgentSkill {
|
|
19
|
+
id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
description: string;
|
|
22
|
+
tags: string[];
|
|
23
|
+
examples?: string[];
|
|
24
|
+
}
|
|
25
|
+
export interface A2ATask {
|
|
26
|
+
id: string;
|
|
27
|
+
sessionId: string;
|
|
28
|
+
status: A2ATaskStatus;
|
|
29
|
+
history: A2AMessage[];
|
|
30
|
+
artifacts: A2AArtifact[];
|
|
31
|
+
metadata?: Record<string, any>;
|
|
32
|
+
}
|
|
33
|
+
export type A2ATaskState = 'submitted' | 'working' | 'input-required' | 'completed' | 'canceled' | 'failed';
|
|
34
|
+
export interface A2ATaskStatus {
|
|
35
|
+
state: A2ATaskState;
|
|
36
|
+
message?: A2AMessage;
|
|
37
|
+
timestamp: string;
|
|
38
|
+
}
|
|
39
|
+
export interface A2AMessage {
|
|
40
|
+
role: 'user' | 'agent';
|
|
41
|
+
parts: A2AMessagePart[];
|
|
42
|
+
}
|
|
43
|
+
export type A2AMessagePart = {
|
|
44
|
+
type: 'text';
|
|
45
|
+
text: string;
|
|
46
|
+
} | {
|
|
47
|
+
type: 'file';
|
|
48
|
+
file: {
|
|
49
|
+
name: string;
|
|
50
|
+
mimeType: string;
|
|
51
|
+
bytes?: string;
|
|
52
|
+
uri?: string;
|
|
53
|
+
};
|
|
54
|
+
} | {
|
|
55
|
+
type: 'data';
|
|
56
|
+
data: Record<string, any>;
|
|
57
|
+
};
|
|
58
|
+
export interface A2AArtifact {
|
|
59
|
+
name: string;
|
|
60
|
+
description?: string;
|
|
61
|
+
parts: A2AMessagePart[];
|
|
62
|
+
index: number;
|
|
63
|
+
append?: boolean;
|
|
64
|
+
lastChunk?: boolean;
|
|
65
|
+
}
|
|
66
|
+
export interface JsonRpcRequest {
|
|
67
|
+
jsonrpc: '2.0';
|
|
68
|
+
id: string | number;
|
|
69
|
+
method: string;
|
|
70
|
+
params?: any;
|
|
71
|
+
}
|
|
72
|
+
export interface JsonRpcResponse {
|
|
73
|
+
jsonrpc: '2.0';
|
|
74
|
+
id: string | number | null;
|
|
75
|
+
result?: any;
|
|
76
|
+
error?: {
|
|
77
|
+
code: number;
|
|
78
|
+
message: string;
|
|
79
|
+
data?: any;
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
export declare const JSON_RPC_ERRORS: {
|
|
83
|
+
readonly PARSE_ERROR: -32700;
|
|
84
|
+
readonly INVALID_REQUEST: -32600;
|
|
85
|
+
readonly METHOD_NOT_FOUND: -32601;
|
|
86
|
+
readonly INVALID_PARAMS: -32602;
|
|
87
|
+
readonly INTERNAL_ERROR: -32603;
|
|
88
|
+
readonly TASK_NOT_FOUND: -32001;
|
|
89
|
+
readonly TASK_CANCELED: -32002;
|
|
90
|
+
};
|
|
91
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Google A2A Protocol Types — https://google.github.io/A2A/
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.JSON_RPC_ERRORS = void 0;
|
|
5
|
+
// Standard JSON-RPC error codes
|
|
6
|
+
exports.JSON_RPC_ERRORS = {
|
|
7
|
+
PARSE_ERROR: -32700,
|
|
8
|
+
INVALID_REQUEST: -32600,
|
|
9
|
+
METHOD_NOT_FOUND: -32601,
|
|
10
|
+
INVALID_PARAMS: -32602,
|
|
11
|
+
INTERNAL_ERROR: -32603,
|
|
12
|
+
TASK_NOT_FOUND: -32001,
|
|
13
|
+
TASK_CANCELED: -32002,
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.oadToAgentCard = oadToAgentCard;
|
|
4
|
+
/**
|
|
5
|
+
* Convert an OAD (Open Agent Definition) document to an A2A AgentCard.
|
|
6
|
+
*/
|
|
7
|
+
function oadToAgentCard(oad, baseUrl) {
|
|
8
|
+
const meta = oad?.metadata || {};
|
|
9
|
+
const spec = oad?.spec || {};
|
|
10
|
+
// Extract skills from OAD
|
|
11
|
+
const skills = (spec.skills || []).map((s, i) => ({
|
|
12
|
+
id: s.id || s.name || `skill-${i}`,
|
|
13
|
+
name: s.name || `Skill ${i}`,
|
|
14
|
+
description: s.description || '',
|
|
15
|
+
tags: s.tags || [],
|
|
16
|
+
examples: s.examples || [],
|
|
17
|
+
}));
|
|
18
|
+
// If no skills defined, create one from the agent description
|
|
19
|
+
if (skills.length === 0 && (spec.systemPrompt || meta.description)) {
|
|
20
|
+
skills.push({
|
|
21
|
+
id: 'default',
|
|
22
|
+
name: meta.name || 'default',
|
|
23
|
+
description: meta.description || spec.systemPrompt?.slice(0, 200) || 'General agent capability',
|
|
24
|
+
tags: ['general'],
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
// Detect capabilities from OAD
|
|
28
|
+
const channels = spec.channels || [];
|
|
29
|
+
const hasStreaming = channels.some((c) => c.type === 'websocket' || c.type === 'web');
|
|
30
|
+
const url = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
|
|
31
|
+
return {
|
|
32
|
+
name: meta.name || 'opc-agent',
|
|
33
|
+
description: meta.description || '',
|
|
34
|
+
url,
|
|
35
|
+
version: meta.version || '1.0.0',
|
|
36
|
+
capabilities: {
|
|
37
|
+
streaming: hasStreaming,
|
|
38
|
+
pushNotifications: false,
|
|
39
|
+
stateTransitionHistory: true,
|
|
40
|
+
},
|
|
41
|
+
skills,
|
|
42
|
+
defaultInputModes: ['text'],
|
|
43
|
+
defaultOutputModes: ['text'],
|
|
44
|
+
authentication: spec.auth ? { schemes: [spec.auth.type || 'bearer'] } : undefined,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AGUIEvent, AGUIRunRequest } from './types';
|
|
2
|
+
export declare class AGUIClient {
|
|
3
|
+
private endpoint;
|
|
4
|
+
private controller?;
|
|
5
|
+
constructor(endpoint: string);
|
|
6
|
+
run(request: AGUIRunRequest, onEvent: (event: AGUIEvent) => void): Promise<void>;
|
|
7
|
+
sendText(text: string, onChunk: (text: string) => void): Promise<string>;
|
|
8
|
+
abort(): void;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AGUIClient = void 0;
|
|
4
|
+
const types_1 = require("./types");
|
|
5
|
+
class AGUIClient {
|
|
6
|
+
endpoint;
|
|
7
|
+
controller;
|
|
8
|
+
constructor(endpoint) {
|
|
9
|
+
this.endpoint = endpoint;
|
|
10
|
+
}
|
|
11
|
+
async run(request, onEvent) {
|
|
12
|
+
this.controller = new AbortController();
|
|
13
|
+
const res = await fetch(this.endpoint, {
|
|
14
|
+
method: 'POST',
|
|
15
|
+
headers: { 'Content-Type': 'application/json' },
|
|
16
|
+
body: JSON.stringify(request),
|
|
17
|
+
signal: this.controller.signal,
|
|
18
|
+
});
|
|
19
|
+
if (!res.ok) {
|
|
20
|
+
throw new Error(`AG-UI request failed: ${res.status} ${res.statusText}`);
|
|
21
|
+
}
|
|
22
|
+
if (!res.body) {
|
|
23
|
+
throw new Error('No response body');
|
|
24
|
+
}
|
|
25
|
+
const reader = res.body.getReader();
|
|
26
|
+
const decoder = new TextDecoder();
|
|
27
|
+
let buffer = '';
|
|
28
|
+
try {
|
|
29
|
+
while (true) {
|
|
30
|
+
const { done, value } = await reader.read();
|
|
31
|
+
if (done)
|
|
32
|
+
break;
|
|
33
|
+
buffer += decoder.decode(value, { stream: true });
|
|
34
|
+
const lines = buffer.split('\n');
|
|
35
|
+
buffer = lines.pop() || '';
|
|
36
|
+
for (const line of lines) {
|
|
37
|
+
if (line.startsWith('data: ')) {
|
|
38
|
+
try {
|
|
39
|
+
const event = JSON.parse(line.slice(6));
|
|
40
|
+
if (event.type && (0, types_1.isValidEventType)(event.type)) {
|
|
41
|
+
onEvent(event);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// skip malformed events
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
reader.releaseLock();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async sendText(text, onChunk) {
|
|
56
|
+
let fullText = '';
|
|
57
|
+
const request = {
|
|
58
|
+
messages: [{ id: `msg_${Date.now()}`, role: 'user', content: text }],
|
|
59
|
+
};
|
|
60
|
+
await this.run(request, (event) => {
|
|
61
|
+
if (event.type === 'TEXT_MESSAGE_CONTENT') {
|
|
62
|
+
const delta = event.delta;
|
|
63
|
+
fullText += delta;
|
|
64
|
+
onChunk(delta);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
return fullText;
|
|
68
|
+
}
|
|
69
|
+
abort() {
|
|
70
|
+
this.controller?.abort();
|
|
71
|
+
this.controller = undefined;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.AGUIClient = AGUIClient;
|
|
75
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.AGUIClient = exports.AGUIEventEmitter = exports.AGUIServer = void 0;
|
|
18
|
+
// AG-UI Protocol — barrel export
|
|
19
|
+
__exportStar(require("./types"), exports);
|
|
20
|
+
var server_1 = require("./server");
|
|
21
|
+
Object.defineProperty(exports, "AGUIServer", { enumerable: true, get: function () { return server_1.AGUIServer; } });
|
|
22
|
+
Object.defineProperty(exports, "AGUIEventEmitter", { enumerable: true, get: function () { return server_1.AGUIEventEmitter; } });
|
|
23
|
+
var client_1 = require("./client");
|
|
24
|
+
Object.defineProperty(exports, "AGUIClient", { enumerable: true, get: function () { return client_1.AGUIClient; } });
|
|
25
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { IncomingMessage, ServerResponse, Server } from 'http';
|
|
2
|
+
import type { AGUIEvent, AGUIMessage } from './types';
|
|
3
|
+
import type { BaseAgent } from '../../core/agent';
|
|
4
|
+
export declare class AGUIEventEmitter {
|
|
5
|
+
private res;
|
|
6
|
+
private closed;
|
|
7
|
+
constructor(res: ServerResponse);
|
|
8
|
+
emit(event: AGUIEvent): void;
|
|
9
|
+
textStart(messageId: string): void;
|
|
10
|
+
textContent(messageId: string, delta: string): void;
|
|
11
|
+
textEnd(messageId: string): void;
|
|
12
|
+
toolCallStart(id: string, name: string): void;
|
|
13
|
+
toolCallArgs(id: string, delta: string): void;
|
|
14
|
+
toolCallEnd(id: string): void;
|
|
15
|
+
stateSnapshot(snapshot: Record<string, any>): void;
|
|
16
|
+
stateDelta(delta: any[]): void;
|
|
17
|
+
runStarted(runId: string, threadId?: string): void;
|
|
18
|
+
runFinished(runId: string): void;
|
|
19
|
+
runError(runId: string, message: string, code?: string): void;
|
|
20
|
+
stepStarted(stepId: string, stepName?: string): void;
|
|
21
|
+
stepFinished(stepId: string): void;
|
|
22
|
+
messagesSnapshot(messages: AGUIMessage[]): void;
|
|
23
|
+
custom(name: string, value: any): void;
|
|
24
|
+
close(): void;
|
|
25
|
+
get isClosed(): boolean;
|
|
26
|
+
}
|
|
27
|
+
export declare class AGUIServer {
|
|
28
|
+
private agent;
|
|
29
|
+
private path;
|
|
30
|
+
constructor(agent: BaseAgent, config?: {
|
|
31
|
+
path?: string;
|
|
32
|
+
});
|
|
33
|
+
mount(server: Server): void;
|
|
34
|
+
handleRun(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
35
|
+
private streamResponse;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=server.d.ts.map
|