import { HandlerContext } from './types'; import { _parseCalEventAttrs } from '../attrParsers'; export async function applyCalendarActions(ctx: HandlerContext): Promise { const { aiMessage, report } = ctx; let match: RegExpExecArray | null; // Action 8: Create Calendar Event (OAuth) — agent 가 회의록·작업 분석 후 일정 자동 생성. // 형식: 설명 // 속성: title (필수), start (필수, ISO 'YYYY-MM-DDTHH:MM' 또는 timezone 포함), // end | duration (분, default 60), location, all_day (true/false) const calRegex = /]*)>([\s\S]*?)<\/create_calendar_event>/gi; while ((match = calRegex.exec(aiMessage)) !== null) { const attrs = _parseCalEventAttrs(match[1]); const desc = match[2].trim(); if (!attrs.title || !attrs.start) { report.push(`❌ Calendar Event: title / start 누락`); continue; } // ── 충돌 게이트 (Self-Evolving OS Track 6-2/6-3) — 기존 일정과 겹치면 생성 보류. // force="true" 는 사용자 확인 후에만 (Constitution: 승인 없는 외부 액션 금지). try { const { readCalendarEventsCache } = await import('../../features/calendar'); const { findScheduleConflicts, formatConflictReport } = await import('../../features/calendar/conflictCheck'); const existing = readCalendarEventsCache(ctx.context); const conflicts = findScheduleConflicts(existing, { startIso: attrs.start, endIso: attrs.end, durationMinutes: attrs.duration, allDay: attrs.allDay, }); if (conflicts.length > 0 && attrs.force !== true) { const msg = formatConflictReport(conflicts); report.push(`⚠️ Calendar Event 보류 — ${attrs.title}: 일정 충돌 ${conflicts.length}건`); ctx.chatHistory.push({ role: 'system', content: `[Calendar conflict — 생성 보류] "${attrs.title}" (${attrs.start})\n${msg}\n사용자에게 충돌 사실을 알리고 진행 여부를 물을 것.`, internal: true, }); continue; } } catch { /* 충돌 검사 실패가 일정 생성을 막지 않음 — 캐시 없으면 검사 skip */ } try { const { createCalendarEvent } = await import('../../features/calendar'); const r = await createCalendarEvent(ctx.context, { title: attrs.title, start: attrs.start, end: attrs.end, durationMinutes: attrs.duration, location: attrs.location, description: desc || undefined, allDay: attrs.allDay, }); if (r.ok) { report.push(`📅 Calendar Event Created: ${r.event.title} (${r.event.startIso})`); // chatHistory 에 결과 주입 — agent 가 다음 답변에서 link 인용 가능. ctx.chatHistory.push({ role: 'system', content: `[Calendar event created] ${r.event.title} · ${r.event.startIso}\nLink: ${r.event.htmlLink}`, internal: true, }); } else { report.push(`❌ Calendar Event Failed: ${r.error}`); } } catch (err: any) { report.push(`❌ Calendar Event Error: ${err?.message ?? String(err)}`); } } }