dsh-a2a-server 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/LICENSE +21 -0
- package/README.md +335 -0
- package/README.zh-CN.md +316 -0
- package/cordis.patch.yml +30 -0
- package/lib/config.d.ts +116 -0
- package/lib/config.d.ts.map +1 -0
- package/lib/config.js +110 -0
- package/lib/config.js.map +1 -0
- package/lib/contexts.d.ts +84 -0
- package/lib/contexts.d.ts.map +1 -0
- package/lib/contexts.js +103 -0
- package/lib/contexts.js.map +1 -0
- package/lib/index.d.ts +33 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +505 -0
- package/lib/index.js.map +1 -0
- package/lib/projection.d.ts +131 -0
- package/lib/projection.d.ts.map +1 -0
- package/lib/projection.js +98 -0
- package/lib/projection.js.map +1 -0
- package/lib/protocol/brand.d.ts +32 -0
- package/lib/protocol/brand.d.ts.map +1 -0
- package/lib/protocol/brand.js +25 -0
- package/lib/protocol/brand.js.map +1 -0
- package/lib/protocol/card.d.ts +43 -0
- package/lib/protocol/card.d.ts.map +1 -0
- package/lib/protocol/card.js +58 -0
- package/lib/protocol/card.js.map +1 -0
- package/lib/protocol/index.d.ts +23 -0
- package/lib/protocol/index.d.ts.map +1 -0
- package/lib/protocol/index.js +20 -0
- package/lib/protocol/index.js.map +1 -0
- package/lib/protocol/jsonrpc.d.ts +93 -0
- package/lib/protocol/jsonrpc.d.ts.map +1 -0
- package/lib/protocol/jsonrpc.js +81 -0
- package/lib/protocol/jsonrpc.js.map +1 -0
- package/lib/protocol/normalize.d.ts +72 -0
- package/lib/protocol/normalize.d.ts.map +1 -0
- package/lib/protocol/normalize.js +278 -0
- package/lib/protocol/normalize.js.map +1 -0
- package/lib/protocol/sse.d.ts +20 -0
- package/lib/protocol/sse.d.ts.map +1 -0
- package/lib/protocol/sse.js +23 -0
- package/lib/protocol/sse.js.map +1 -0
- package/lib/protocol/wire.d.ts +164 -0
- package/lib/protocol/wire.d.ts.map +1 -0
- package/lib/protocol/wire.js +26 -0
- package/lib/protocol/wire.js.map +1 -0
- package/lib/router.d.ts +56 -0
- package/lib/router.d.ts.map +1 -0
- package/lib/router.js +432 -0
- package/lib/router.js.map +1 -0
- package/lib/security.d.ts +89 -0
- package/lib/security.d.ts.map +1 -0
- package/lib/security.js +171 -0
- package/lib/security.js.map +1 -0
- package/lib/tasks.d.ts +75 -0
- package/lib/tasks.d.ts.map +1 -0
- package/lib/tasks.js +84 -0
- package/lib/tasks.js.map +1 -0
- package/lib/types.d.ts +71 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +17 -0
- package/lib/types.js.map +1 -0
- package/package.json +94 -0
package/lib/index.js
ADDED
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inbound A2A protocol server for DeepSeek Harness.
|
|
3
|
+
*
|
|
4
|
+
* Publishes an Agent Card at a well-known URI and serves the A2A v0.3.0
|
|
5
|
+
* JSON-RPC binding, so any compliant peer that knows this deployment's URL can
|
|
6
|
+
* discover it and submit tasks to a harness agent. There is no outbound client:
|
|
7
|
+
* this plugin never connects to another agent.
|
|
8
|
+
*
|
|
9
|
+
* It is a TRANSPORT ADAPTER, not a capability seam — the same self-limitation
|
|
10
|
+
* `dsh-acp` states. It exposes no editor navigation, transcript replay,
|
|
11
|
+
* commands, modes, or tool presentation.
|
|
12
|
+
*
|
|
13
|
+
* @module dsh-a2a-server
|
|
14
|
+
*/
|
|
15
|
+
import { randomUUID } from 'node:crypto';
|
|
16
|
+
import { mkdir, access } from 'node:fs/promises';
|
|
17
|
+
import { constants } from 'node:fs';
|
|
18
|
+
import { isAbsolute, join } from 'node:path';
|
|
19
|
+
import { SessionId } from '@deepseek-ai/dsh-session';
|
|
20
|
+
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
21
|
+
import { A2AContextId, A2ATaskId, buildAgentCard, nowIso, } from "./protocol/index.js";
|
|
22
|
+
import { assertConfigCoherent, Config } from "./config.js";
|
|
23
|
+
import { ContextRegistry } from "./contexts.js";
|
|
24
|
+
import { identifyPeer, RateLimiter, TurnTracker } from "./security.js";
|
|
25
|
+
import { artifactsFromTexts, createSlot, stateFromEnding } from "./tasks.js";
|
|
26
|
+
import { createRouter } from "./router.js";
|
|
27
|
+
import { a2aTaskProjection } from "./projection.js";
|
|
28
|
+
export { Config };
|
|
29
|
+
export const name = 'a2a-server';
|
|
30
|
+
/**
|
|
31
|
+
* The server creates and owns agents, needs an HTTP carrier for its routes, and
|
|
32
|
+
* cannot authenticate a single request without the credential seam. Everything
|
|
33
|
+
* else it uses is probed with `ctx.get()` so a composition missing an optional
|
|
34
|
+
* capability still boots with A2A serving.
|
|
35
|
+
*/
|
|
36
|
+
export const inject = ['agents', 'webServer', 'credentials'];
|
|
37
|
+
/**
|
|
38
|
+
* Mount the inbound A2A server.
|
|
39
|
+
* @param ctx - the Cordis context carrying the agent factory, HTTP carrier, and credentials.
|
|
40
|
+
* @param config - the validated plugin configuration.
|
|
41
|
+
*/
|
|
42
|
+
export function apply(ctx, config) {
|
|
43
|
+
assertConfigCoherent(config);
|
|
44
|
+
// Handlers run on node's IO callbacks, outside this fiber's injection scope.
|
|
45
|
+
// Snapshot the injected services here; validate individual object liveness
|
|
46
|
+
// lazily at each use, because an agent-loop-only reload disposes agents while
|
|
47
|
+
// our records survive.
|
|
48
|
+
const agents = ctx.agents;
|
|
49
|
+
const webServer = ctx.webServer;
|
|
50
|
+
const credentials = ctx.credentials;
|
|
51
|
+
const logger = ctx.logger;
|
|
52
|
+
const contexts = new ContextRegistry(config.maxResidentContexts, config.contextIdleTtlMs);
|
|
53
|
+
const rateLimiter = new RateLimiter(config.rateLimitPerMinute);
|
|
54
|
+
const turns = new TurnTracker();
|
|
55
|
+
let closed = false;
|
|
56
|
+
/** Reject a request that arrives while teardown is in progress. */
|
|
57
|
+
const assertOpen = () => {
|
|
58
|
+
if (closed)
|
|
59
|
+
throw new Error('the A2A server has been disposed');
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* Return the Activation owning this agent, rejecting same-id impostors.
|
|
63
|
+
*
|
|
64
|
+
* Identity is compared by object reference, not session id: a reload can
|
|
65
|
+
* rebuild an agent under the same id, and routing events to the replacement
|
|
66
|
+
* would silently cross wires.
|
|
67
|
+
*/
|
|
68
|
+
const ownedActivation = (agent) => {
|
|
69
|
+
const activation = contexts.lookup(A2AContextId(agent.session.id), '');
|
|
70
|
+
if (typeof activation === 'string') {
|
|
71
|
+
// Ownership check is peer-scoped; for event routing we only need identity.
|
|
72
|
+
const direct = contexts.values().find(a => a.agent === agent);
|
|
73
|
+
return direct;
|
|
74
|
+
}
|
|
75
|
+
return activation.agent === agent ? activation : undefined;
|
|
76
|
+
};
|
|
77
|
+
// ── Resolve declared peer credentials ──────────────────────────────────
|
|
78
|
+
/**
|
|
79
|
+
* Resolve every declared peer's secret.
|
|
80
|
+
*
|
|
81
|
+
* The seam's rule is to resolve per operation and never cache across them —
|
|
82
|
+
* that read is what makes a rotated credential reach the very next request.
|
|
83
|
+
*/
|
|
84
|
+
const resolvePeerSecrets = async () => {
|
|
85
|
+
const resolved = new Map();
|
|
86
|
+
for (const [peer, entry] of Object.entries(config.peers)) {
|
|
87
|
+
const hit = await credentials.resolve(entry.tokenEnv);
|
|
88
|
+
if (hit !== undefined && hit.value.length > 0)
|
|
89
|
+
resolved.set(peer, hit.value);
|
|
90
|
+
}
|
|
91
|
+
return resolved;
|
|
92
|
+
};
|
|
93
|
+
// Activation-time completeness check. `describe()` never holds a value; it
|
|
94
|
+
// only answers whether a reference is configured. A peer declared here but
|
|
95
|
+
// unconfigured would otherwise receive 401 forever with no diagnostic.
|
|
96
|
+
ctx.effect(() => {
|
|
97
|
+
void (async () => {
|
|
98
|
+
const missing = [];
|
|
99
|
+
for (const [peer, entry] of Object.entries(config.peers)) {
|
|
100
|
+
try {
|
|
101
|
+
const info = await credentials.describe(entry.tokenEnv);
|
|
102
|
+
if (info === undefined || !info.configured)
|
|
103
|
+
missing.push(`${peer} (${entry.tokenEnv})`);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
missing.push(`${peer} (${entry.tokenEnv})`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (missing.length > 0) {
|
|
110
|
+
logger.error(`a2a: declared peers have no configured credential and can never authenticate: ${missing.join(', ')}`);
|
|
111
|
+
}
|
|
112
|
+
if (Object.keys(config.peers).length === 0) {
|
|
113
|
+
logger.warn('a2a: no peers declared; every request will be rejected as unauthorized');
|
|
114
|
+
}
|
|
115
|
+
})();
|
|
116
|
+
return () => { };
|
|
117
|
+
}, 'a2a.credentialCheck');
|
|
118
|
+
// ── Workspace resolution ───────────────────────────────────────────────
|
|
119
|
+
const workspaceFor = (peer) => {
|
|
120
|
+
const override = config.isolation.peerWorkspaces[peer];
|
|
121
|
+
if (override !== undefined)
|
|
122
|
+
return override;
|
|
123
|
+
return config.isolation.workspaceMode === 'shared'
|
|
124
|
+
? config.isolation.workspaceRoot
|
|
125
|
+
: join(config.isolation.workspaceRoot, peer);
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* Create the workspace directory and prove it is enterable.
|
|
129
|
+
*
|
|
130
|
+
* A failure here refuses the request rather than falling back to a shared
|
|
131
|
+
* directory: silently downgrading isolation is the one outcome worse than an
|
|
132
|
+
* error, since nothing downstream would ever report it.
|
|
133
|
+
*/
|
|
134
|
+
const ensureWorkspace = async (cwd) => {
|
|
135
|
+
if (!isAbsolute(cwd))
|
|
136
|
+
throw new Error(`workspace must be an absolute path: ${cwd}`);
|
|
137
|
+
await mkdir(cwd, { recursive: true });
|
|
138
|
+
await access(cwd, constants.X_OK);
|
|
139
|
+
};
|
|
140
|
+
// ── Public URL ─────────────────────────────────────────────────────────
|
|
141
|
+
/**
|
|
142
|
+
* The URL peers should post to.
|
|
143
|
+
*
|
|
144
|
+
* Never the webserver's bind address: that is typically 127.0.0.1, and
|
|
145
|
+
* publishing it on a card served through a reverse proxy is always wrong.
|
|
146
|
+
*/
|
|
147
|
+
const publicUrl = (hostHeader) => {
|
|
148
|
+
if (config.publicUrl !== undefined)
|
|
149
|
+
return config.publicUrl;
|
|
150
|
+
const host = hostHeader ?? `127.0.0.1:${webServer.port}`;
|
|
151
|
+
return `http://${host}${config.basePath}`;
|
|
152
|
+
};
|
|
153
|
+
const cardFor = (hostHeader) => buildAgentCard({
|
|
154
|
+
name: config.card.name,
|
|
155
|
+
description: config.card.description,
|
|
156
|
+
version: '0.1.0',
|
|
157
|
+
url: publicUrl(hostHeader),
|
|
158
|
+
protocolVersion: config.protocolVersion,
|
|
159
|
+
skills: config.card.skills,
|
|
160
|
+
streaming: true,
|
|
161
|
+
pushNotifications: config.push.enabled,
|
|
162
|
+
authRequired: true,
|
|
163
|
+
// An organization-less provider block is the schema's shape for "omitted",
|
|
164
|
+
// and A2A readers expect the member to be absent rather than blank.
|
|
165
|
+
...config.card.provider === undefined || config.card.provider.organization.length === 0
|
|
166
|
+
? {}
|
|
167
|
+
: { provider: config.card.provider },
|
|
168
|
+
});
|
|
169
|
+
// ── Durable task edges ─────────────────────────────────────────────────
|
|
170
|
+
/**
|
|
171
|
+
* Append one `a2a/task` lifecycle edge to the context's own session log.
|
|
172
|
+
*
|
|
173
|
+
* This is what makes `tasks/get` answerable after a restart: the state lives
|
|
174
|
+
* in the append-only log, not in this process's memory.
|
|
175
|
+
*/
|
|
176
|
+
const appendTaskEdge = (activation, taskId, state, extra = {}) => {
|
|
177
|
+
try {
|
|
178
|
+
activation.agent.session.append('a2a/task', {
|
|
179
|
+
taskId,
|
|
180
|
+
peer: activation.peer,
|
|
181
|
+
state,
|
|
182
|
+
...extra.turn === undefined ? {} : { turn: extra.turn },
|
|
183
|
+
...extra.stopReason === undefined ? {} : { stopReason: extra.stopReason },
|
|
184
|
+
...extra.output === undefined ? {} : { output: extra.output },
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
// A log append failure must not take down the request: the peer still
|
|
189
|
+
// gets a correct answer for THIS exchange; only durability is lost.
|
|
190
|
+
logger.warn(`a2a: could not append a2a/task edge: ${String(error)}`);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
// ── Event wiring: the three-stage correlation ──────────────────────────
|
|
194
|
+
ctx.on('agent/inbox/claimed', ({ agent, message, turn }) => {
|
|
195
|
+
const activation = ownedActivation(agent);
|
|
196
|
+
if (activation === undefined)
|
|
197
|
+
return;
|
|
198
|
+
for (const slot of activation.slots.values()) {
|
|
199
|
+
if (slot.messageId === message.id && slot.turn === undefined) {
|
|
200
|
+
slot.turn = turn;
|
|
201
|
+
appendTaskEdge(activation, slot.taskId, 'working', { turn });
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
ctx.on('session/event', (session, event) => {
|
|
207
|
+
const activation = contexts.values().find(a => a.agent.session === session);
|
|
208
|
+
if (activation === undefined)
|
|
209
|
+
return;
|
|
210
|
+
if (event.type === 'assistant/message') {
|
|
211
|
+
// Committed messages only. Raw chunks and retry attempts are presentation
|
|
212
|
+
// and trace data; letting them onto the wire would leak text the agent
|
|
213
|
+
// later discarded.
|
|
214
|
+
for (const block of event.data.message.content) {
|
|
215
|
+
if (block.type === 'text' && block.text.length > 0) {
|
|
216
|
+
for (const slot of activation.slots.values())
|
|
217
|
+
slot.texts.push(block.text);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (event.type === 'turn/end') {
|
|
223
|
+
const reason = String(event.data.reason.kind ?? 'unknown');
|
|
224
|
+
for (const slot of activation.slots.values()) {
|
|
225
|
+
if (slot.turn !== event.data.turn)
|
|
226
|
+
continue;
|
|
227
|
+
if (reason === 'error') {
|
|
228
|
+
// A model error on the correlated turn fails the task immediately
|
|
229
|
+
// rather than waiting out whole-agent quiescence.
|
|
230
|
+
settleSlot(activation, slot, 'failed', reason);
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
slot.endReason = reason;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
ctx.on('agent/error', ({ agent, turn }) => {
|
|
239
|
+
const activation = ownedActivation(agent);
|
|
240
|
+
if (activation === undefined)
|
|
241
|
+
return;
|
|
242
|
+
for (const slot of activation.slots.values()) {
|
|
243
|
+
if (slot.turn === turn)
|
|
244
|
+
settleSlot(activation, slot, 'failed', 'error');
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
/**
|
|
248
|
+
* Settle one task slot and record the terminal edge.
|
|
249
|
+
* @param activation - the owning context.
|
|
250
|
+
* @param slot - the slot to settle.
|
|
251
|
+
* @param state - the terminal state.
|
|
252
|
+
* @param stopReason - the harness turn ending, for `Task.metadata`.
|
|
253
|
+
*/
|
|
254
|
+
function settleSlot(activation, slot, state, stopReason) {
|
|
255
|
+
if (slot.done)
|
|
256
|
+
return;
|
|
257
|
+
activation.slots.delete(slot.taskId);
|
|
258
|
+
const artifacts = artifactsFromTexts(slot.taskId, slot.texts);
|
|
259
|
+
// The terminal edge carries the output, so the projection can serve the
|
|
260
|
+
// ANSWER to a polling peer and not merely the fact that work finished.
|
|
261
|
+
const output = slot.texts.filter(text => text.length > 0).join('\n');
|
|
262
|
+
appendTaskEdge(activation, slot.taskId, state, {
|
|
263
|
+
...stopReason === undefined ? {} : { stopReason },
|
|
264
|
+
...output.length === 0 ? {} : { output },
|
|
265
|
+
});
|
|
266
|
+
slot.settle({
|
|
267
|
+
state,
|
|
268
|
+
artifacts,
|
|
269
|
+
...stopReason === undefined ? {} : { stopReason },
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
// ── Context materialization ────────────────────────────────────────────
|
|
273
|
+
/**
|
|
274
|
+
* Create a fresh context and its owning agent.
|
|
275
|
+
*
|
|
276
|
+
* The policy events written onto the child's own log are what make an
|
|
277
|
+
* A2A-driven agent safe to run unattended: approvals are deterministically
|
|
278
|
+
* rejected rather than waiting on a prompt nobody is watching, and the policy
|
|
279
|
+
* stays reconstructable from that log alone.
|
|
280
|
+
*/
|
|
281
|
+
const createActivation = async (peer) => {
|
|
282
|
+
const cwd = workspaceFor(peer);
|
|
283
|
+
await ensureWorkspace(cwd);
|
|
284
|
+
const sessionId = SessionId(randomUUID());
|
|
285
|
+
const handle = await agents.create({
|
|
286
|
+
sessionId,
|
|
287
|
+
meta: { cwd },
|
|
288
|
+
agentOptions: {
|
|
289
|
+
...config.provider === undefined ? {} : { provider: config.provider },
|
|
290
|
+
...config.model === undefined ? {} : { model: config.model },
|
|
291
|
+
},
|
|
292
|
+
});
|
|
293
|
+
if (closed) {
|
|
294
|
+
// Teardown can begin while create() is awaited. Such an agent is not in
|
|
295
|
+
// the registry and quiesce() would never release it — the classic orphan.
|
|
296
|
+
await handle.dispose();
|
|
297
|
+
throw new Error('server closed during context creation');
|
|
298
|
+
}
|
|
299
|
+
const activation = {
|
|
300
|
+
contextId: A2AContextId(sessionId),
|
|
301
|
+
agent: handle.agent,
|
|
302
|
+
handle,
|
|
303
|
+
peer,
|
|
304
|
+
cwd,
|
|
305
|
+
slots: new Map(),
|
|
306
|
+
lastTouchedAt: Date.now(),
|
|
307
|
+
};
|
|
308
|
+
// Pin the approval policy on the agent's OWN log so its effective policy
|
|
309
|
+
// stays reconstructable from that log alone — the same discipline
|
|
310
|
+
// `captureDelegatedPolicyOverrides` applies to a delegated child. Nobody
|
|
311
|
+
// watches an A2A-driven agent, so an ask must be deterministically rejected
|
|
312
|
+
// rather than waiting out a prompt no human will ever answer.
|
|
313
|
+
//
|
|
314
|
+
// The event key is written through an untyped view because the approval
|
|
315
|
+
// vocabulary belongs to a package a composition may not mount at all; when
|
|
316
|
+
// it is absent this append is simply a log row nothing folds.
|
|
317
|
+
try {
|
|
318
|
+
const session = handle.agent.session;
|
|
319
|
+
session.append('approval/policy', { policy: 'never', source: 'a2a' });
|
|
320
|
+
}
|
|
321
|
+
catch (error) {
|
|
322
|
+
logger.warn(`a2a: could not pin approval policy: ${String(error)}`);
|
|
323
|
+
}
|
|
324
|
+
contexts.add(activation);
|
|
325
|
+
return activation;
|
|
326
|
+
};
|
|
327
|
+
// ── Durable task read model ────────────────────────────────────────────
|
|
328
|
+
// Optional capability: a composition without the registry keeps working, it
|
|
329
|
+
// just cannot answer for a task after that task settles.
|
|
330
|
+
const projections = ctx.get('sessionProjections');
|
|
331
|
+
if (projections !== undefined) {
|
|
332
|
+
ctx.effect(() => projections.register(a2aTaskProjection), 'a2a.projection');
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
logger.warn('a2a: no sessionProjections registry composed; tasks/get cannot answer '
|
|
336
|
+
+ 'once a task settles, so a polling peer will never learn its result');
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Read a settled task back from the projection.
|
|
340
|
+
*
|
|
341
|
+
* The fold is authoritative for anything not in the live slot table, so this
|
|
342
|
+
* is what makes the polling path work at all.
|
|
343
|
+
*/
|
|
344
|
+
const readProjectedTask = (activation, taskId) => {
|
|
345
|
+
if (projections === undefined)
|
|
346
|
+
return undefined;
|
|
347
|
+
const snapshot = projections.snapshot(activation.agent.session);
|
|
348
|
+
const view = snapshot.values.a2aTask?.tasks[taskId];
|
|
349
|
+
// Ownership is re-checked against the RECORDED peer rather than the
|
|
350
|
+
// activation's, so a context that somehow served two identities could not
|
|
351
|
+
// leak one's task to the other.
|
|
352
|
+
if (view === undefined || view.peer !== activation.peer)
|
|
353
|
+
return undefined;
|
|
354
|
+
return {
|
|
355
|
+
kind: 'task',
|
|
356
|
+
id: taskId,
|
|
357
|
+
contextId: activation.contextId,
|
|
358
|
+
status: { state: view.state, timestamp: view.updatedAt },
|
|
359
|
+
artifacts: view.output === undefined || view.output.length === 0
|
|
360
|
+
? []
|
|
361
|
+
: [{
|
|
362
|
+
artifactId: `${taskId}-result`,
|
|
363
|
+
name: 'result',
|
|
364
|
+
parts: [{ kind: 'text', text: view.output }],
|
|
365
|
+
}],
|
|
366
|
+
...view.stopReason === undefined ? {} : { metadata: { dsh: { stopReason: view.stopReason } } },
|
|
367
|
+
};
|
|
368
|
+
};
|
|
369
|
+
// ── Router ─────────────────────────────────────────────────────────────
|
|
370
|
+
const deps = {
|
|
371
|
+
readProjectedTask,
|
|
372
|
+
config,
|
|
373
|
+
contexts,
|
|
374
|
+
turns,
|
|
375
|
+
rateLimiter,
|
|
376
|
+
logger,
|
|
377
|
+
assertOpen,
|
|
378
|
+
resolvePeerSecrets,
|
|
379
|
+
identify: identifyPeer,
|
|
380
|
+
cardFor,
|
|
381
|
+
createActivation,
|
|
382
|
+
submit: async (activation, text, peer) => {
|
|
383
|
+
const liveAgent = ctx.agents.get(activation.agent.id);
|
|
384
|
+
if (liveAgent !== activation.agent) {
|
|
385
|
+
throw new Error('the agent was disposed outside the A2A server');
|
|
386
|
+
}
|
|
387
|
+
const taskId = A2ATaskId(randomUUID());
|
|
388
|
+
const message = createUserMessage({
|
|
389
|
+
content: [{ type: 'text', text }],
|
|
390
|
+
source: { kind: 'a2a-peer', peer, taskId, form: 'relay' },
|
|
391
|
+
});
|
|
392
|
+
const slot = createSlot(taskId, message.id);
|
|
393
|
+
// Arm the slot before followup(): a listener-driven synchronous turn would
|
|
394
|
+
// otherwise slip past correlation and leave the task turnless forever.
|
|
395
|
+
activation.slots.set(taskId, slot);
|
|
396
|
+
appendTaskEdge(activation, taskId, 'submitted');
|
|
397
|
+
try {
|
|
398
|
+
activation.agent.followup(message);
|
|
399
|
+
}
|
|
400
|
+
catch (error) {
|
|
401
|
+
activation.slots.delete(taskId);
|
|
402
|
+
throw error;
|
|
403
|
+
}
|
|
404
|
+
void activation.agent.whenIdle().then(() => {
|
|
405
|
+
if (activation.slots.get(taskId) !== slot)
|
|
406
|
+
return;
|
|
407
|
+
settleSlot(activation, slot, stateFromEnding(slot.endReason), slot.endReason);
|
|
408
|
+
});
|
|
409
|
+
return slot;
|
|
410
|
+
},
|
|
411
|
+
cancel: (activation, slot) => {
|
|
412
|
+
activation.agent.cancel({ kind: 'user' }, { keepInbox: true });
|
|
413
|
+
settleSlot(activation, slot, 'canceled', 'cancelled');
|
|
414
|
+
turns.reset(activation.contextId);
|
|
415
|
+
},
|
|
416
|
+
taskSnapshot: (activation, slot, state, artifacts, stopReason) => ({
|
|
417
|
+
kind: 'task',
|
|
418
|
+
id: slot.taskId,
|
|
419
|
+
contextId: activation.contextId,
|
|
420
|
+
status: { state, timestamp: nowIso() },
|
|
421
|
+
artifacts,
|
|
422
|
+
...stopReason === undefined ? {} : { metadata: { dsh: { stopReason } } },
|
|
423
|
+
}),
|
|
424
|
+
};
|
|
425
|
+
const router = createRouter(deps);
|
|
426
|
+
// ── HTTP routes ────────────────────────────────────────────────────────
|
|
427
|
+
ctx.effect(function* () {
|
|
428
|
+
yield webServer.register({
|
|
429
|
+
kind: 'exact',
|
|
430
|
+
path: '/.well-known/agent-card.json',
|
|
431
|
+
handler: (req, res) => { router.serveCard(req, res); },
|
|
432
|
+
});
|
|
433
|
+
yield webServer.register({
|
|
434
|
+
kind: 'exact',
|
|
435
|
+
path: '/.well-known/agent.json',
|
|
436
|
+
handler: (req, res) => { router.serveCard(req, res); },
|
|
437
|
+
});
|
|
438
|
+
yield webServer.register({
|
|
439
|
+
kind: 'exact',
|
|
440
|
+
path: config.basePath,
|
|
441
|
+
handler: (req, res) => { void router.serveRpc(req, res); },
|
|
442
|
+
});
|
|
443
|
+
}, 'a2a.routes');
|
|
444
|
+
// ── Idle eviction ──────────────────────────────────────────────────────
|
|
445
|
+
ctx.effect(() => {
|
|
446
|
+
const timer = setInterval(() => {
|
|
447
|
+
for (const activation of contexts.evictable()) {
|
|
448
|
+
contexts.remove(activation.contextId);
|
|
449
|
+
void activation.handle.dispose().catch((error) => {
|
|
450
|
+
logger.warn(`a2a: evicting ${activation.contextId} failed: ${String(error)}`);
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
}, Math.max(1000, Math.floor(config.contextIdleTtlMs / 4)));
|
|
454
|
+
timer.unref?.();
|
|
455
|
+
return () => { clearInterval(timer); };
|
|
456
|
+
}, 'a2a.reaper');
|
|
457
|
+
// ── Teardown ───────────────────────────────────────────────────────────
|
|
458
|
+
let quiescing;
|
|
459
|
+
const quiesce = () => {
|
|
460
|
+
if (quiescing !== undefined)
|
|
461
|
+
return quiescing;
|
|
462
|
+
closed = true;
|
|
463
|
+
const activations = contexts.drain();
|
|
464
|
+
// Send every stream its terminal frame BEFORE the carrier destroys sockets:
|
|
465
|
+
// a raw socket destroy is indistinguishable from a network fault, and the
|
|
466
|
+
// peer would retry a task that no longer exists.
|
|
467
|
+
router.closeStreams();
|
|
468
|
+
// Stop this server's own work before any await. A descendant drain can block
|
|
469
|
+
// on persistence, and top-level agents must not keep running model and tool
|
|
470
|
+
// calls for its whole duration.
|
|
471
|
+
for (const activation of activations) {
|
|
472
|
+
activation.agent.cancel({ kind: 'user' });
|
|
473
|
+
for (const slot of [...activation.slots.values()]) {
|
|
474
|
+
settleSlot(activation, slot, 'canceled', 'cancelled');
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
rateLimiter.clear();
|
|
478
|
+
turns.clear();
|
|
479
|
+
quiescing = (async () => {
|
|
480
|
+
// Continuable subagents outlive the turn that started them. Drain only the
|
|
481
|
+
// forests below OUR agents, child-first, before releasing them — another
|
|
482
|
+
// frontend sharing this Context keeps its own forest and admission.
|
|
483
|
+
const subagents = ctx.get('subagents');
|
|
484
|
+
if (subagents !== undefined) {
|
|
485
|
+
try {
|
|
486
|
+
await subagents.drainContinuableDescendants(activations.map(a => a.agent));
|
|
487
|
+
}
|
|
488
|
+
catch (error) {
|
|
489
|
+
logger.warn(`a2a: continuable subagent teardown failed: ${String(error)}`);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
const results = await Promise.allSettled(activations.map(a => a.handle.dispose()));
|
|
493
|
+
const failures = results.flatMap(r => r.status === 'rejected' ? [r.reason] : []);
|
|
494
|
+
if (failures.length > 0) {
|
|
495
|
+
// The production consumer logs this through String(), which renders only
|
|
496
|
+
// the message — so every per-context diagnostic must live in it.
|
|
497
|
+
throw new AggregateError(failures, `A2A agent teardown failed for ${failures.length} context(s): ` +
|
|
498
|
+
failures.map(f => f instanceof Error ? f.message : String(f)).join('; '));
|
|
499
|
+
}
|
|
500
|
+
})();
|
|
501
|
+
return quiescing;
|
|
502
|
+
};
|
|
503
|
+
ctx.effect(() => quiesce, 'a2a.server');
|
|
504
|
+
}
|
|
505
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `a2aTask` projection unit: task state read back from the session log.
|
|
3
|
+
*
|
|
4
|
+
* Without this, task state lives only in the process-local slot table, and
|
|
5
|
+
* `settleSlot` removes a slot the moment it settles — so a peer that polls
|
|
6
|
+
* `tasks/get` is told the task never existed, moments after it completed. That
|
|
7
|
+
* breaks the polling path A2A treats as the baseline update mechanism
|
|
8
|
+
* (`message/stream` and push notifications are both optional capabilities;
|
|
9
|
+
* `tasks/get` is not).
|
|
10
|
+
*
|
|
11
|
+
* The unit is a pure left fold over the `a2a/task` edges the server already
|
|
12
|
+
* appends. It holds no subscriptions: the registry drives every committed event
|
|
13
|
+
* through `apply` once, and the persisted projection cache turns a cold read
|
|
14
|
+
* into a cache row plus a tail replay rather than a full log load.
|
|
15
|
+
*
|
|
16
|
+
* @module dsh-a2a/projection
|
|
17
|
+
*/
|
|
18
|
+
import { z } from 'zod';
|
|
19
|
+
import type { SessionEvent } from '@deepseek-ai/dsh-session';
|
|
20
|
+
import type { A2ATaskState } from './protocol/index.ts';
|
|
21
|
+
/** One task's durable read model. */
|
|
22
|
+
export interface A2ATaskView {
|
|
23
|
+
taskId: string;
|
|
24
|
+
/** The authenticated peer that submitted it. Ownership is checked against this. */
|
|
25
|
+
peer: string;
|
|
26
|
+
state: A2ATaskState;
|
|
27
|
+
/**
|
|
28
|
+
* The committed assistant text, when the terminal edge recorded any.
|
|
29
|
+
*
|
|
30
|
+
* This is what lets a polling peer receive the ANSWER rather than only the
|
|
31
|
+
* fact that the task finished — an empty artifact list on a `completed` task
|
|
32
|
+
* reads as "it worked and produced nothing".
|
|
33
|
+
*/
|
|
34
|
+
output?: string | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* The harness turn ending, when the terminal edge recorded one.
|
|
37
|
+
*
|
|
38
|
+
* Explicitly `| undefined` because the value round-trips through a zod schema
|
|
39
|
+
* whose inferred optional includes it, and this project compiles with
|
|
40
|
+
* `exactOptionalPropertyTypes`.
|
|
41
|
+
*/
|
|
42
|
+
stopReason?: string | undefined;
|
|
43
|
+
/** Wall-clock of the last recorded edge, for `Task.status.timestamp`. */
|
|
44
|
+
updatedAt: string;
|
|
45
|
+
}
|
|
46
|
+
/** The whole projected value: every task this session has seen. */
|
|
47
|
+
export interface A2ATaskProjection {
|
|
48
|
+
tasks: Record<string, A2ATaskView>;
|
|
49
|
+
}
|
|
50
|
+
declare module '@deepseek-ai/dsh-session-projection/types' {
|
|
51
|
+
interface SessionProjectionMap {
|
|
52
|
+
/** Per-session A2A task states, folded from `a2a/task` edges. */
|
|
53
|
+
a2aTask: A2ATaskProjection;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** Validates the wire payload before it leaves the host. */
|
|
57
|
+
export declare const A2A_TASK_VIEW_SCHEMA: z.ZodObject<{
|
|
58
|
+
tasks: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
59
|
+
taskId: z.ZodString;
|
|
60
|
+
peer: z.ZodString;
|
|
61
|
+
state: z.ZodEnum<{
|
|
62
|
+
submitted: "submitted";
|
|
63
|
+
working: "working";
|
|
64
|
+
"input-required": "input-required";
|
|
65
|
+
"auth-required": "auth-required";
|
|
66
|
+
completed: "completed";
|
|
67
|
+
canceled: "canceled";
|
|
68
|
+
failed: "failed";
|
|
69
|
+
rejected: "rejected";
|
|
70
|
+
}>;
|
|
71
|
+
output: z.ZodOptional<z.ZodString>;
|
|
72
|
+
stopReason: z.ZodOptional<z.ZodString>;
|
|
73
|
+
updatedAt: z.ZodString;
|
|
74
|
+
}, z.core.$strip>>;
|
|
75
|
+
}, z.core.$strip>;
|
|
76
|
+
/** The projection unit's internal state. Plain JSON, per the cache precondition. */
|
|
77
|
+
export interface A2ATaskState_ {
|
|
78
|
+
tasks: Record<string, A2ATaskView>;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The projection definition, in the shape `ctx.sessionProjections.register()` wants.
|
|
82
|
+
*
|
|
83
|
+
* Declared as a plain object rather than built inside `apply()` so the fold can
|
|
84
|
+
* be unit-tested without a Cordis context or a session.
|
|
85
|
+
*/
|
|
86
|
+
export declare const a2aTaskProjection: {
|
|
87
|
+
key: "a2aTask";
|
|
88
|
+
schema: z.ZodObject<{
|
|
89
|
+
tasks: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
90
|
+
taskId: z.ZodString;
|
|
91
|
+
peer: z.ZodString;
|
|
92
|
+
state: z.ZodEnum<{
|
|
93
|
+
submitted: "submitted";
|
|
94
|
+
working: "working";
|
|
95
|
+
"input-required": "input-required";
|
|
96
|
+
"auth-required": "auth-required";
|
|
97
|
+
completed: "completed";
|
|
98
|
+
canceled: "canceled";
|
|
99
|
+
failed: "failed";
|
|
100
|
+
rejected: "rejected";
|
|
101
|
+
}>;
|
|
102
|
+
output: z.ZodOptional<z.ZodString>;
|
|
103
|
+
stopReason: z.ZodOptional<z.ZodString>;
|
|
104
|
+
updatedAt: z.ZodString;
|
|
105
|
+
}, z.core.$strip>>;
|
|
106
|
+
}, z.core.$strip>;
|
|
107
|
+
stateVersion: number;
|
|
108
|
+
/**
|
|
109
|
+
* State for the empty log.
|
|
110
|
+
* @returns the initial state.
|
|
111
|
+
*/
|
|
112
|
+
init(): A2ATaskState_;
|
|
113
|
+
/**
|
|
114
|
+
* Fold one committed event.
|
|
115
|
+
*
|
|
116
|
+
* Returns the SAME reference for every event that is not an `a2a/task` edge:
|
|
117
|
+
* the drive gates its change feed on `Object.is`, so a fresh object here would
|
|
118
|
+
* wake every downstream consumer on every unrelated event in the session.
|
|
119
|
+
* @param state - the state covering all prior events.
|
|
120
|
+
* @param event - the next committed session event.
|
|
121
|
+
* @returns the next state, or `state` unchanged.
|
|
122
|
+
*/
|
|
123
|
+
apply(state: A2ATaskState_, event: SessionEvent): A2ATaskState_;
|
|
124
|
+
/**
|
|
125
|
+
* State → wire payload.
|
|
126
|
+
* @param state - the current state.
|
|
127
|
+
* @returns the whole current value.
|
|
128
|
+
*/
|
|
129
|
+
view(state: A2ATaskState_): A2ATaskProjection;
|
|
130
|
+
};
|
|
131
|
+
//# sourceMappingURL=projection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projection.d.ts","sourceRoot":"","sources":["../src/projection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,KAAK,EAAa,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAElE,qCAAqC;AACrC,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,mFAAmF;IACnF,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,YAAY,CAAA;IACnB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC/B,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,mEAAmE;AACnE,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;CACnC;AAED,OAAO,QAAQ,2CAA2C,CAAC;IACzD,UAAU,oBAAoB;QAC5B,iEAAiE;QACjE,OAAO,EAAE,iBAAiB,CAAA;KAC3B;CACF;AAOD,4DAA4D;AAC5D,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;iBAS/B,CAAA;AAEF,oFAAoF;AACpF,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;CACnC;AAYD;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;IAK5B;;;OAGG;YACK,aAAa;IAIrB;;;;;;;;;OASG;iBACU,aAAa,SAAS,YAAY,GAAG,aAAa;IA2B/D;;;;OAIG;gBACS,aAAa,GAAG,iBAAiB;CAG9C,CAAA"}
|