diff --git a/apps/web/config/chat-models.yaml b/apps/web/config/chat-models.yaml index e85903206..a59c68636 100644 --- a/apps/web/config/chat-models.yaml +++ b/apps/web/config/chat-models.yaml @@ -17,27 +17,29 @@ version: 1 models: - # Default: Google Gemini. Reached at - # CHAT_BASE_URL=https://generativelanguage.googleapis.com/v1beta/openai, - # which is also where chat falls back when CHAT_BASE_URL is unset. + # Default: Google Gemini, reached through OpenRouter + # (CHAT_BASE_URL=https://openrouter.ai/api/v1). # - # Model ids here are the BARE ids Google's endpoint expects. The `google/` - # prefix belongs only to the `preset:` field, which names a bundled behavior - # entry — see packages/core/src/llm/presets.ts. + # Ids are sent to the endpoint verbatim, so they carry OpenRouter's `google/` + # vendor prefix. Talking to Google's own compatibility endpoint + # (https://generativelanguage.googleapis.com/v1beta/openai, also the fallback + # when CHAT_BASE_URL is unset) instead? Drop the prefix from `id:` — it + # expects the bare ids. The `preset:` field is unaffected either way: it names + # a bundled behavior entry, not a model on the endpoint. primary: - id: gemini-2.5-flash + id: google/gemini-2.5-flash preset: google/gemini-2.5-flash # The cheap tier. Its preset sets reasoning `default: none`, so routine work # does not pay for thinking tokens. fast: - id: gemini-2.5-flash-lite + id: google/gemini-2.5-flash-lite preset: google/gemini-2.5-flash-lite # The reasoning tier. 2.5 Pro always reasons, so its preset omits the `none` # level rather than claiming a capability the endpoint would reject. deep: - id: gemini-2.5-pro + id: google/gemini-2.5-pro preset: google/gemini-2.5-pro # Talking to something else instead? Any OpenAI-compatible endpoint works — diff --git a/services/document-converter/src/docling.ts b/services/document-converter/src/docling.ts index 684cca60b..cda96abf3 100644 --- a/services/document-converter/src/docling.ts +++ b/services/document-converter/src/docling.ts @@ -1,6 +1,6 @@ /** * docling-serve client — the consolidation of the old ocr-worker's - * docling_runner.py. Same conversion parameters (to_formats=["md"], do_ocr, + * docling_runner.py. Same conversion parameters (to_formats=md, do_ocr, * do_table_structure, image_export_mode=placeholder); failures surface as * typed ServiceErrors instead of opaque 500s. */ @@ -25,7 +25,10 @@ export const doclingConvertFile: DoclingConvert = async (config, file, filename) const form = new FormData(); form.append("files", new Blob([new Uint8Array(file)]), filename); - form.append("to_formats", '["md"]'); + // One repeated form field per format. docling-serve validates each entry + // against its OutputFormat enum, so a JSON-encoded array ("[\"md\"]") + // arrives as a single bogus member and the request fails 422. + form.append("to_formats", "md"); form.append("do_ocr", "true"); form.append("do_table_structure", "true"); form.append("image_export_mode", "placeholder"); diff --git a/services/document-converter/test/docling.test.ts b/services/document-converter/test/docling.test.ts index 79b4b9dcc..3f2a89c9d 100644 --- a/services/document-converter/test/docling.test.ts +++ b/services/document-converter/test/docling.test.ts @@ -39,7 +39,7 @@ describe("doclingConvertFile outgoing request", () => { expect(form).toBeInstanceOf(FormData); expect(form!.get("md_page_break_placeholder")).toBe(PAGE_BREAK_PLACEHOLDER); // Pre-existing conversion parameters stay intact. - expect(form!.get("to_formats")).toBe('["md"]'); + expect(form!.get("to_formats")).toBe("md"); expect(form!.get("do_ocr")).toBe("true"); expect(form!.get("do_table_structure")).toBe("true"); expect(form!.get("image_export_mode")).toBe("placeholder");