@ryubyte/dsh-a2a 0.2.0 → 0.2.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/README.en.md +19 -81
- package/README.md +16 -77
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -9,6 +9,23 @@ It turns a DSH instance into a full A2A peer in both directions:
|
|
|
9
9
|
- **Client mode (outbound)** — discover a remote agent via its **AgentCard**, map each **skill** to a DSH model tool (`a2a__<name>__<skill>`), and execute remote tasks through A2A **JSON-RPC**.
|
|
10
10
|
- **Server mode (inbound)** — expose this DSH to other agents: `/.well-known/agent-card.json` plus a JSON-RPC endpoint (`SendMessage`, `GetTask`, `ListTasks`, `CancelTask`, `SendStreamingMessage` over SSE) on the DSH webserver.
|
|
11
11
|
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
Install into a profile with one command and restart:
|
|
15
|
+
|
|
16
|
+
dsh plugin --profile web add @ryubyte/dsh-a2a
|
|
17
|
+
dsh --profile web
|
|
18
|
+
|
|
19
|
+
`dsh plugin` installs the package into the profile and auto-registers the
|
|
20
|
+
plugin layer (this package declares `dsh.bundle.patch` in `package.json`) — no
|
|
21
|
+
manual configuration is needed.
|
|
22
|
+
|
|
23
|
+
## Screenshots
|
|
24
|
+
|
|
25
|
+
| Connected agents (this DSH as a client) | Public service (this DSH as an agent) |
|
|
26
|
+
|---|---|
|
|
27
|
+
|  |  |
|
|
28
|
+
|
|
12
29
|
## Features
|
|
13
30
|
|
|
14
31
|
### Protocol surface (A2A v1.0)
|
|
@@ -51,46 +68,6 @@ land in that profile directory, so they are read no matter which working
|
|
|
51
68
|
directory you launch from. Hand-writing `a2a.json` is still supported (below),
|
|
52
69
|
but **a new user can do everything through the UI**.
|
|
53
70
|
|
|
54
|
-
## Screenshots
|
|
55
|
-
|
|
56
|
-
| Connected agents (this DSH as a client) | Public service (this DSH as an agent) |
|
|
57
|
-
|---|---|
|
|
58
|
-
|  |  |
|
|
59
|
-
|
|
60
|
-
## Installation
|
|
61
|
-
|
|
62
|
-
### Option 1: from npm (recommended)
|
|
63
|
-
|
|
64
|
-
Once published to npm, install into the target profile with one command and
|
|
65
|
-
restart:
|
|
66
|
-
|
|
67
|
-
dsh plugin --profile <profile> add @ryubyte/dsh-a2a
|
|
68
|
-
dsh --profile <profile>
|
|
69
|
-
|
|
70
|
-
`dsh plugin` installs the package into the profile and auto-registers the
|
|
71
|
-
plugin layer (this package declares `dsh.bundle.patch` in `package.json`) — no
|
|
72
|
-
manual configuration is needed.
|
|
73
|
-
|
|
74
|
-
### Option 2: from the repository (development)
|
|
75
|
-
|
|
76
|
-
For hacking on the code, requires Node.js >= 22:
|
|
77
|
-
|
|
78
|
-
# 1. Clone the repo
|
|
79
|
-
git clone https://github.com/ryubyte/dsh-a2a.git
|
|
80
|
-
cd dsh-a2a
|
|
81
|
-
|
|
82
|
-
# 2. Install deps and build
|
|
83
|
-
npm install
|
|
84
|
-
npm run build
|
|
85
|
-
|
|
86
|
-
# 3. Link into the target profile
|
|
87
|
-
dsh plugin --profile <profile> add link:$(pwd)
|
|
88
|
-
|
|
89
|
-
# 4. Restart
|
|
90
|
-
dsh --profile <profile>
|
|
91
|
-
|
|
92
|
-
After changing source, re-run `npm run build` and restart.
|
|
93
|
-
|
|
94
71
|
## Usage
|
|
95
72
|
|
|
96
73
|
### 1. Configure a remote agent (outbound)
|
|
@@ -160,7 +137,7 @@ Other A2A clients discover this DSH via the auto-inferred
|
|
|
160
137
|
|
|
161
138
|
On each inbound task the server picks an executor in this order:
|
|
162
139
|
|
|
163
|
-
1. **Explicit `execute`** (injected
|
|
140
|
+
1. **Explicit `execute`** (injected via composition config) — yours wins.
|
|
164
141
|
2. **This DSH's own agent session** (the default, when an agent loop is
|
|
165
142
|
present) — **one session per A2A `contextId`**: the first task for a context
|
|
166
143
|
`ctx.agents.create()`s a session (later tasks for the same context reuse it,
|
|
@@ -195,37 +172,6 @@ On each inbound task the server picks an executor in this order:
|
|
|
195
172
|
> a `/bin/sh -c` command — trusted clients only. For production put a TLS
|
|
196
173
|
> reverse proxy in front and set `authToken` as needed.
|
|
197
174
|
|
|
198
|
-
### 3. Programmatic use
|
|
199
|
-
|
|
200
|
-
```ts
|
|
201
|
-
import { A2AClient, A2AServer, TaskStore } from '@ryubyte/dsh-a2a';
|
|
202
|
-
|
|
203
|
-
// outbound: connect to a remote agent
|
|
204
|
-
const client = await A2AClient.connect('https://agent.example.com');
|
|
205
|
-
const { task } = await client.sendMessage({
|
|
206
|
-
messageId: crypto.randomUUID(),
|
|
207
|
-
role: 'ROLE_USER',
|
|
208
|
-
parts: [{ text: 'Draft a report' }],
|
|
209
|
-
});
|
|
210
|
-
for await (const ev of client.streamMessage({ messageId: crypto.randomUUID(), role: 'ROLE_USER', parts: [{ text: 'hi' }] })) {
|
|
211
|
-
// ev.statusUpdate | ev.artifactUpdate | ev.task | ev.message
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// inbound: wire a custom executor to your own agent loop
|
|
215
|
-
const store = new TaskStore();
|
|
216
|
-
const server = new A2AServer({
|
|
217
|
-
baseUrl: 'http://127.0.0.1:3080',
|
|
218
|
-
agentName: 'My DSH',
|
|
219
|
-
agentDescription: '...',
|
|
220
|
-
agentVersion: '1.0.0',
|
|
221
|
-
execute: async ({ message }) => ({
|
|
222
|
-
messageId: crypto.randomUUID(),
|
|
223
|
-
role: 'ROLE_AGENT',
|
|
224
|
-
parts: [{ text: await myAgentRun(message.parts) }],
|
|
225
|
-
}),
|
|
226
|
-
}, store);
|
|
227
|
-
```
|
|
228
|
-
|
|
229
175
|
## Directory structure
|
|
230
176
|
|
|
231
177
|
src/
|
|
@@ -282,12 +228,4 @@ const server = new A2AServer({
|
|
|
282
228
|
webserver binds loopback by default, so put a TLS reverse proxy in front
|
|
283
229
|
before exposing beyond localhost.
|
|
284
230
|
- Bearer tokens — both the outbound per-agent token and the inbound endpoint
|
|
285
|
-
`authToken` — are stored in plaintext in `a2a.json`; secure the file yourself.
|
|
286
|
-
|
|
287
|
-
## Development
|
|
288
|
-
|
|
289
|
-
```bash
|
|
290
|
-
npm install
|
|
291
|
-
npm run build # tsc(types) + tsdown(lib) + wrap client → lib/client.js
|
|
292
|
-
npm test # node:test + tsx (unit/integration) + client-bundle smoke
|
|
293
|
-
```
|
|
231
|
+
`authToken` — are stored in plaintext in `a2a.json`; secure the file yourself.
|
package/README.md
CHANGED
|
@@ -9,6 +9,21 @@
|
|
|
9
9
|
- **Client 模式(出站)**——通过远程 Agent 的 **AgentCard** 发现它,把每个 **skill** 映射为 DSH 模型工具(`a2a__<name>__<skill>`),通过 A2A **JSON-RPC** 执行远程任务。
|
|
10
10
|
- **Server 模式(入站)**——把本 DSH 暴露给其他 Agent:在 DSH webserver 上提供 `/.well-known/agent-card.json` 与 JSON-RPC 端点(`SendMessage`、`GetTask`、`ListTasks`、`CancelTask`、基于 SSE 的 `SendStreamingMessage`)。
|
|
11
11
|
|
|
12
|
+
## 安装
|
|
13
|
+
|
|
14
|
+
一行命令装进 profile,重启即生效:
|
|
15
|
+
|
|
16
|
+
dsh plugin --profile web add @ryubyte/dsh-a2a
|
|
17
|
+
dsh --profile web
|
|
18
|
+
|
|
19
|
+
`dsh plugin` 会把包装进 profile 并自动加入插件层(本包在 package.json 里声明了 `dsh.bundle.patch`),无需手动改任何配置。
|
|
20
|
+
|
|
21
|
+
## 截图
|
|
22
|
+
|
|
23
|
+
| 连接的 Agent(本 DSH 作为客户端) | 对外服务(本 DSH 作为 Agent) |
|
|
24
|
+
|---|---|
|
|
25
|
+
|  |  |
|
|
26
|
+
|
|
12
27
|
## 功能
|
|
13
28
|
|
|
14
29
|
### 协议能力(A2A v1.0)
|
|
@@ -43,43 +58,6 @@
|
|
|
43
58
|
|
|
44
59
|
配置以 **`a2a.json`(按 profile 存放,可完全通过 UI 管理)为准**,无需改动组合配置即可管理 Agent 与对外服务。文件定位不依赖启动目录:插件解析进程命令行里的 `--profile <name>`(`dsh web` 别名同样识别为 `web` profile),读写 `~/.dsh/profiles/<name>/a2a.json`——UI 首次生成的配置也会写到该 profile 目录,从任意工作目录启动都能读到。手写 `a2a.json` 仍然支持(见下文),但**新用户完全靠 UI 即可完成配置与上线**。
|
|
45
60
|
|
|
46
|
-
## 截图
|
|
47
|
-
|
|
48
|
-
| 连接的 Agent(本 DSH 作为客户端) | 对外服务(本 DSH 作为 Agent) |
|
|
49
|
-
|---|---|
|
|
50
|
-
|  |  |
|
|
51
|
-
|
|
52
|
-
## 安装
|
|
53
|
-
|
|
54
|
-
### 方式一:从 npm 安装(推荐)
|
|
55
|
-
|
|
56
|
-
插件发布到 npm 后,一行命令装进目标 profile,重启即生效:
|
|
57
|
-
|
|
58
|
-
dsh plugin --profile <profile> add @ryubyte/dsh-a2a
|
|
59
|
-
dsh --profile <profile>
|
|
60
|
-
|
|
61
|
-
`dsh plugin` 会把包装进 profile 并自动加入插件层(本包在 package.json 里声明了 `dsh.bundle.patch`),无需手动改任何配置。
|
|
62
|
-
|
|
63
|
-
### 方式二:从仓库安装(开发调试)
|
|
64
|
-
|
|
65
|
-
用于改代码调试,需要 Node.js >= 22 与 pnpm:
|
|
66
|
-
|
|
67
|
-
# 1. 克隆仓库
|
|
68
|
-
git clone https://github.com/ryubyte/dsh-a2a.git
|
|
69
|
-
cd dsh-a2a
|
|
70
|
-
|
|
71
|
-
# 2. 安装依赖并构建
|
|
72
|
-
npm install
|
|
73
|
-
npm run build
|
|
74
|
-
|
|
75
|
-
# 3. 链接进目标 profile
|
|
76
|
-
dsh plugin --profile <profile> add link:$(pwd)
|
|
77
|
-
|
|
78
|
-
# 4. 重启
|
|
79
|
-
dsh --profile <profile>
|
|
80
|
-
|
|
81
|
-
改完源码后重跑 `npm run build` 再重启即可。
|
|
82
|
-
|
|
83
61
|
## 使用
|
|
84
62
|
|
|
85
63
|
### 1. 配置远程 Agent(出站)
|
|
@@ -139,7 +117,7 @@
|
|
|
139
117
|
|
|
140
118
|
server 模式收到任务后,按以下优先级选择 executor:
|
|
141
119
|
|
|
142
|
-
1. **显式 `execute
|
|
120
|
+
1. **显式 `execute`**(通过 composition 配置注入)—— 用你的。
|
|
143
121
|
2. **本 DSH 的 agent 会话**(默认,当 agent 循环就位时)—— 按 A2A `contextId` **一个对话一个会话**:某 `contextId` 首个任务 `ctx.agents.create()` 建会话(后续同 `contextId` 复用同一会话,历史累积;进程重启后按需 `resume`),把消息作为 `next-turn` 唤醒项发给它,等 `whenIdle()`,取最新 assistant 回复作为 A2A artifact。同一 `contextId` 的并发任务按序串行,不同 `contextId` 并行。会话不逐任务释放(否则无法累积上下文),插件卸载/下线时统一释放。开 server 即可「接收并处理任务」,无需写代码。
|
|
144
122
|
3. **`notConfiguredExecutor`**(兜底)—— 既没注入 `execute`、composition 里又没有可用 agent 循环(如仅 dsh-base 的最小 profile)时,返回「no executor configured — inject one」,**不执行任何命令**。
|
|
145
123
|
|
|
@@ -151,37 +129,6 @@ server 模式收到任务后,按以下优先级选择 executor:
|
|
|
151
129
|
>
|
|
152
130
|
> 本机自测也可显式传入 `shellExecutor`(把 prompt 当作 shell 命令执行,仅限可信客户端);生产请置于 TLS 反向代理之后并按需配 `authToken`。
|
|
153
131
|
|
|
154
|
-
### 3. 编程接入
|
|
155
|
-
|
|
156
|
-
```ts
|
|
157
|
-
import { A2AClient, A2AServer, TaskStore } from '@ryubyte/dsh-a2a';
|
|
158
|
-
|
|
159
|
-
// 出站:连接远程 Agent
|
|
160
|
-
const client = await A2AClient.connect('https://agent.example.com');
|
|
161
|
-
const { task } = await client.sendMessage({
|
|
162
|
-
messageId: crypto.randomUUID(),
|
|
163
|
-
role: 'ROLE_USER',
|
|
164
|
-
parts: [{ text: 'Draft a report' }],
|
|
165
|
-
});
|
|
166
|
-
for await (const ev of client.streamMessage({ messageId: crypto.randomUUID(), role: 'ROLE_USER', parts: [{ text: 'hi' }] })) {
|
|
167
|
-
// ev.statusUpdate | ev.artifactUpdate | ev.task | ev.message
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// 入站:自定义 executor 接入 DSH agent 循环
|
|
171
|
-
const store = new TaskStore();
|
|
172
|
-
const server = new A2AServer({
|
|
173
|
-
baseUrl: 'http://127.0.0.1:3080',
|
|
174
|
-
agentName: 'My DSH',
|
|
175
|
-
agentDescription: '...',
|
|
176
|
-
agentVersion: '1.0.0',
|
|
177
|
-
execute: async ({ message }) => ({
|
|
178
|
-
messageId: crypto.randomUUID(),
|
|
179
|
-
role: 'ROLE_AGENT',
|
|
180
|
-
parts: [{ text: await myAgentRun(message.parts) }],
|
|
181
|
-
}),
|
|
182
|
-
}, store);
|
|
183
|
-
```
|
|
184
|
-
|
|
185
132
|
## 目录结构
|
|
186
133
|
|
|
187
134
|
src/
|
|
@@ -217,11 +164,3 @@ const server = new A2AServer({
|
|
|
217
164
|
- 入站服务的执行策略见[入站任务由谁执行](#入站任务由谁执行executor-优先级):有 agent 循环时默认由本 DSH 会话执行(绑定工作目录 cwd),否则(且未注入 executor)**拒绝执行**并返回「no executor configured」。`shellExecutor` 仅限本地自测。无论哪种 executor,都切勿向不受信网络暴露 server 模式(默认无鉴权,除非配置 `authToken`)。
|
|
218
165
|
- A2A 规范要求生产 `AgentInterface.url` 使用 HTTPS;DSH webServer 默认仅绑 loopback,对外暴露前需自行加 TLS。
|
|
219
166
|
- Bearer token(出站按 Agent 配置的、入站保护端点的 `authToken`)均明文存于 `a2a.json`,请自行保证该文件权限。
|
|
220
|
-
|
|
221
|
-
## 开发
|
|
222
|
-
|
|
223
|
-
```bash
|
|
224
|
-
npm install
|
|
225
|
-
npm run build # tsc(types) + tsdown(lib) + wrap client → lib/client.js
|
|
226
|
-
npm test # node:test + tsx(单元 / 集成)+ client-bundle smoke
|
|
227
|
-
```
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ryubyte/dsh-a2a",
|
|
3
3
|
"description": "Agent2Agent (A2A) protocol v1.0 plugin for DeepSeek Harness (DSH): outbound client (remote AgentCard skills as ctx.tools), inbound server (A2A JSON-RPC + AgentCard endpoint), and a settings dashboard of live A2A connections",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "lib/types/index.d.ts",
|