2afd1ac589
신뢰성 코어 (P1~P2): - Requirement Graph: 업무 유형(회의록/시장조사/업무조사/일정) 필수 요소 주입 + 커버리지 hook - Confidence Engine(0~100 결정론적) / Escalation Engine(검토 요청) / Epistemic Guard(모름·추정·확실 3분류) - Provenance: citationTrace 에 출처 수정일·오래됨 경고 - Critic Loop: 문제 신호 turn 만 LLM 검수 1회 + 보완 카드 성장 루프 (P3): - Gap Detector(Requirement-Knowledge) / Need Engine(30/25/20/15/10 공식) / Knowledge Inventory - Learning Queue(proposed 전용 병합 — 승인은 사람만) / Decision Journal / Reflection 기록 - 반복 누락 요소(3회+)는 다음 turn 체크리스트에 자동 강조 (T5 루프) 지식 운영 (P4) + 기억 (P5) + 학습 실행 (P6): - Knowledge Validation + Belief Revision(중복 reject·충돌 시 update/add 권고) - Knowledge Decay(분야별 반감기 감사) / Knowledge Debt(blocked x impact) - Organizational Memory(.astra/organization.md 상시 주입) - Research Agent(approved 큐 -> 조사 브리프+추정 라벨 초안+Validation 게이트 -> proposals/) - Skill Score(전/후반 추세) + Success Pattern DB(전요소충족+확신도90+ 자동 적재) 병렬 트랙: - 캘린더 충돌 게이트: conflictCheck + 구조화 이벤트 캐시 + create_calendar_event 차단(force 는 사용자 승인 후) - Task Eval Harness: 회의록 골든셋 자동 채점 명령 + 성장 리포트/학습 큐/노후 점검 명령 신규 모듈 17종(src/intelligence/), VS Code 명령 5종, 설정 11종, 테스트 +89건(전체 508 통과). 설계 문서: docs/SELF_EVOLVING_OS_MASTER_PLAN.md Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
67 lines
3.6 KiB
TypeScript
67 lines
3.6 KiB
TypeScript
import { HandlerContext } from './types';
|
|
import { _parseCalEventAttrs } from '../attrParsers';
|
|
|
|
export async function applyCalendarActions(ctx: HandlerContext): Promise<void> {
|
|
const { aiMessage, report } = ctx;
|
|
let match: RegExpExecArray | null;
|
|
// Action 8: Create Calendar Event (OAuth) — agent 가 회의록·작업 분석 후 일정 자동 생성.
|
|
// 형식: <create_calendar_event title="..." start="2026-05-21T14:00" duration="60" location="...">설명</create_calendar_event>
|
|
// 속성: title (필수), start (필수, ISO 'YYYY-MM-DDTHH:MM' 또는 timezone 포함),
|
|
// end | duration (분, default 60), location, all_day (true/false)
|
|
const calRegex = /<create_calendar_event\b([^>]*)>([\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)}`); }
|
|
}
|
|
}
|