feat: add gateway protocol attachment support
Extends the gateway wire protocol with GatewayAttachment type and attachment event. agent.send handler now accepts optional attachments parameter and converts them for the agent pipeline. Includes 5 new tests for protocol and handler layers.
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import type { GatewayRequest, OutboundMessage } from '../protocol.js';
|
||||
import type { GatewayRequest, GatewayAttachment, OutboundMessage } from '../protocol.js';
|
||||
import type { SendFn } from '../router.js';
|
||||
import { makeEvent, makeError, ErrorCode } from '../protocol.js';
|
||||
import type { SessionBridge } from '../session-bridge.js';
|
||||
import type { Attachment } from '../../channels/types.js';
|
||||
|
||||
export interface AgentHandlerDeps {
|
||||
sessionBridge: SessionBridge;
|
||||
@@ -10,7 +11,7 @@ export interface AgentHandlerDeps {
|
||||
export function createAgentHandlers(deps: AgentHandlerDeps) {
|
||||
return {
|
||||
'agent.send': async (request: GatewayRequest, send: SendFn): Promise<OutboundMessage | void> => {
|
||||
const params = request.params as { message?: string; connectionId?: string } | undefined;
|
||||
const params = request.params as { message?: string; connectionId?: string; attachments?: GatewayAttachment[] } | undefined;
|
||||
if (!params?.message) {
|
||||
return makeError(request.id, ErrorCode.InvalidRequest, 'message is required');
|
||||
}
|
||||
@@ -48,7 +49,15 @@ export function createAgentHandlers(deps: AgentHandlerDeps) {
|
||||
});
|
||||
|
||||
try {
|
||||
const response = await agent.process(params.message);
|
||||
// Convert gateway attachments to channel attachments
|
||||
const attachments: Attachment[] | undefined = params.attachments?.map(a => ({
|
||||
mimeType: a.mimeType,
|
||||
data: a.data,
|
||||
url: a.url,
|
||||
filename: a.filename,
|
||||
}));
|
||||
|
||||
const response = await agent.process(params.message, attachments);
|
||||
send(makeEvent(request.id, 'done', { content: response }));
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : 'Unknown error';
|
||||
|
||||
@@ -206,13 +206,51 @@ describe('agent handlers', () => {
|
||||
|
||||
await handlers['agent.send'](req, send);
|
||||
|
||||
expect(mockAgent.process).toHaveBeenCalledWith('hello');
|
||||
expect(mockAgent.process).toHaveBeenCalledWith('hello', undefined);
|
||||
expect(sent).toHaveLength(1);
|
||||
const doneEvent = sent[0] as GatewayEvent;
|
||||
expect(doneEvent.event).toBe('done');
|
||||
expect((doneEvent.data as any).content).toBe('response text');
|
||||
});
|
||||
|
||||
it('agent.send passes attachments to agent.process', async () => {
|
||||
const attachments = [
|
||||
{ mimeType: 'image/png', data: 'iVBOR...', filename: 'screenshot.png' },
|
||||
{ mimeType: 'application/pdf', url: 'https://example.com/doc.pdf' },
|
||||
];
|
||||
const req: GatewayRequest = {
|
||||
id: 10,
|
||||
method: 'agent.send',
|
||||
params: { message: 'describe this', connectionId: 'conn-1', attachments },
|
||||
};
|
||||
const sent: OutboundMessage[] = [];
|
||||
const send = vi.fn((msg: OutboundMessage) => sent.push(msg));
|
||||
|
||||
await handlers['agent.send'](req, send);
|
||||
|
||||
expect(mockAgent.process).toHaveBeenCalledWith('describe this', [
|
||||
{ mimeType: 'image/png', data: 'iVBOR...', url: undefined, filename: 'screenshot.png' },
|
||||
{ mimeType: 'application/pdf', data: undefined, url: 'https://example.com/doc.pdf', filename: undefined },
|
||||
]);
|
||||
const doneEvent = sent[0] as GatewayEvent;
|
||||
expect(doneEvent.event).toBe('done');
|
||||
});
|
||||
|
||||
it('agent.send works with empty attachments array', async () => {
|
||||
const req: GatewayRequest = {
|
||||
id: 11,
|
||||
method: 'agent.send',
|
||||
params: { message: 'hi', connectionId: 'conn-1', attachments: [] },
|
||||
};
|
||||
const sent: OutboundMessage[] = [];
|
||||
const send = vi.fn((msg: OutboundMessage) => sent.push(msg));
|
||||
|
||||
await handlers['agent.send'](req, send);
|
||||
|
||||
expect(mockAgent.process).toHaveBeenCalledWith('hi', []);
|
||||
expect(sent).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('agent.send requires message', async () => {
|
||||
const req: GatewayRequest = { id: 2, method: 'agent.send', params: { connectionId: 'conn-1' } };
|
||||
const send = vi.fn();
|
||||
|
||||
Reference in New Issue
Block a user