/**
* Gemini Chat Tool
*
* 세션 기반 멀티턴 대화 지원
* - 코드 리뷰 토론
* - 문서 분석 후 질의응답
* - 기술 토론
*/
import { z } from 'zod';
import { runGeminiCli, listSessions, isCliAvailable, SessionInfo } from '../services/gemini-cli.js';
import { logRequest, logResponse } from '../services/logger.js';
// ============================================================
// Schema
// ============================================================
export const geminiChatSchema = z.object({
message: z.string().describe('대화 메시지'),
resume: z
.union([z.literal('latest'), z.number()])
.optional()
.describe('이전 세션 재개 (latest 또는 세션 인덱스)'),
model: z.string().optional().describe('모델 선택 (flash/pro)'),
});
export const listSessionsSchema = z.object({});
export type GeminiChatInput = z.infer<typeof geminiChatSchema>;
// ============================================================
// Tool Implementation
// ============================================================
export async function geminiChat(input: GeminiChatInput) {
const { message, resume, model } = input;
if (!isCliAvailable()) {
return {
content: [
{
type: 'text' as const,
text: JSON.stringify(
{
success: false,
error: 'Gemini CLI가 설치되어 있지 않습니다. 세션 기능은 CLI에서만 지원됩니다.',
},
null,
2
),
},
],
};
}
const startTime = Date.now();
const modelId = model === 'pro' ? 'gemini-2.5-pro' : undefined;
// Log request
logRequest({
tool: 'gemini_chat',
provider: 'cli',
model: modelId || 'default',
prompt: message,
context: resume !== undefined ? `resume: ${resume}` : undefined,
});
try {
const result = await runGeminiCli(message, {
model: modelId,
resume,
});
const durationMs = Date.now() - startTime;
// Log response
logResponse({
tool: 'gemini_chat',
provider: 'cli',
model: result.model || modelId || 'unknown',
success: result.success,
response: result.text,
responseLength: result.text?.length,
tokenUsage: result.tokenUsage,
durationMs,
error: result.error,
});
if (!result.success) {
return {
content: [
{
type: 'text' as const,
text: JSON.stringify(
{
success: false,
error: result.error,
},
null,
2
),
},
],
};
}
return {
content: [
{
type: 'text' as const,
text: JSON.stringify(
{
success: true,
response: result.text,
sessionId: result.sessionId,
model: result.model,
tokenUsage: result.tokenUsage,
resumed: resume !== undefined,
},
null,
2
),
},
],
};
} catch (error: any) {
const durationMs = Date.now() - startTime;
logResponse({
tool: 'gemini_chat',
provider: 'cli',
model: modelId || 'unknown',
success: false,
durationMs,
error: error.message,
});
return {
content: [
{
type: 'text' as const,
text: JSON.stringify(
{
success: false,
error: error.message,
},
null,
2
),
},
],
};
}
}
// ============================================================
// List Sessions Tool
// ============================================================
export async function geminiListSessions() {
if (!isCliAvailable()) {
return {
content: [
{
type: 'text' as const,
text: JSON.stringify(
{
success: false,
error: 'Gemini CLI가 설치되어 있지 않습니다.',
sessions: [],
},
null,
2
),
},
],
};
}
try {
const sessions = await listSessions();
return {
content: [
{
type: 'text' as const,
text: JSON.stringify(
{
success: true,
sessions: sessions.map((s: SessionInfo) => ({
index: s.index,
title: s.title,
timeAgo: s.timeAgo,
sessionId: s.sessionId,
})),
count: sessions.length,
},
null,
2
),
},
],
};
} catch (error: any) {
return {
content: [
{
type: 'text' as const,
text: JSON.stringify(
{
success: false,
error: error.message,
sessions: [],
},
null,
2
),
},
],
};
}
}