refactor: improve OpenAI service and tools
- Enhance OpenAI message types with tool_calls support - Improve security validation and rate limiting - Update utility tools and weather tool - Minor fixes in deposit-agent and domain-register Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import type { Env } from './types';
|
||||
import type { Env, OpenAIMessage, ToolCall } from './types';
|
||||
import { tools, selectToolsForMessage, executeTool } from './tools';
|
||||
import { retryWithBackoff, RetryError } from './utils/retry';
|
||||
import { CircuitBreaker, CircuitBreakerError } from './utils/circuit-breaker';
|
||||
@@ -6,6 +6,9 @@ import { createLogger } from './utils/logger';
|
||||
import { metrics } from './utils/metrics';
|
||||
import { getOpenAIUrl } from './utils/api-urls';
|
||||
import { ERROR_MESSAGES } from './constants/messages';
|
||||
import { getServerSession, processServerConsultation } from './server-agent';
|
||||
import { getTroubleshootSession, processTroubleshoot } from './troubleshoot-agent';
|
||||
import { sendMessage } from './telegram';
|
||||
|
||||
const logger = createLogger('openai');
|
||||
|
||||
@@ -95,20 +98,24 @@ async function saveMemorySilently(
|
||||
.bind(user.id)
|
||||
.all<{ id: number; content: string }>();
|
||||
|
||||
if (existing.results) {
|
||||
for (const memory of existing.results) {
|
||||
if (detectMemoryCategory(memory.content) === category) {
|
||||
await db
|
||||
.prepare('DELETE FROM user_memories WHERE id = ?')
|
||||
.bind(memory.id)
|
||||
.run();
|
||||
logger.info('Memory replaced (same category)', {
|
||||
userId: telegramUserId,
|
||||
category,
|
||||
oldContent: memory.content.slice(0, 30),
|
||||
newContent: content.slice(0, 30)
|
||||
});
|
||||
}
|
||||
if (existing.results && existing.results.length > 0) {
|
||||
// Collect IDs to delete
|
||||
const idsToDelete = existing.results
|
||||
.filter(memory => detectMemoryCategory(memory.content) === category)
|
||||
.map(memory => memory.id);
|
||||
|
||||
if (idsToDelete.length > 0) {
|
||||
// Single batch delete instead of N individual deletes
|
||||
const placeholders = idsToDelete.map(() => '?').join(',');
|
||||
await db.prepare(
|
||||
`DELETE FROM user_memories WHERE id IN (${placeholders})`
|
||||
).bind(...idsToDelete).run();
|
||||
|
||||
logger.info('Deleted existing memories of same category', {
|
||||
userId: telegramUserId,
|
||||
category,
|
||||
deletedCount: idsToDelete.length
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,22 +143,6 @@ export const openaiCircuitBreaker = new CircuitBreaker({
|
||||
monitoringWindowMs: 60000 // 1분 윈도우
|
||||
});
|
||||
|
||||
interface OpenAIMessage {
|
||||
role: 'system' | 'user' | 'assistant' | 'tool';
|
||||
content: string | null;
|
||||
tool_calls?: ToolCall[];
|
||||
tool_call_id?: string;
|
||||
}
|
||||
|
||||
interface ToolCall {
|
||||
id: string;
|
||||
type: 'function';
|
||||
function: {
|
||||
name: string;
|
||||
arguments: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface OpenAIResponse {
|
||||
choices: {
|
||||
message: OpenAIMessage;
|
||||
@@ -188,7 +179,7 @@ async function callOpenAI(
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.text();
|
||||
throw new Error(`OpenAI API error: ${response.status} - ${error}`);
|
||||
throw new Error(`OpenAI API 오류: ${response.status} - ${error}`);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
@@ -211,20 +202,32 @@ export async function generateOpenAIResponse(
|
||||
systemPrompt: string,
|
||||
recentContext: { role: 'user' | 'assistant'; content: string }[],
|
||||
telegramUserId?: string,
|
||||
db?: D1Database
|
||||
db?: D1Database,
|
||||
chatIdStr?: string
|
||||
): Promise<string> {
|
||||
// Check if server consultation session is active
|
||||
if (telegramUserId && env.SESSION_KV) {
|
||||
if (telegramUserId && env.DB) {
|
||||
try {
|
||||
const { getServerSession, processServerConsultation } = await import('./server-agent');
|
||||
const session = await getServerSession(env.SESSION_KV, telegramUserId);
|
||||
const session = await getServerSession(env.DB, telegramUserId);
|
||||
|
||||
if (session && session.status !== 'completed') {
|
||||
logger.info('Active server session detected, routing to consultation', {
|
||||
userId: telegramUserId,
|
||||
status: session.status
|
||||
status: session.status,
|
||||
hasLastRecommendation: !!session.lastRecommendation
|
||||
});
|
||||
const result = await processServerConsultation(userMessage, session, env);
|
||||
|
||||
// Create callback for intermediate messages
|
||||
let sendIntermediateMessage: ((message: string) => Promise<void>) | undefined;
|
||||
if (chatIdStr) {
|
||||
sendIntermediateMessage = async (message: string) => {
|
||||
logger.info('Sending intermediate message', { chatId: chatIdStr, messagePreview: message.substring(0, 50) });
|
||||
await sendMessage(env.BOT_TOKEN, parseInt(chatIdStr), message);
|
||||
logger.info('Intermediate message sent successfully', { chatId: chatIdStr });
|
||||
};
|
||||
}
|
||||
|
||||
const result = await processServerConsultation(userMessage, session, env, sendIntermediateMessage);
|
||||
|
||||
// PASSTHROUGH: 무관한 메시지는 일반 처리로 전환
|
||||
if (result !== '__PASSTHROUGH__') {
|
||||
@@ -233,13 +236,14 @@ export async function generateOpenAIResponse(
|
||||
// Continue to normal flow below
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Session check failed, continuing with normal flow', error as Error);
|
||||
logger.error('Session check failed, continuing with normal flow', error as Error, {
|
||||
telegramUserId
|
||||
});
|
||||
// Continue with normal flow if session check fails
|
||||
}
|
||||
|
||||
// Check if troubleshoot session is active
|
||||
try {
|
||||
const { getTroubleshootSession, processTroubleshoot } = await import('./troubleshoot-agent');
|
||||
const troubleshootSession = await getTroubleshootSession(env.SESSION_KV, telegramUserId);
|
||||
|
||||
if (troubleshootSession && troubleshootSession.status !== 'completed') {
|
||||
@@ -343,7 +347,9 @@ export async function generateOpenAIResponse(
|
||||
);
|
||||
if (earlyResult) {
|
||||
if (earlyResult.result.includes('__DIRECT__')) {
|
||||
return earlyResult.result.replace('__DIRECT__', '').trim();
|
||||
// Remove __DIRECT__ marker and everything before it (AI commentary)
|
||||
const directIndex = earlyResult.result.indexOf('__DIRECT__');
|
||||
return earlyResult.result.slice(directIndex + '__DIRECT__'.length).trim();
|
||||
}
|
||||
return earlyResult.result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user