@wings006/agent-link 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +298 -0
- package/dist/a2a-client.d.ts +12 -0
- package/dist/a2a-client.js +94 -0
- package/dist/a2a-client.js.map +1 -0
- package/dist/a2a-server.d.ts +20 -0
- package/dist/a2a-server.js +168 -0
- package/dist/a2a-server.js.map +1 -0
- package/dist/config.d.ts +4 -0
- package/dist/config.js +39 -0
- package/dist/config.js.map +1 -0
- package/dist/daemon-api.d.ts +23 -0
- package/dist/daemon-api.js +272 -0
- package/dist/daemon-api.js.map +1 -0
- package/dist/daemon.d.ts +2 -0
- package/dist/daemon.js +141 -0
- package/dist/daemon.js.map +1 -0
- package/dist/discovery.d.ts +18 -0
- package/dist/discovery.js +104 -0
- package/dist/discovery.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +92 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server.d.ts +13 -0
- package/dist/mcp-server.js +354 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/notify.d.ts +1 -0
- package/dist/notify.js +9 -0
- package/dist/notify.js.map +1 -0
- package/dist/relay-client.d.ts +29 -0
- package/dist/relay-client.js +199 -0
- package/dist/relay-client.js.map +1 -0
- package/dist/relay-server.d.ts +8 -0
- package/dist/relay-server.js +108 -0
- package/dist/relay-server.js.map +1 -0
- package/dist/task-store.d.ts +36 -0
- package/dist/task-store.js +167 -0
- package/dist/task-store.js.map +1 -0
- package/dist/types.d.ts +74 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
# Agent Link
|
|
2
|
+
|
|
3
|
+
多 Agent 聊天系统 — 连接多台电脑上的 Claude Code,实现 Agent 间互相通信。支持局域网自动发现和跨网络中继通信。
|
|
4
|
+
|
|
5
|
+
## 工作原理
|
|
6
|
+
|
|
7
|
+
每台电脑运行一个 `agent-link` 进程,同时承担:
|
|
8
|
+
|
|
9
|
+
- **MCP Server** — 给本地 Claude Code 提供 `agent_list`、`agent_send`、`agent_inbox`、`agent_reply` 工具
|
|
10
|
+
- **A2A Server** — 接收其他电脑 Agent 发来的任务(HTTP JSON-RPC)
|
|
11
|
+
- **A2A Client** — 向其他电脑的 Agent 发送任务
|
|
12
|
+
- **mDNS 广播** — 零配置自动发现局域网内所有 Agent
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
电脑A (wings-macbook) 电脑B (office-pc) 电脑C (lab-server)
|
|
16
|
+
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
|
|
17
|
+
│ agent-link │◄──HTTP───►│ agent-link │◄──HTTP──►│ agent-link │
|
|
18
|
+
│ + Claude Code│ (A2A) │ + Claude Code│ (A2A) │ + Claude Code│
|
|
19
|
+
└───────────────┘ └───────────────┘ └───────────────┘
|
|
20
|
+
▲ mDNS 自动发现 ▲ ▲ mDNS 自动发现 ▲
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## 安装
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
git clone <repo-url> agent-link
|
|
27
|
+
cd agent-link
|
|
28
|
+
npm install
|
|
29
|
+
npm run build
|
|
30
|
+
npm link
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
执行 `npm link` 后,`agent-link` 命令全局可用。
|
|
34
|
+
|
|
35
|
+
## 配置 Claude Code
|
|
36
|
+
|
|
37
|
+
编辑 `~/.claude/settings.json`,添加 MCP Server:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"mcpServers": {
|
|
42
|
+
"agent-link": {
|
|
43
|
+
"command": "agent-link",
|
|
44
|
+
"args": ["--name", "你的Agent名称", "--port", "3456"]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
每台电脑使用不同的 `--name`,同一局域网内 `--port` 保持一致即可。
|
|
51
|
+
|
|
52
|
+
### 参数说明
|
|
53
|
+
|
|
54
|
+
| 参数 | 简写 | 说明 | 默认值 |
|
|
55
|
+
|------|------|------|--------|
|
|
56
|
+
| `--name` | `-n` | Agent 名称(全局唯一) | 随机生成 |
|
|
57
|
+
| `--port` | `-p` | A2A Server 监听端口 | 3456 |
|
|
58
|
+
| `--relay` | `-r` | 中继服务器地址(跨网络通信) | 无 |
|
|
59
|
+
| `--skills` | `-s` | 能力标签,逗号分隔 | general |
|
|
60
|
+
|
|
61
|
+
### 配置示例
|
|
62
|
+
|
|
63
|
+
**电脑 A(开发机):**
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"mcpServers": {
|
|
67
|
+
"agent-link": {
|
|
68
|
+
"command": "agent-link",
|
|
69
|
+
"args": ["--name", "dev-macbook", "--port", "3456", "--skills", "code,test"]
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**电脑 B(办公电脑):**
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"mcpServers": {
|
|
79
|
+
"agent-link": {
|
|
80
|
+
"command": "agent-link",
|
|
81
|
+
"args": ["--name", "office-pc", "--port", "3456", "--skills", "report,doc"]
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## 使用
|
|
88
|
+
|
|
89
|
+
配置完成后重启 Claude Code,agent-link 会自动启动。直接用自然语言和 Claude Code 对话即可:
|
|
90
|
+
|
|
91
|
+
### 查看在线 Agent
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
你: 有哪些 agent 在线?
|
|
95
|
+
Claude Code → 调用 agent_list
|
|
96
|
+
Claude Code: 当前在线 Agent:
|
|
97
|
+
- dev-macbook (192.168.1.50:3456) [code, test]
|
|
98
|
+
- office-pc (192.168.1.100:3456) [report, doc]
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 发送任务
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
你: 告诉 office-pc 帮我生成本周周报
|
|
105
|
+
Claude Code → 调用 agent_send(to: "office-pc", message: "帮我生成本周周报")
|
|
106
|
+
Claude Code: 任务已发送,等待 office-pc 处理...
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
对方电脑的 Claude Code 会收到消息,询问用户是否执行。
|
|
110
|
+
|
|
111
|
+
### 查看收件箱
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
你: 看看有没有人给我发消息
|
|
115
|
+
Claude Code → 调用 agent_inbox
|
|
116
|
+
Claude Code: 收到 1 条消息:
|
|
117
|
+
- 来自 dev-macbook: "帮我检查一下测试覆盖率" (待处理)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 回复任务
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
你: 回复这个任务,告诉他测试覆盖率是 85%
|
|
124
|
+
Claude Code → 调用 agent_reply(task_id: "xxx", message: "测试覆盖率 85%", status: "completed")
|
|
125
|
+
Claude Code: 已回复 dev-macbook
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## 消息流转
|
|
129
|
+
|
|
130
|
+
完整的一次跨机器任务流程:
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
1. A 用户 → A Claude Code: "告诉 office-pc 生成周报"
|
|
134
|
+
2. A Claude Code 调用 agent_list 确认 office-pc 在线
|
|
135
|
+
3. A Claude Code 调用 agent_send → A 的 agent-link 发送 HTTP 请求到 B
|
|
136
|
+
4. B 的 agent-link 收到任务,存入 inbox
|
|
137
|
+
5. B 的 Claude Code 通过 agent_inbox 看到新消息
|
|
138
|
+
6. B 的 Claude Code 询问 B 用户: "收到 dev-macbook 的请求,是否执行?"
|
|
139
|
+
7. B 用户确认 → B Claude Code 执行任务
|
|
140
|
+
8. B Claude Code 调用 agent_reply 回复结果
|
|
141
|
+
9. A Claude Code 收到结果,展示给 A 用户
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## MCP 工具一览
|
|
145
|
+
|
|
146
|
+
| 工具 | 说明 |
|
|
147
|
+
|------|------|
|
|
148
|
+
| `agent_list` | 列出所有在线 Agent(局域网 + 中继) |
|
|
149
|
+
| `agent_send` | 向目标 Agent 发送消息/任务 |
|
|
150
|
+
| `agent_inbox` | 查看收到的消息(显示已读/未读状态) |
|
|
151
|
+
| `agent_reply` | 回复任务(完成/拒绝/需要更多信息) |
|
|
152
|
+
| `agent_mark_read` | 标记消息已读(单条或全部) |
|
|
153
|
+
| `agent_clear_inbox` | 清理收件箱(已读/全部/最早N条) |
|
|
154
|
+
| `agent_task_status` | 查询已发出任务的状态和回复 |
|
|
155
|
+
|
|
156
|
+
## 跨网络通信(中继模式)
|
|
157
|
+
|
|
158
|
+
当 Agent 不在同一局域网时,可通过公网中继服务器实现通信。
|
|
159
|
+
|
|
160
|
+
### 部署中继服务器
|
|
161
|
+
|
|
162
|
+
在公网服务器上:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
# 创建目录
|
|
166
|
+
mkdir -p /opt/agent-link-relay && cd /opt/agent-link-relay
|
|
167
|
+
|
|
168
|
+
# 复制中继服务器文件
|
|
169
|
+
scp dist/relay-server.js user@server:/opt/agent-link-relay/
|
|
170
|
+
|
|
171
|
+
# 安装依赖
|
|
172
|
+
npm init -y
|
|
173
|
+
sed -i 's/"type": "commonjs"/"type": "module"/' package.json
|
|
174
|
+
npm install ws
|
|
175
|
+
|
|
176
|
+
# 启动
|
|
177
|
+
node relay-server.js --port 3458
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
建议用 systemd 管理:
|
|
181
|
+
|
|
182
|
+
```ini
|
|
183
|
+
# /etc/systemd/system/agent-link-relay.service
|
|
184
|
+
[Unit]
|
|
185
|
+
Description=Agent Link Relay Server
|
|
186
|
+
After=network.target
|
|
187
|
+
|
|
188
|
+
[Service]
|
|
189
|
+
Type=simple
|
|
190
|
+
WorkingDirectory=/opt/agent-link-relay
|
|
191
|
+
ExecStart=/usr/bin/node relay-server.js --port 3458
|
|
192
|
+
Restart=always
|
|
193
|
+
RestartSec=5
|
|
194
|
+
|
|
195
|
+
[Install]
|
|
196
|
+
WantedBy=multi-user.target
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
systemctl enable agent-link-relay && systemctl start agent-link-relay
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
> 注意:需要在云服务商安全组中放行 3458 端口(TCP 入方向)。
|
|
204
|
+
|
|
205
|
+
### 配置 Agent 连接中继
|
|
206
|
+
|
|
207
|
+
在 MCP 配置中添加 `--relay` 参数:
|
|
208
|
+
|
|
209
|
+
```json
|
|
210
|
+
{
|
|
211
|
+
"mcpServers": {
|
|
212
|
+
"agent-link": {
|
|
213
|
+
"command": "agent-link",
|
|
214
|
+
"args": ["--name", "my-agent", "--relay", "ws://your-server-ip:3458"]
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### 工作原理
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
电脑A (家里) 公网中继服务器 电脑B (公司)
|
|
224
|
+
┌───────────┐ WebSocket ┌──────────────┐ WebSocket ┌───────────┐
|
|
225
|
+
│ agent-link├──────────────►│ relay-server │◄──────────────┤agent-link │
|
|
226
|
+
└───────────┘ └──────────────┘ └───────────┘
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
- 双方通过 WebSocket 长连接到中继服务器
|
|
230
|
+
- 中继服务器维护在线 Agent 列表,推送给所有客户端
|
|
231
|
+
- 消息通过中继转发,中继不存储数据
|
|
232
|
+
- 局域网 mDNS 发现照常工作,同网络内优先直连
|
|
233
|
+
|
|
234
|
+
## 本机测试
|
|
235
|
+
|
|
236
|
+
在同一台机器上模拟多 Agent 通信(使用不同端口):
|
|
237
|
+
|
|
238
|
+
**终端 1:**
|
|
239
|
+
```bash
|
|
240
|
+
agent-link --name agent-a --port 3456
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**终端 2:**
|
|
244
|
+
```bash
|
|
245
|
+
agent-link --name agent-b --port 3457
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
两个进程会通过 mDNS 自动发现对方。
|
|
249
|
+
|
|
250
|
+
## 故障排查
|
|
251
|
+
|
|
252
|
+
### mDNS 发现调试
|
|
253
|
+
|
|
254
|
+
如果两台电脑都配置了 agent-link 但 `agent_list` 看不到对方,使用调试脚本排查:
|
|
255
|
+
|
|
256
|
+
**电脑 A:**
|
|
257
|
+
```bash
|
|
258
|
+
npx tsx tests/mdns-debug.ts pc-a
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**电脑 B:**
|
|
262
|
+
```bash
|
|
263
|
+
npx tsx tests/mdns-debug.ts pc-b
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
脚本会广播自身并监听局域网内的其他 Agent。如果 10 秒内双方都能看到 `[mDNS] 发现服务: ...` 输出,说明 mDNS 工作正常。
|
|
267
|
+
|
|
268
|
+
如果发现不了对方,常见原因:
|
|
269
|
+
|
|
270
|
+
| 原因 | 排查方法 |
|
|
271
|
+
|------|---------|
|
|
272
|
+
| macOS 防火墙阻止 UDP 5353 | 系统设置 → 网络 → 防火墙,关闭或添加例外 |
|
|
273
|
+
| 两台电脑不在同一子网 | 确认 IP 在同一网段(如都是 192.168.1.x) |
|
|
274
|
+
| 路由器禁用多播转发 | 检查路由器设置,启用 mDNS/Bonjour 转发 |
|
|
275
|
+
| 企业网络隔离 | 部分企业 WiFi 会隔离客户端间通信 |
|
|
276
|
+
|
|
277
|
+
## 开发
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
npm run build # 编译 TypeScript
|
|
281
|
+
npm run dev # 开发模式运行(tsx)
|
|
282
|
+
npm test # 运行测试
|
|
283
|
+
npm run test:watch # 测试监听模式
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## 技术栈
|
|
287
|
+
|
|
288
|
+
- TypeScript + Node.js
|
|
289
|
+
- [A2A 协议](https://github.com/a2aproject/A2A) — Agent 间通信(JSON-RPC over HTTP)
|
|
290
|
+
- [MCP 协议](https://modelcontextprotocol.io/) — Claude Code 工具集成
|
|
291
|
+
- [bonjour-service](https://www.npmjs.com/package/bonjour-service) — mDNS 零配置局域网发现
|
|
292
|
+
- [ws](https://www.npmjs.com/package/ws) — WebSocket 中继通信
|
|
293
|
+
- [better-sqlite3](https://www.npmjs.com/package/better-sqlite3) — SQLite 持久化存储
|
|
294
|
+
- [Vitest](https://vitest.dev/) — 测试框架
|
|
295
|
+
|
|
296
|
+
## 许可证
|
|
297
|
+
|
|
298
|
+
MIT
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AgentInfo, Task } from "./types.js";
|
|
2
|
+
export declare class A2AClient {
|
|
3
|
+
sendTask(target: AgentInfo, from: string, message: string, callbackUrl?: string): Promise<{
|
|
4
|
+
taskId: string;
|
|
5
|
+
status: string;
|
|
6
|
+
}>;
|
|
7
|
+
getTask(target: AgentInfo, taskId: string): Promise<Task>;
|
|
8
|
+
sendTaskNotification(callbackUrl: string, task: Task): Promise<void>;
|
|
9
|
+
waitForTask(target: AgentInfo, taskId: string, timeoutMs?: number, pollIntervalMs?: number): Promise<Task>;
|
|
10
|
+
getAgentCard(target: AgentInfo): Promise<Record<string, unknown>>;
|
|
11
|
+
private rpcCall;
|
|
12
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
export class A2AClient {
|
|
2
|
+
// 向远端 Agent 发送任务
|
|
3
|
+
async sendTask(target, from, message, callbackUrl) {
|
|
4
|
+
const rpcReq = {
|
|
5
|
+
jsonrpc: "2.0",
|
|
6
|
+
id: Date.now(),
|
|
7
|
+
method: "message/send",
|
|
8
|
+
params: { from, message, callbackUrl },
|
|
9
|
+
};
|
|
10
|
+
const res = await this.rpcCall(target, rpcReq);
|
|
11
|
+
if (res.error) {
|
|
12
|
+
throw new Error(`RPC error: ${res.error.message}`);
|
|
13
|
+
}
|
|
14
|
+
return res.result;
|
|
15
|
+
}
|
|
16
|
+
// 查询远端任务状态
|
|
17
|
+
async getTask(target, taskId) {
|
|
18
|
+
const rpcReq = {
|
|
19
|
+
jsonrpc: "2.0",
|
|
20
|
+
id: Date.now(),
|
|
21
|
+
method: "tasks/get",
|
|
22
|
+
params: { taskId },
|
|
23
|
+
};
|
|
24
|
+
const res = await this.rpcCall(target, rpcReq);
|
|
25
|
+
if (res.error) {
|
|
26
|
+
throw new Error(`RPC error: ${res.error.message}`);
|
|
27
|
+
}
|
|
28
|
+
return res.result;
|
|
29
|
+
}
|
|
30
|
+
// 向发送方回调通知任务状态变更
|
|
31
|
+
async sendTaskNotification(callbackUrl, task) {
|
|
32
|
+
const rpcReq = {
|
|
33
|
+
jsonrpc: "2.0",
|
|
34
|
+
id: Date.now(),
|
|
35
|
+
method: "tasks/notify",
|
|
36
|
+
params: {
|
|
37
|
+
taskId: task.id,
|
|
38
|
+
status: task.status,
|
|
39
|
+
result: task.result,
|
|
40
|
+
from: task.from,
|
|
41
|
+
to: task.to,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
try {
|
|
45
|
+
const res = await fetch(callbackUrl, {
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: { "Content-Type": "application/json" },
|
|
48
|
+
body: JSON.stringify(rpcReq),
|
|
49
|
+
});
|
|
50
|
+
if (!res.ok) {
|
|
51
|
+
console.error(`[a2a-client] 回调通知失败: HTTP ${res.status}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
console.error(`[a2a-client] 回调通知失败: ${err instanceof Error ? err.message : String(err)}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// 轮询等待任务完成(备用,SSE 不可用时使用)
|
|
59
|
+
async waitForTask(target, taskId, timeoutMs = 300000, pollIntervalMs = 2000) {
|
|
60
|
+
const start = Date.now();
|
|
61
|
+
while (Date.now() - start < timeoutMs) {
|
|
62
|
+
const task = await this.getTask(target, taskId);
|
|
63
|
+
if (task.status === "completed" ||
|
|
64
|
+
task.status === "rejected" ||
|
|
65
|
+
task.status === "canceled") {
|
|
66
|
+
return task;
|
|
67
|
+
}
|
|
68
|
+
await new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
69
|
+
}
|
|
70
|
+
throw new Error(`Task ${taskId} timed out after ${timeoutMs}ms`);
|
|
71
|
+
}
|
|
72
|
+
// 获取远端 Agent Card
|
|
73
|
+
async getAgentCard(target) {
|
|
74
|
+
const url = `http://${target.host}:${target.port}/.well-known/agent-card.json`;
|
|
75
|
+
const res = await fetch(url);
|
|
76
|
+
if (!res.ok) {
|
|
77
|
+
throw new Error(`Failed to fetch agent card: ${res.status}`);
|
|
78
|
+
}
|
|
79
|
+
return (await res.json());
|
|
80
|
+
}
|
|
81
|
+
async rpcCall(target, req) {
|
|
82
|
+
const url = `http://${target.host}:${target.port}/a2a`;
|
|
83
|
+
const res = await fetch(url, {
|
|
84
|
+
method: "POST",
|
|
85
|
+
headers: { "Content-Type": "application/json" },
|
|
86
|
+
body: JSON.stringify(req),
|
|
87
|
+
});
|
|
88
|
+
if (!res.ok) {
|
|
89
|
+
throw new Error(`HTTP error: ${res.status}`);
|
|
90
|
+
}
|
|
91
|
+
return (await res.json());
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=a2a-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a2a-client.js","sourceRoot":"","sources":["../src/a2a-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AgentLinkConfig, Task } from "./types.js";
|
|
2
|
+
import type { TaskStore } from "./task-store.js";
|
|
3
|
+
export declare class A2AServer {
|
|
4
|
+
private server;
|
|
5
|
+
private config;
|
|
6
|
+
private taskStore;
|
|
7
|
+
private onTaskReceived?;
|
|
8
|
+
private onTaskNotified?;
|
|
9
|
+
constructor(config: AgentLinkConfig, taskStore: TaskStore);
|
|
10
|
+
setOnTaskReceived(handler: (task: Task) => void): void;
|
|
11
|
+
setOnTaskNotified(handler: (task: Partial<Task> & {
|
|
12
|
+
id: string;
|
|
13
|
+
}) => void): void;
|
|
14
|
+
start(): Promise<number>;
|
|
15
|
+
stop(): Promise<void>;
|
|
16
|
+
private getAgentCard;
|
|
17
|
+
private handleRequest;
|
|
18
|
+
private handleRpc;
|
|
19
|
+
private readBody;
|
|
20
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import http from "node:http";
|
|
2
|
+
export class A2AServer {
|
|
3
|
+
server;
|
|
4
|
+
config;
|
|
5
|
+
taskStore;
|
|
6
|
+
onTaskReceived;
|
|
7
|
+
onTaskNotified;
|
|
8
|
+
constructor(config, taskStore) {
|
|
9
|
+
this.config = config;
|
|
10
|
+
this.taskStore = taskStore;
|
|
11
|
+
this.server = http.createServer(this.handleRequest.bind(this));
|
|
12
|
+
}
|
|
13
|
+
setOnTaskReceived(handler) {
|
|
14
|
+
this.onTaskReceived = handler;
|
|
15
|
+
}
|
|
16
|
+
setOnTaskNotified(handler) {
|
|
17
|
+
this.onTaskNotified = handler;
|
|
18
|
+
}
|
|
19
|
+
// 尝试监听指定端口,被占用则自动分配随机端口
|
|
20
|
+
start() {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
const tryListen = (port) => {
|
|
23
|
+
const server = this.server;
|
|
24
|
+
const onError = (err) => {
|
|
25
|
+
if (err.code === "EADDRINUSE") {
|
|
26
|
+
// 端口被占用,使用 0 让系统自动分配
|
|
27
|
+
server.removeListener("error", onError);
|
|
28
|
+
tryListen(0);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
reject(err);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
server.once("error", onError);
|
|
35
|
+
server.listen(port, () => {
|
|
36
|
+
server.removeListener("error", onError);
|
|
37
|
+
const addr = server.address();
|
|
38
|
+
this.config.port = addr.port;
|
|
39
|
+
resolve(addr.port);
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
tryListen(this.config.port);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
stop() {
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
this.server.close((err) => (err ? reject(err) : resolve()));
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
getAgentCard() {
|
|
51
|
+
return {
|
|
52
|
+
name: this.config.name,
|
|
53
|
+
description: `Agent "${this.config.name}" on agent-link network`,
|
|
54
|
+
url: `http://localhost:${this.config.port}/a2a`,
|
|
55
|
+
version: "1.0",
|
|
56
|
+
capabilities: {
|
|
57
|
+
streaming: false,
|
|
58
|
+
pushNotifications: false,
|
|
59
|
+
},
|
|
60
|
+
skills: this.config.skills,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async handleRequest(req, res) {
|
|
64
|
+
// CORS
|
|
65
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
66
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
67
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
68
|
+
if (req.method === "OPTIONS") {
|
|
69
|
+
res.writeHead(204);
|
|
70
|
+
res.end();
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
// Agent Card
|
|
74
|
+
if (req.method === "GET" &&
|
|
75
|
+
(req.url === "/.well-known/agent-card.json" || req.url === "/agent-card")) {
|
|
76
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
77
|
+
res.end(JSON.stringify(this.getAgentCard()));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
// A2A JSON-RPC endpoint
|
|
81
|
+
if (req.method === "POST" && req.url === "/a2a") {
|
|
82
|
+
const body = await this.readBody(req);
|
|
83
|
+
try {
|
|
84
|
+
const rpcReq = JSON.parse(body);
|
|
85
|
+
const rpcRes = this.handleRpc(rpcReq);
|
|
86
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
87
|
+
res.end(JSON.stringify(rpcRes));
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
91
|
+
res.end(JSON.stringify({
|
|
92
|
+
jsonrpc: "2.0",
|
|
93
|
+
id: null,
|
|
94
|
+
error: { code: -32700, message: "Parse error" },
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
res.writeHead(404);
|
|
100
|
+
res.end("Not found");
|
|
101
|
+
}
|
|
102
|
+
handleRpc(req) {
|
|
103
|
+
switch (req.method) {
|
|
104
|
+
case "message/send": {
|
|
105
|
+
const params = req.params;
|
|
106
|
+
const task = this.taskStore.createTask(params.from, this.config.name, params.message, params.callbackUrl);
|
|
107
|
+
this.onTaskReceived?.(task);
|
|
108
|
+
return {
|
|
109
|
+
jsonrpc: "2.0",
|
|
110
|
+
id: req.id,
|
|
111
|
+
result: { taskId: task.id, status: task.status },
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
case "tasks/notify": {
|
|
115
|
+
const params = req.params;
|
|
116
|
+
this.onTaskNotified?.({
|
|
117
|
+
id: params.taskId,
|
|
118
|
+
status: params.status,
|
|
119
|
+
result: params.result,
|
|
120
|
+
from: params.from,
|
|
121
|
+
to: params.to,
|
|
122
|
+
});
|
|
123
|
+
return { jsonrpc: "2.0", id: req.id, result: { ok: true } };
|
|
124
|
+
}
|
|
125
|
+
case "tasks/get": {
|
|
126
|
+
const params = req.params;
|
|
127
|
+
const task = this.taskStore.getTask(params.taskId);
|
|
128
|
+
if (!task) {
|
|
129
|
+
return {
|
|
130
|
+
jsonrpc: "2.0",
|
|
131
|
+
id: req.id,
|
|
132
|
+
error: { code: -32001, message: "Task not found" },
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
return { jsonrpc: "2.0", id: req.id, result: task };
|
|
136
|
+
}
|
|
137
|
+
case "tasks/cancel": {
|
|
138
|
+
const params = req.params;
|
|
139
|
+
const task = this.taskStore.updateTask(params.taskId, {
|
|
140
|
+
status: "canceled",
|
|
141
|
+
});
|
|
142
|
+
if (!task) {
|
|
143
|
+
return {
|
|
144
|
+
jsonrpc: "2.0",
|
|
145
|
+
id: req.id,
|
|
146
|
+
error: { code: -32001, message: "Task not found" },
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return { jsonrpc: "2.0", id: req.id, result: task };
|
|
150
|
+
}
|
|
151
|
+
default:
|
|
152
|
+
return {
|
|
153
|
+
jsonrpc: "2.0",
|
|
154
|
+
id: req.id,
|
|
155
|
+
error: { code: -32601, message: `Method not found: ${req.method}` },
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
readBody(req) {
|
|
160
|
+
return new Promise((resolve, reject) => {
|
|
161
|
+
const chunks = [];
|
|
162
|
+
req.on("data", (chunk) => chunks.push(chunk));
|
|
163
|
+
req.on("end", () => resolve(Buffer.concat(chunks).toString()));
|
|
164
|
+
req.on("error", reject);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=a2a-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a2a-server.js","sourceRoot":"","sources":["../src/a2a-server.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
package/dist/config.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export const DEFAULT_A2A_PORT = 3456;
|
|
2
|
+
export const DEFAULT_API_PORT = 3457;
|
|
3
|
+
export function parseArgs(args) {
|
|
4
|
+
let name = `agent-${Math.random().toString(36).slice(2, 6)}`;
|
|
5
|
+
let port = DEFAULT_A2A_PORT;
|
|
6
|
+
let apiPort = DEFAULT_API_PORT;
|
|
7
|
+
let relayUrl;
|
|
8
|
+
const skills = [
|
|
9
|
+
{ id: "general", name: "通用", description: "通用任务处理" },
|
|
10
|
+
];
|
|
11
|
+
for (let i = 0; i < args.length; i++) {
|
|
12
|
+
switch (args[i]) {
|
|
13
|
+
case "--name":
|
|
14
|
+
case "-n":
|
|
15
|
+
name = args[++i];
|
|
16
|
+
break;
|
|
17
|
+
case "--port":
|
|
18
|
+
case "-p":
|
|
19
|
+
port = parseInt(args[++i], 10);
|
|
20
|
+
break;
|
|
21
|
+
case "--api-port":
|
|
22
|
+
apiPort = parseInt(args[++i], 10);
|
|
23
|
+
break;
|
|
24
|
+
case "--relay":
|
|
25
|
+
case "-r":
|
|
26
|
+
relayUrl = args[++i];
|
|
27
|
+
break;
|
|
28
|
+
case "--skills":
|
|
29
|
+
case "-s":
|
|
30
|
+
skills.length = 0;
|
|
31
|
+
for (const s of args[++i].split(",")) {
|
|
32
|
+
skills.push({ id: s.trim(), name: s.trim(), description: s.trim() });
|
|
33
|
+
}
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return { name, port, apiPort, relayUrl, skills };
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC;AACrC,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAErC,MAAM,UAAU,SAAS,CAAC,IAAc;IACtC,IAAI,IAAI,GAAG,SAAS,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAC7D,IAAI,IAAI,GAAG,gBAAgB,CAAC;IAC5B,IAAI,OAAO,GAAG,gBAAgB,CAAC;IAC/B,IAAI,QAA4B,CAAC;IACjC,MAAM,MAAM,GAA8B;QACxC,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE;KACrD,CAAC;IAEF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,QAAQ,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YAChB,KAAK,QAAQ,CAAC;YACd,KAAK,IAAI;gBACP,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;gBACjB,MAAM;YACR,KAAK,QAAQ,CAAC;YACd,KAAK,IAAI;gBACP,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC/B,MAAM;YACR,KAAK,YAAY;gBACf,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAClC,MAAM;YACR,KAAK,SAAS,CAAC;YACf,KAAK,IAAI;gBACP,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;gBACrB,MAAM;YACR,KAAK,UAAU,CAAC;YAChB,KAAK,IAAI;gBACP,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;gBAClB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;oBACrC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBACvE,CAAC;gBACD,MAAM;QACV,CAAC;IACH,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AACnD,CAAC"}
|