mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-20 10:10:56 -07:00
feat(cli): migrate nonInteractiveCli to LegacyAgentSession (#22987)
This commit is contained in:
@@ -7,7 +7,19 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { AgentSession } from './agent-session.js';
|
||||
import { MockAgentProtocol } from './mock.js';
|
||||
import type { AgentEvent } from './types.js';
|
||||
import type { AgentEvent, AgentSend } from './types.js';
|
||||
|
||||
function makeMessageSend(
|
||||
text: string,
|
||||
displayContent?: string,
|
||||
): Extract<AgentSend, { message: unknown }> {
|
||||
return {
|
||||
message: {
|
||||
content: [{ type: 'text', text }],
|
||||
...(displayContent ? { displayContent } : {}),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe('AgentSession', () => {
|
||||
it('should passthrough simple methods', async () => {
|
||||
@@ -51,7 +63,7 @@ describe('AgentSession', () => {
|
||||
|
||||
const events: AgentEvent[] = [];
|
||||
for await (const event of session.sendStream({
|
||||
message: [{ type: 'text', text: 'hi' }],
|
||||
...makeMessageSend('hi'),
|
||||
})) {
|
||||
events.push(event);
|
||||
}
|
||||
@@ -139,7 +151,7 @@ describe('AgentSession', () => {
|
||||
|
||||
const events: AgentEvent[] = [];
|
||||
for await (const event of session.sendStream({
|
||||
message: [{ type: 'text', text: 'hi' }],
|
||||
...makeMessageSend('hi'),
|
||||
})) {
|
||||
events.push(event);
|
||||
}
|
||||
@@ -178,7 +190,7 @@ describe('AgentSession', () => {
|
||||
|
||||
protocol.pushResponse([{ type: 'message' }]);
|
||||
const { streamId } = await session.send({
|
||||
message: [{ type: 'text', text: 'request' }],
|
||||
...makeMessageSend('request'),
|
||||
});
|
||||
await new Promise((resolve) => setTimeout(resolve, 10));
|
||||
|
||||
@@ -242,7 +254,7 @@ describe('AgentSession', () => {
|
||||
},
|
||||
]);
|
||||
await session.send({
|
||||
message: [{ type: 'text', text: 'request' }],
|
||||
...makeMessageSend('request'),
|
||||
});
|
||||
await new Promise((resolve) => setTimeout(resolve, 10));
|
||||
|
||||
@@ -303,7 +315,7 @@ describe('AgentSession', () => {
|
||||
},
|
||||
]);
|
||||
const { streamId: streamId1 } = await session.send({
|
||||
message: [{ type: 'text', text: 'first request' }],
|
||||
...makeMessageSend('first request'),
|
||||
});
|
||||
await new Promise((resolve) => setTimeout(resolve, 10));
|
||||
|
||||
@@ -315,7 +327,7 @@ describe('AgentSession', () => {
|
||||
},
|
||||
]);
|
||||
await session.send({
|
||||
message: [{ type: 'text', text: 'second request' }],
|
||||
...makeMessageSend('second request'),
|
||||
});
|
||||
await new Promise((resolve) => setTimeout(resolve, 10));
|
||||
|
||||
|
||||
@@ -679,6 +679,7 @@ describe('mapError', () => {
|
||||
expect(result.status).toBe('RESOURCE_EXHAUSTED');
|
||||
expect(result.message).toBe('Rate limit');
|
||||
expect(result.fatal).toBe(true);
|
||||
expect(result._meta?.['status']).toBe(429);
|
||||
expect(result._meta?.['rawError']).toEqual({
|
||||
message: 'Rate limit',
|
||||
status: 429,
|
||||
|
||||
@@ -403,7 +403,7 @@ export function mapError(
|
||||
}
|
||||
|
||||
if (isStructuredError(error)) {
|
||||
const structuredMeta = { ...meta, rawError: error };
|
||||
const structuredMeta = { ...meta, rawError: error, status: error.status };
|
||||
return {
|
||||
status: mapHttpToGrpcStatus(error.status),
|
||||
message: error.message,
|
||||
|
||||
@@ -10,7 +10,7 @@ import { LegacyAgentSession } from './legacy-agent-session.js';
|
||||
import type { LegacyAgentSessionDeps } from './legacy-agent-session.js';
|
||||
import { GeminiEventType } from '../core/turn.js';
|
||||
import type { ServerGeminiStreamEvent } from '../core/turn.js';
|
||||
import type { AgentEvent } from './types.js';
|
||||
import type { AgentEvent, AgentSend } from './types.js';
|
||||
import { ToolErrorType } from '../tools/tool-error.js';
|
||||
import type {
|
||||
CompletedToolCall,
|
||||
@@ -72,6 +72,18 @@ function makeToolRequest(callId: string, name: string): ToolCallRequestInfo {
|
||||
};
|
||||
}
|
||||
|
||||
function makeMessageSend(
|
||||
text: string,
|
||||
displayContent?: string,
|
||||
): Extract<AgentSend, { message: unknown }> {
|
||||
return {
|
||||
message: {
|
||||
content: [{ type: 'text', text }],
|
||||
...(displayContent ? { displayContent } : {}),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function makeCompletedToolCall(
|
||||
callId: string,
|
||||
name: string,
|
||||
@@ -140,9 +152,7 @@ describe('LegacyAgentSession', () => {
|
||||
);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
const result = await session.send({
|
||||
message: [{ type: 'text', text: 'hi' }],
|
||||
});
|
||||
const result = await session.send(makeMessageSend('hi'));
|
||||
|
||||
expect(result.streamId).toBe('test-stream');
|
||||
});
|
||||
@@ -162,7 +172,10 @@ describe('LegacyAgentSession', () => {
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
const { streamId } = await session.send({
|
||||
message: [{ type: 'text', text: 'hi' }],
|
||||
message: {
|
||||
content: [{ type: 'text', text: 'hi' }],
|
||||
displayContent: 'raw input',
|
||||
},
|
||||
_meta: { source: 'user-test' },
|
||||
});
|
||||
|
||||
@@ -170,8 +183,19 @@ describe('LegacyAgentSession', () => {
|
||||
(e): e is AgentEvent<'message'> =>
|
||||
e.type === 'message' && e.role === 'user' && e.streamId === streamId,
|
||||
);
|
||||
expect(userMessage?.content).toEqual([{ type: 'text', text: 'hi' }]);
|
||||
expect(userMessage?.content).toEqual([
|
||||
{ type: 'text', text: 'raw input' },
|
||||
]);
|
||||
expect(userMessage?._meta).toEqual({ source: 'user-test' });
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
expect(sendMock).toHaveBeenCalledWith(
|
||||
[{ text: 'hi' }],
|
||||
expect.any(AbortSignal),
|
||||
'test-prompt',
|
||||
undefined,
|
||||
false,
|
||||
'raw input',
|
||||
);
|
||||
|
||||
await collectEvents(session, { streamId: streamId ?? undefined });
|
||||
});
|
||||
@@ -195,9 +219,7 @@ describe('LegacyAgentSession', () => {
|
||||
liveEvents.push(event);
|
||||
});
|
||||
|
||||
const { streamId } = await session.send({
|
||||
message: [{ type: 'text', text: 'hi' }],
|
||||
});
|
||||
const { streamId } = await session.send(makeMessageSend('hi'));
|
||||
|
||||
expect(streamId).toBe('test-stream');
|
||||
expect(liveEvents.some((event) => event.type === 'agent_start')).toBe(
|
||||
@@ -235,14 +257,12 @@ describe('LegacyAgentSession', () => {
|
||||
);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
const { streamId } = await session.send({
|
||||
message: [{ type: 'text', text: 'first' }],
|
||||
});
|
||||
const { streamId } = await session.send(makeMessageSend('first'));
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
|
||||
await expect(
|
||||
session.send({ message: [{ type: 'text', text: 'second' }] }),
|
||||
).rejects.toThrow('cannot be called while a stream is active');
|
||||
await expect(session.send(makeMessageSend('second'))).rejects.toThrow(
|
||||
'cannot be called while a stream is active',
|
||||
);
|
||||
|
||||
resolveHang?.();
|
||||
await collectEvents(session, { streamId: streamId ?? undefined });
|
||||
@@ -273,16 +293,12 @@ describe('LegacyAgentSession', () => {
|
||||
);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
const first = await session.send({
|
||||
message: [{ type: 'text', text: 'first' }],
|
||||
});
|
||||
const first = await session.send(makeMessageSend('first'));
|
||||
const firstEvents = await collectEvents(session, {
|
||||
streamId: first.streamId ?? undefined,
|
||||
});
|
||||
|
||||
const second = await session.send({
|
||||
message: [{ type: 'text', text: 'second' }],
|
||||
});
|
||||
const second = await session.send(makeMessageSend('second'));
|
||||
const secondEvents = await collectEvents(session, {
|
||||
streamId: second.streamId ?? undefined,
|
||||
});
|
||||
@@ -330,7 +346,7 @@ describe('LegacyAgentSession', () => {
|
||||
);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
await session.send({ message: [{ type: 'text', text: 'hi' }] });
|
||||
await session.send(makeMessageSend('hi'));
|
||||
const events = await collectEvents(session);
|
||||
|
||||
const types = events.map((e) => e.type);
|
||||
@@ -387,7 +403,7 @@ describe('LegacyAgentSession', () => {
|
||||
]);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
await session.send({ message: [{ type: 'text', text: 'read a file' }] });
|
||||
await session.send(makeMessageSend('read a file'));
|
||||
const events = await collectEvents(session);
|
||||
|
||||
const types = events.map((e) => e.type);
|
||||
@@ -455,9 +471,7 @@ describe('LegacyAgentSession', () => {
|
||||
scheduleMock.mockResolvedValueOnce([errorToolCall]);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
await session.send({
|
||||
message: [{ type: 'text', text: 'write file' }],
|
||||
});
|
||||
await session.send(makeMessageSend('write file'));
|
||||
const events = await collectEvents(session);
|
||||
|
||||
const toolResp = events.find(
|
||||
@@ -506,9 +520,7 @@ describe('LegacyAgentSession', () => {
|
||||
scheduleMock.mockResolvedValueOnce([stopToolCall]);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
await session.send({
|
||||
message: [{ type: 'text', text: 'do something' }],
|
||||
});
|
||||
await session.send(makeMessageSend('do something'));
|
||||
const events = await collectEvents(session);
|
||||
|
||||
const streamEnd = events.find(
|
||||
@@ -552,9 +564,7 @@ describe('LegacyAgentSession', () => {
|
||||
scheduleMock.mockResolvedValueOnce([fatalToolCall]);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
await session.send({
|
||||
message: [{ type: 'text', text: 'write file' }],
|
||||
});
|
||||
await session.send(makeMessageSend('write file'));
|
||||
const events = await collectEvents(session);
|
||||
|
||||
const toolResp = events.find(
|
||||
@@ -592,7 +602,7 @@ describe('LegacyAgentSession', () => {
|
||||
);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
await session.send({ message: [{ type: 'text', text: 'hi' }] });
|
||||
await session.send(makeMessageSend('hi'));
|
||||
const events = await collectEvents(session);
|
||||
|
||||
const streamEnd = events.find(
|
||||
@@ -621,7 +631,7 @@ describe('LegacyAgentSession', () => {
|
||||
);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
await session.send({ message: [{ type: 'text', text: 'hi' }] });
|
||||
await session.send(makeMessageSend('hi'));
|
||||
const events = await collectEvents(session);
|
||||
|
||||
const blocked = events.find(
|
||||
@@ -663,7 +673,7 @@ describe('LegacyAgentSession', () => {
|
||||
);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
await session.send({ message: [{ type: 'text', text: 'hi' }] });
|
||||
await session.send(makeMessageSend('hi'));
|
||||
const events = await collectEvents(session);
|
||||
|
||||
const err = events.find(
|
||||
@@ -690,7 +700,7 @@ describe('LegacyAgentSession', () => {
|
||||
);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
await session.send({ message: [{ type: 'text', text: 'hi' }] });
|
||||
await session.send(makeMessageSend('hi'));
|
||||
const events = await collectEvents(session);
|
||||
|
||||
const warning = events.find(
|
||||
@@ -738,7 +748,7 @@ describe('LegacyAgentSession', () => {
|
||||
);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
await session.send({ message: [{ type: 'text', text: 'hi' }] });
|
||||
await session.send(makeMessageSend('hi'));
|
||||
const events = await collectEvents(session);
|
||||
|
||||
const streamEnd = events.find(
|
||||
@@ -762,7 +772,7 @@ describe('LegacyAgentSession', () => {
|
||||
);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
await session.send({ message: [{ type: 'text', text: 'hi' }] });
|
||||
await session.send(makeMessageSend('hi'));
|
||||
const events = await collectEvents(session);
|
||||
|
||||
const errorEvents = events.filter(
|
||||
@@ -799,9 +809,7 @@ describe('LegacyAgentSession', () => {
|
||||
);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
const { streamId } = await session.send({
|
||||
message: [{ type: 'text', text: 'hi' }],
|
||||
});
|
||||
const { streamId } = await session.send(makeMessageSend('hi'));
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
|
||||
await session.abort();
|
||||
@@ -847,7 +855,7 @@ describe('LegacyAgentSession', () => {
|
||||
);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
await session.send({ message: [{ type: 'text', text: 'hi' }] });
|
||||
await session.send(makeMessageSend('hi'));
|
||||
|
||||
// Give the loop time to start processing
|
||||
await new Promise((r) => setTimeout(r, 50));
|
||||
@@ -891,9 +899,7 @@ describe('LegacyAgentSession', () => {
|
||||
);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
const { streamId } = await session.send({
|
||||
message: [{ type: 'text', text: 'hi' }],
|
||||
});
|
||||
const { streamId } = await session.send(makeMessageSend('hi'));
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 25));
|
||||
await session.abort();
|
||||
@@ -935,7 +941,7 @@ describe('LegacyAgentSession', () => {
|
||||
);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
await session.send({ message: [{ type: 'text', text: 'hi' }] });
|
||||
await session.send(makeMessageSend('hi'));
|
||||
await collectEvents(session);
|
||||
|
||||
expect(session.events.length).toBeGreaterThan(0);
|
||||
@@ -964,9 +970,7 @@ describe('LegacyAgentSession', () => {
|
||||
liveEvents.push(event);
|
||||
});
|
||||
|
||||
const { streamId } = await session.send({
|
||||
message: [{ type: 'text', text: 'hi' }],
|
||||
});
|
||||
const { streamId } = await session.send(makeMessageSend('hi'));
|
||||
await collectEvents(session, { streamId: streamId ?? undefined });
|
||||
unsubscribe();
|
||||
|
||||
@@ -1002,9 +1006,7 @@ describe('LegacyAgentSession', () => {
|
||||
);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
const first = await session.send({
|
||||
message: [{ type: 'text', text: 'first request' }],
|
||||
});
|
||||
const first = await session.send(makeMessageSend('first request'));
|
||||
await collectEvents(session, { streamId: first.streamId ?? undefined });
|
||||
|
||||
const liveEvents: AgentEvent[] = [];
|
||||
@@ -1012,9 +1014,7 @@ describe('LegacyAgentSession', () => {
|
||||
liveEvents.push(event);
|
||||
});
|
||||
|
||||
const second = await session.send({
|
||||
message: [{ type: 'text', text: 'second request' }],
|
||||
});
|
||||
const second = await session.send(makeMessageSend('second request'));
|
||||
await collectEvents(session, { streamId: second.streamId ?? undefined });
|
||||
unsubscribe();
|
||||
|
||||
@@ -1058,14 +1058,10 @@ describe('LegacyAgentSession', () => {
|
||||
);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
const first = await session.send({
|
||||
message: [{ type: 'text', text: 'first request' }],
|
||||
});
|
||||
const first = await session.send(makeMessageSend('first request'));
|
||||
await collectEvents(session, { streamId: first.streamId ?? undefined });
|
||||
|
||||
const second = await session.send({
|
||||
message: [{ type: 'text', text: 'second request' }],
|
||||
});
|
||||
const second = await session.send(makeMessageSend('second request'));
|
||||
await collectEvents(session, { streamId: second.streamId ?? undefined });
|
||||
|
||||
const firstStreamEvents = await collectEvents(session, {
|
||||
@@ -1120,14 +1116,10 @@ describe('LegacyAgentSession', () => {
|
||||
);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
const first = await session.send({
|
||||
message: [{ type: 'text', text: 'first request' }],
|
||||
});
|
||||
const first = await session.send(makeMessageSend('first request'));
|
||||
await collectEvents(session, { streamId: first.streamId ?? undefined });
|
||||
|
||||
await session.send({
|
||||
message: [{ type: 'text', text: 'second request' }],
|
||||
});
|
||||
await session.send(makeMessageSend('second request'));
|
||||
await collectEvents(session);
|
||||
|
||||
const firstAgentMessage = session.events.find(
|
||||
@@ -1175,7 +1167,7 @@ describe('LegacyAgentSession', () => {
|
||||
);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
await session.send({ message: [{ type: 'text', text: 'hi' }] });
|
||||
await session.send(makeMessageSend('hi'));
|
||||
const events = await collectEvents(session);
|
||||
|
||||
expect(events.length).toBeGreaterThan(0);
|
||||
@@ -1196,7 +1188,7 @@ describe('LegacyAgentSession', () => {
|
||||
);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
await session.send({ message: [{ type: 'text', text: 'hi' }] });
|
||||
await session.send(makeMessageSend('hi'));
|
||||
const events = await collectEvents(session);
|
||||
|
||||
expect(events[events.length - 1]?.type).toBe('agent_end');
|
||||
@@ -1244,7 +1236,7 @@ describe('LegacyAgentSession', () => {
|
||||
]);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
await session.send({ message: [{ type: 'text', text: 'do it' }] });
|
||||
await session.send(makeMessageSend('do it'));
|
||||
const events = await collectEvents(session);
|
||||
|
||||
// Only one agent_end at the very end
|
||||
@@ -1291,7 +1283,7 @@ describe('LegacyAgentSession', () => {
|
||||
]);
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
await session.send({ message: [{ type: 'text', text: 'go' }] });
|
||||
await session.send(makeMessageSend('go'));
|
||||
const events = await collectEvents(session);
|
||||
|
||||
// Should have at least one usage event from the intermediate Finished
|
||||
@@ -1314,7 +1306,7 @@ describe('LegacyAgentSession', () => {
|
||||
});
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
await session.send({ message: [{ type: 'text', text: 'hi' }] });
|
||||
await session.send(makeMessageSend('hi'));
|
||||
const events = await collectEvents(session);
|
||||
|
||||
const err = events.find(
|
||||
@@ -1342,7 +1334,7 @@ describe('LegacyAgentSession', () => {
|
||||
});
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
await session.send({ message: [{ type: 'text', text: 'hi' }] });
|
||||
await session.send(makeMessageSend('hi'));
|
||||
const events = await collectEvents(session);
|
||||
|
||||
const err = events.find(
|
||||
@@ -1365,7 +1357,7 @@ describe('LegacyAgentSession', () => {
|
||||
});
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
await session.send({ message: [{ type: 'text', text: 'hi' }] });
|
||||
await session.send(makeMessageSend('hi'));
|
||||
const events = await collectEvents(session);
|
||||
|
||||
const err = events.find(
|
||||
@@ -1385,7 +1377,7 @@ describe('LegacyAgentSession', () => {
|
||||
});
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
await session.send({ message: [{ type: 'text', text: 'hi' }] });
|
||||
await session.send(makeMessageSend('hi'));
|
||||
const events = await collectEvents(session);
|
||||
|
||||
const err = events.find(
|
||||
@@ -1405,7 +1397,7 @@ describe('LegacyAgentSession', () => {
|
||||
});
|
||||
|
||||
const session = new LegacyAgentSession(deps);
|
||||
await session.send({ message: [{ type: 'text', text: 'hi' }] });
|
||||
await session.send(makeMessageSend('hi'));
|
||||
const events = await collectEvents(session);
|
||||
|
||||
const err = events.find(
|
||||
|
||||
@@ -105,12 +105,16 @@ class LegacyAgentProtocol implements AgentProtocol {
|
||||
|
||||
this._beginNewStream();
|
||||
const streamId = this._translationState.streamId;
|
||||
const parts = contentPartsToGeminiParts(message);
|
||||
const userMessage = this._makeUserMessageEvent(message, payload._meta);
|
||||
const parts = contentPartsToGeminiParts(message.content);
|
||||
const userMessage = this._makeUserMessageEvent(
|
||||
message.content,
|
||||
message.displayContent,
|
||||
payload._meta,
|
||||
);
|
||||
|
||||
this._emit([userMessage]);
|
||||
|
||||
this._scheduleRunLoop(parts);
|
||||
this._scheduleRunLoop(parts, message.displayContent);
|
||||
|
||||
return { streamId };
|
||||
}
|
||||
@@ -119,18 +123,24 @@ class LegacyAgentProtocol implements AgentProtocol {
|
||||
this._abortController.abort();
|
||||
}
|
||||
|
||||
private _scheduleRunLoop(initialParts: Part[]): void {
|
||||
private _scheduleRunLoop(
|
||||
initialParts: Part[],
|
||||
displayContent?: string,
|
||||
): void {
|
||||
// Use a macrotask so send() resolves with the streamId before agent_start
|
||||
// is emitted and consumers can attach to the stream without racing startup.
|
||||
setTimeout(() => {
|
||||
void this._runLoopInBackground(initialParts);
|
||||
void this._runLoopInBackground(initialParts, displayContent);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
private async _runLoopInBackground(initialParts: Part[]): Promise<void> {
|
||||
private async _runLoopInBackground(
|
||||
initialParts: Part[],
|
||||
displayContent?: string,
|
||||
): Promise<void> {
|
||||
this._ensureAgentStart();
|
||||
try {
|
||||
await this._runLoop(initialParts);
|
||||
await this._runLoop(initialParts, displayContent);
|
||||
} catch (err: unknown) {
|
||||
if (this._abortController.signal.aborted || isAbortLikeError(err)) {
|
||||
this._ensureAgentEnd('aborted');
|
||||
@@ -141,8 +151,12 @@ class LegacyAgentProtocol implements AgentProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
private async _runLoop(initialParts: Part[]): Promise<void> {
|
||||
private async _runLoop(
|
||||
initialParts: Part[],
|
||||
initialDisplayContent?: string,
|
||||
): Promise<void> {
|
||||
let currentParts: Part[] = initialParts;
|
||||
let currentDisplayContent = initialDisplayContent;
|
||||
let turnCount = 0;
|
||||
const maxTurns = this._config.getMaxSessionTurns();
|
||||
|
||||
@@ -162,7 +176,11 @@ class LegacyAgentProtocol implements AgentProtocol {
|
||||
currentParts,
|
||||
this._abortController.signal,
|
||||
this._promptId,
|
||||
undefined,
|
||||
false,
|
||||
currentDisplayContent,
|
||||
);
|
||||
currentDisplayContent = undefined;
|
||||
|
||||
for await (const event of responseStream) {
|
||||
if (this._abortController.signal.aborted) {
|
||||
@@ -383,13 +401,17 @@ class LegacyAgentProtocol implements AgentProtocol {
|
||||
|
||||
private _makeUserMessageEvent(
|
||||
content: ContentPart[],
|
||||
displayContent?: string,
|
||||
meta?: Record<string, unknown>,
|
||||
): AgentEvent<'message'> {
|
||||
const eventContent: ContentPart[] = displayContent
|
||||
? [{ type: 'text', text: displayContent }]
|
||||
: content;
|
||||
const event = {
|
||||
...this._nextEventFields(),
|
||||
type: 'message',
|
||||
role: 'user',
|
||||
content,
|
||||
content: eventContent,
|
||||
...(meta ? { _meta: meta } : {}),
|
||||
} satisfies AgentEvent<'message'>;
|
||||
return event;
|
||||
|
||||
@@ -34,7 +34,7 @@ describe('MockAgentProtocol', () => {
|
||||
const streamPromise = waitForStreamEnd(session);
|
||||
|
||||
const { streamId } = await session.send({
|
||||
message: [{ type: 'text', text: 'hi' }],
|
||||
message: { content: [{ type: 'text', text: 'hi' }] },
|
||||
});
|
||||
expect(streamId).toBeDefined();
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import type {
|
||||
AgentEventData,
|
||||
AgentProtocol,
|
||||
AgentSend,
|
||||
ContentPart,
|
||||
Unsubscribe,
|
||||
} from './types.js';
|
||||
|
||||
@@ -133,11 +134,17 @@ export class MockAgentProtocol implements AgentProtocol {
|
||||
|
||||
// 1. User/Update event (BEFORE agent_start)
|
||||
if ('message' in payload && payload.message) {
|
||||
const message = Array.isArray(payload.message)
|
||||
? { content: payload.message, displayContent: undefined }
|
||||
: payload.message;
|
||||
const userContent: ContentPart[] = message.displayContent
|
||||
? [{ type: 'text', text: message.displayContent }]
|
||||
: message.content;
|
||||
eventsToEmit.push(
|
||||
normalize({
|
||||
type: 'message',
|
||||
role: 'user',
|
||||
content: payload.message,
|
||||
content: userContent,
|
||||
_meta: payload._meta,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -46,7 +46,10 @@ type RequireExactlyOne<T> = {
|
||||
}[keyof T];
|
||||
|
||||
interface AgentSendPayloads {
|
||||
message: ContentPart[];
|
||||
message: {
|
||||
content: ContentPart[];
|
||||
displayContent?: string;
|
||||
};
|
||||
elicitations: ElicitationResponse[];
|
||||
update: { title?: string; model?: string; config?: Record<string, unknown> };
|
||||
action: { type: string; data: unknown };
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
import stripAnsi from 'strip-ansi';
|
||||
import type { SessionMetrics } from '../telemetry/uiTelemetry.js';
|
||||
import { getErrorType } from '../utils/errors.js';
|
||||
import type { JsonError, JsonOutput } from './types.js';
|
||||
|
||||
export class JsonFormatter {
|
||||
@@ -42,7 +43,7 @@ export class JsonFormatter {
|
||||
sessionId?: string,
|
||||
): string {
|
||||
const jsonError: JsonError = {
|
||||
type: error.constructor.name,
|
||||
type: getErrorType(error),
|
||||
message: stripAnsi(error.message),
|
||||
...(code && { code }),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user