@amaster.ai/dsh-a2a 0.1.8 → 0.1.9
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/lib/bridge.js +41 -22
- package/lib/executor.js +3 -2
- package/lib/index.js +2 -0
- package/lib/types/bridge.d.ts +1 -1
- package/lib/types/index.d.ts +14 -0
- package/package.json +1 -1
package/lib/bridge.js
CHANGED
|
@@ -170,10 +170,10 @@ export class A2aBridge {
|
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
172
|
/** Queue one user-message turn on the task's agent and await its `turn/end`. */
|
|
173
|
-
async runTurn(entry, content, bus) {
|
|
173
|
+
async runTurn(entry, content, bus, a2aMessageId, requestHeaders) {
|
|
174
174
|
if (this.clearing.has(entry.sessionId))
|
|
175
175
|
throw new Error('Context is being cleared.');
|
|
176
|
-
const running = this.runTurnInner(entry, content, bus);
|
|
176
|
+
const running = this.runTurnInner(entry, content, bus, a2aMessageId, requestHeaders);
|
|
177
177
|
entry.running.add(running);
|
|
178
178
|
try {
|
|
179
179
|
await running;
|
|
@@ -182,7 +182,7 @@ export class A2aBridge {
|
|
|
182
182
|
entry.running.delete(running);
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
|
-
async runTurnInner(entry, content, bus) {
|
|
185
|
+
async runTurnInner(entry, content, bus, a2aMessageId, requestHeaders) {
|
|
186
186
|
let resolveSettled;
|
|
187
187
|
const settled = new Promise((resolve) => {
|
|
188
188
|
resolveSettled = resolve;
|
|
@@ -190,26 +190,45 @@ export class A2aBridge {
|
|
|
190
190
|
entry.settled.push(resolveSettled);
|
|
191
191
|
entry.bus = bus;
|
|
192
192
|
try {
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
})
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
193
|
+
const message = createUserMessage({ content, source: { kind: 'user' } });
|
|
194
|
+
// followup() inserts synchronously, then may claim the message before
|
|
195
|
+
// returning. Observe that insertion so the mapping is both real and early.
|
|
196
|
+
const stopListening = this.ctx.on('agent/inbox/inserted', ({ agent, message: inserted }) => {
|
|
197
|
+
if (agent !== entry.handle.agent || inserted.id !== message.id)
|
|
198
|
+
return;
|
|
199
|
+
stopListening();
|
|
200
|
+
void this.ctx
|
|
201
|
+
.parallel('a2a/message-admitted', {
|
|
202
|
+
contextId: entry.sessionId,
|
|
203
|
+
taskId: entry.taskId,
|
|
204
|
+
a2aMessageId,
|
|
205
|
+
dshMessageId: message.id,
|
|
206
|
+
requestHeaders,
|
|
207
|
+
})
|
|
208
|
+
.catch((error) => {
|
|
209
|
+
console.error('[dsh-a2a] message-admitted listener failed:', error);
|
|
210
|
+
});
|
|
207
211
|
});
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
212
|
+
try {
|
|
213
|
+
const result = entry.handle.agent.followup(message);
|
|
214
|
+
// followup() is typed void; guard a mistyped async impl anyway — an
|
|
215
|
+
// unhandled rejection would crash the host process, and no turn/end
|
|
216
|
+
// would ever settle this waiter.
|
|
217
|
+
void Promise.resolve(result).catch((error) => {
|
|
218
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
219
|
+
console.error('[dsh-a2a] followup failed:', error);
|
|
220
|
+
if (entry.bus === bus) {
|
|
221
|
+
entry.bus.publish(terminalStatusUpdate(entry.taskId, entry.sessionId, 'failed', message));
|
|
222
|
+
}
|
|
223
|
+
resolveSettled();
|
|
224
|
+
});
|
|
225
|
+
// Never rejects: waiters only resolve. A synchronous followup() throw
|
|
226
|
+
// means no turn started, so pull its waiter from the FIFO below.
|
|
227
|
+
await settled;
|
|
228
|
+
}
|
|
229
|
+
finally {
|
|
230
|
+
stopListening();
|
|
231
|
+
}
|
|
213
232
|
}
|
|
214
233
|
catch (error) {
|
|
215
234
|
const index = entry.settled.indexOf(resolveSettled);
|
package/lib/executor.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* `cancelTask` is an arrow property because the SDK destructures it.
|
|
19
19
|
*/
|
|
20
20
|
import { TaskState } from '@a2a-js/sdk';
|
|
21
|
-
import { AgentEvent } from '@a2a-js/sdk/server';
|
|
21
|
+
import { AgentEvent, STATE_HEADERS_KEY } from '@a2a-js/sdk/server';
|
|
22
22
|
import { agentTextMessage, terminalStatusUpdate } from './translator.js';
|
|
23
23
|
export class DshAgentExecutor {
|
|
24
24
|
bridge;
|
|
@@ -48,7 +48,8 @@ export class DshAgentExecutor {
|
|
|
48
48
|
// stored task (history/artifacts preserved).
|
|
49
49
|
taskEvent(taskId, contextId, TaskState.TASK_STATE_WORKING));
|
|
50
50
|
anchored = true;
|
|
51
|
-
|
|
51
|
+
const requestHeaders = requestContext.context.state.get(STATE_HEADERS_KEY);
|
|
52
|
+
await this.bridge.runTurn(entry, content, eventBus, userMessage.messageId, requestHeaders);
|
|
52
53
|
}
|
|
53
54
|
catch (error) {
|
|
54
55
|
if (this.bridge.isClearing(contextId))
|
package/lib/index.js
CHANGED
|
@@ -20,6 +20,8 @@ import { startA2aServer } from './server.js';
|
|
|
20
20
|
import { GcsTaskStore } from './stores/gcs.js';
|
|
21
21
|
import { RedisTaskStore } from './stores/redis.js';
|
|
22
22
|
import { MemoryTaskStore, SanitizedTaskStore } from './task-store.js';
|
|
23
|
+
/** Event emitted when one A2A user message enters the dsh inbox. */
|
|
24
|
+
export const A2A_MESSAGE_ADMITTED_EVENT = 'a2a/message-admitted';
|
|
23
25
|
export const name = 'dsh-a2a';
|
|
24
26
|
/** The bridge creates and owns agents through the registry service. */
|
|
25
27
|
export const inject = ['agents'];
|
package/lib/types/bridge.d.ts
CHANGED
|
@@ -78,7 +78,7 @@ export declare class A2aBridge {
|
|
|
78
78
|
/** Include content preparation in the work a context clear must drain. */
|
|
79
79
|
trackExecution(contextId: string, run: () => Promise<void>): Promise<void>;
|
|
80
80
|
/** Queue one user-message turn on the task's agent and await its `turn/end`. */
|
|
81
|
-
runTurn(entry: TaskEntry, content: ContentBlock[], bus: ExecutionEventBus): Promise<void>;
|
|
81
|
+
runTurn(entry: TaskEntry, content: ContentBlock[], bus: ExecutionEventBus, a2aMessageId: string, requestHeaders: unknown): Promise<void>;
|
|
82
82
|
private runTurnInner;
|
|
83
83
|
/** Cancel and release the live binding before the caller deletes stored shells. */
|
|
84
84
|
clearContext(contextId: string, clearStored?: (liveIds: string[]) => Promise<string[]>): Promise<string[]>;
|
package/lib/types/index.d.ts
CHANGED
|
@@ -14,6 +14,20 @@
|
|
|
14
14
|
import type { Context } from '@deepseek-ai/cordis';
|
|
15
15
|
import Schema from '@deepseek-ai/schemastery';
|
|
16
16
|
export type { A2aFileMaterializer } from './content.js';
|
|
17
|
+
/** Event emitted when one A2A user message enters the dsh inbox. */
|
|
18
|
+
export declare const A2A_MESSAGE_ADMITTED_EVENT: "a2a/message-admitted";
|
|
19
|
+
declare module '@deepseek-ai/cordis' {
|
|
20
|
+
interface Events {
|
|
21
|
+
/** Link a protocol message to the dsh inbox message created for its turn. */
|
|
22
|
+
'a2a/message-admitted'(detail: {
|
|
23
|
+
contextId: string;
|
|
24
|
+
taskId: string;
|
|
25
|
+
a2aMessageId: string;
|
|
26
|
+
dshMessageId: string;
|
|
27
|
+
requestHeaders: unknown;
|
|
28
|
+
}): void;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
17
31
|
export declare const name = "dsh-a2a";
|
|
18
32
|
/** The bridge creates and owns agents through the registry service. */
|
|
19
33
|
export declare const inject: string[];
|
package/package.json
CHANGED