Files
life-helper/CHANGELOG.md
joungmin 7037b9e245 [07-Release] #260 v0.4.0 — in-app tool calling
Phase 2-B 릴리스. on-device Gemma 4 가 6 tool 로 카탈로그/습관 CRUD.

- pubspec.yaml: 0.3.0+3 → 0.4.0+4
- CHANGELOG.md: [0.4.0] 섹션 추가
- APK: app-release.apk 287MB
  SHA-256 6670da0c4e9bf5e826174ebc48088540867d877cf58699119a519e2ffb40ea3a

회귀: 154 passed (1 skip), flutter analyze clean.

Refs #260
2026-06-15 11:13:12 +09:00

8.8 KiB

Changelog

본 프로젝트의 모든 의미있는 변경은 본 파일에 기록한다. 형식: Keep a Changelog · 버전: SemVer.

[0.4.0] — 2026-06-15

Added — Phase 2-B in-app tool calling (Redmine #260)

  • In-process Dart tool runtime (ADR-0005): MCP 와 동등한 capability 추상화를 별도 서버 없이 in-process Dart 함수로 구현. latency 거의 0.
  • 6 tools (app/lib/ai/tools/): search_catalog, query_protocol, list_active_habits, get_streak (read-only) / add_habit, log_tracker_entry (destructive).
  • Multi-turn loop (ChatSessionController) — MAX_TURNS=4 안전 cap, 8-turn soft history warning. ToolChoice.auto 로 reply-only + tool call 모두 지원.
  • ConfirmGate 모달 — destructive tool 호출 시 AlertDialog (이 작업을 수행할까요?) 의무. 좁은 화면 SingleChildScrollView.
  • 2KB result cap (ADR-0005 §OQ-2) — encodeToolResult 가 ToolOk payload 초과 시 _truncated:true + _hint 로 잘림 (chat_providers.dart:192 에서 runtime wire).
  • R 규칙 enforce = 핸들러 책임 — 모델 prompt 학습 아닌 코드 게이트. R3 quota, R5 (habit,date) dedup, R7 회피 키워드, R8 XOR (build/break) 모두 ToolErr 코드로 노출.
  • ChatScreen (app/lib/ui/screens/chat_screen.dart) — 신규 AI 코치 화면. HabitListScreen AppBar 의 🤖 entry (AI opt-in 시).
  • schema SoT = Dart 코드 (ADR-0005 §D-4) — ToolDefinition.parametersSchema Map 리터럴.

Polish (Designer)

  • ToolCallChatMessage 라벨 한국어화 (_kToolKoreanLabelsadd_habit → 습관 추가 등 6종 매핑).
  • ConfirmDialog content 를 SingleChildScrollView 로 감싸 좁은 폰 + 긴 description 대응.
  • Streaming cursor Text.rich 로 분리 후 colorScheme.primary 적용 — 다크 모드 contrast.
  • AppBar tooltip 새 대화새 대화 (이전 기록 비우기).

Added — Tests

  • 154/154 passed (1 skip) — 신규 41 → 43 (tool_envelope 6 + catalog_tools 7 + habit_tools 8 + tracker_tools 7 + dispatcher 6 + controller 8 + widget E2E 2).
  • AC-9 회귀: 인위 huge_dump tool 로 _truncated:true + _hint 직접 검증.
  • AC-10 widget E2E (test/ui/chat_screen_test.dart): add_habit 호출 → ConfirmDialog 수행 → habits +1 / 취소 → 무변화 + 취소됨 라벨.

Docs

  • 설계서 docs/design/260-gemma-tool-calling/ (5 파일, 844 라인) — README + 4 함수 fn-spec.
  • ADR-0005 — In-app tool calling architecture (4 결정사항).

Known follow-ups (후속 이슈 권장)

  • ToolDefinition.koreanLabel 필드 도입 — 현재 _kToolKoreanLabels hardcoded.
  • log_tracker_entry value=blank 시 confirm skip — 현재 done/blank 무차별 모달.
  • search_catalog category matching case-insensitive — 모델 hallucination 대비.

Release artifact

  • app-release.apk 287MB (300.9MB raw / 287MB on-disk), SHA-256 6670da0c4e9bf5e826174ebc48088540867d877cf58699119a519e2ffb40ea3a.
  • Build: flutter build apk --release (Gradle assembleRelease 106.4s).

[0.3.0] — 2026-06-12

Added — Phase 2-A OQ-1 resolved: real Gemma 4 E2B inference (Redmine #218)

  • GemmaLlmService 본문 구현 — flutter_gemma 0.16.5 위에 Gemma 4 E2B 실 추론. InferenceModel.createChat(modelType: gemma4, supportsFunctionCalls: true, toolChoice: required, tools: [...]) + collectFunctionCall(stream) 로 structured JSON 강제.
  • _LazyLlmService (main.dart) — Mock ↔ Gemma 런타임 어댑터. 매 호출마다 checkAvailability 재평가 → opt-in/opt-out 즉시 반영 (앱 재시작 불필요).
  • 실 모델 핀: gemma-4-E2B-it.litertlm 2.41GB, SHA-256 181938105e0eefd105961417e8da75903eacda102c4fce9ce90f50b97139a63c (HF litert-community/gemma-4-E2B-it-litert-lm).
  • HF_TOKEN --dart-define 주입 — 빈 기본값으로 빌드 안전.

Added — Device gate (AC-6)

  • 플랫폼 채널 life_helper/device_caps (MainActivity.ktActivityManager.MemoryInfo.totalMem) — Android 단말 실 RAM 측정. device_info_plusisLowRamDevice (~1GB) 로는 4GB 임계치 불가하여 채널 도입.
  • DeviceCapabilities 추상 + PlatformDeviceCapabilities 구현 (테스트 주입 가능). kAiMinRamBytes = 4 GiB. fail-closed (null → false).
  • deviceMeetsAiRamProvider (Riverpod FutureProvider) — SettingsScreen 토글 disabled + 안내 문구.

Added — Tests

  • 88/88 통과 — 신규 10 (device_capabilities_test.dart 7 + lazy resolve regression 3).

Polish (Designer)

  • AC-6 게이트 안내 톤 정렬 — "RAM 부족" → "이 단말에서는 AI 도움을 사용할 수 없어요 (RAM 4GB 이상 필요)".
  • _describe(missing, meetsRam:) 분기 — 토글 disabled 상황에서 "토글 켜면" 모순 제거.
  • 옵트아웃 다이얼로그 "다시 다시" 중복 → "처음부터".

Fixed (Reviewer)

  • _LazyLlmService._delegate sticky cache — 첫 호출 시점의 delegate 종류가 앱 재시작까지 유지되던 버그 (Mock → Gemma 전환 안 됨). re-resolve + (kind + modelPath) 일치 시만 캐시 재사용.
  • Reference 문서 nit 3건 — 215-ai-frame-suggest.md (L184 채널 사실 정정 / L186 F1 follow-up 매핑 / L191 OOS 기준).

Release artifact

  • app-release.apk 286MB, SHA-256 4a237d5124bfcd56aaa8c0ae89060a9ecf9ce7cc739f0b056ce66e9b9ca6b54a.

Known limitations (deferred to #219~#222)

  • AC-7 (실 단말 cold-start 예산) — DEFER. 실기기 E2E 검증은 본 릴리스 후 권고.
  • #219 F1: 60초 idle auto-unload.
  • #220 GemmaLlmService.load 동시성 가드 + isThinking:false 명시.
  • #221 AC-10 한국어 corpus ≥70%.
  • #222 HF_TOKEN keystore 기반 secret 전환.

[0.2.0] — 2026-06-12

Added — Phase 2-A: On-device Gemma 4 frame suggestion (Redmine #215)

  • LlmService 추상 인터페이스 + MockLlmService (테스트/v1 런타임 주입) + GemmaLlmService stub (OQ-1 시점 활성화).
  • ModelLifecycle — Range 기반 재개 가능 다운로드 + SHA-256 검증 + opt-out 즉시 삭제.
  • ModelDownloadController (Riverpod StateNotifier) — start / pause / resume / cancel.
  • 도메인 함수 suggestFrame + buildFewShotPrompt + parseFrameCandidates (모두 순수, graceful — 실패 시 빈 리스트).
  • FrameSuggestionDialog — L2/L3 후보 카드 + 컬러 배지.
  • SettingsScreen 신규 — AI 도움 토글 (기본 OFF, 옵트인 시 동의 다이얼로그 → 다운로드 시작), 진행률 + 일시정지/재개/취소, 옵트아웃 시 즉시 purge + 해제 공간 토스트.
  • HabitCreateScreen 의 "AI 제안" 버튼 3분기 (hidden / visible+disabled+tooltip / enabled).
  • ADR-0003 — on-device LLM Gemma 도입 결정 + 5 대안 기각.
  • 설계서 docs/design/215-gemma-frame-suggest/ (README + fn-suggest_frame + fn-model_lifecycle).
  • 신규 31 테스트 (parse 8 + few_shot 7 + suggest 12 + lifecycle 7 + AC2 state 3 + AC6 widget 4).
  • 9/10 AC PASS — AC10 (한국어 평가 corpus ≥70%) DEFER → OQ-1 해결 후 수행.

Architecture

  • lib/data/ai/ (I/O 경계) ↔ lib/domain/ai/ (순수 도메인) 분리.
  • meta_kv 5 키 추가 (ai_opt_in / ai_model_path / ai_model_sha256 / ai_download_state / ai_download_bytes) — schema migration 0.
  • 프라이버시: 사용자 raw text 단말 밖 송출 0. 추론 100% 단말.

Known limitations

  • OQ-1 미해결: 실제 Gemma 4 E2B Q4_0 모델 URL + SHA-256 미확정. _kModelUrlPlaceholder / _kModelShaPlaceholder 상태. v1 런타임은 MockLlmService 주입 — opt-in 토글 시 다운로드는 placeholder URL 로 실패 (graceful 처리).
  • F1: 60초 idle auto-unload 미구현 (현재 stub 라 무의미).
  • F2: ModelLifecycle.purge()File.delete() try/catch 미감쌈 (placeholder URL 라 도달 불가).
  • 위 3건 모두 OQ-1 후속 이슈에서 처리.

Polish (Designer)

  • 다운로드 타일 상태 라벨 + 컬러 텍스트 + 라운드 progress bar + FilledButton.tonalIcon 재개/재시도.
  • _friendlyError() — 내부 코드 (network: / http / stream: / sha mismatch) 를 한국어 다음행동 문구로 매핑.
  • 옵트인/아웃 다이얼로그 _Bullet 위젯으로 정렬.
  • FrameCandidate 카드에서 confidence% 표기 제거 (내부값).

[0.1.0] — 2026-06-12 (retro-tagged)

Added — Phase 1 MVP (Redmine #204)

  • Flutter 3.x + Drift 21 테이블 (habits, habit_variants, checkins, ladders, frame_patterns, reward_menu_items, references, protocols, methodologies, diet_patterns ...).
  • 도메인 함수 6개 (validateFrameLevel / judgeActiveHabitQuota / computeStreak / 등).
  • UI 화면 4개 (HabitListScreen / HabitCreateScreen / CheckinScreen / RewardListScreen).
  • 시드 데이터 8 JSON (refs 84 / protocols 34 / break 8 / common 5 / methodology 21 / frame 30 / reward 30 / diet 5).
  • ADR-0001 (dose_variants 도입) + ADR-0002 (정규화 방식).
  • 62 테스트 통과.