Download packages/core/src/agent/mock.test.ts from SaylorTwift/gemini-cli: direct link, hf CLI and curl.
- Browser
- Download file 7.9 kB
-
https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/core/src/agent/mock.test.ts
- Command line
-
hf download hf://SaylorTwift/gemini-cli/packages/core/src/agent/mock.test.ts
-
curl -L -o mock.test.ts https://huggingface.co/SaylorTwift/gemini-cli/resolve/main/packages/core/src/agent/mock.test.ts
7.9 kB
| /** | |
| * @license | |
| * Copyright 2026 Google LLC | |
| * SPDX-License-Identifier: Apache-2.0 | |
| */ | |
| import { describe, expect, it } from 'vitest'; | |
| import { MockAgentProtocol } from './mock.js'; | |
| import type { AgentEvent, AgentProtocol } from './types.js'; | |
| const waitForStreamEnd = (session: AgentProtocol): Promise<AgentEvent[]> => | |
| new Promise((resolve) => { | |
| const events: AgentEvent[] = []; | |
| const unsubscribe = session.subscribe((e) => { | |
| events.push(e); | |
| if (e.type === 'agent_end') { | |
| unsubscribe(); | |
| resolve(events); | |
| } | |
| }); | |
| }); | |
| describe('MockAgentProtocol', () => { | |
| it('should emit queued events on send and subscribe', async () => { | |
| const session = new MockAgentProtocol(); | |
| const event1 = { | |
| type: 'message', | |
| role: 'agent', | |
| content: [{ type: 'text', text: 'hello' }], | |
| } as AgentEvent; | |
| session.pushResponse([event1]); | |
| const streamPromise = waitForStreamEnd(session); | |
| const { streamId } = await session.send({ | |
| message: { content: [{ type: 'text', text: 'hi' }] }, | |
| }); | |
| expect(streamId).toBeDefined(); | |
| const streamedEvents = await streamPromise; | |
| // Ordered: user message, agent_start, agent message, agent_end = 4 events | |
| expect(streamedEvents).toHaveLength(4); | |
| expect(streamedEvents[0].type).toBe('message'); | |
| expect((streamedEvents[0] as AgentEvent<'message'>).role).toBe('user'); | |
| expect(streamedEvents[1].type).toBe('agent_start'); | |
| expect(streamedEvents[2].type).toBe('message'); | |
| expect((streamedEvents[2] as AgentEvent<'message'>).role).toBe('agent'); | |
| expect(streamedEvents[3].type).toBe('agent_end'); | |
| expect(session.events).toHaveLength(4); | |
| expect(session.events).toEqual(streamedEvents); | |
| }); | |
| it('should handle multiple responses', async () => { | |
| const session = new MockAgentProtocol(); | |
| // Test with empty payload (no message injected) | |
| session.pushResponse([]); | |
| session.pushResponse([ | |
| { | |
| type: 'error', | |
| message: 'fail', | |
| fatal: true, | |
| status: 'RESOURCE_EXHAUSTED', | |
| }, | |
| ]); | |
| // First send | |
| const stream1Promise = waitForStreamEnd(session); | |
| const { streamId: s1 } = await session.send({ | |
| update: { title: 't1' }, | |
| }); | |
| const events1 = await stream1Promise; | |
| expect(events1).toHaveLength(3); // session_update, agent_start, agent_end | |
| expect(events1[0].type).toBe('session_update'); | |
| expect(events1[1].type).toBe('agent_start'); | |
| expect(events1[2].type).toBe('agent_end'); | |
| // Second send | |
| const stream2Promise = waitForStreamEnd(session); | |
| const { streamId: s2 } = await session.send({ | |
| update: { title: 't2' }, | |
| }); | |
| expect(s1).not.toBe(s2); | |
| const events2 = await stream2Promise; | |
| expect(events2).toHaveLength(4); // session_update, agent_start, error, agent_end | |
| expect(events2[0].type).toBe('session_update'); | |
| expect(events2[1].type).toBe('agent_start'); | |
| expect(events2[2].type).toBe('error'); | |
| expect(events2[3].type).toBe('agent_end'); | |
| expect(session.events).toHaveLength(7); | |
| }); | |
| it('should handle abort on a waiting stream', async () => { | |
| const session = new MockAgentProtocol(); | |
| // Use keepOpen to prevent auto agent_end | |
| session.pushResponse([{ type: 'message' }], { keepOpen: true }); | |
| const events: AgentEvent[] = []; | |
| let resolveStream: (evs: AgentEvent[]) => void; | |
| const streamPromise = new Promise<AgentEvent[]>((res) => { | |
| resolveStream = res; | |
| }); | |
| session.subscribe((e) => { | |
| events.push(e); | |
| if (e.type === 'agent_end') { | |
| resolveStream(events); | |
| } | |
| }); | |
| const { streamId: _streamId } = await session.send({ | |
| update: { title: 't' }, | |
| }); | |
| // Initial events should have been emitted | |
| expect(events.map((e) => e.type)).toEqual([ | |
| 'session_update', | |
| 'agent_start', | |
| 'message', | |
| ]); | |
| // At this point, the stream should be "waiting" for more events because it's still active | |
| // and hasn't seen an agent_end. | |
| await session.abort(); | |
| const finalEvents = await streamPromise; | |
| expect(finalEvents[3].type).toBe('agent_end'); | |
| expect((finalEvents[3] as AgentEvent<'agent_end'>).reason).toBe('aborted'); | |
| }); | |
| it('should handle pushToStream on a waiting stream', async () => { | |
| const session = new MockAgentProtocol(); | |
| session.pushResponse([], { keepOpen: true }); | |
| const events: AgentEvent[] = []; | |
| session.subscribe((e) => events.push(e)); | |
| const { streamId } = await session.send({ update: { title: 't' } }); | |
| expect(events.map((e) => e.type)).toEqual([ | |
| 'session_update', | |
| 'agent_start', | |
| ]); | |
| // Push new event to active stream | |
| session.pushToStream(streamId!, [{ type: 'message' }]); | |
| expect(events).toHaveLength(3); | |
| expect(events[2].type).toBe('message'); | |
| await session.abort(); | |
| expect(events).toHaveLength(4); | |
| expect(events[3].type).toBe('agent_end'); | |
| }); | |
| it('should handle pushToStream with close option', async () => { | |
| const session = new MockAgentProtocol(); | |
| session.pushResponse([], { keepOpen: true }); | |
| const streamPromise = waitForStreamEnd(session); | |
| const { streamId } = await session.send({ update: { title: 't' } }); | |
| // Push new event and close | |
| session.pushToStream(streamId!, [{ type: 'message' }], { close: true }); | |
| const events = await streamPromise; | |
| expect(events.map((e) => e.type)).toEqual([ | |
| 'session_update', | |
| 'agent_start', | |
| 'message', | |
| 'agent_end', | |
| ]); | |
| expect((events[3] as AgentEvent<'agent_end'>).reason).toBe('completed'); | |
| }); | |
| it('should not double up on agent_end if provided manually', async () => { | |
| const session = new MockAgentProtocol(); | |
| session.pushResponse([ | |
| { type: 'message' }, | |
| { type: 'agent_end', reason: 'completed' }, | |
| ]); | |
| const streamPromise = waitForStreamEnd(session); | |
| await session.send({ update: { title: 't' } }); | |
| const events = await streamPromise; | |
| const endEvents = events.filter((e) => e.type === 'agent_end'); | |
| expect(endEvents).toHaveLength(1); | |
| }); | |
| it('should handle elicitations', async () => { | |
| const session = new MockAgentProtocol(); | |
| session.pushResponse([]); | |
| const streamPromise = waitForStreamEnd(session); | |
| await session.send({ | |
| elicitations: [ | |
| { requestId: 'r1', action: 'accept', content: { foo: 'bar' } }, | |
| ], | |
| }); | |
| const events = await streamPromise; | |
| expect(events[0].type).toBe('elicitation_response'); | |
| expect((events[0] as AgentEvent<'elicitation_response'>).requestId).toBe( | |
| 'r1', | |
| ); | |
| expect(events[1].type).toBe('agent_start'); | |
| }); | |
| it('should handle updates and track state', async () => { | |
| const session = new MockAgentProtocol(); | |
| session.pushResponse([]); | |
| const streamPromise = waitForStreamEnd(session); | |
| await session.send({ | |
| update: { title: 'New Title', model: 'gpt-4', config: { x: 1 } }, | |
| }); | |
| expect(session.title).toBe('New Title'); | |
| expect(session.model).toBe('gpt-4'); | |
| expect(session.config).toEqual({ x: 1 }); | |
| const events = await streamPromise; | |
| expect(events[0].type).toBe('session_update'); | |
| expect(events[1].type).toBe('agent_start'); | |
| }); | |
| it('should return streamId: null if no response queued', async () => { | |
| const session = new MockAgentProtocol(); | |
| const { streamId } = await session.send({ update: { title: 'foo' } }); | |
| expect(streamId).toBeNull(); | |
| expect(session.events).toHaveLength(1); | |
| expect(session.events[0].type).toBe('session_update'); | |
| expect(session.events[0].streamId).toEqual(expect.any(String)); | |
| }); | |
| it('should throw on action', async () => { | |
| const session = new MockAgentProtocol(); | |
| await expect( | |
| session.send({ action: { type: 'foo', data: {} } }), | |
| ).rejects.toThrow('Actions not supported in MockAgentProtocol: foo'); | |
| }); | |
| }); | |