Jev 내담자 평가·표현 v2와 속마음 공개
상담자 발화 판정(A)·감정(B)·표현(C) 20문항 질문 세트, 감쇠 없는 이번 턴 반응과 비대칭 기분 전이, 개방도 게이트로 생성 지시를 만들고 ccd.coping_strategy 전달 누락을 고친다. trace v2와 고정 문구 속마음 요약(migration 24, AI 경로 차단 RLS)을 같은 트랜잭션에 저장하고 피드백 정책이 켜진 경우에만 done·TurnResponse·음성 reply·리뷰로 노출한다. 회기 화면 속마음 보기 토글, 리뷰 접힘 블록, 관리자 감정 관측 v2 표시를 추가한다.
This commit is contained in:
parent
36cb847e38
commit
29c406d89f
39 changed files with 5726 additions and 343 deletions
|
|
@ -14,7 +14,11 @@ from typing import Any, Awaitable, Callable, Iterable, Literal
|
|||
from .db import acquire, get_pool
|
||||
from .deps import Principal
|
||||
from .config import settings
|
||||
from .contracts.client_affect import ClientAffectTraceV1
|
||||
from .contracts.client_affect import (
|
||||
ClientAffectTraceV1,
|
||||
ClientAffectTraceV2,
|
||||
ClientInnerReactionV1,
|
||||
)
|
||||
from .persona_repository import (
|
||||
SEED_VERSION,
|
||||
card_from_row,
|
||||
|
|
@ -2903,9 +2907,14 @@ async def append_client_turn_with_affect_trace(
|
|||
learner_id: str,
|
||||
turn: TurnRecord,
|
||||
state: state_machine.SessionState,
|
||||
trace: ClientAffectTraceV1,
|
||||
trace: ClientAffectTraceV1 | ClientAffectTraceV2,
|
||||
inner_reaction: ClientInnerReactionV1 | None = None,
|
||||
) -> bool:
|
||||
"""성공 내담자 턴·Jev trace·전이 상태를 하나의 DB 트랜잭션에 기록한다."""
|
||||
"""성공 내담자 턴·Jev trace·전이 상태를 하나의 DB 트랜잭션에 기록한다.
|
||||
|
||||
inner_reaction이 있으면(§8.2) trace insert 직후 같은 트랜잭션에서
|
||||
app.client_inner_reaction에도 기록한다. None이면 insert를 생략한다.
|
||||
"""
|
||||
inserted_turn_id: str | None = None
|
||||
try:
|
||||
get_pool()
|
||||
|
|
@ -2977,6 +2986,16 @@ async def append_client_turn_with_affect_trace(
|
|||
session_id,
|
||||
trace.model_dump(mode="json"),
|
||||
)
|
||||
if inner_reaction is not None:
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO app.client_inner_reaction (turn_id, session_id, reaction)
|
||||
VALUES ($1::uuid, $2::uuid, $3::jsonb)
|
||||
""",
|
||||
inserted_turn_id,
|
||||
session_id,
|
||||
inner_reaction.model_dump(mode="json"),
|
||||
)
|
||||
await _upsert_state(conn, session_id, state)
|
||||
except ClientAffectTracePersistenceError:
|
||||
raise
|
||||
|
|
@ -2991,6 +3010,41 @@ async def append_client_turn_with_affect_trace(
|
|||
return True
|
||||
|
||||
|
||||
async def list_client_inner_reactions(
|
||||
session_id: str,
|
||||
principal: Principal,
|
||||
) -> dict[str, ClientInnerReactionV1]:
|
||||
"""세션의 학습자·교수자용 속마음 요약을 turn_id로 매핑해 반환한다.
|
||||
|
||||
호출자의 실제 역할·cohort로 acquire하며 RLS(§8.2 SELECT 정책 + app.sessions의
|
||||
instructor cohort 요구)가 접근을 걸러낸다. cohort_ids를 넘기지 않으면 교수자는
|
||||
app.sessions SELECT RLS(04_audit_eval_rls.sql)를 통과하지 못해 항상 빈 결과를
|
||||
받는다. DB 미가용 환경에서는 다른 회기 파생 조회와 같은 패턴으로 빈 dict를 돌려준다.
|
||||
"""
|
||||
try:
|
||||
get_pool()
|
||||
async with acquire(
|
||||
role=principal.role.value,
|
||||
user_id=principal.user_id,
|
||||
cohort_ids=principal.cohort_ids,
|
||||
) as conn:
|
||||
rows = await conn.fetch(
|
||||
"""
|
||||
SELECT turn_id, reaction
|
||||
FROM app.client_inner_reaction
|
||||
WHERE session_id = $1::uuid
|
||||
""",
|
||||
session_id,
|
||||
)
|
||||
except Exception:
|
||||
require_runtime_fallback_allowed("client inner reaction read")
|
||||
return {}
|
||||
return {
|
||||
str(row["turn_id"]): ClientInnerReactionV1.model_validate(row["reaction"])
|
||||
for row in rows
|
||||
}
|
||||
|
||||
|
||||
async def update_state(
|
||||
*,
|
||||
session_id: str,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue