mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-03 08:24:10 -07:00
Implementing support for recitations events in responses from A2A Server (#12067)
Co-authored-by: Alisa Novikova <alisanovikova@google.com>
This commit is contained in:
@@ -4,11 +4,24 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
import {
|
||||||
|
describe,
|
||||||
|
it,
|
||||||
|
expect,
|
||||||
|
vi,
|
||||||
|
beforeEach,
|
||||||
|
afterEach,
|
||||||
|
type Mock,
|
||||||
|
} from 'vitest';
|
||||||
import { Task } from './task.js';
|
import { Task } from './task.js';
|
||||||
import type { Config, ToolCallRequestInfo } from '@google/gemini-cli-core';
|
import {
|
||||||
|
GeminiEventType,
|
||||||
|
type Config,
|
||||||
|
type ToolCallRequestInfo,
|
||||||
|
} from '@google/gemini-cli-core';
|
||||||
import { createMockConfig } from '../utils/testing_utils.js';
|
import { createMockConfig } from '../utils/testing_utils.js';
|
||||||
import type { ExecutionEventBus } from '@a2a-js/sdk/server';
|
import type { ExecutionEventBus } from '@a2a-js/sdk/server';
|
||||||
|
import { CoderAgentEvent } from '../types.js';
|
||||||
import type { ToolCall } from '@google/gemini-cli-core';
|
import type { ToolCall } from '@google/gemini-cli-core';
|
||||||
|
|
||||||
describe('Task', () => {
|
describe('Task', () => {
|
||||||
@@ -94,6 +107,50 @@ describe('Task', () => {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should handle Citation event and publish to event bus', async () => {
|
||||||
|
const mockConfig = createMockConfig();
|
||||||
|
const mockEventBus: ExecutionEventBus = {
|
||||||
|
publish: vi.fn(),
|
||||||
|
on: vi.fn(),
|
||||||
|
off: vi.fn(),
|
||||||
|
once: vi.fn(),
|
||||||
|
removeAllListeners: vi.fn(),
|
||||||
|
finished: vi.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// @ts-expect-error - Calling private constructor for test purposes.
|
||||||
|
const task = new Task(
|
||||||
|
'task-id',
|
||||||
|
'context-id',
|
||||||
|
mockConfig as Config,
|
||||||
|
mockEventBus,
|
||||||
|
);
|
||||||
|
|
||||||
|
const citationText = 'Source: example.com';
|
||||||
|
const citationEvent = {
|
||||||
|
type: GeminiEventType.Citation,
|
||||||
|
value: citationText,
|
||||||
|
};
|
||||||
|
|
||||||
|
await task.acceptAgentMessage(citationEvent);
|
||||||
|
|
||||||
|
expect(mockEventBus.publish).toHaveBeenCalledOnce();
|
||||||
|
const publishedEvent = (mockEventBus.publish as Mock).mock.calls[0][0];
|
||||||
|
|
||||||
|
expect(publishedEvent.kind).toBe('status-update');
|
||||||
|
expect(publishedEvent.taskId).toBe('task-id');
|
||||||
|
expect(publishedEvent.metadata.coderAgent.kind).toBe(
|
||||||
|
CoderAgentEvent.CitationEvent,
|
||||||
|
);
|
||||||
|
expect(publishedEvent.status.message).toBeDefined();
|
||||||
|
expect(publishedEvent.status.message.parts).toEqual([
|
||||||
|
{
|
||||||
|
kind: 'text',
|
||||||
|
text: citationText,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('_schedulerToolCallsUpdate', () => {
|
describe('_schedulerToolCallsUpdate', () => {
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ import type {
|
|||||||
TaskMetadata,
|
TaskMetadata,
|
||||||
Thought,
|
Thought,
|
||||||
ThoughtSummary,
|
ThoughtSummary,
|
||||||
|
Citation,
|
||||||
} from '../types.js';
|
} from '../types.js';
|
||||||
import type { PartUnion, Part as genAiPart } from '@google/genai';
|
import type { PartUnion, Part as genAiPart } from '@google/genai';
|
||||||
|
|
||||||
@@ -638,6 +639,10 @@ export class Task {
|
|||||||
logger.info('[Task] Sending agent thought...');
|
logger.info('[Task] Sending agent thought...');
|
||||||
this._sendThought(event.value, traceId);
|
this._sendThought(event.value, traceId);
|
||||||
break;
|
break;
|
||||||
|
case GeminiEventType.Citation:
|
||||||
|
logger.info('[Task] Received citation from LLM stream.');
|
||||||
|
this._sendCitation(event.value);
|
||||||
|
break;
|
||||||
case GeminiEventType.ChatCompressed:
|
case GeminiEventType.ChatCompressed:
|
||||||
break;
|
break;
|
||||||
case GeminiEventType.Finished:
|
case GeminiEventType.Finished:
|
||||||
@@ -979,4 +984,18 @@ export class Task {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_sendCitation(citation: string) {
|
||||||
|
if (!citation || citation.trim() === '') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logger.info('[Task] Sending citation to event bus.');
|
||||||
|
const message = this._createTextMessage(citation);
|
||||||
|
const citationEvent: Citation = {
|
||||||
|
kind: CoderAgentEvent.CitationEvent,
|
||||||
|
};
|
||||||
|
this.eventBus?.publish(
|
||||||
|
this._createStatusUpdateEvent(this.taskState, citationEvent, message),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ export enum CoderAgentEvent {
|
|||||||
* An event that contains a thought from the agent.
|
* An event that contains a thought from the agent.
|
||||||
*/
|
*/
|
||||||
ThoughtEvent = 'thought',
|
ThoughtEvent = 'thought',
|
||||||
|
/**
|
||||||
|
* An event that contains citation from the agent.
|
||||||
|
*/
|
||||||
|
CitationEvent = 'citation',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AgentSettings {
|
export interface AgentSettings {
|
||||||
@@ -64,6 +68,10 @@ export interface Thought {
|
|||||||
kind: CoderAgentEvent.ThoughtEvent;
|
kind: CoderAgentEvent.ThoughtEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Citation {
|
||||||
|
kind: CoderAgentEvent.CitationEvent;
|
||||||
|
}
|
||||||
|
|
||||||
export type ThoughtSummary = {
|
export type ThoughtSummary = {
|
||||||
subject: string;
|
subject: string;
|
||||||
description: string;
|
description: string;
|
||||||
@@ -80,7 +88,8 @@ export type CoderAgentMessage =
|
|||||||
| ToolCallUpdate
|
| ToolCallUpdate
|
||||||
| TextContent
|
| TextContent
|
||||||
| StateChange
|
| StateChange
|
||||||
| Thought;
|
| Thought
|
||||||
|
| Citation;
|
||||||
|
|
||||||
export interface TaskMetadata {
|
export interface TaskMetadata {
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user