@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.
- package/README.md +101 -106
- package/README.zh.md +50 -74
- package/cordis.patch.yml +4 -7
- package/lib/client.js +217 -73
- package/lib/index.js +1258 -867
- package/lib/types/api.d.ts +40 -23
- package/lib/types/api.d.ts.map +1 -1
- package/lib/types/api.js +58 -23
- package/lib/types/api.js.map +1 -1
- package/lib/types/client/index.d.ts +50 -19
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/commands.d.ts +4 -2
- package/lib/types/commands.d.ts.map +1 -1
- package/lib/types/commands.js +59 -46
- package/lib/types/commands.js.map +1 -1
- package/lib/types/events.d.ts +32 -9
- package/lib/types/events.d.ts.map +1 -1
- package/lib/types/index.d.ts +21 -32
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +173 -272
- package/lib/types/index.js.map +1 -1
- package/lib/types/outbound/calls.d.ts.map +1 -1
- package/lib/types/outbound/calls.js +8 -6
- package/lib/types/outbound/calls.js.map +1 -1
- package/lib/types/protocol.d.ts +174 -109
- package/lib/types/protocol.d.ts.map +1 -1
- package/lib/types/protocol.js +58 -34
- package/lib/types/protocol.js.map +1 -1
- package/lib/types/server/a2a-server.d.ts +4 -0
- package/lib/types/server/a2a-server.d.ts.map +1 -1
- package/lib/types/server/a2a-server.js +6 -2
- package/lib/types/server/a2a-server.js.map +1 -1
- package/lib/types/server/card.d.ts +6 -30
- package/lib/types/server/card.d.ts.map +1 -1
- package/lib/types/server/card.js +13 -49
- package/lib/types/server/card.js.map +1 -1
- package/lib/types/server/exec/agent-runtime.d.ts +3 -0
- package/lib/types/server/exec/agent-runtime.d.ts.map +1 -1
- package/lib/types/server/exec/agent-runtime.js +2 -1
- package/lib/types/server/exec/agent-runtime.js.map +1 -1
- package/lib/types/server/routes.d.ts +5 -1
- package/lib/types/server/routes.d.ts.map +1 -1
- package/lib/types/server/routes.js +9 -5
- package/lib/types/server/routes.js.map +1 -1
- package/lib/types/server/store.d.ts +35 -1
- package/lib/types/server/store.d.ts.map +1 -1
- package/lib/types/server/store.js +10 -0
- package/lib/types/server/store.js.map +1 -1
- package/lib/types/servers/inbound-manager.d.ts +131 -0
- package/lib/types/servers/inbound-manager.d.ts.map +1 -0
- package/lib/types/servers/inbound-manager.js +312 -0
- package/lib/types/servers/inbound-manager.js.map +1 -0
- package/lib/types/servers/outbound-manager.d.ts +129 -0
- package/lib/types/servers/outbound-manager.d.ts.map +1 -0
- package/lib/types/servers/outbound-manager.js +238 -0
- package/lib/types/servers/outbound-manager.js.map +1 -0
- package/lib/types/service.d.ts +106 -40
- package/lib/types/service.d.ts.map +1 -1
- package/lib/types/service.js +36 -27
- package/lib/types/service.js.map +1 -1
- package/package.json +2 -2
- package/src/api.ts +67 -53
- package/src/client/index.ts +309 -148
- package/src/commands.ts +59 -43
- package/src/events.ts +14 -7
- package/src/index.ts +199 -310
- package/src/outbound/calls.ts +8 -6
- package/src/protocol.ts +204 -95
- package/src/server/a2a-server.ts +9 -2
- package/src/server/card.ts +13 -62
- package/src/server/exec/agent-runtime.ts +5 -2
- package/src/server/routes.ts +6 -4
- package/src/server/store.ts +45 -4
- package/src/servers/inbound-manager.ts +385 -0
- package/src/servers/outbound-manager.ts +289 -0
- package/src/service.ts +125 -40
- package/lib/tsconfig.client.tsbuildinfo +0 -1
- package/lib/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outbound server manager: owns every outbound A2A connection instance. Each
|
|
3
|
+
* instance is one connected remote — its own AgentCard URL, auth env, timeout,
|
|
4
|
+
* creator-declared name, and an optional agent-preset binding. Each live
|
|
5
|
+
* instance is one `OutboundAgentRegistry` with an isolated per-instance agent
|
|
6
|
+
* store; enabled instances map their remote skills to `a2a__<name>__<skill>`
|
|
7
|
+
* model tools. The manager owns the full lifecycle (add/enable/disable/remove/
|
|
8
|
+
* refresh) driven from the GUI and facade, persists each instance in the
|
|
9
|
+
* `outbound_servers` domain table, and disposes every connection on teardown.
|
|
10
|
+
*
|
|
11
|
+
* The `preset` field names the agent preset this DSH would compose its local
|
|
12
|
+
* hand-off session with when driving that remote. P0 connects skills to tools
|
|
13
|
+
* and manages the connection; the hand-off session composition behind `preset`
|
|
14
|
+
* is a documented extension point (the outbound tools currently call the
|
|
15
|
+
* remote directly) and the value is persisted metadata surfaced to the GUI.
|
|
16
|
+
* @module dsh-a2a/servers/outbound-manager
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { OutboundAgentRegistry, type AgentStore } from '../outbound/registry.ts'
|
|
20
|
+
import type { OutboundAgentRecord, OutboundServerRecord } from '../server/store.ts'
|
|
21
|
+
|
|
22
|
+
/** Tool-registrar slice (structural `ctx.tools.register`). */
|
|
23
|
+
export interface ToolRegistrar {
|
|
24
|
+
register(def: unknown): (() => void) | void
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Host slices one manager needs. */
|
|
28
|
+
export interface OutboundManagerHost {
|
|
29
|
+
readonly registrar: ToolRegistrar
|
|
30
|
+
readonly tokenOf: (env: string | undefined) => string | undefined
|
|
31
|
+
readonly onError: (message: string) => void
|
|
32
|
+
readonly defaultTimeoutMs: number
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface OpResult {
|
|
36
|
+
readonly ok: boolean
|
|
37
|
+
readonly message: string
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** One outbound instance as the GUI/facade reads it. */
|
|
41
|
+
export interface OutboundServerView {
|
|
42
|
+
readonly id: string
|
|
43
|
+
readonly name: string
|
|
44
|
+
readonly agentCardUrl: string
|
|
45
|
+
readonly preset?: string
|
|
46
|
+
readonly enabled: boolean
|
|
47
|
+
readonly timeoutMs: number
|
|
48
|
+
readonly state: 'connected' | 'disconnected' | 'failed'
|
|
49
|
+
readonly skillCount: number
|
|
50
|
+
readonly toolCount: number
|
|
51
|
+
readonly lastError?: string
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** An `AgentStore` bound to one outbound server instance's agents-table key. */
|
|
55
|
+
export class ServerAgentStore implements AgentStore {
|
|
56
|
+
constructor(
|
|
57
|
+
private readonly table: {
|
|
58
|
+
get(key: string): string | undefined
|
|
59
|
+
put(key: string, value: string): Promise<void>
|
|
60
|
+
},
|
|
61
|
+
private readonly key: string,
|
|
62
|
+
) {}
|
|
63
|
+
|
|
64
|
+
list(): OutboundAgentRecord[] {
|
|
65
|
+
const raw = this.table.get(this.key)
|
|
66
|
+
if (raw === undefined || raw === '') return []
|
|
67
|
+
try {
|
|
68
|
+
const parsed = JSON.parse(raw) as unknown
|
|
69
|
+
return Array.isArray(parsed) ? (parsed as OutboundAgentRecord[]) : []
|
|
70
|
+
} catch {
|
|
71
|
+
return []
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async save(records: readonly OutboundAgentRecord[]): Promise<void> {
|
|
76
|
+
await this.table.put(this.key, JSON.stringify(records))
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Persisted-instance store over the outbound_servers table. */
|
|
81
|
+
export class DomainOutboundStore {
|
|
82
|
+
private static KEY(id: string): string {
|
|
83
|
+
return `out:${id}`
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
constructor(private readonly table: {
|
|
87
|
+
get(key: string): string | undefined
|
|
88
|
+
put(key: string, value: string): Promise<void>
|
|
89
|
+
entries?(): IterableIterator<[string, string]>
|
|
90
|
+
}) {}
|
|
91
|
+
|
|
92
|
+
list(): OutboundServerRecord[] {
|
|
93
|
+
const out: OutboundServerRecord[] = []
|
|
94
|
+
const entries = this.table.entries
|
|
95
|
+
if (entries === undefined) return out
|
|
96
|
+
// Call through the table (method `this` stays bound); the real KvTable's
|
|
97
|
+
// `entries()` reads instance state.
|
|
98
|
+
for (const [key, raw] of entries.call(this.table)) {
|
|
99
|
+
if (!key.startsWith('out:')) continue
|
|
100
|
+
const parsed = safeParse(raw)
|
|
101
|
+
if (parsed !== undefined) out.push(parsed)
|
|
102
|
+
}
|
|
103
|
+
return out
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
get(id: string): OutboundServerRecord | undefined {
|
|
107
|
+
const raw = this.table.get(DomainOutboundStore.KEY(id))
|
|
108
|
+
return raw === undefined ? undefined : safeParse(raw)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async save(record: OutboundServerRecord): Promise<void> {
|
|
112
|
+
await this.table.put(DomainOutboundStore.KEY(record.id), JSON.stringify(record))
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async remove(id: string): Promise<void> {
|
|
116
|
+
await this.table.put(DomainOutboundStore.KEY(id), '')
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function safeParse(raw: string): OutboundServerRecord | undefined {
|
|
121
|
+
try {
|
|
122
|
+
const parsed = JSON.parse(raw) as OutboundServerRecord
|
|
123
|
+
if (typeof parsed.id !== 'string' || typeof parsed.name !== 'string' || typeof parsed.agentCardUrl !== 'string') return undefined
|
|
124
|
+
return parsed
|
|
125
|
+
} catch {
|
|
126
|
+
return undefined
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** Creator input for a new outbound instance (id optional; manager allocates). */
|
|
131
|
+
export interface OutboundCreateInput {
|
|
132
|
+
readonly id?: string
|
|
133
|
+
readonly name: string
|
|
134
|
+
readonly agentCardUrl: string
|
|
135
|
+
readonly bearerTokenEnv?: string
|
|
136
|
+
readonly preset?: string
|
|
137
|
+
readonly enabled?: boolean
|
|
138
|
+
readonly timeoutMs?: number
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Manages the live set of outbound connection instances. */
|
|
142
|
+
export class OutboundServerManager {
|
|
143
|
+
private readonly registries = new Map<string, OutboundAgentRegistry>()
|
|
144
|
+
|
|
145
|
+
constructor(
|
|
146
|
+
private readonly host: OutboundManagerHost,
|
|
147
|
+
/** Persistence sink for each instance's agent records (the `agents` table). */
|
|
148
|
+
private readonly agentSink: { get(key: string): string | undefined; put(key: string, value: string): Promise<void> },
|
|
149
|
+
/** Persisted OutboundServerRecord store (the `outbound_servers` table). */
|
|
150
|
+
private readonly records: DomainOutboundStore,
|
|
151
|
+
/** Allocate a fresh stable instance id. */
|
|
152
|
+
private readonly newId: () => string,
|
|
153
|
+
) {}
|
|
154
|
+
|
|
155
|
+
/** The host default connection timeout (what a minimal record falls back to). */
|
|
156
|
+
get defaultTimeoutMs(): number {
|
|
157
|
+
return this.host.defaultTimeoutMs
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private agentKeyFor(id: string): string {
|
|
161
|
+
return `out:${id}`
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private makeRegistry(record: OutboundServerRecord): OutboundAgentRegistry {
|
|
165
|
+
return new OutboundAgentRegistry({
|
|
166
|
+
registrar: { register: (def) => this.host.registrar.register(def) },
|
|
167
|
+
store: new ServerAgentStore(this.agentSink, this.agentKeyFor(record.id)),
|
|
168
|
+
toolPrefix: 'a2a',
|
|
169
|
+
defaultTimeoutMs: this.host.defaultTimeoutMs,
|
|
170
|
+
tokenOf: (env) => this.host.tokenOf(env),
|
|
171
|
+
onError: this.host.onError,
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** Record → registry spec for connecting one instance. */
|
|
176
|
+
private toSpec(record: OutboundServerRecord): { name: string; agentCardUrl: string; bearerTokenEnv?: string; enabled?: boolean; timeoutMs?: number } {
|
|
177
|
+
return {
|
|
178
|
+
name: record.name,
|
|
179
|
+
agentCardUrl: record.agentCardUrl,
|
|
180
|
+
...(record.bearerTokenEnv !== undefined ? { bearerTokenEnv: record.bearerTokenEnv } : {}),
|
|
181
|
+
enabled: record.enabled,
|
|
182
|
+
timeoutMs: record.timeoutMs ?? this.host.defaultTimeoutMs,
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** Boot every persisted enabled instance as a connected registry. */
|
|
187
|
+
boot(): void {
|
|
188
|
+
for (const record of this.records.list()) {
|
|
189
|
+
try {
|
|
190
|
+
const registry = this.makeRegistry(record)
|
|
191
|
+
this.registries.set(record.id, registry)
|
|
192
|
+
if (record.enabled) registry.loadAll()
|
|
193
|
+
} catch (err) {
|
|
194
|
+
this.host.onError(`[a2a:out:${record.id}] failed to boot: ${String((err as Error).message)}`)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** One view per live instance (enriched from its registry / record). */
|
|
200
|
+
list(): readonly OutboundServerView[] {
|
|
201
|
+
return [...this.registries.keys()].map((id) => this.viewFor(id)).filter((v): v is OutboundServerView => v !== undefined)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
get(id: string): OutboundServerRegistryHandle | undefined {
|
|
205
|
+
const registry = this.registries.get(id)
|
|
206
|
+
return registry === undefined ? undefined : { id, registry }
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
private viewFor(id: string): OutboundServerView | undefined {
|
|
210
|
+
const registry = this.registries.get(id)
|
|
211
|
+
const record = this.records.get(id)
|
|
212
|
+
if (registry === undefined || record === undefined) return undefined
|
|
213
|
+
const agent = registry.list()[0]
|
|
214
|
+
return {
|
|
215
|
+
id,
|
|
216
|
+
name: record.name,
|
|
217
|
+
agentCardUrl: record.agentCardUrl,
|
|
218
|
+
...(record.preset !== undefined ? { preset: record.preset } : {}),
|
|
219
|
+
enabled: agent?.enabled ?? record.enabled,
|
|
220
|
+
timeoutMs: record.timeoutMs,
|
|
221
|
+
state: agent?.state ?? 'disconnected',
|
|
222
|
+
skillCount: agent?.skillCount ?? 0,
|
|
223
|
+
toolCount: agent?.toolCount ?? 0,
|
|
224
|
+
...(agent?.lastError !== undefined ? { lastError: agent.lastError } : {}),
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/** Create, persist, and connect a new outbound instance. */
|
|
229
|
+
async add(input: OutboundCreateInput): Promise<OpResult & { readonly id?: string }> {
|
|
230
|
+
const record: OutboundServerRecord = {
|
|
231
|
+
id: input.id ?? this.newId(),
|
|
232
|
+
name: input.name,
|
|
233
|
+
agentCardUrl: input.agentCardUrl,
|
|
234
|
+
...(input.bearerTokenEnv !== undefined ? { bearerTokenEnv: input.bearerTokenEnv } : {}),
|
|
235
|
+
...(input.preset !== undefined ? { preset: input.preset } : {}),
|
|
236
|
+
enabled: input.enabled ?? true,
|
|
237
|
+
timeoutMs: input.timeoutMs ?? this.host.defaultTimeoutMs,
|
|
238
|
+
}
|
|
239
|
+
if (this.registries.has(record.id)) return { ok: false, message: `outbound server ${record.id} already exists` }
|
|
240
|
+
const registry = this.makeRegistry(record)
|
|
241
|
+
await this.records.save(record)
|
|
242
|
+
this.registries.set(record.id, registry)
|
|
243
|
+
if (record.enabled) {
|
|
244
|
+
const result = await registry.add(this.toSpec(record))
|
|
245
|
+
return result.ok ? { ...result, id: record.id } : result
|
|
246
|
+
}
|
|
247
|
+
return { ok: true, message: `outbound server "${record.name}" added (disabled)`, id: record.id }
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
async setEnabled(id: string, enabled: boolean): Promise<OpResult> {
|
|
251
|
+
const registry = this.registries.get(id)
|
|
252
|
+
if (registry === undefined) return { ok: false, message: `outbound server ${id} not found` }
|
|
253
|
+
const view = registry.list()[0]
|
|
254
|
+
const record = this.records.get(id)
|
|
255
|
+
if (record !== undefined) await this.records.save({ ...record, enabled })
|
|
256
|
+
if (view === undefined) return { ok: true, message: `outbound server ${id} marked ${enabled ? 'enabled' : 'disabled'}` }
|
|
257
|
+
return registry.setEnabled(view.id, enabled)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
async remove(id: string): Promise<OpResult> {
|
|
261
|
+
const registry = this.registries.get(id)
|
|
262
|
+
if (registry === undefined) return { ok: false, message: `outbound server ${id} not found` }
|
|
263
|
+
const view = registry.list()[0]
|
|
264
|
+
if (view !== undefined) await registry.remove(view.id)
|
|
265
|
+
await registry.disposeAll()
|
|
266
|
+
this.registries.delete(id)
|
|
267
|
+
await this.records.remove(id)
|
|
268
|
+
return { ok: true, message: `outbound server ${id} removed` }
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
async refresh(id: string): Promise<OpResult> {
|
|
272
|
+
const registry = this.registries.get(id)
|
|
273
|
+
if (registry === undefined) return { ok: false, message: `outbound server ${id} not found` }
|
|
274
|
+
const view = registry.list()[0]
|
|
275
|
+
if (view === undefined) return { ok: false, message: `outbound server ${id} has no connected agent` }
|
|
276
|
+
return registry.refresh(view.id)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
async disposeAll(): Promise<void> {
|
|
280
|
+
for (const registry of this.registries.values()) await registry.disposeAll()
|
|
281
|
+
this.registries.clear()
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/** Handle to one live outbound connection (registry + derived view). */
|
|
286
|
+
export interface OutboundServerRegistryHandle {
|
|
287
|
+
readonly id: string
|
|
288
|
+
readonly registry: OutboundAgentRegistry
|
|
289
|
+
}
|
package/src/service.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The `ctx.a2a` service facade: the thin read/control surface commands
|
|
3
|
-
* other plugins use. Registered as a Cordis Service so the key
|
|
4
|
-
* with the plugin fiber.
|
|
2
|
+
* The `ctx.a2a` service facade: the thin read/control surface commands, the
|
|
3
|
+
* GUI API, and other plugins use. Registered as a Cordis Service so the key
|
|
4
|
+
* disappears with the plugin fiber.
|
|
5
5
|
* @module dsh-a2a/service
|
|
6
6
|
*/
|
|
7
7
|
|
|
@@ -13,25 +13,98 @@ export interface OpResult {
|
|
|
13
13
|
readonly message: string
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
/** Agent-preset roster row shown in the instance pickers. */
|
|
17
|
+
export interface PresetView {
|
|
18
|
+
readonly id: string
|
|
19
|
+
readonly name?: string
|
|
20
|
+
readonly description?: string
|
|
21
|
+
/** Whether this preset is the deployment default when none is named. */
|
|
22
|
+
readonly isDefault?: boolean
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** A skill declaration as the GUI reads it. */
|
|
26
|
+
export interface SkillView {
|
|
27
|
+
readonly id: string
|
|
28
|
+
readonly name: string
|
|
29
|
+
readonly description?: string
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** One inbound server instance, as the GUI/facade reads it. */
|
|
33
|
+
export interface InboundServerView {
|
|
34
|
+
readonly id: string
|
|
35
|
+
readonly name: string
|
|
36
|
+
readonly description: string
|
|
37
|
+
readonly version: string
|
|
38
|
+
readonly endpointPath: string
|
|
39
|
+
readonly preset?: string
|
|
40
|
+
readonly authTokenEnv?: string
|
|
41
|
+
readonly cardPath: string
|
|
42
|
+
readonly cardUrl?: string
|
|
43
|
+
readonly enabled: boolean
|
|
44
|
+
readonly skills: readonly SkillView[]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** One outbound server instance, as the GUI/facade reads it. */
|
|
48
|
+
export interface OutboundServerView {
|
|
49
|
+
readonly id: string
|
|
50
|
+
readonly name: string
|
|
51
|
+
readonly agentCardUrl: string
|
|
52
|
+
readonly preset?: string
|
|
53
|
+
readonly enabled: boolean
|
|
54
|
+
readonly timeoutMs: number
|
|
55
|
+
readonly state: 'connected' | 'disconnected' | 'failed'
|
|
56
|
+
readonly skillCount: number
|
|
57
|
+
readonly toolCount: number
|
|
58
|
+
readonly lastError?: string
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Creator input for an inbound server instance. */
|
|
62
|
+
export interface InboundCreateInput {
|
|
63
|
+
readonly name: string
|
|
64
|
+
readonly description: string
|
|
65
|
+
readonly version: string
|
|
66
|
+
readonly endpointPath?: string
|
|
67
|
+
readonly preset?: string
|
|
68
|
+
readonly authTokenEnv?: string
|
|
69
|
+
readonly skills?: readonly SkillView[]
|
|
70
|
+
readonly enabled?: boolean
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Creator input for an outbound server instance. */
|
|
74
|
+
export interface OutboundCreateInput {
|
|
75
|
+
readonly id?: string
|
|
76
|
+
readonly name: string
|
|
77
|
+
readonly agentCardUrl: string
|
|
78
|
+
readonly bearerTokenEnv?: string
|
|
79
|
+
readonly preset?: string
|
|
80
|
+
readonly enabled?: boolean
|
|
81
|
+
readonly timeoutMs?: number
|
|
82
|
+
}
|
|
83
|
+
|
|
16
84
|
/** The implementation the facade delegates to (owned by the plugin assembly). */
|
|
17
85
|
export interface A2AServiceImpl {
|
|
18
86
|
status(): unknown
|
|
19
|
-
|
|
87
|
+
/** Agent-preset roster for the GUI pickers. */
|
|
88
|
+
presets(): Promise<PresetView[]>
|
|
89
|
+
// ── inbound server instances ────────────────────────────────────────
|
|
90
|
+
listInboundServers(): InboundServerView[]
|
|
91
|
+
createInboundServer(input: InboundCreateInput): Promise<OpResult>
|
|
92
|
+
removeInboundServer(id: string): Promise<OpResult>
|
|
93
|
+
setInboundServerEnabled(id: string, enabled: boolean): Promise<OpResult>
|
|
94
|
+
updateInboundServer(id: string, patch: { name?: string; description?: string; version?: string; endpointPath?: string; preset?: string; authTokenEnv?: string; skills?: readonly SkillView[] }): Promise<OpResult>
|
|
95
|
+
// ── outbound server instances ───────────────────────────────────────
|
|
96
|
+
listOutboundServers(): OutboundServerView[]
|
|
97
|
+
createOutboundServer(input: OutboundCreateInput): Promise<OpResult>
|
|
98
|
+
removeOutboundServer(id: string): Promise<OpResult>
|
|
99
|
+
setOutboundServerEnabled(id: string, enabled: boolean): Promise<OpResult>
|
|
100
|
+
refreshOutboundServer(id: string): Promise<OpResult>
|
|
101
|
+
// ── tasks ───────────────────────────────────────────────────────────
|
|
20
102
|
getTask(taskId: string): unknown
|
|
21
103
|
listTasks(): unknown
|
|
22
104
|
cancelTask(taskId: string): Promise<OpResult>
|
|
23
|
-
|
|
24
|
-
addAgent(spec: { readonly name: string; readonly agentCardUrl: string; readonly bearerTokenEnv?: string }): Promise<OpResult>
|
|
25
|
-
removeAgent(id: string): Promise<OpResult>
|
|
26
|
-
setAgentEnabled(id: string, enabled: boolean): Promise<OpResult>
|
|
27
|
-
refreshAgentCard(id: string): Promise<OpResult>
|
|
28
|
-
/** Current service identity (persisted override + composition defaults). */
|
|
29
|
-
identity(): unknown
|
|
30
|
-
/** Persist and apply a new service identity onto the live AgentCard. */
|
|
31
|
-
updateIdentity(patch: { readonly name?: string; readonly description?: string; readonly version?: string }): Promise<OpResult>
|
|
32
|
-
/** Cancel an inbound peer's active tasks and drop its record. */
|
|
33
|
-
closeInbound(peerId: string): Promise<OpResult>
|
|
105
|
+
// ── inbound peer monitoring (per instance) ──────────────────────────
|
|
34
106
|
inbounds(): unknown
|
|
107
|
+
closeInbound(peerId: string): Promise<OpResult>
|
|
35
108
|
}
|
|
36
109
|
|
|
37
110
|
/** The service other plugins read as `ctx.a2a`. */
|
|
@@ -47,55 +120,67 @@ export class A2AService extends Service {
|
|
|
47
120
|
return this.impl.status()
|
|
48
121
|
}
|
|
49
122
|
|
|
50
|
-
async
|
|
51
|
-
return this.impl.
|
|
123
|
+
async presets(): Promise<PresetView[]> {
|
|
124
|
+
return this.impl.presets()
|
|
52
125
|
}
|
|
53
126
|
|
|
54
|
-
|
|
55
|
-
return this.impl.
|
|
127
|
+
listInboundServers(): InboundServerView[] {
|
|
128
|
+
return this.impl.listInboundServers()
|
|
56
129
|
}
|
|
57
130
|
|
|
58
|
-
|
|
59
|
-
return this.impl.
|
|
131
|
+
async createInboundServer(input: InboundCreateInput): Promise<OpResult> {
|
|
132
|
+
return this.impl.createInboundServer(input)
|
|
60
133
|
}
|
|
61
134
|
|
|
62
|
-
async
|
|
63
|
-
return this.impl.
|
|
135
|
+
async removeInboundServer(id: string): Promise<OpResult> {
|
|
136
|
+
return this.impl.removeInboundServer(id)
|
|
64
137
|
}
|
|
65
138
|
|
|
66
|
-
|
|
67
|
-
return this.impl.
|
|
139
|
+
async setInboundServerEnabled(id: string, enabled: boolean): Promise<OpResult> {
|
|
140
|
+
return this.impl.setInboundServerEnabled(id, enabled)
|
|
68
141
|
}
|
|
69
142
|
|
|
70
|
-
async
|
|
71
|
-
return this.impl.
|
|
143
|
+
async updateInboundServer(id: string, patch: { name?: string; description?: string; version?: string; endpointPath?: string; preset?: string; authTokenEnv?: string; skills?: readonly SkillView[] }): Promise<OpResult> {
|
|
144
|
+
return this.impl.updateInboundServer(id, patch)
|
|
72
145
|
}
|
|
73
146
|
|
|
74
|
-
|
|
75
|
-
return this.impl.
|
|
147
|
+
listOutboundServers(): OutboundServerView[] {
|
|
148
|
+
return this.impl.listOutboundServers()
|
|
76
149
|
}
|
|
77
150
|
|
|
78
|
-
async
|
|
79
|
-
return this.impl.
|
|
151
|
+
async createOutboundServer(input: OutboundCreateInput): Promise<OpResult> {
|
|
152
|
+
return this.impl.createOutboundServer(input)
|
|
80
153
|
}
|
|
81
154
|
|
|
82
|
-
async
|
|
83
|
-
return this.impl.
|
|
155
|
+
async removeOutboundServer(id: string): Promise<OpResult> {
|
|
156
|
+
return this.impl.removeOutboundServer(id)
|
|
84
157
|
}
|
|
85
158
|
|
|
86
|
-
|
|
87
|
-
return this.impl.
|
|
159
|
+
async setOutboundServerEnabled(id: string, enabled: boolean): Promise<OpResult> {
|
|
160
|
+
return this.impl.setOutboundServerEnabled(id, enabled)
|
|
88
161
|
}
|
|
89
162
|
|
|
90
|
-
async
|
|
91
|
-
return this.impl.
|
|
163
|
+
async refreshOutboundServer(id: string): Promise<OpResult> {
|
|
164
|
+
return this.impl.refreshOutboundServer(id)
|
|
92
165
|
}
|
|
93
166
|
|
|
94
|
-
|
|
95
|
-
return this.impl.
|
|
167
|
+
getTask(taskId: string): unknown {
|
|
168
|
+
return this.impl.getTask(taskId)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
listTasks(): unknown {
|
|
172
|
+
return this.impl.listTasks()
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async cancelTask(taskId: string): Promise<OpResult> {
|
|
176
|
+
return this.impl.cancelTask(taskId)
|
|
96
177
|
}
|
|
97
178
|
|
|
98
179
|
inbounds(): unknown {
|
|
99
180
|
return this.impl.inbounds()
|
|
100
181
|
}
|
|
101
|
-
|
|
182
|
+
|
|
183
|
+
async closeInbound(peerId: string): Promise<OpResult> {
|
|
184
|
+
return this.impl.closeInbound(peerId)
|
|
185
|
+
}
|
|
186
|
+
}
|