From bd71bba2da93adc0cda315ac6d42a1b230a7bc74 Mon Sep 17 00:00:00 2001
From: th-kim0823
Date: Tue, 12 May 2026 13:39:11 +0900
Subject: [PATCH] =?UTF-8?q?chore(release):=20v0.3.13=20=E2=80=94=20vision?=
=?UTF-8?q?=20generate=20timeout=20120s=20=E2=86=92=20300s?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
gemma4:26b (25B MoE + vision encoder 550M) 등 대형 vision 모델의
cold-start 가 60-180s 소요. 기본 120s timeout 으로 첫 호출 fail 빈번.
vision path 에 한해 Math.max(timeoutMs, 300_000) — text-only 영향 없음.
gemma4:26b 가 Text+Image 양 modality 지원 검증 완료
(blog.google/gemma-4, ollama.com/library/gemma4:26b).
Co-Authored-By: Claude Opus 4.7 (1M context)
---
CHANGELOG.md | 27 +++++++++++++++++++++++++++
package-lock.json | 4 ++--
package.json | 2 +-
src/main/ai/LocalOllamaProvider.ts | 6 +++++-
4 files changed, 35 insertions(+), 4 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 57183f6..2d2aea2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,33 @@
본 파일은 Inkling 의 버전별 사용자 영향 변경 사항을 기록한다.
형식은 [Keep a Changelog](https://keepachangelog.com/) 를 느슨하게 따른다.
+## [0.3.13] — 2026-05-12
+
+대형 vision 모델 (gemma4:26b 등) 의 cold-start timeout 으로 인한 AI 처리 실패 fix.
+
+### 수정
+
+- **Vision generate 의 timeout 확장 120s → 300s (P1).** `gemma4:26b` (25B MoE 가중치 + vision encoder 550M) 같은 대형 vision 모델은 첫 generate 시 모델 load + 이미지 encoding 으로 60-180s 소요. 기본 120s timeout 으로 첫 호출 시 abort → fail 빈번. vision path 에 한해 `Math.max(timeoutMs, 300_000)` 적용 (text-only path 영향 없음).
+
+확인: gemma4 family 는 [공식 release](https://blog.google/innovation-and-ai/technology/developers-tools/gemma-4/) — 26B variant 가 Text+Image 양 modality 지원 ([ollama library](https://ollama.com/library/gemma4:26b)). 본 코드의 `VisionDetect` 가 'gemma4' family 인식하므로 사용자가 settings → Vision 섹션에서 선택 가능.
+
+### 사용자 안내
+
+이미지 AI 처리가 여전히 실패한다면:
+1. 설정 → AI 제공자 → Vision 섹션에서 `gemma4:26b` (또는 vision-capable 모델) 가 선택돼있는지 확인
+2. `ollama list` 로 모델 실제 설치 여부 확인 (`ollama pull gemma4:26b` 필요)
+3. NoteCard 의 failed 노트 텍스트 위에 마우스 오버 → tooltip 의 `ai_error` 확인 (구체 fail mode 진단)
+
+### 게이트
+
+- 단위 752 PASS (timeout 상수만 변경 — 회귀 없음)
+- typecheck 0 errors
+- 신규 npm dependency 0
+
+### 업그레이드
+
+v0.3.12 인스톨러 위에 v0.3.13 인스톨러를 같은 위치에 실행하면 in-place 업그레이드.
+
## [0.3.12] — 2026-05-12
이미지 AI 처리 실패 fix. vision model 의 응답이 strict JSON 이 아닌 경우 (markdown fence / prose 섞임) 가 흔해 schema parse 단계에서 throw → `ai_status='failed'` 도달.
diff --git a/package-lock.json b/package-lock.json
index f2666a0..b52e644 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "inkling",
- "version": "0.3.12",
+ "version": "0.3.13",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "inkling",
- "version": "0.3.12",
+ "version": "0.3.13",
"dependencies": {
"better-sqlite3": "12.9.0",
"electron-log": "5.2.0",
diff --git a/package.json b/package.json
index 3773ff8..ea76f9d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "inkling",
- "version": "0.3.12",
+ "version": "0.3.13",
"private": true,
"description": "Inkling — local-first 한 줄 보관 도구",
"author": "altair823 ",
diff --git a/src/main/ai/LocalOllamaProvider.ts b/src/main/ai/LocalOllamaProvider.ts
index 818df67..ca510da 100644
--- a/src/main/ai/LocalOllamaProvider.ts
+++ b/src/main/ai/LocalOllamaProvider.ts
@@ -62,8 +62,12 @@ export class LocalOllamaProvider implements InferenceProvider {
? buildVisionPrompt(input.text, input.todayKst, input.dueDateCandidates.map((c) => c.iso ?? c.matchedToken ?? ''), input.vocab ?? [])
: buildPrompt(input.text, input.todayKst, input.dueDateCandidates, input.vocab ?? []);
+ // v0.3.13 — vision model 은 cold-start (모델 load + 이미지 encoding) 가 매우 느려
+ // 120s 기본 timeout 으로 첫 호출 fail 빈번. gemma4:26b (MoE 25B) 같은 대형 vision
+ // 모델은 첫 generate 가 60-180s 소요. 5분 (300s) 으로 확장.
+ const effectiveTimeout = useVision ? Math.max(this.timeoutMs, 300_000) : this.timeoutMs;
this.abortController = new AbortController();
- const timer = setTimeout(() => this.abortController?.abort(), this.timeoutMs);
+ const timer = setTimeout(() => this.abortController?.abort(), effectiveTimeout);
try {
const body: Record = {
model,