- db/database.py: conversation_messages 테이블 + save/load/cleanup 헬퍼
- conversation.py: write-through (memory + DB) + lazy load on first access
- 메모리 캐시 1시간 TTL, DB 7일 보관
- add/get/format_for_prompt가 async로 변경
- worker.py: 모든 conversation_store 호출에 await 추가
- main.py lifespan에 startup cleanup 호출 (7일 이상 정리)
서버 재시작 후 "방금 그거 더 자세히" 같은 후속 질문이 컨텍스트 유지
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
reasoner_messages에 conversation_store의 최근 10개 메시지 포함.
"더 자세히 설명해줘" 같은 후속 질문이 이전 컨텍스트를 잇도록.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
EXAONE classifier가 route prompt 필드에 답변을 미리 작성해서
Gemma가 그것을 사용자 입력으로 받아 메타 응답을 하는 문제.
원본 job.message를 그대로 Gemma에 전달하도록 변경.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 분류기 input의 [현재 시간]을 KST로 명시
- reasoner system prompt에도 현재 KST 시간 주입
- GPU 서버가 UTC라 모델이 시간 개념을 이상하게 가졌던 문제 해결
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- model_adapter: measure_inference_latency() (max_tokens=1, 최소 부하)
- backend_registry:
- health latency baseline 학습 (초기 5회 max, 이후 EMA)
- get_load_status(): inference 우선, health/queue 보조
- cache 30s + cooldown 10s + asyncio.Lock으로 자기증폭 루프 방지
- 조건: health > baseline*3 또는 사용자 명시 요청 시에만 ping
- worker:
- "system_status" 액션 — 사용자 상태 조회 시 force_measure
- _build_system_status() 응답 빌더 (health/baseline/ping/queue)
- route busy 안내를 get_load_status 기반으로 변경
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
"create post too fast" 에러로 응답이 누락되던 문제.
전송 간 최소 1.5초 간격 보장 + API success:false 시 2초 후 1회 재시도.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
"테크니컬코리아 메일만" → Technicalkorea 폴더만 검색
"구글 메일" → Gmail만, "개인 메일" → INBOX만
폴더 미지정 시 전체 검색 유지
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- email_tool: INBOX/Gmail/Technicalkorea 3개 폴더 순회
- 폴더별 try/except isolation (하나 실패해도 나머지 조회)
- UID → folder:uid 형식 (폴더간 충돌 방지)
- 날짜 parsedate_to_datetime 정렬
- 폴더 라벨 표시 (개인/Gmail/회사)
- worker: response_sent 플래그 + finally 무응답 방지
- 어떤 에러 경로에서든 Synology에 최소 1회 응답 보장
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
분류기 system prompt가 JSON 강제라서 결과 포맷도 JSON으로 나옴.
도구 결과 정리 시 별도 평문 프롬프트를 messages로 직접 전달.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
EXAONE 7.8B가 복잡한 JSON 분류를 안정적으로 못함.
키워드 매칭으로 일정/메일/문서/확인 요청을 사전 감지하여
분류기를 건너뛰고 바로 도구로 라우팅.
날짜 계산(오늘/내일/이번주)도 코드에서 처리.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- _parse_classification: 어떤 형태든 첫{~마지막} 추출, 백틱 잔재 제거
- 분류기: 판단 예시 추가 (일정→tools, 인사→direct 등), 백틱/코드블록 금지 명시
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
응답이 중간에 끊기는 문제 해결. ModelAdapter에 max_tokens
파라미터 추가, stream/complete 양쪽 payload에 반영.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- EXAONE: 분류기+프롬프트엔지니어+직접응답 (JSON 출력)
- 간단한 질문은 EXAONE이 직접 답변 (파이프라인 스킵)
- 복잡한 질문은 AI 최적화 프롬프트로 Gemma에 전달
- 모호한 질문은 사용자에게 추가 질문 (clarify)
- user별 최근 대화 기억 (최대 10개, 1시간 TTL)
- ModelAdapter: messages 직접 전달 옵션 추가
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- reasoner: EXAONE+Gemma4 파이프라인 자기 인식 추가
- rewriter: 간단한 질문/인사는 원문 그대로 통과, 복잡한 것만 재구성
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- POST /webhook/synology: outgoing webhook 수신 + token 검증
- 파이프라인 완료 시 incoming webhook으로 응답 자동 전송
- "분석 중..." typing 메시지 선전송
- 응답 길이 1500자 제한 (Synology Chat 제한 대응)
- 에러/실패 시에도 사용자에게 알림 메시지 전송
- 중복 요청 방지 (30초 TTL dedup)
- Synology에서 rewrite 이벤트 숨김 (SSE에서만 노출)
- callback 구조로 확장 가능 (Slack, Discord 등)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- ModelAdapter: 범용 OpenAI-compat 어댑터 (stream/complete/health)
- BackendRegistry: rewriter(EXAONE) + reasoner(Gemma4) 헬스체크 루프
- 2단계 파이프라인: EXAONE rewrite → Gemma reasoning (SSE rewrite 이벤트 노출)
- Fallback: 맥미니 다운 시 EXAONE 단독 모드, stream 중간 실패 시 자동 전환
- Cancel-safe: rewrite 전/후, streaming loop 내, fallback 경로 모두 체크
- Rewrite heartbeat: complete_chat 대기 중 2초 간격 processing 이벤트
- JobQueue: Semaphore(3) 기반 동시성 제한, 정확한 queue position
- GET /chat/{job_id}/status, GET /queue/stats 엔드포인트
- DB: rewrite_model, reasoning_model, rewritten_message 컬럼 추가
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
POST /chat → job_id ACK, GET /chat/{job_id}/stream → SSE 스트리밍,
EXAONE Ollama adapter, JobManager, StateStream, Worker 구조
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Caddy 프록시를 거치면서 httpOnly 쿠키가 제대로 전달 안 되는 문제.
로그인 시 받은 토큰을 메모리에 저장하고 Authorization: Bearer 헤더로
전송하는 방식으로 변경. 쿠키 의존성 제거.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
MLX 서버 모델 ID(mlx-community/Qwen3.5-35B-A3B-4bit)와
사용자 노출 ID(qwen3.5:35b-a3b)가 달라 500 에러 발생.
registry에 backend_model_id 필드 추가하여 프록시 시 변환.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- proxy_openai.py 추가: MLX 서버 SSE 패스스루
- chat.py: openai-compat 백엔드 타입 라우팅 추가
- backends.json: GPU=embed(bge-m3)만, 맥미니MLX=채팅(qwen3.5:35b-a3b)
- LAN IP(192.168.1.122) 사용 (같은 서브넷, Tailscale 불필요)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>