@hanphone/dsh-a2a 0.2.0 → 0.3.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.
Files changed (78) hide show
  1. package/README.md +101 -106
  2. package/README.zh.md +50 -74
  3. package/cordis.patch.yml +4 -7
  4. package/lib/client.js +217 -73
  5. package/lib/index.js +1258 -867
  6. package/lib/types/api.d.ts +40 -23
  7. package/lib/types/api.d.ts.map +1 -1
  8. package/lib/types/api.js +58 -23
  9. package/lib/types/api.js.map +1 -1
  10. package/lib/types/client/index.d.ts +50 -19
  11. package/lib/types/client/index.d.ts.map +1 -1
  12. package/lib/types/commands.d.ts +4 -2
  13. package/lib/types/commands.d.ts.map +1 -1
  14. package/lib/types/commands.js +59 -46
  15. package/lib/types/commands.js.map +1 -1
  16. package/lib/types/events.d.ts +32 -9
  17. package/lib/types/events.d.ts.map +1 -1
  18. package/lib/types/index.d.ts +21 -32
  19. package/lib/types/index.d.ts.map +1 -1
  20. package/lib/types/index.js +173 -272
  21. package/lib/types/index.js.map +1 -1
  22. package/lib/types/outbound/calls.d.ts.map +1 -1
  23. package/lib/types/outbound/calls.js +8 -6
  24. package/lib/types/outbound/calls.js.map +1 -1
  25. package/lib/types/protocol.d.ts +174 -109
  26. package/lib/types/protocol.d.ts.map +1 -1
  27. package/lib/types/protocol.js +58 -34
  28. package/lib/types/protocol.js.map +1 -1
  29. package/lib/types/server/a2a-server.d.ts +4 -0
  30. package/lib/types/server/a2a-server.d.ts.map +1 -1
  31. package/lib/types/server/a2a-server.js +6 -2
  32. package/lib/types/server/a2a-server.js.map +1 -1
  33. package/lib/types/server/card.d.ts +6 -30
  34. package/lib/types/server/card.d.ts.map +1 -1
  35. package/lib/types/server/card.js +13 -49
  36. package/lib/types/server/card.js.map +1 -1
  37. package/lib/types/server/exec/agent-runtime.d.ts +3 -0
  38. package/lib/types/server/exec/agent-runtime.d.ts.map +1 -1
  39. package/lib/types/server/exec/agent-runtime.js +2 -1
  40. package/lib/types/server/exec/agent-runtime.js.map +1 -1
  41. package/lib/types/server/routes.d.ts +5 -1
  42. package/lib/types/server/routes.d.ts.map +1 -1
  43. package/lib/types/server/routes.js +9 -5
  44. package/lib/types/server/routes.js.map +1 -1
  45. package/lib/types/server/store.d.ts +35 -1
  46. package/lib/types/server/store.d.ts.map +1 -1
  47. package/lib/types/server/store.js +10 -0
  48. package/lib/types/server/store.js.map +1 -1
  49. package/lib/types/servers/inbound-manager.d.ts +131 -0
  50. package/lib/types/servers/inbound-manager.d.ts.map +1 -0
  51. package/lib/types/servers/inbound-manager.js +312 -0
  52. package/lib/types/servers/inbound-manager.js.map +1 -0
  53. package/lib/types/servers/outbound-manager.d.ts +129 -0
  54. package/lib/types/servers/outbound-manager.d.ts.map +1 -0
  55. package/lib/types/servers/outbound-manager.js +238 -0
  56. package/lib/types/servers/outbound-manager.js.map +1 -0
  57. package/lib/types/service.d.ts +106 -40
  58. package/lib/types/service.d.ts.map +1 -1
  59. package/lib/types/service.js +36 -27
  60. package/lib/types/service.js.map +1 -1
  61. package/package.json +2 -2
  62. package/src/api.ts +67 -53
  63. package/src/client/index.ts +309 -148
  64. package/src/commands.ts +59 -43
  65. package/src/events.ts +14 -7
  66. package/src/index.ts +199 -310
  67. package/src/outbound/calls.ts +8 -6
  68. package/src/protocol.ts +204 -95
  69. package/src/server/a2a-server.ts +9 -2
  70. package/src/server/card.ts +13 -62
  71. package/src/server/exec/agent-runtime.ts +5 -2
  72. package/src/server/routes.ts +6 -4
  73. package/src/server/store.ts +45 -4
  74. package/src/servers/inbound-manager.ts +385 -0
  75. package/src/servers/outbound-manager.ts +289 -0
  76. package/src/service.ts +125 -40
  77. package/lib/tsconfig.client.tsbuildinfo +0 -1
  78. package/lib/tsconfig.tsbuildinfo +0 -1
package/lib/client.js CHANGED
@@ -17,7 +17,7 @@ window.__ModuleLoader__.load({
17
17
  .dsh-a2a-panel { display: flex; flex-direction: column; gap: 16px; padding: 12px 0; }
18
18
  .dsh-a2a-card { border: 1px solid var(--dsw-alias-border, #d0d7de); border-radius: 8px; padding: 12px 14px; }
19
19
  .dsh-a2a-card h3 { margin: 0 0 8px; font-size: 14px; }
20
- .dsh-a2a-row { display: flex; align-items: center; gap: 8px; margin: 4px 0; }
20
+ .dsh-a2a-row { display: flex; align-items: center; gap: 8px; margin: 4px 0; flex-wrap: wrap; }
21
21
  .dsh-a2a-row .muted { color: var(--dsw-alias-text-secondary, #59636e); font-size: 12px; }
22
22
  .dsh-a2a-row button { padding: 2px 10px; border-radius: 6px; border: 1px solid var(--dsw-alias-border, #d0d7de); background: transparent; cursor: pointer; }
23
23
  .dsh-a2a-row button.primary { background: var(--dsw-alias-accent, #0f6); color: var(--dsw-alias-bg, #fff); border-color: transparent; }
@@ -25,10 +25,13 @@ window.__ModuleLoader__.load({
25
25
  .dsh-a2a-state.ok { background: #1a7f3722; color: #1a7f37; }
26
26
  .dsh-a2a-state.bad { background: #d1242f22; color: #d1242f; }
27
27
  .dsh-a2a-form { display: flex; gap: 6px; margin: 8px 0; flex-wrap: wrap; }
28
- .dsh-a2a-form input { padding: 4px 8px; border-radius: 6px; border: 1px solid var(--dsw-alias-border, #d0d7de); background: transparent; color: inherit; }
28
+ .dsh-a2a-form input, .dsh-a2a-form select, .dsh-a2a-form textarea { padding: 4px 8px; border-radius: 6px; border: 1px solid var(--dsw-alias-border, #d0d7de); background: transparent; color: inherit; }
29
+ .dsh-a2a-form textarea { font-family: inherit; width: 100%; min-height: 64px; resize: vertical; }
29
30
  .dsh-a2a-table { width: 100%; border-collapse: collapse; font-size: 13px; }
30
- .dsh-a2a-table th, .dsh-a2a-table td { text-align: left; padding: 4px 8px; border-bottom: 1px solid var(--dsw-alias-border, #d0d7de); }
31
+ .dsh-a2a-table th, .dsh-a2a-table td { text-align: left; padding: 4px 8px; border-bottom: 1px solid var(--dsw-alias-border, #d0d7de); vertical-align: top; }
32
+ .dsh-a2a-skill { display: inline-block; margin: 1px 4px 1px 0; padding: 0 6px; border-radius: 10px; background: #6e778122; font-size: 12px; }
31
33
  .dsh-a2a-error { color: #d1242f; font-size: 12px; }
34
+ .dsh-a2a-hint { color: var(--dsw-alias-text-secondary, #59636e); font-size: 12px; margin: 2px 0 6px; }
32
35
  `;
33
36
  document.head.appendChild(tag);
34
37
  return () => tag.remove();
@@ -48,6 +51,11 @@ window.__ModuleLoader__.load({
48
51
  if (!res.ok) throw new Error(`snapshot HTTP ${res.status}`);
49
52
  return await res.json();
50
53
  }
54
+ async function fetchPresets() {
55
+ const res = await fetch("/a2a/api/presets", { headers: { accept: "application/json" } });
56
+ if (!res.ok) return [];
57
+ return await res.json();
58
+ }
51
59
  async function postControl(payload) {
52
60
  const res = await fetch("/a2a/api", {
53
61
  method: "POST",
@@ -59,29 +67,53 @@ window.__ModuleLoader__.load({
59
67
  message: `HTTP ${res.status}`
60
68
  }));
61
69
  }
70
+ /** One skill declaration per line: `id|name|description` (name/description default to id). */
71
+ function parseSkills(text) {
72
+ const lines = text.split("\n").map((l) => l.trim()).filter(Boolean);
73
+ if (lines.length === 0) return void 0;
74
+ return lines.map((line) => {
75
+ const [id, name, ...descParts] = line.split("|").map((p) => p.trim());
76
+ const skillId = id ?? "";
77
+ return {
78
+ id: skillId,
79
+ name: name && name.length > 0 ? name : skillId,
80
+ ...descParts.length > 0 || (descParts[0]?.length ?? 0) > 0 ? { description: descParts.join("|") } : {}
81
+ };
82
+ });
83
+ }
84
+ function skillsToText(skills) {
85
+ return skills.map((s) => [
86
+ s.id,
87
+ s.name,
88
+ s.description
89
+ ].filter((p) => p !== void 0 && p.length > 0).join("|")).join("\n");
90
+ }
62
91
  function A2aSection(_props) {
63
92
  const [snap, setSnap] = (0, react.useState)(void 0);
93
+ const [presets, setPresets] = (0, react.useState)([]);
64
94
  const [error, setError] = (0, react.useState)(void 0);
65
- const [agentName, setAgentName] = (0, react.useState)("");
66
- const [agentUrl, setAgentUrl] = (0, react.useState)("");
67
95
  const [busy, setBusy] = (0, react.useState)(false);
68
- const [editing, setEditing] = (0, react.useState)(false);
69
- const [idName, setIdName] = (0, react.useState)("");
70
- const [idDescription, setIdDescription] = (0, react.useState)("");
71
- const [idVersion, setIdVersion] = (0, react.useState)("");
96
+ const [editingIn, setEditingIn] = (0, react.useState)(void 0);
97
+ const [inName, setInName] = (0, react.useState)("");
98
+ const [inDesc, setInDesc] = (0, react.useState)("");
99
+ const [inVersion, setInVersion] = (0, react.useState)("1.0.0");
100
+ const [inPreset, setInPreset] = (0, react.useState)("");
101
+ const [inAuthEnv, setInAuthEnv] = (0, react.useState)("");
102
+ const [inSkills, setInSkills] = (0, react.useState)("");
103
+ const [outName, setOutName] = (0, react.useState)("");
104
+ const [outUrl, setOutUrl] = (0, react.useState)("");
105
+ const [outPreset, setOutPreset] = (0, react.useState)("");
106
+ const [outTokenEnv, setOutTokenEnv] = (0, react.useState)("");
107
+ const [outTimeout, setOutTimeout] = (0, react.useState)("60000");
72
108
  (0, react.useEffect)(() => {
73
109
  let alive = true;
74
110
  const tick = async () => {
75
111
  try {
76
- const next = await fetchSnapshot();
112
+ const [next, presetRows] = await Promise.all([fetchSnapshot(), fetchPresets()]);
77
113
  if (alive) {
78
114
  setSnap(next);
115
+ setPresets(presetRows);
79
116
  setError(void 0);
80
- if (!editing) {
81
- setIdName(next.server.name ?? "");
82
- setIdDescription(next.server.description ?? "");
83
- setIdVersion(next.server.version ?? "");
84
- }
85
117
  }
86
118
  } catch (err) {
87
119
  if (alive) setError(err.message);
@@ -106,97 +138,209 @@ window.__ModuleLoader__.load({
106
138
  setBusy(false);
107
139
  }
108
140
  };
109
- const server = snap?.server;
110
- const agents = snap?.agents ?? [];
141
+ const startCreateInbound = () => {
142
+ setEditingIn(void 0);
143
+ setInName("");
144
+ setInDesc("");
145
+ setInVersion("1.0.0");
146
+ setInPreset("");
147
+ setInAuthEnv("");
148
+ setInSkills("");
149
+ };
150
+ const submitInbound = () => {
151
+ if (!inName.trim()) return;
152
+ const skills = parseSkills(inSkills);
153
+ if (editingIn !== void 0) {
154
+ control({
155
+ action: "inbound.update",
156
+ id: editingIn,
157
+ name: inName.trim(),
158
+ description: inDesc.trim(),
159
+ version: inVersion.trim() || "1.0.0",
160
+ ...inPreset !== "" ? { preset: inPreset } : {},
161
+ ...inAuthEnv.trim() !== "" ? { authTokenEnv: inAuthEnv.trim() } : {},
162
+ ...skills !== void 0 ? { skills } : {}
163
+ }).then(() => setEditingIn(void 0));
164
+ return;
165
+ }
166
+ control({
167
+ action: "inbound.create",
168
+ name: inName.trim(),
169
+ description: inDesc.trim() || "An A2A inbound server",
170
+ version: inVersion.trim() || "1.0.0",
171
+ ...inPreset !== "" ? { preset: inPreset } : {},
172
+ ...inAuthEnv.trim() !== "" ? { authTokenEnv: inAuthEnv.trim() } : {},
173
+ ...skills !== void 0 ? { skills } : {}
174
+ }).then(() => startCreateInbound());
175
+ };
176
+ const beginEditInbound = (v) => {
177
+ setEditingIn(v.id);
178
+ setInName(v.name);
179
+ setInDesc(v.description);
180
+ setInVersion(v.version);
181
+ setInPreset(v.preset ?? "");
182
+ setInAuthEnv(v.authTokenEnv ?? "");
183
+ setInSkills(skillsToText(v.skills));
184
+ };
185
+ const submitOutbound = () => {
186
+ if (!outName.trim() || !outUrl.trim()) return;
187
+ const timeout = Number.parseInt(outTimeout, 10);
188
+ control({
189
+ action: "outbound.create",
190
+ name: outName.trim(),
191
+ agentCardUrl: outUrl.trim(),
192
+ ...outPreset !== "" ? { preset: outPreset } : {},
193
+ ...outTokenEnv.trim() !== "" ? { bearerTokenEnv: outTokenEnv.trim() } : {},
194
+ ...Number.isFinite(timeout) && timeout > 0 ? { timeoutMs: timeout } : {}
195
+ }).then(() => {
196
+ setOutName("");
197
+ setOutUrl("");
198
+ setOutPreset("");
199
+ setOutTokenEnv("");
200
+ });
201
+ };
111
202
  const inbounds = snap?.inbounds ?? [];
203
+ const outbounds = snap?.outbounds ?? [];
204
+ const peers = snap?.peers ?? [];
112
205
  const tasks = snap?.tasks ?? [];
113
- return (0, react.createElement)("div", { className: "dsh-a2a-panel" }, error !== void 0 ? (0, react.createElement)("div", { className: "dsh-a2a-error" }, error) : null, (0, react.createElement)("div", { className: "dsh-a2a-card" }, (0, react.createElement)("h3", null, "入站 Server"), server === void 0 ? (0, react.createElement)("div", { className: "muted" }, "加载中…") : (0, react.createElement)("div", { className: "dsh-a2a-row" }, (0, react.createElement)("span", { className: `dsh-a2a-state ${server.enabled ? "ok" : "bad"}` }, server.enabled ? "已启用" : "已停用"), (0, react.createElement)("button", {
114
- className: server.enabled ? "" : "primary",
206
+ return (0, react.createElement)("div", { className: "dsh-a2a-panel" }, error !== void 0 ? (0, react.createElement)("div", { className: "dsh-a2a-error" }, error) : null, (0, react.createElement)("div", { className: "dsh-a2a-card" }, (0, react.createElement)("h3", null, `入站 Servers(${inbounds.length})`), inbounds.length === 0 ? (0, react.createElement)("div", { className: "muted" }, "还没有入站 server。创建一个即可对外发布 A2A 端点。") : (0, react.createElement)("table", { className: "dsh-a2a-table" }, (0, react.createElement)("thead", null, (0, react.createElement)("tr", null, (0, react.createElement)("th", null, "名称 / 端点"), (0, react.createElement)("th", null, "Preset"), (0, react.createElement)("th", null, "技能宣告"), (0, react.createElement)("th", null, "状态"), (0, react.createElement)("th", null, "操作"))), (0, react.createElement)("tbody", null, ...inbounds.map((v) => (0, react.createElement)("tr", { key: v.id }, (0, react.createElement)("td", null, (0, react.createElement)("div", null, v.name), (0, react.createElement)("div", { className: "muted" }, `${v.endpointPath} · ${v.cardUrl ?? v.cardPath}`), v.authTokenEnv !== void 0 && v.authTokenEnv !== "" ? (0, react.createElement)("div", { className: "muted" }, `鉴权: $${v.authTokenEnv}`) : null), (0, react.createElement)("td", null, v.preset ?? (0, react.createElement)("span", { className: "muted" }, "默认")), (0, react.createElement)("td", null, (0, react.createElement)("div", null, ...v.skills.map((s) => (0, react.createElement)("span", {
207
+ className: "dsh-a2a-skill",
208
+ key: s.id,
209
+ title: s.description ?? ""
210
+ }, s.name)))), (0, react.createElement)("td", null, (0, react.createElement)("span", { className: `dsh-a2a-state ${v.enabled ? "ok" : "bad"}` }, v.enabled ? "运行中" : "已停用")), (0, react.createElement)("td", null, (0, react.createElement)("button", {
115
211
  disabled: busy,
116
- onClick: () => void control({ action: server.enabled ? "server.disable" : "server.enable" })
117
- }, server.enabled ? "停用" : "启用")), server !== void 0 && server.enabled ? (0, react.createElement)("div", { className: "dsh-a2a-row muted" }, `AgentCard: ${server.cardUrl ?? "(n/a)"} · 技能: ${server.skills.join(", ") || "(chat)"}`) : null), (0, react.createElement)("div", { className: "dsh-a2a-card" }, server === void 0 || server.configured === false ? (0, react.createElement)("h3", null, "服务身份(首次配置)") : (0, react.createElement)("h3", null, "服务身份"), (0, react.createElement)("form", {
212
+ onClick: () => void control({
213
+ action: v.enabled ? "inbound.disable" : "inbound.enable",
214
+ id: v.id
215
+ })
216
+ }, v.enabled ? "停用" : "启用"), " ", (0, react.createElement)("button", {
217
+ disabled: busy,
218
+ onClick: () => beginEditInbound(v)
219
+ }, "编辑"), " ", (0, react.createElement)("button", {
220
+ disabled: busy,
221
+ onClick: () => void control({
222
+ action: "inbound.remove",
223
+ id: v.id
224
+ })
225
+ }, "删除")))))), (0, react.createElement)("h3", { style: { marginTop: "12px" } }, editingIn !== void 0 ? "编辑入站 Server" : "新建入站 Server"), (0, react.createElement)("form", {
118
226
  className: "dsh-a2a-form",
119
227
  onSubmit: (ev) => {
120
228
  ev.preventDefault();
121
- control({
122
- action: "identity.update",
123
- name: idName,
124
- description: idDescription,
125
- version: idVersion
126
- }).then(() => {
127
- setEditing(false);
128
- });
229
+ submitInbound();
129
230
  }
130
231
  }, (0, react.createElement)("input", {
131
- value: idVersion,
132
- placeholder: "版本",
133
- onChange: (e) => setIdVersion(e.target.value),
134
- style: { width: "60px" }
135
- }), (0, react.createElement)("input", {
136
- value: idName,
137
- placeholder: "服务名称",
138
- onChange: (e) => setIdName(e.target.value),
139
- style: { width: "160px" }
232
+ value: inName,
233
+ placeholder: "名称",
234
+ onChange: (e) => setInName(e.target.value)
140
235
  }), (0, react.createElement)("input", {
141
- value: idDescription,
142
- placeholder: "服务描述",
143
- onChange: (e) => setIdDescription(e.target.value),
144
- style: { width: "260px" }
236
+ value: inVersion,
237
+ placeholder: "版本",
238
+ onChange: (e) => setInVersion(e.target.value),
239
+ style: { width: "70px" }
240
+ }), (0, react.createElement)("select", {
241
+ value: inPreset,
242
+ onChange: (e) => setInPreset(e.target.value)
243
+ }, (0, react.createElement)("option", { value: "" }, "Preset(默认)"), ...presets.map((p) => (0, react.createElement)("option", {
244
+ value: p.id,
245
+ key: p.id
246
+ }, `${p.name ?? p.id}${p.isDefault ? "(默认)" : ""}`))), (0, react.createElement)("input", {
247
+ value: inAuthEnv,
248
+ placeholder: "鉴权 env 变量名(可选)",
249
+ onChange: (e) => setInAuthEnv(e.target.value)
250
+ })), (0, react.createElement)("form", {
251
+ className: "dsh-a2a-form",
252
+ onSubmit: (ev) => {
253
+ ev.preventDefault();
254
+ submitInbound();
255
+ }
256
+ }, (0, react.createElement)("textarea", {
257
+ value: inSkills,
258
+ placeholder: "技能宣告(每行 id|名称|描述,留空默认取 preset 名)",
259
+ onChange: (e) => setInSkills(e.target.value)
260
+ })), (0, react.createElement)("form", {
261
+ className: "dsh-a2a-form",
262
+ onSubmit: (ev) => {
263
+ ev.preventDefault();
264
+ submitInbound();
265
+ }
266
+ }, (0, react.createElement)("input", {
267
+ value: inDesc,
268
+ placeholder: "描述",
269
+ onChange: (e) => setInDesc(e.target.value),
270
+ style: {
271
+ flex: 1,
272
+ minWidth: "260px"
273
+ }
145
274
  }), (0, react.createElement)("button", {
146
275
  type: "submit",
147
276
  className: "primary",
148
- disabled: busy
149
- }, "保存身份")), (0, react.createElement)("div", { className: "dsh-a2a-row muted" }, "名称、描述、版本即刻重建 AgentCard;技能始终从工具注册表派生。")), (0, react.createElement)("div", { className: "dsh-a2a-card" }, (0, react.createElement)("h3", null, `入站连接(${inbounds.length})`), inbounds.length === 0 ? (0, react.createElement)("div", { className: "muted" }, "当前无远程对端正在调用本服务。") : (0, react.createElement)("table", { className: "dsh-a2a-table" }, (0, react.createElement)("thead", null, (0, react.createElement)("tr", null, (0, react.createElement)("th", null, "来源"), (0, react.createElement)("th", null, "任务"), (0, react.createElement)("th", null, "流式"), (0, react.createElement)("th", null, "首次 / 最近"), (0, react.createElement)("th", null, "操作"))), (0, react.createElement)("tbody", null, ...inbounds.map((p) => (0, react.createElement)("tr", { key: p.id }, (0, react.createElement)("td", null, p.source ?? p.label), (0, react.createElement)("td", null, `${p.taskCount}(活跃 ${p.activeTaskIds.length})`), (0, react.createElement)("td", null, p.streaming ? "●" : "—"), (0, react.createElement)("td", null, (0, react.createElement)("span", { className: "muted" }, `${p.firstSeen ?? ""} / ${p.lastSeen ?? ""}`)), (0, react.createElement)("td", null, (0, react.createElement)("button", {
277
+ disabled: busy || !inName.trim()
278
+ }, editingIn !== void 0 ? "保存修改" : "创建 Server"), editingIn !== void 0 ? (0, react.createElement)("button", {
279
+ type: "button",
150
280
  disabled: busy,
151
- onClick: () => void control({
152
- action: "inbound.close",
153
- id: p.id
154
- })
155
- }, "关闭"))))))), (0, react.createElement)("div", { className: "dsh-a2a-card" }, (0, react.createElement)("h3", null, `出站 Agents(${agents.length})`), agents.length === 0 ? (0, react.createElement)("div", { className: "muted" }, "未配置远程 agent。") : (0, react.createElement)("table", { className: "dsh-a2a-table" }, (0, react.createElement)("thead", null, (0, react.createElement)("tr", null, (0, react.createElement)("th", null, "名称"), (0, react.createElement)("th", null, "状态"), (0, react.createElement)("th", null, "工具"), (0, react.createElement)("th", null, "操作"))), (0, react.createElement)("tbody", null, ...agents.map((a) => (0, react.createElement)("tr", { key: a.id }, (0, react.createElement)("td", null, (0, react.createElement)("div", null, a.name), (0, react.createElement)("div", { className: "muted" }, a.agentCardUrl), a.lastError !== void 0 ? (0, react.createElement)("div", { className: "dsh-a2a-error" }, a.lastError) : null), (0, react.createElement)("td", null, (0, react.createElement)("span", { className: `dsh-a2a-state ${a.state === "connected" ? "ok" : "bad"}` }, a.state)), (0, react.createElement)("td", null, `${a.toolCount} / ${a.skillCount}`), (0, react.createElement)("td", null, (0, react.createElement)("button", {
281
+ onClick: () => startCreateInbound()
282
+ }, "取消") : null), (0, react.createElement)("div", { className: "dsh-a2a-hint" }, "技能宣告由创建者输入,默认取所绑定的 preset 展示名(无 preset 时为内置 chat)。")), (0, react.createElement)("div", { className: "dsh-a2a-card" }, (0, react.createElement)("h3", null, `出站 Servers(${outbounds.length})`), outbounds.length === 0 ? (0, react.createElement)("div", { className: "muted" }, "还没有出站 server。添加一个远端 A2A 连接即可把其技能注册为模型工具。") : (0, react.createElement)("table", { className: "dsh-a2a-table" }, (0, react.createElement)("thead", null, (0, react.createElement)("tr", null, (0, react.createElement)("th", null, "名称 / 远端"), (0, react.createElement)("th", null, "Preset"), (0, react.createElement)("th", null, "状态"), (0, react.createElement)("th", null, "工具"), (0, react.createElement)("th", null, "操作"))), (0, react.createElement)("tbody", null, ...outbounds.map((v) => (0, react.createElement)("tr", { key: v.id }, (0, react.createElement)("td", null, (0, react.createElement)("div", null, v.name), (0, react.createElement)("div", { className: "muted" }, v.agentCardUrl), v.lastError !== void 0 ? (0, react.createElement)("div", { className: "dsh-a2a-error" }, v.lastError) : null), (0, react.createElement)("td", null, v.preset ?? (0, react.createElement)("span", { className: "muted" }, "默认")), (0, react.createElement)("td", null, (0, react.createElement)("span", { className: `dsh-a2a-state ${v.state === "connected" ? "ok" : "bad"}` }, v.state === "connected" ? "已连接" : v.state)), (0, react.createElement)("td", null, `${v.toolCount} / ${v.skillCount}`), (0, react.createElement)("td", null, (0, react.createElement)("button", {
156
283
  disabled: busy,
157
284
  onClick: () => void control({
158
- action: a.enabled ? "agent.disable" : "agent.enable",
159
- id: a.id
285
+ action: v.enabled ? "outbound.disable" : "outbound.enable",
286
+ id: v.id
160
287
  })
161
- }, a.enabled ? "停用" : "启用"), " ", (0, react.createElement)("button", {
288
+ }, v.enabled ? "停用" : "启用"), " ", (0, react.createElement)("button", {
162
289
  disabled: busy,
163
290
  onClick: () => void control({
164
- action: "agent.refresh",
165
- id: a.id
291
+ action: "outbound.refresh",
292
+ id: v.id
166
293
  })
167
294
  }, "刷新"), " ", (0, react.createElement)("button", {
168
295
  disabled: busy,
169
296
  onClick: () => void control({
170
- action: "agent.remove",
171
- id: a.id
297
+ action: "outbound.remove",
298
+ id: v.id
172
299
  })
173
- }, "删除")))))), (0, react.createElement)("form", {
300
+ }, "删除")))))), (0, react.createElement)("h3", { style: { marginTop: "12px" } }, "新建出站 Server"), (0, react.createElement)("form", {
174
301
  className: "dsh-a2a-form",
175
302
  onSubmit: (ev) => {
176
303
  ev.preventDefault();
177
- if (!agentName.trim() || !agentUrl.trim()) return;
178
- control({
179
- action: "agent.add",
180
- name: agentName.trim(),
181
- agentCardUrl: agentUrl.trim()
182
- }).then(() => {
183
- setAgentName("");
184
- setAgentUrl("");
185
- });
304
+ submitOutbound();
186
305
  }
187
306
  }, (0, react.createElement)("input", {
188
- value: agentName,
307
+ value: outName,
189
308
  placeholder: "名称",
190
- onChange: (e) => setAgentName(e.target.value)
309
+ onChange: (e) => setOutName(e.target.value)
310
+ }), (0, react.createElement)("input", {
311
+ value: outUrl,
312
+ placeholder: "远端 AgentCard URL",
313
+ onChange: (e) => setOutUrl(e.target.value),
314
+ style: {
315
+ flex: 1,
316
+ minWidth: "240px"
317
+ }
318
+ }), (0, react.createElement)("select", {
319
+ value: outPreset,
320
+ onChange: (e) => setOutPreset(e.target.value)
321
+ }, (0, react.createElement)("option", { value: "" }, "Preset(默认)"), ...presets.map((p) => (0, react.createElement)("option", {
322
+ value: p.id,
323
+ key: p.id
324
+ }, `${p.name ?? p.id}${p.isDefault ? "(默认)" : ""}`))), (0, react.createElement)("input", {
325
+ value: outTokenEnv,
326
+ placeholder: "Bearer env 变量名(可选)",
327
+ onChange: (e) => setOutTokenEnv(e.target.value)
191
328
  }), (0, react.createElement)("input", {
192
- value: agentUrl,
193
- placeholder: "AgentCard URL",
194
- onChange: (e) => setAgentUrl(e.target.value)
329
+ value: outTimeout,
330
+ placeholder: "超时 ms",
331
+ onChange: (e) => setOutTimeout(e.target.value),
332
+ style: { width: "90px" }
195
333
  }), (0, react.createElement)("button", {
196
334
  type: "submit",
197
335
  className: "primary",
198
- disabled: busy
199
- }, "添加 Agent"))), (0, react.createElement)("div", { className: "dsh-a2a-card" }, (0, react.createElement)("h3", null, `任务(${tasks.length})`), tasks.length === 0 ? (0, react.createElement)("div", { className: "muted" }, "暂无任务。") : (0, react.createElement)("table", { className: "dsh-a2a-table" }, (0, react.createElement)("thead", null, (0, react.createElement)("tr", null, (0, react.createElement)("th", null, "ID"), (0, react.createElement)("th", null, "技能"), (0, react.createElement)("th", null, "状态"), (0, react.createElement)("th", null, "操作"))), (0, react.createElement)("tbody", null, ...tasks.slice(-20).reverse().map((t) => (0, react.createElement)("tr", { key: t.id }, (0, react.createElement)("td", null, (0, react.createElement)("span", { className: "muted" }, t.id)), (0, react.createElement)("td", null, t.metadata?.skill ?? "-"), (0, react.createElement)("td", null, t.status?.state ?? "-"), (0, react.createElement)("td", null, (0, react.createElement)("button", {
336
+ disabled: busy || !outName.trim() || !outUrl.trim()
337
+ }, "添加出站 Server"))), (0, react.createElement)("div", { className: "dsh-a2a-card" }, (0, react.createElement)("h3", null, `入站连接(${peers.length})`), peers.length === 0 ? (0, react.createElement)("div", { className: "muted" }, "当前无远程对端正在调用本服务。") : (0, react.createElement)("table", { className: "dsh-a2a-table" }, (0, react.createElement)("thead", null, (0, react.createElement)("tr", null, (0, react.createElement)("th", null, "来源"), (0, react.createElement)("th", null, "任务"), (0, react.createElement)("th", null, "流式"), (0, react.createElement)("th", null, "首次 / 最近"), (0, react.createElement)("th", null, "操作"))), (0, react.createElement)("tbody", null, ...peers.map((p) => (0, react.createElement)("tr", { key: p.id }, (0, react.createElement)("td", null, p.source ?? p.label), (0, react.createElement)("td", null, `${p.taskCount}(活跃 ${p.activeTaskIds.length})`), (0, react.createElement)("td", null, p.streaming ? "" : "—"), (0, react.createElement)("td", null, (0, react.createElement)("span", { className: "muted" }, `${p.firstSeen ?? ""} / ${p.lastSeen ?? ""}`)), (0, react.createElement)("td", null, (0, react.createElement)("button", {
338
+ disabled: busy,
339
+ onClick: () => void control({
340
+ action: "inbound.close",
341
+ id: p.id
342
+ })
343
+ }, "关闭"))))))), (0, react.createElement)("div", { className: "dsh-a2a-card" }, (0, react.createElement)("h3", null, `任务(${tasks.length})`), tasks.length === 0 ? (0, react.createElement)("div", { className: "muted" }, "暂无任务。") : (0, react.createElement)("table", { className: "dsh-a2a-table" }, (0, react.createElement)("thead", null, (0, react.createElement)("tr", null, (0, react.createElement)("th", null, "ID"), (0, react.createElement)("th", null, "技能"), (0, react.createElement)("th", null, "状态"), (0, react.createElement)("th", null, "操作"))), (0, react.createElement)("tbody", null, ...tasks.slice(-20).reverse().map((t) => (0, react.createElement)("tr", { key: t.id }, (0, react.createElement)("td", null, (0, react.createElement)("span", { className: "muted" }, t.id)), (0, react.createElement)("td", null, t.metadata?.skill ?? "-"), (0, react.createElement)("td", null, t.status?.state ?? "-"), (0, react.createElement)("td", null, (0, react.createElement)("button", {
200
344
  disabled: busy,
201
345
  onClick: () => void control({
202
346
  action: "task.cancel",