@cicctencent/agent-midway 0.1.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.
Files changed (160) hide show
  1. package/README.md +280 -0
  2. package/dist/adapters/express.d.ts +8 -0
  3. package/dist/adapters/express.js +91 -0
  4. package/dist/adapters/index.d.ts +5 -0
  5. package/dist/adapters/index.js +21 -0
  6. package/dist/adapters/koa.d.ts +3 -0
  7. package/dist/adapters/koa.js +75 -0
  8. package/dist/adapters/midway.d.ts +5 -0
  9. package/dist/adapters/midway.js +11 -0
  10. package/dist/adapters/next.d.ts +12 -0
  11. package/dist/adapters/next.js +89 -0
  12. package/dist/adapters/shared.d.ts +4 -0
  13. package/dist/adapters/shared.js +31 -0
  14. package/dist/channel/dingtalk.d.ts +18 -0
  15. package/dist/channel/dingtalk.js +68 -0
  16. package/dist/channel/feishu.d.ts +20 -0
  17. package/dist/channel/feishu.js +96 -0
  18. package/dist/channel/index.d.ts +46 -0
  19. package/dist/channel/index.js +311 -0
  20. package/dist/channel/types.d.ts +77 -0
  21. package/dist/channel/types.js +7 -0
  22. package/dist/channel/wecom.d.ts +22 -0
  23. package/dist/channel/wecom.js +106 -0
  24. package/dist/component.d.ts +49 -0
  25. package/dist/component.js +129 -0
  26. package/dist/connector/calendar-adapter.d.ts +19 -0
  27. package/dist/connector/calendar-adapter.js +236 -0
  28. package/dist/connector/db-adapter.d.ts +28 -0
  29. package/dist/connector/db-adapter.js +193 -0
  30. package/dist/connector/email-adapter.d.ts +23 -0
  31. package/dist/connector/email-adapter.js +192 -0
  32. package/dist/connector/fs-adapter.d.ts +15 -0
  33. package/dist/connector/fs-adapter.js +199 -0
  34. package/dist/connector/http-adapter.d.ts +29 -0
  35. package/dist/connector/http-adapter.js +181 -0
  36. package/dist/connector/index.d.ts +24 -0
  37. package/dist/connector/index.js +454 -0
  38. package/dist/connector/mcp-adapter.d.ts +27 -0
  39. package/dist/connector/mcp-adapter.js +156 -0
  40. package/dist/connector/mq-adapter.d.ts +25 -0
  41. package/dist/connector/mq-adapter.js +181 -0
  42. package/dist/connector/types.d.ts +205 -0
  43. package/dist/connector/types.js +9 -0
  44. package/dist/controller/a2a.controller.d.ts +41 -0
  45. package/dist/controller/a2a.controller.js +150 -0
  46. package/dist/controller/agent-profile.controller.d.ts +97 -0
  47. package/dist/controller/agent-profile.controller.js +200 -0
  48. package/dist/controller/agent.controller.d.ts +199 -0
  49. package/dist/controller/agent.controller.js +414 -0
  50. package/dist/controller/application.controller.d.ts +113 -0
  51. package/dist/controller/application.controller.js +217 -0
  52. package/dist/controller/automation.controller.d.ts +113 -0
  53. package/dist/controller/automation.controller.js +246 -0
  54. package/dist/controller/channel.controller.d.ts +73 -0
  55. package/dist/controller/channel.controller.js +183 -0
  56. package/dist/controller/chat.controller.d.ts +188 -0
  57. package/dist/controller/chat.controller.js +375 -0
  58. package/dist/controller/connector.controller.d.ts +134 -0
  59. package/dist/controller/connector.controller.js +257 -0
  60. package/dist/controller/knowledge-base.controller.d.ts +157 -0
  61. package/dist/controller/knowledge-base.controller.js +278 -0
  62. package/dist/controller/mcp-server.controller.d.ts +115 -0
  63. package/dist/controller/mcp-server.controller.js +236 -0
  64. package/dist/controller/model-config.controller.d.ts +139 -0
  65. package/dist/controller/model-config.controller.js +274 -0
  66. package/dist/controller/observability.controller.d.ts +124 -0
  67. package/dist/controller/observability.controller.js +142 -0
  68. package/dist/controller/security.controller.d.ts +91 -0
  69. package/dist/controller/security.controller.js +172 -0
  70. package/dist/controller/settings.controller.d.ts +83 -0
  71. package/dist/controller/settings.controller.js +280 -0
  72. package/dist/core/ai-workstation.d.ts +17 -0
  73. package/dist/core/ai-workstation.js +129 -0
  74. package/dist/core/index.d.ts +4 -0
  75. package/dist/core/index.js +20 -0
  76. package/dist/core/service-container.d.ts +12 -0
  77. package/dist/core/service-container.js +54 -0
  78. package/dist/core/sse.d.ts +6 -0
  79. package/dist/core/sse.js +56 -0
  80. package/dist/core/types.d.ts +72 -0
  81. package/dist/core/types.js +2 -0
  82. package/dist/dto/agent.dto.d.ts +21 -0
  83. package/dist/dto/agent.dto.js +79 -0
  84. package/dist/dto/ai-config.dto.d.ts +67 -0
  85. package/dist/dto/ai-config.dto.js +249 -0
  86. package/dist/dto/chat.dto.d.ts +40 -0
  87. package/dist/dto/chat.dto.js +122 -0
  88. package/dist/index.d.ts +101 -0
  89. package/dist/index.js +195 -0
  90. package/dist/memory/db-store.d.ts +33 -0
  91. package/dist/memory/db-store.js +143 -0
  92. package/dist/memory/index.d.ts +187 -0
  93. package/dist/memory/index.js +443 -0
  94. package/dist/model/ai-agent-profile.entity.d.ts +32 -0
  95. package/dist/model/ai-agent-profile.entity.js +289 -0
  96. package/dist/model/ai-application.entity.d.ts +20 -0
  97. package/dist/model/ai-application.entity.js +166 -0
  98. package/dist/model/ai-chat-memory.entity.d.ts +16 -0
  99. package/dist/model/ai-chat-memory.entity.js +123 -0
  100. package/dist/model/ai-chat-message.entity.d.ts +16 -0
  101. package/dist/model/ai-chat-message.entity.js +122 -0
  102. package/dist/model/ai-chat-skill.entity.d.ts +19 -0
  103. package/dist/model/ai-chat-skill.entity.js +155 -0
  104. package/dist/model/ai-chat-thread.entity.d.ts +15 -0
  105. package/dist/model/ai-chat-thread.entity.js +113 -0
  106. package/dist/model/ai-chat-workspace.entity.d.ts +17 -0
  107. package/dist/model/ai-chat-workspace.entity.js +136 -0
  108. package/dist/model/ai-kb-document.entity.d.ts +16 -0
  109. package/dist/model/ai-kb-document.entity.js +122 -0
  110. package/dist/model/ai-knowledge-base.entity.d.ts +22 -0
  111. package/dist/model/ai-knowledge-base.entity.js +185 -0
  112. package/dist/model/ai-mcp-server.entity.d.ts +23 -0
  113. package/dist/model/ai-mcp-server.entity.js +198 -0
  114. package/dist/model/ai-model-config.entity.d.ts +24 -0
  115. package/dist/model/ai-model-config.entity.js +200 -0
  116. package/dist/service/a2a.service.d.ts +142 -0
  117. package/dist/service/a2a.service.js +537 -0
  118. package/dist/service/agent-profile.service.d.ts +34 -0
  119. package/dist/service/agent-profile.service.js +110 -0
  120. package/dist/service/agent-server.service.d.ts +91 -0
  121. package/dist/service/agent-server.service.js +634 -0
  122. package/dist/service/agent-task-queue.service.d.ts +98 -0
  123. package/dist/service/agent-task-queue.service.js +283 -0
  124. package/dist/service/ai-chat.service.d.ts +103 -0
  125. package/dist/service/ai-chat.service.js +431 -0
  126. package/dist/service/ai-skill.service.d.ts +116 -0
  127. package/dist/service/ai-skill.service.js +457 -0
  128. package/dist/service/application.service.d.ts +42 -0
  129. package/dist/service/application.service.js +139 -0
  130. package/dist/service/automation.service.d.ts +37 -0
  131. package/dist/service/automation.service.js +196 -0
  132. package/dist/service/connector.service.d.ts +136 -0
  133. package/dist/service/connector.service.js +524 -0
  134. package/dist/service/knowledge-base.service.d.ts +138 -0
  135. package/dist/service/knowledge-base.service.js +528 -0
  136. package/dist/service/mcp-server.service.d.ts +39 -0
  137. package/dist/service/mcp-server.service.js +143 -0
  138. package/dist/service/model-config.service.d.ts +57 -0
  139. package/dist/service/model-config.service.js +168 -0
  140. package/dist/service/observability.service.d.ts +145 -0
  141. package/dist/service/observability.service.js +281 -0
  142. package/dist/service/openai.service.d.ts +88 -0
  143. package/dist/service/openai.service.js +406 -0
  144. package/dist/service/prompt-builder.service.d.ts +50 -0
  145. package/dist/service/prompt-builder.service.js +246 -0
  146. package/dist/tools/code-exec.tool.d.ts +37 -0
  147. package/dist/tools/code-exec.tool.js +162 -0
  148. package/dist/tools/datetime.tool.d.ts +21 -0
  149. package/dist/tools/datetime.tool.js +379 -0
  150. package/dist/tools/http-request.tool.d.ts +43 -0
  151. package/dist/tools/http-request.tool.js +455 -0
  152. package/dist/tools/registry.d.ts +71 -0
  153. package/dist/tools/registry.js +77 -0
  154. package/dist/tools/text-process.tool.d.ts +7 -0
  155. package/dist/tools/text-process.tool.js +366 -0
  156. package/dist/tools/web-search.tool.d.ts +28 -0
  157. package/dist/tools/web-search.tool.js +304 -0
  158. package/dist/types.d.ts +70 -0
  159. package/dist/types.js +7 -0
  160. package/package.json +69 -0
@@ -0,0 +1,537 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.A2AService = void 0;
13
+ /**
14
+ * A2A (Agent-to-Agent) 协议服务
15
+ *
16
+ * 实现 A2A 协议核心功能:
17
+ * - Agent Card 生成(描述本机 Agent 能力)+ 30s TTL 缓存
18
+ * - JSON-RPC 2.0 分发(tasks/send, tasks/get, tasks/cancel)
19
+ * - 同步/流式任务执行
20
+ * - SSE 心跳机制(每 3 秒发送 keep-alive)
21
+ * - 事件映射表(EVENT_MAPPERS)
22
+ * - contextId → threadId LRU 映射(500 条上限)
23
+ * - 远程 Agent 发现 + A2A Client(支持 bearer/basic/apiKey/custom 认证)
24
+ *
25
+ * 参考 A2A 协议规范:https://github.com/google-a2a/A2A
26
+ */
27
+ const core_1 = require("@midwayjs/core");
28
+ const midwayjs_base_1 = require("@cicctencent/midwayjs-base");
29
+ const agent_server_service_1 = require("./agent-server.service");
30
+ const agent_core_1 = require("@cicctencent/agent-core");
31
+ /** JSON-RPC 错误码 */
32
+ const RPC_ERRORS = {
33
+ PARSE_ERROR: { code: -32700, message: 'Parse error' },
34
+ INVALID_REQUEST: { code: -32600, message: 'Invalid Request' },
35
+ METHOD_NOT_FOUND: { code: -32601, message: 'Method not found' },
36
+ INVALID_PARAMS: { code: -32602, message: 'Invalid params' },
37
+ INTERNAL_ERROR: { code: -32603, message: 'Internal error' },
38
+ TASK_NOT_FOUND: { code: -32001, message: 'Task not found' },
39
+ TASK_NOT_CANCELABLE: { code: -32002, message: 'Task not cancelable' },
40
+ };
41
+ // ---- 常量 ----
42
+ const A2A_THREAD_MAP_MAX = 500;
43
+ const CARD_CACHE_TTL = 30000; // 30 秒缓存
44
+ const EVENT_MAPPERS = {
45
+ // content → message 事件(累积文本)
46
+ content: (e, taskId, contextId, acc) => {
47
+ const text = typeof e.data === 'string' ? e.data : '';
48
+ if (!text)
49
+ return null;
50
+ acc.finalContent += text;
51
+ return {
52
+ type: 'message',
53
+ data: {
54
+ role: 'agent',
55
+ parts: [{ kind: 'text', text: acc.finalContent }],
56
+ messageId: genId(),
57
+ taskId,
58
+ contextId,
59
+ },
60
+ };
61
+ },
62
+ // tool_call → data 事件
63
+ tool_call: (e, taskId, contextId) => ({
64
+ type: 'message',
65
+ data: {
66
+ role: 'agent',
67
+ parts: [{ kind: 'data', data: { type: 'tool_call', ...e.data } }],
68
+ messageId: genId(),
69
+ taskId,
70
+ contextId,
71
+ },
72
+ }),
73
+ // tool_result → data 事件
74
+ tool_result: (e, taskId, contextId) => ({
75
+ type: 'message',
76
+ data: {
77
+ role: 'agent',
78
+ parts: [{ kind: 'data', data: { type: 'tool_result', ...e.data } }],
79
+ messageId: genId(),
80
+ taskId,
81
+ contextId,
82
+ },
83
+ }),
84
+ // reasoning → thinking 事件
85
+ reasoning: (e, taskId, contextId) => ({
86
+ type: 'message',
87
+ data: {
88
+ role: 'agent',
89
+ parts: [{ kind: 'data', data: { type: 'thinking', content: e.data } }],
90
+ messageId: genId(),
91
+ taskId,
92
+ contextId,
93
+ },
94
+ }),
95
+ };
96
+ /** 透传任意引擎事件:将事件属性作为 metadata 直接转发 */
97
+ function passthroughEvent(event, taskId, contextId) {
98
+ return {
99
+ type: 'message',
100
+ data: {
101
+ role: 'agent',
102
+ parts: [{ kind: 'data', data: { type: event.type, ...event.data } }],
103
+ messageId: genId(),
104
+ taskId,
105
+ contextId,
106
+ },
107
+ };
108
+ }
109
+ /** 生成唯一 ID */
110
+ function genId() {
111
+ return `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
112
+ }
113
+ let A2AService = class A2AService extends midwayjs_base_1.BaseService {
114
+ constructor() {
115
+ super(...arguments);
116
+ /** 任务存储(内存) */
117
+ this.tasks = new Map();
118
+ /** 运行中的任务 AbortController */
119
+ this.abortControllers = new Map();
120
+ /** contextId → threadId LRU 映射(同一会话多轮复用线程) */
121
+ this.a2aThreadMap = new Map();
122
+ /** 缓存的 Agent Card */
123
+ this.cachedCard = null;
124
+ this.cardGeneratedAt = 0;
125
+ }
126
+ // ---- Agent Card 缓存 ----
127
+ /** 生成 Agent Card(带 30s TTL 缓存) */
128
+ generateAgentCard(baseUrl) {
129
+ const now = Date.now();
130
+ if (this.cachedCard && now - this.cardGeneratedAt < CARD_CACHE_TTL) {
131
+ return { ...this.cachedCard, url: `${baseUrl || process.env.A2A_BASE_URL || 'http://localhost:7001'}/a2a` };
132
+ }
133
+ const url = baseUrl || process.env.A2A_BASE_URL || 'http://localhost:7001';
134
+ const card = {
135
+ name: 'AI Workstation Agent',
136
+ description: 'An AI agent powered by the workstation, supporting tool calls, memory, and streaming output.',
137
+ url: `${url}/a2a`,
138
+ version: '1.0.0',
139
+ capabilities: {
140
+ streaming: true,
141
+ pushNotifications: false,
142
+ stateTransitionHistory: true,
143
+ },
144
+ defaultInputModes: ['text'],
145
+ defaultOutputModes: ['text'],
146
+ skills: [
147
+ {
148
+ id: 'chat',
149
+ name: 'General Chat',
150
+ description: 'General-purpose conversational AI assistant with tool calling capabilities.',
151
+ tags: ['chat', 'general'],
152
+ inputModes: ['text'],
153
+ outputModes: ['text'],
154
+ },
155
+ {
156
+ id: 'data-analyst',
157
+ name: 'Data Analyst',
158
+ description: 'AI agent specialized in data analysis, statistics, and visualization.',
159
+ tags: ['data', 'analysis'],
160
+ inputModes: ['text'],
161
+ outputModes: ['text'],
162
+ },
163
+ ],
164
+ };
165
+ this.cachedCard = card;
166
+ this.cardGeneratedAt = now;
167
+ return card;
168
+ }
169
+ /** 使 Agent Card 缓存失效(profile 变更时调用) */
170
+ invalidateAgentCard() {
171
+ this.cachedCard = null;
172
+ this.cardGeneratedAt = 0;
173
+ }
174
+ // ---- contextId → threadId LRU 映射 ----
175
+ /** 获取 contextId 对应的 threadId */
176
+ getThreadForContext(contextId) {
177
+ return this.a2aThreadMap.get(contextId);
178
+ }
179
+ /** 设置 contextId → threadId 映射(LRU 淘汰) */
180
+ setThreadForContext(contextId, threadId) {
181
+ if (this.a2aThreadMap.size >= A2A_THREAD_MAP_MAX && !this.a2aThreadMap.has(contextId)) {
182
+ const oldestKey = this.a2aThreadMap.keys().next().value;
183
+ if (oldestKey !== undefined)
184
+ this.a2aThreadMap.delete(oldestKey);
185
+ }
186
+ this.a2aThreadMap.set(contextId, threadId);
187
+ }
188
+ /** JSON-RPC 2.0 分发 */
189
+ async handleJsonRpc(body) {
190
+ if (!body || typeof body !== 'object') {
191
+ return this.makeError(null, RPC_ERRORS.INVALID_REQUEST);
192
+ }
193
+ const { jsonrpc, id, method, params } = body;
194
+ if (jsonrpc !== '2.0') {
195
+ return this.makeError(id ?? null, RPC_ERRORS.INVALID_REQUEST);
196
+ }
197
+ try {
198
+ let result;
199
+ switch (method) {
200
+ case 'tasks/send':
201
+ result = await this.handleSendTask(params);
202
+ break;
203
+ case 'tasks/sendSubscribe':
204
+ // 流式方法在 controller 中直接处理,这里返回提示
205
+ return this.makeError(id, {
206
+ code: -32000,
207
+ message: 'Streaming method requires SSE connection. Use the /a2a endpoint with Accept: text/event-stream.',
208
+ });
209
+ case 'tasks/get':
210
+ result = await this.handleGetTask(params);
211
+ break;
212
+ case 'tasks/cancel':
213
+ result = await this.handleCancelTask(params);
214
+ break;
215
+ default:
216
+ return this.makeError(id, RPC_ERRORS.METHOD_NOT_FOUND);
217
+ }
218
+ return { jsonrpc: '2.0', id, result };
219
+ }
220
+ catch (error) {
221
+ return this.makeError(id, {
222
+ code: RPC_ERRORS.INTERNAL_ERROR.code,
223
+ message: error.message || 'Internal error',
224
+ });
225
+ }
226
+ }
227
+ /** 同步执行 Agent 任务 */
228
+ async handleSendTask(params) {
229
+ const taskId = params?.id || genId();
230
+ const contextId = params?.contextId || genId();
231
+ const message = params?.message;
232
+ const prompt = this.extractText(message);
233
+ if (!prompt) {
234
+ throw new Error('No text content found in message');
235
+ }
236
+ const task = {
237
+ id: taskId,
238
+ contextId,
239
+ state: 'submitted',
240
+ message,
241
+ createdAt: Date.now(),
242
+ updatedAt: Date.now(),
243
+ history: [],
244
+ };
245
+ this.tasks.set(taskId, task);
246
+ try {
247
+ task.state = 'working';
248
+ task.updatedAt = Date.now();
249
+ const result = await this.agentServerService.runAgent(prompt, {
250
+ userId: 'a2a-agent',
251
+ maxSteps: 20,
252
+ timeout: 120000,
253
+ });
254
+ const resultText = typeof result === 'string'
255
+ ? result
256
+ : result?.text || JSON.stringify(result);
257
+ task.result = {
258
+ role: 'agent',
259
+ parts: [{ kind: 'text', text: resultText }],
260
+ messageId: genId(),
261
+ taskId,
262
+ contextId,
263
+ };
264
+ task.state = 'completed';
265
+ task.updatedAt = Date.now();
266
+ }
267
+ catch (error) {
268
+ task.state = 'failed';
269
+ task.error = error.message;
270
+ task.updatedAt = Date.now();
271
+ }
272
+ return { task };
273
+ }
274
+ /** 流式执行 Agent 任务(带 SSE 心跳 + 事件映射表) */
275
+ async *handleSendTaskStreaming(params) {
276
+ const taskId = params?.id || genId();
277
+ const contextId = params?.contextId || genId();
278
+ const message = params?.message;
279
+ const prompt = this.extractText(message);
280
+ if (!prompt) {
281
+ yield {
282
+ type: 'error',
283
+ data: { message: 'No text content found in message' },
284
+ };
285
+ return;
286
+ }
287
+ const task = {
288
+ id: taskId,
289
+ contextId,
290
+ state: 'submitted',
291
+ message,
292
+ createdAt: Date.now(),
293
+ updatedAt: Date.now(),
294
+ history: [],
295
+ };
296
+ this.tasks.set(taskId, task);
297
+ const abortController = new AbortController();
298
+ this.abortControllers.set(taskId, abortController);
299
+ task.state = 'working';
300
+ task.updatedAt = Date.now();
301
+ yield {
302
+ type: 'task',
303
+ data: { id: taskId, state: 'working', contextId },
304
+ };
305
+ // 心跳定时器:每 3 秒触发 keep-alive
306
+ let heartbeatPending = false;
307
+ const heartbeatTimer = setInterval(() => {
308
+ heartbeatPending = true;
309
+ }, 3000);
310
+ if (heartbeatTimer && typeof heartbeatTimer === 'object' && 'unref' in heartbeatTimer) {
311
+ heartbeatTimer.unref();
312
+ }
313
+ try {
314
+ const generator = this.agentServerService.runAgentStream(prompt, {
315
+ userId: 'a2a-agent',
316
+ maxSteps: 20,
317
+ timeout: 120000,
318
+ });
319
+ const acc = { finalContent: '' };
320
+ const iterator = generator[Symbol.asyncIterator]();
321
+ let engineNext = null;
322
+ while (true) {
323
+ // 先发送心跳(如果 pending)
324
+ if (heartbeatPending) {
325
+ heartbeatPending = false;
326
+ yield { type: 'heartbeat', data: null };
327
+ }
328
+ // 等待下一个引擎事件 或 心跳超时(先到先用)
329
+ if (!engineNext) {
330
+ engineNext = iterator.next();
331
+ }
332
+ // 创建心跳 Promise(3 秒后触发)
333
+ const heartbeatPromise = new Promise(resolve => {
334
+ setTimeout(() => resolve('heartbeat'), 3000);
335
+ });
336
+ const raceResult = await Promise.race([
337
+ engineNext.then(r => ({ type: 'engine', result: r })),
338
+ heartbeatPromise.then(() => ({ type: 'heartbeat', result: null })),
339
+ ]);
340
+ if (raceResult.type === 'heartbeat') {
341
+ // 心跳先到 — 发送 keep-alive,继续等待引擎
342
+ yield { type: 'heartbeat', data: null };
343
+ continue;
344
+ }
345
+ // 引擎事件到达 — 重置 engineNext
346
+ engineNext = null;
347
+ const { value: event, done } = raceResult.result;
348
+ if (done || !event)
349
+ break;
350
+ if (abortController.signal.aborted) {
351
+ break;
352
+ }
353
+ // ---- 使用事件映射表处理事件 ----
354
+ const mapper = EVENT_MAPPERS[event.type];
355
+ const a2aEvent = mapper
356
+ ? mapper(event, taskId, contextId, acc)
357
+ : passthroughEvent(event, taskId, contextId);
358
+ if (a2aEvent) {
359
+ yield a2aEvent;
360
+ }
361
+ // done 事件:提取最终内容
362
+ if (event.type === 'done') {
363
+ if (!acc.finalContent && event.data) {
364
+ acc.finalContent =
365
+ typeof event.data === 'string'
366
+ ? event.data
367
+ : event.data?.text ||
368
+ JSON.stringify(event.data);
369
+ }
370
+ break;
371
+ }
372
+ // error 事件
373
+ if (event.type === 'error') {
374
+ yield {
375
+ type: 'error',
376
+ data: { message: String(event.data) },
377
+ };
378
+ }
379
+ }
380
+ task.result = {
381
+ role: 'agent',
382
+ parts: [{ kind: 'text', text: acc.finalContent || 'Task completed.' }],
383
+ messageId: genId(),
384
+ taskId,
385
+ contextId,
386
+ };
387
+ task.state = abortController.signal.aborted
388
+ ? 'canceled'
389
+ : 'completed';
390
+ task.updatedAt = Date.now();
391
+ }
392
+ catch (error) {
393
+ task.state = 'failed';
394
+ task.error = error.message;
395
+ task.updatedAt = Date.now();
396
+ yield {
397
+ type: 'error',
398
+ data: { message: error.message },
399
+ };
400
+ }
401
+ finally {
402
+ clearInterval(heartbeatTimer);
403
+ this.abortControllers.delete(taskId);
404
+ }
405
+ yield {
406
+ type: 'done',
407
+ data: { id: taskId, state: task.state, result: task.result, contextId },
408
+ };
409
+ }
410
+ /** 获取任务 */
411
+ async handleGetTask(params) {
412
+ const taskId = params?.id;
413
+ if (!taskId) {
414
+ throw new Error('Task ID is required');
415
+ }
416
+ const task = this.tasks.get(taskId);
417
+ if (!task) {
418
+ throw new Error('Task not found');
419
+ }
420
+ return { task };
421
+ }
422
+ /** 取消任务 */
423
+ async handleCancelTask(params) {
424
+ const taskId = params?.id;
425
+ if (!taskId) {
426
+ throw new Error('Task ID is required');
427
+ }
428
+ const task = this.tasks.get(taskId);
429
+ if (!task) {
430
+ throw new Error('Task not found');
431
+ }
432
+ if (task.state !== 'working' && task.state !== 'submitted') {
433
+ throw new Error('Task is not cancelable');
434
+ }
435
+ const abortController = this.abortControllers.get(taskId);
436
+ if (abortController) {
437
+ abortController.abort();
438
+ }
439
+ task.state = 'canceled';
440
+ task.updatedAt = Date.now();
441
+ return { task };
442
+ }
443
+ /** 发现远程 Agent(使用 A2AClient,支持 bearer/basic/apiKey/custom 认证) */
444
+ async discoverRemoteAgent(url, auth) {
445
+ // 兼容旧接口:auth 为字符串时视为 raw Authorization header
446
+ const authConfig = typeof auth === 'string'
447
+ ? { type: 'custom', value: auth, name: 'Authorization' }
448
+ : auth;
449
+ const headers = (0, agent_core_1.buildAuthHeaders)(authConfig || null);
450
+ const client = new agent_core_1.A2AClient({ timeout: 300000, headers });
451
+ return client.discoverAgent(url);
452
+ }
453
+ /**
454
+ * 将远程 Agent Profile 包装为 SubAgentRunner,供 delegate_task 使用
455
+ * 支持 JSON-RPC A2A 和 REST A2A 两种协议
456
+ */
457
+ createRunnerFromProfile(profile) {
458
+ const headers = (0, agent_core_1.buildAuthHeaders)(profile.remoteAuth || null);
459
+ // ---- REST 风格 A2A ----
460
+ if (profile.a2aProtocol === 'rest') {
461
+ const restConfig = profile.restA2AConfig;
462
+ if (!restConfig?.capabilityId) {
463
+ throw new Error(`REST A2A profile '${profile.name}' missing capabilityId in restA2AConfig`);
464
+ }
465
+ const client = new agent_core_1.RestA2AClient({ timeout: 300000, headers });
466
+ const runner = (0, agent_core_1.createRestA2ARemoteRunner)({
467
+ baseUrl: profile.remoteUrl,
468
+ capabilityId: restConfig.capabilityId,
469
+ name: `[Remote] ${profile.name}`,
470
+ description: `${profile.description || profile.name} (via REST A2A)`,
471
+ client,
472
+ staticFields: restConfig.staticFields,
473
+ taskField: restConfig.taskField,
474
+ streaming: true,
475
+ });
476
+ return {
477
+ ...runner,
478
+ priority: profile.priority ?? 0,
479
+ scope: profile.scope,
480
+ keywords: profile.keywords,
481
+ exclusiveScope: profile.exclusiveScope,
482
+ };
483
+ }
484
+ // ---- 标准 JSON-RPC A2A(默认)----
485
+ const client = new agent_core_1.A2AClient({ timeout: 300000, headers });
486
+ const agentUrl = resolveA2AEndpoint(profile.remoteUrl);
487
+ const runner = (0, agent_core_1.createA2ARemoteRunner)({
488
+ agentUrl,
489
+ name: `[Remote] ${profile.name}`,
490
+ description: `${profile.description || profile.name} (via A2A)`,
491
+ streaming: true,
492
+ client,
493
+ skillId: `specialist_${profile.id}`,
494
+ });
495
+ return {
496
+ ...runner,
497
+ priority: profile.priority ?? 0,
498
+ scope: profile.scope,
499
+ keywords: profile.keywords,
500
+ exclusiveScope: profile.exclusiveScope,
501
+ };
502
+ }
503
+ /** 从 A2A 消息中提取文本 */
504
+ extractText(message) {
505
+ if (!message)
506
+ return '';
507
+ const parts = message.parts || [];
508
+ return parts
509
+ .filter(p => p.kind === 'text' && p.text)
510
+ .map(p => p.text)
511
+ .join('\n');
512
+ }
513
+ /** 构造 JSON-RPC 错误响应 */
514
+ makeError(id, error) {
515
+ return {
516
+ jsonrpc: '2.0',
517
+ id: id ?? null,
518
+ error: { code: error.code, message: error.message },
519
+ };
520
+ }
521
+ };
522
+ exports.A2AService = A2AService;
523
+ __decorate([
524
+ (0, core_1.Inject)(),
525
+ __metadata("design:type", agent_server_service_1.AgentServerService)
526
+ ], A2AService.prototype, "agentServerService", void 0);
527
+ exports.A2AService = A2AService = __decorate([
528
+ (0, core_1.Provide)(),
529
+ (0, core_1.Scope)(core_1.ScopeEnum.Singleton)
530
+ ], A2AService);
531
+ /** 将用户输入的基础 URL 规范化为 A2A JSON-RPC 端点 URL */
532
+ function resolveA2AEndpoint(baseUrl) {
533
+ const trimmed = baseUrl.replace(/\/+$/, '');
534
+ if (trimmed.endsWith('/a2a'))
535
+ return trimmed;
536
+ return `${trimmed}/a2a`;
537
+ }
@@ -0,0 +1,34 @@
1
+ import { BaseService } from '@cicctencent/midwayjs-base';
2
+ import { DataSource, Repository } from 'typeorm';
3
+ import AIAgentProfileEntity from '../model/ai-agent-profile.entity';
4
+ /**
5
+ * Agent Profile 服务
6
+ * 管理 Agent 配置、Prompt、工具绑定等
7
+ */
8
+ export declare class AgentProfileService extends BaseService {
9
+ dataSource: DataSource;
10
+ private repo?;
11
+ get model(): Repository<AIAgentProfileEntity>;
12
+ /** 获取所有 Profile(按应用隔离) */
13
+ list(applicationId: number, _options?: {
14
+ includeDisabled?: boolean;
15
+ }): Promise<AIAgentProfileEntity[]>;
16
+ /** 获取单个 Profile */
17
+ get(id: number, applicationId?: number): Promise<AIAgentProfileEntity>;
18
+ /** 获取默认 Profile */
19
+ getDefault(applicationId: number): Promise<AIAgentProfileEntity>;
20
+ /** 创建 Profile */
21
+ create(applicationId: number, data: Partial<AIAgentProfileEntity>): Promise<AIAgentProfileEntity>;
22
+ /** 更新 Profile */
23
+ update(id: number, applicationId: number, data: Partial<AIAgentProfileEntity>): Promise<AIAgentProfileEntity>;
24
+ /** 删除 Profile */
25
+ delete(id: number, applicationId: number): Promise<void>;
26
+ /** 设置为默认 */
27
+ setDefault(id: number, applicationId: number): Promise<AIAgentProfileEntity>;
28
+ /** 获取 Profile 完整配置(包含关联的 MCP Server 和 Skill) */
29
+ getFullConfig(id: number, applicationId: number): Promise<{
30
+ profile: AIAgentProfileEntity;
31
+ mcpServers: any[];
32
+ skills: any[];
33
+ }>;
34
+ }
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.AgentProfileService = void 0;
16
+ const core_1 = require("@midwayjs/core");
17
+ const midwayjs_base_1 = require("@cicctencent/midwayjs-base");
18
+ const typeorm_1 = require("@midwayjs/typeorm");
19
+ const typeorm_2 = require("typeorm");
20
+ const ai_agent_profile_entity_1 = __importDefault(require("../model/ai-agent-profile.entity"));
21
+ /**
22
+ * Agent Profile 服务
23
+ * 管理 Agent 配置、Prompt、工具绑定等
24
+ */
25
+ let AgentProfileService = class AgentProfileService extends midwayjs_base_1.BaseService {
26
+ get model() {
27
+ if (this.repo)
28
+ return this.repo;
29
+ return (this.repo =
30
+ this.dataSource.getRepository(ai_agent_profile_entity_1.default));
31
+ }
32
+ /** 获取所有 Profile(按应用隔离) */
33
+ async list(applicationId, _options) {
34
+ const where = { applicationId };
35
+ return this.model.find({
36
+ where,
37
+ order: { isDefault: 'DESC', createTime: 'DESC' },
38
+ });
39
+ }
40
+ /** 获取单个 Profile */
41
+ async get(id, applicationId) {
42
+ const where = { id };
43
+ if (applicationId)
44
+ where.applicationId = applicationId;
45
+ return this.model.findOne({ where });
46
+ }
47
+ /** 获取默认 Profile */
48
+ async getDefault(applicationId) {
49
+ return this.model.findOne({ where: { applicationId, isDefault: 1 } });
50
+ }
51
+ /** 创建 Profile */
52
+ async create(applicationId, data) {
53
+ // 如果设置为默认,先清除其他默认
54
+ if (data.isDefault === 1) {
55
+ await this.model.update({ applicationId, isDefault: 1 }, { isDefault: 0 });
56
+ }
57
+ const profile = this.model.create({ ...data, applicationId });
58
+ return this.model.save(profile);
59
+ }
60
+ /** 更新 Profile */
61
+ async update(id, applicationId, data) {
62
+ // 如果设置为默认,先清除其他默认
63
+ if (data.isDefault === 1) {
64
+ await this.model.update({ applicationId, isDefault: 1 }, { isDefault: 0 });
65
+ }
66
+ await this.model.update({ id, applicationId }, data);
67
+ return this.get(id, applicationId);
68
+ }
69
+ /** 删除 Profile */
70
+ async delete(id, applicationId) {
71
+ await this.model.delete({ id, applicationId });
72
+ }
73
+ /** 设置为默认 */
74
+ async setDefault(id, applicationId) {
75
+ await this.model.update({ applicationId, isDefault: 1 }, { isDefault: 0 });
76
+ await this.model.update({ id, applicationId }, { isDefault: 1 });
77
+ return this.get(id, applicationId);
78
+ }
79
+ /** 获取 Profile 完整配置(包含关联的 MCP Server 和 Skill) */
80
+ async getFullConfig(id, applicationId) {
81
+ const profile = await this.get(id, applicationId);
82
+ if (!profile)
83
+ return null;
84
+ // 加载关联的 MCP Server
85
+ let mcpServers = [];
86
+ if (profile.mcpServers && profile.mcpServers.length > 0) {
87
+ mcpServers = await this.dataSource.query('SELECT * FROM t_mcp_server WHERE id IN (?) AND Fapplication_id = ?', [profile.mcpServers, applicationId]);
88
+ }
89
+ // 加载关联的 Skill
90
+ let skills = [];
91
+ if (profile.selectedSkills && profile.selectedSkills.length > 0) {
92
+ // Skill 存储在文件中,需要通过 AISkillService 获取
93
+ // 这里返回 ID 列表,由上层服务加载
94
+ skills = profile.selectedSkills;
95
+ }
96
+ return {
97
+ profile,
98
+ mcpServers,
99
+ skills,
100
+ };
101
+ }
102
+ };
103
+ exports.AgentProfileService = AgentProfileService;
104
+ __decorate([
105
+ (0, typeorm_1.InjectDataSource)('default'),
106
+ __metadata("design:type", typeorm_2.DataSource)
107
+ ], AgentProfileService.prototype, "dataSource", void 0);
108
+ exports.AgentProfileService = AgentProfileService = __decorate([
109
+ (0, core_1.Provide)()
110
+ ], AgentProfileService);