라이브코치 소스팩 새로고침 보강

This commit is contained in:
Yun Chan 2026-06-28 23:52:55 +09:00
parent 84599bbaa2
commit 1e9f293fda
5 changed files with 182 additions and 8 deletions

View file

@ -18,11 +18,12 @@ import hashlib
from functools import lru_cache
from typing import TYPE_CHECKING, Any, Literal, Optional
from pydantic import BaseModel, Field
from pydantic import BaseModel, Field, field_validator
from ..config import settings
from ..engine_client import EngineClient, EngineError, EngineMessage, GenerateRequest, GenerateResponse
from ..paths import repo_root, repo_path
from ..session_read_model import StageLabel, stage_label_or_none
from . import guardrail
if TYPE_CHECKING:
@ -77,12 +78,17 @@ class LiveCoachEvent(BaseModel):
event_id: str
session_id: str
turn_seq: int
stage: str
stage: StageLabel | None = None
created_at: str
learner_text_excerpt: Optional[str] = None
client_reply_excerpt: Optional[str] = None
suggestion: LiveCoachSuggestion
@field_validator("stage", mode="before")
@classmethod
def _normalize_stage(cls, value: object) -> StageLabel | None:
return stage_label_or_none(value)
class LiveCoachInput(BaseModel):
"""라이브 코칭 입력. raw text는 서비스 내부에서 마스킹 후 프롬프트에 쓴다."""
@ -126,6 +132,8 @@ _ALLOWED_KB_KINDS = {
"ko_context",
"microskill",
}
LOCAL_SOURCE_PACK_CACHE_KEY = "repo:data/kb/live_coaching_workbook_0615.json+data/kb/live_coaching_sources/*.json"
LOCAL_SOURCE_PACK_CACHE_LIFETIME = "api-process"
def _configured_model(value: str | None) -> str | None:
@ -135,6 +143,13 @@ def _configured_model(value: str | None) -> str | None:
@lru_cache(maxsize=1)
def _local_source_entries() -> tuple[tuple[str, dict[str, Any]], ...]:
"""Load repo-managed live-coach source packs.
Cache ownership: live turn generation keeps this process-local snapshot to
avoid per-turn file IO. Admin/CLI source-pack sync is the invalidation
boundary because that path explicitly compares repo files with kb.document.
"""
entries: list[tuple[str, dict[str, Any]]] = []
paths = [_WORKBOOK_PATH]
if _SOURCE_DIR.exists():
@ -164,6 +179,12 @@ def _local_source_entries() -> tuple[tuple[str, dict[str, Any]], ...]:
)
def clear_local_source_pack_cache() -> None:
"""Invalidate the process-local source pack snapshot for admin/CLI refresh."""
_local_source_entries.cache_clear()
def _local_source_payloads() -> list[dict[str, Any]]:
return [payload for _, payload in _local_source_entries()]
@ -673,5 +694,6 @@ __all__ = [
"LiveCoachInput",
"LiveCoachSource",
"LiveCoachSuggestion",
"clear_local_source_pack_cache",
"generate_live_coaching",
]