f512d94c74
git-subtree-dir: clients/ds-app git-subtree-mainline:a24e3e6f22git-subtree-split:5206cf3b0c
97 lines
4.9 KiB
JSON
97 lines
4.9 KiB
JSON
{
|
|
"_meta": {
|
|
"fixture": "foundationmodels-respond",
|
|
"purpose": "S2-3a — Apple FoundationModels live capture (OnDeviceProvider 결선 + 테스트 동결 기준)",
|
|
"captured_on": "M5 Max MacBook Pro (128GB, Apple Intelligence)",
|
|
"captured_date": "2026-06-04",
|
|
"sdk": "macOS 26.5 SDK / FoundationModels.framework",
|
|
"note": "SDK 가 marshaling 하므로 raw request_body 는 없음. 이 파일은 응답 모양 + 에러 타입 + 취소 동작의 동결 기준."
|
|
},
|
|
|
|
"availability": {
|
|
"observed": "available",
|
|
"is_available_convenience": true,
|
|
"read_is_synchronous": true,
|
|
"api": "SystemLanguageModel.default.availability",
|
|
"enum": {
|
|
"available": "case available",
|
|
"unavailable_reasons": ["deviceNotEligible", "appleIntelligenceNotEnabled", "modelNotReady"]
|
|
},
|
|
"supports_korean": true,
|
|
"supported_language_count": 23
|
|
},
|
|
|
|
"happy_path": {
|
|
"api": "session.respond(to: String, options: GenerationOptions) async throws -> Response<String>",
|
|
"content_accessor": "response.content (Response<String>.content : String)",
|
|
"observed_content": "압력용기의 충격시험(Charpy) 면제 판정은, 용기의 압력 등급이 10MPa 이하인 경우, 충격 시험을 면제할 수 있으며, 이는 용기의 안전성을 보장하기 위한 중요한 기준입니다.",
|
|
"observed_latency_ms": 1291.3,
|
|
"transcript_entries_count": 1,
|
|
"is_responding_after": false,
|
|
"quality_note": "내용은 부정확(온디바이스 ~3B/2-bit QAT). corpusAsk 부적합·quickSummarize/classify 적합 라우팅 정합 — 사실성은 RemoteDS 코퍼스가 담당."
|
|
},
|
|
|
|
"session_init": {
|
|
"api": "LanguageModelSession(model: .default, tools: [], instructions: String?)",
|
|
"instructions_timing": "init (per-call 아님)",
|
|
"instructions_nil_handling": "systemPrompt == nil 이면 instructions 인자 생략 (빈 문자열 금지)",
|
|
"prewarm": "session.prewarm() — 동기 반환(관찰 ~1.3ms), 백그라운드 워밍",
|
|
"stateless_per_request": "호출마다 새 세션 생성 → instructions(init-time) + rateLimited/concurrentRequests(세션 상태) 둘 다 우회"
|
|
},
|
|
|
|
"generation_options": {
|
|
"api": "GenerationOptions(sampling: SamplingMode? = nil, temperature: Double? = nil, maximumResponseTokens: Int? = nil)",
|
|
"mapping": "AICompletionRequest.maxTokens -> maximumResponseTokens",
|
|
"temperature_note": "AICompletionRequest 에 temperature 필드 없음(동결) → 미설정(모델 기본). LocalMLX 와 동일 정책(둘 다 미설정)."
|
|
},
|
|
|
|
"generation_error": {
|
|
"_source": "Xcode jump-to-def / swiftinterface (LanguageModelSession.GenerationError) — authoritative, version-accurate",
|
|
"type": "LanguageModelSession.GenerationError : Error, LocalizedError",
|
|
"associated_value": "각 case 는 GenerationError.Context (refusal 은 (Refusal, Context))",
|
|
"cases": [
|
|
"exceededContextWindowSize(Context)",
|
|
"assetsUnavailable(Context)",
|
|
"guardrailViolation(Context)",
|
|
"unsupportedGuide(Context)",
|
|
"unsupportedLanguageOrLocale(Context)",
|
|
"decodingFailure(Context)",
|
|
"rateLimited(Context)",
|
|
"concurrentRequests(Context)",
|
|
"refusal(Refusal, Context)"
|
|
],
|
|
"plan_corrections": [
|
|
"plan 가정 'refusal 케이스명 없음' = 틀림 → refusal 은 별도 case 로 존재(guardrailViolation 과 구분).",
|
|
"plan 에 없던 concurrentRequests case 존재 — rateLimited 와 함께 stateless 세션에서 뜨면 세션 공유 버그 신호.",
|
|
"assetsUnavailable 정확명 확정(모델 자산 미가용)."
|
|
],
|
|
"reproduced_live": {
|
|
"exceededContextWindowSize": {
|
|
"trigger": "의도적 컨텍스트 오버플로(긴 프롬프트)",
|
|
"errorDescription": "Exceeded model context window size"
|
|
}
|
|
},
|
|
"finish_reason_mapping": {
|
|
"guardrailViolation": ".refused",
|
|
"refusal": ".refused",
|
|
"exceededContextWindowSize": ".unavailable",
|
|
"rateLimited": ".unavailable + loud log (stateless 인데 발생 = 세션 재사용 버그 신호)",
|
|
"concurrentRequests": ".unavailable + loud log (동일 — stateless 위반 신호)",
|
|
"unsupportedLanguageOrLocale": ".unavailable (+ supportedLocale 사전체크로 회피)",
|
|
"unsupportedGuide": ".unavailable",
|
|
"decodingFailure": ".unavailable",
|
|
"assetsUnavailable": ".unavailable",
|
|
"@unknown default": ".unavailable + loud log"
|
|
}
|
|
},
|
|
|
|
"cancellation": {
|
|
"_finding": "S2-Fe 전제 확정 — COOPERATIVE",
|
|
"cancel_requested_at_ms": 500,
|
|
"threw": "CancellationError",
|
|
"elapsed_ms": 533.6,
|
|
"interpretation": "respond() 는 mid-flight Task 취소를 협조적으로 honor(요청 33ms 후 CancellationError throw).",
|
|
"implication": "OnDevice complete() 에 surrounding Task.checkCancellation() 은 belt-and-suspenders(실제 중단은 respond() 내부). streamResponse 토큰단위 취소 폴백 불필요(선전환 금지)."
|
|
}
|
|
}
|