@ryubyte/dsh-a2a 0.1.2 → 0.1.4
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 +267 -0
- package/README.md +101 -112
- package/lib/client.js +110 -12
- package/lib/index.js +454 -26
- package/lib/types/a2a-config.d.ts +2 -0
- package/lib/types/a2a-config.d.ts.map +1 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/dashboard.d.ts +8 -2
- package/lib/types/dashboard.d.ts.map +1 -1
- package/lib/types/index.d.ts +41 -2
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/outbound.d.ts.map +1 -1
- package/lib/types/server.d.ts +225 -1
- package/lib/types/server.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/a2a-config.ts +3 -0
- package/src/client/index.ts +111 -12
- package/src/dashboard.ts +16 -4
- package/src/index.ts +221 -16
- package/src/outbound.ts +31 -4
- package/src/server.ts +474 -9
- package/README.zh-CN.md +0 -196
package/lib/client.js
CHANGED
|
@@ -54,6 +54,10 @@ window.__ModuleLoader__.load({
|
|
|
54
54
|
const [tab, setTab] = (0, react.useState)("out");
|
|
55
55
|
/** connection ids whose skill list is expanded in the outbound tab. */
|
|
56
56
|
const [expanded, setExpanded] = (0, react.useState)(/* @__PURE__ */ new Set());
|
|
57
|
+
/** Optional bearer token for the add-agent form (outbound). */
|
|
58
|
+
const [addToken, setAddToken] = (0, react.useState)("");
|
|
59
|
+
/** Inbound authToken input (serve tab); empty string means "clear". */
|
|
60
|
+
const [authInput, setAuthInput] = (0, react.useState)("");
|
|
57
61
|
const refresh = async () => {
|
|
58
62
|
try {
|
|
59
63
|
setError(null);
|
|
@@ -101,7 +105,8 @@ window.__ModuleLoader__.load({
|
|
|
101
105
|
headers: { "content-type": "application/json" },
|
|
102
106
|
body: JSON.stringify({
|
|
103
107
|
action: "discover-agent",
|
|
104
|
-
agentCardUrl: u
|
|
108
|
+
agentCardUrl: u,
|
|
109
|
+
bearerToken: addToken.trim() || void 0
|
|
105
110
|
})
|
|
106
111
|
})).json();
|
|
107
112
|
if (!body.ok || !body.message) {
|
|
@@ -118,9 +123,13 @@ window.__ModuleLoader__.load({
|
|
|
118
123
|
const doConnect = async () => {
|
|
119
124
|
if (!discovered) return;
|
|
120
125
|
const n = discovered.name.trim() || "remote";
|
|
121
|
-
await act("add-agent", n, {
|
|
126
|
+
await act("add-agent", n, {
|
|
127
|
+
agentCardUrl: discovered.agentCardUrl,
|
|
128
|
+
bearerToken: addToken.trim() || void 0
|
|
129
|
+
});
|
|
122
130
|
if (!busy) {
|
|
123
131
|
setAddUrl("");
|
|
132
|
+
setAddToken("");
|
|
124
133
|
setDiscovered(null);
|
|
125
134
|
}
|
|
126
135
|
};
|
|
@@ -196,7 +205,25 @@ window.__ModuleLoader__.load({
|
|
|
196
205
|
flex: 1,
|
|
197
206
|
minWidth: 260
|
|
198
207
|
}
|
|
199
|
-
}), actionBtn("导入", false, () => void doDiscover(), discovering || !addUrl.trim())),
|
|
208
|
+
}), actionBtn("导入", false, () => void doDiscover(), discovering || !addUrl.trim())), (0, react.createElement)("div", { style: {
|
|
209
|
+
display: "flex",
|
|
210
|
+
alignItems: "center",
|
|
211
|
+
gap: 8,
|
|
212
|
+
flexWrap: "wrap"
|
|
213
|
+
} }, (0, react.createElement)("input", {
|
|
214
|
+
type: "password",
|
|
215
|
+
placeholder: "Bearer Token(可选,发送为 Authorization: Bearer …)",
|
|
216
|
+
value: addToken,
|
|
217
|
+
onChange: (e) => setAddToken(e.target.value),
|
|
218
|
+
style: {
|
|
219
|
+
...inputStyle,
|
|
220
|
+
flex: 1,
|
|
221
|
+
minWidth: 260
|
|
222
|
+
}
|
|
223
|
+
})), (0, react.createElement)("div", { style: {
|
|
224
|
+
fontSize: 11.5,
|
|
225
|
+
color: "var(--dsw-alias-label-tertiary, #999)"
|
|
226
|
+
} }, "若远程 Agent 需要鉴权,填入 token;导入与后续调用都会带上。token 会明文存入 a2a.json。"), discovering ? (0, react.createElement)("div", { style: {
|
|
200
227
|
fontSize: 13,
|
|
201
228
|
color: "var(--dsw-alias-label-tertiary, #999)"
|
|
202
229
|
} }, "正在读取 Agent Card…") : discovered ? (0, react.createElement)("div", { style: {
|
|
@@ -243,7 +270,7 @@ window.__ModuleLoader__.load({
|
|
|
243
270
|
display: "flex",
|
|
244
271
|
gap: 8,
|
|
245
272
|
marginTop: 2
|
|
246
|
-
} }, actionBtn("连接", true, () => void doConnect(), busy
|
|
273
|
+
} }, actionBtn("连接", true, () => void doConnect(), busy?.startsWith("add-agent:") ?? false), actionBtn("取消", false, () => {
|
|
247
274
|
setDiscovered(null);
|
|
248
275
|
setAddUrl("");
|
|
249
276
|
}, false))) : (0, react.createElement)("div", { style: {
|
|
@@ -263,7 +290,7 @@ window.__ModuleLoader__.load({
|
|
|
263
290
|
} }, sec("A2A 服务(本 DSH 作为 Agent 对外)", 0), stateDot(serve.enabled ? "connected" : "disconnected"), (0, react.createElement)("span", { style: {
|
|
264
291
|
fontSize: 12.5,
|
|
265
292
|
color: serve.enabled ? "#2e7d32" : "#9e9e9e"
|
|
266
|
-
} }, serve.enabled ? "运行中" : "已下线"), (0, react.createElement)("span", { style: { marginLeft: "auto" } }, serve.enabled ? actionBtn("下线", false, () => void act("server-disable", ""), busy === "server-disable") : actionBtn("上线", true, () => void act("server-enable", ""), busy === "server-enable"))), (0, react.createElement)("div", { style: {
|
|
293
|
+
} }, serve.enabled ? "运行中" : "已下线"), (0, react.createElement)("span", { style: { marginLeft: "auto" } }, serve.enabled ? actionBtn("下线", false, () => void act("server-disable", ""), busy === "server-disable:") : actionBtn("上线", true, () => void act("server-enable", ""), busy === "server-enable:"))), (0, react.createElement)("div", { style: {
|
|
267
294
|
display: "flex",
|
|
268
295
|
flexDirection: "column",
|
|
269
296
|
gap: 6
|
|
@@ -301,13 +328,7 @@ window.__ModuleLoader__.load({
|
|
|
301
328
|
fontSize: 12.5,
|
|
302
329
|
color: "var(--dsw-alias-label-primary, #222)"
|
|
303
330
|
}
|
|
304
|
-
}, `• ${s.name}${s.description ? ` — ${s.description}` : ""}`))) : null), serve.enabled
|
|
305
|
-
fontSize: 12,
|
|
306
|
-
color: "var(--dsw-warning, #b26a00)",
|
|
307
|
-
background: "rgba(178,106,0,.08)",
|
|
308
|
-
borderRadius: 6,
|
|
309
|
-
padding: "6px 10px"
|
|
310
|
-
} }, "⚠ 默认 executor 会执行 shell 命令。生产环境请通过配置指定受限的 execute 实现。") : null) : null, tab === "in" ? (0, react.createElement)("div", { style: {
|
|
331
|
+
}, `• ${s.name}${s.description ? ` — ${s.description}` : ""}`))) : null), serve.enabled ? executorNote(serve) : null, serve.enabled ? authControl(serve, busy, act, authInput, setAuthInput) : null) : null, tab === "in" ? (0, react.createElement)("div", { style: {
|
|
311
332
|
display: "flex",
|
|
312
333
|
flexDirection: "column",
|
|
313
334
|
gap: 10
|
|
@@ -557,6 +578,83 @@ window.__ModuleLoader__.load({
|
|
|
557
578
|
}
|
|
558
579
|
}, label);
|
|
559
580
|
}
|
|
581
|
+
/**
|
|
582
|
+
* A semantically-correct note about how inbound tasks are executed. Dispatches
|
|
583
|
+
* on the `executor` field; falls back to the legacy `customExecutor` boolean
|
|
584
|
+
* for snapshots from an older host that didn't send `executor`.
|
|
585
|
+
*/
|
|
586
|
+
function executorNote(serve) {
|
|
587
|
+
const kind = serve.executor ?? (serve.customExecutor ? "custom" : void 0);
|
|
588
|
+
if (kind === "custom") return null;
|
|
589
|
+
if (kind === "dsh-agent") return (0, react.createElement)("div", { style: {
|
|
590
|
+
fontSize: 12,
|
|
591
|
+
color: "var(--dsw-alias-label-secondary, #666)",
|
|
592
|
+
background: "rgba(74,125,255,.08)",
|
|
593
|
+
borderRadius: 6,
|
|
594
|
+
padding: "6px 10px"
|
|
595
|
+
} }, "ℹ 入站任务由本 DSH 的 agent 会话执行,按 A2A contextId 一个对话一个会话。");
|
|
596
|
+
if (kind === "none") return (0, react.createElement)("div", { style: {
|
|
597
|
+
fontSize: 12,
|
|
598
|
+
color: "var(--dsw-warning, #b26a00)",
|
|
599
|
+
background: "rgba(178,106,0,.08)",
|
|
600
|
+
borderRadius: 6,
|
|
601
|
+
padding: "6px 10px"
|
|
602
|
+
} }, "⚠ 未配置 executor,且未检测到可用的 agent 循环:入站任务会被拒绝。通过配置注入 execute,或加载 agent-loop 插件。");
|
|
603
|
+
return null;
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Inbound bearer-token control for the serve tab: shows whether the endpoint is
|
|
607
|
+
* token-gated, and lets the operator set or clear the shared token. The token
|
|
608
|
+
* value is never read back from the host — only whether one is configured.
|
|
609
|
+
*/
|
|
610
|
+
function authControl(serve, busy, act, authInput, setAuthInput) {
|
|
611
|
+
return (0, react.createElement)("div", { style: {
|
|
612
|
+
display: "flex",
|
|
613
|
+
flexDirection: "column",
|
|
614
|
+
gap: 6,
|
|
615
|
+
marginTop: 4
|
|
616
|
+
} }, (0, react.createElement)("div", { style: {
|
|
617
|
+
display: "flex",
|
|
618
|
+
alignItems: "center",
|
|
619
|
+
gap: 8
|
|
620
|
+
} }, (0, react.createElement)("span", { style: {
|
|
621
|
+
fontSize: 12.5,
|
|
622
|
+
fontWeight: 600,
|
|
623
|
+
color: "var(--dsw-alias-label-primary, #222)"
|
|
624
|
+
} }, "入站鉴权"), stateDot(serve.authConfigured ? "connected" : "disabled"), (0, react.createElement)("span", { style: {
|
|
625
|
+
fontSize: 12,
|
|
626
|
+
color: serve.authConfigured ? "#2e7d32" : "#9e9e9e"
|
|
627
|
+
} }, serve.authConfigured ? "已启用 Bearer 鉴权" : "未鉴权(任何客户端可调用)")), (0, react.createElement)("div", { style: {
|
|
628
|
+
display: "flex",
|
|
629
|
+
alignItems: "center",
|
|
630
|
+
gap: 8,
|
|
631
|
+
flexWrap: "wrap"
|
|
632
|
+
} }, (0, react.createElement)("input", {
|
|
633
|
+
type: "password",
|
|
634
|
+
placeholder: serve.authConfigured ? "输入新 token 以替换" : "设置 Bearer Token 以开启鉴权",
|
|
635
|
+
value: authInput,
|
|
636
|
+
onChange: (e) => setAuthInput(e.target.value),
|
|
637
|
+
style: {
|
|
638
|
+
padding: "4px 8px",
|
|
639
|
+
fontSize: 13,
|
|
640
|
+
borderRadius: 6,
|
|
641
|
+
border: "1px solid var(--dsw-alias-border-l2, rgba(127,127,127,.3))",
|
|
642
|
+
background: "var(--dsw-alias-fill-l1, rgba(127,127,127,.06))",
|
|
643
|
+
color: "var(--dsw-alias-label-primary, #222)",
|
|
644
|
+
flex: 1,
|
|
645
|
+
minWidth: 220
|
|
646
|
+
}
|
|
647
|
+
}), actionBtn("保存", true, () => {
|
|
648
|
+
act("set-server-auth", "", { authToken: authInput.trim() });
|
|
649
|
+
setAuthInput("");
|
|
650
|
+
}, busy === "set-server-auth:" || !authInput.trim()), serve.authConfigured ? actionBtn("清除", false, () => {
|
|
651
|
+
act("set-server-auth", "", { authToken: "" });
|
|
652
|
+
setAuthInput("");
|
|
653
|
+
}, busy === "set-server-auth:") : null), (0, react.createElement)("div", { style: {
|
|
654
|
+
fontSize: 11.5,
|
|
655
|
+
color: "var(--dsw-alias-label-tertiary, #999)"
|
|
656
|
+
} }, "token 会明文存入 a2a.json,重启后仍生效。设置后,入站 JSON-RPC 请求需带 Authorization: Bearer <token>。"));
|
|
657
|
+
}
|
|
560
658
|
function inboundRow(p, busy, act) {
|
|
561
659
|
return (0, react.createElement)("tr", { key: p.id }, (0, react.createElement)("td", { style: tdStyle }, p.label), (0, react.createElement)("td", { style: {
|
|
562
660
|
...tdStyle,
|