diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ab0ca99..26adb3f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,9 +25,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 flagging dangling references, empty or duplicate definitions, and `[^id]` markers inside table rows, so an agent can fix its own markup. The page is still created; the field is omitted when there are no problems. (#166) +- **AI chat "Protocol" setting (`chatApiStyle`).** A new admin choice in AI + settings for the `openai` driver: `openai-compatible` (default) routes chat + through `@ai-sdk/openai-compatible`, which surfaces a provider's streamed + reasoning (`reasoning_content` → reasoning parts) for z.ai/GLM, DeepSeek, + OpenRouter, etc.; `openai` uses the official provider (real-OpenAI + reasoning-model request shaping). Chosen explicitly rather than inferred from + the base URL, since a custom URL can front real OpenAI too. (#175, #177) ### Changed +- **AI chat default provider is now `openai-compatible` (reasoning surfaced).** + For the `openai` driver the chat provider defaults to the openai-compatible + implementation, so a workspace pointing at z.ai/GLM/DeepSeek now streams the + model's reasoning out of the box. An endpoint that is real OpenAI behind a + custom base URL should set the new `chatApiStyle` "Protocol" to `openai`. (#177) + - **Footnotes now reuse (Pandoc semantics).** Multiple `[^a]` references to the same id are ONE footnote — one number, one definition, several back-references — instead of being renamed to `a__2`, `a__3`. Duplicate `[^a]:` definitions are diff --git a/apps/client/public/locales/en-US/translation.json b/apps/client/public/locales/en-US/translation.json index b622087b..95fbfc0c 100644 --- a/apps/client/public/locales/en-US/translation.json +++ b/apps/client/public/locales/en-US/translation.json @@ -1307,5 +1307,9 @@ "Page tree (child pages, recursive)": "Page tree (child pages, recursive)", "Render the full nested tree of all descendant pages": "Render the full nested tree of all descendant pages", "Showing {{count}} subpages_one": "Showing {{count}} subpage", - "Showing {{count}} subpages_other": "Showing {{count}} subpages" + "Showing {{count}} subpages_other": "Showing {{count}} subpages", + "Protocol": "Protocol", + "How chat requests are sent and how reasoning is surfaced": "How chat requests are sent and how reasoning is surfaced", + "OpenAI-compatible (surfaces reasoning)": "OpenAI-compatible (surfaces reasoning)", + "OpenAI (official)": "OpenAI (official)" } diff --git a/apps/client/public/locales/ru-RU/translation.json b/apps/client/public/locales/ru-RU/translation.json index 038323a8..0d4926cd 100644 --- a/apps/client/public/locales/ru-RU/translation.json +++ b/apps/client/public/locales/ru-RU/translation.json @@ -1160,5 +1160,9 @@ "Render the full nested tree of all descendant pages": "Показать полное вложенное дерево всех дочерних страниц", "Showing {{count}} subpages_one": "Показано {{count}} подстраница", "Showing {{count}} subpages_few": "Показано {{count}} подстраницы", - "Showing {{count}} subpages_many": "Показано {{count}} подстраниц" + "Showing {{count}} subpages_many": "Показано {{count}} подстраниц", + "Protocol": "Протокол", + "How chat requests are sent and how reasoning is surfaced": "Как отправляются запросы чата и как показывается reasoning", + "OpenAI-compatible (surfaces reasoning)": "OpenAI-совместимый (показывает reasoning)", + "OpenAI (official)": "OpenAI (официальный)" } diff --git a/apps/client/src/features/workspace/components/settings/components/ai-provider-settings.tsx b/apps/client/src/features/workspace/components/settings/components/ai-provider-settings.tsx index 713d9b65..08348756 100644 --- a/apps/client/src/features/workspace/components/settings/components/ai-provider-settings.tsx +++ b/apps/client/src/features/workspace/components/settings/components/ai-provider-settings.tsx @@ -38,6 +38,7 @@ import { AiTestCapability, IAiSettingsUpdate, SttApiStyle, + ChatApiStyle, } from "@/features/workspace/services/ai-settings-service.ts"; import { useAiRolesQuery } from "@/features/ai-chat/queries/ai-chat-query.ts"; import { IAiRole } from "@/features/ai-chat/types/ai-chat.types.ts"; @@ -82,6 +83,8 @@ const STT_LANGUAGE_OPTIONS: { value: string; label: string }[] = [ // (empty means "leave unchanged" unless explicitly cleared). const formSchema = z.object({ chatModel: z.string(), + // Chat provider implementation (reasoning surfacing). Default openai-compatible. + chatApiStyle: z.enum(["openai-compatible", "openai"]), // Cheap model id for the anonymous public-share assistant; empty = use chatModel. publicShareChatModel: z.string(), // Agent-role id whose persona the public-share assistant adopts; empty = @@ -308,6 +311,7 @@ export default function AiProviderSettings() { validate: zod4Resolver(formSchema), initialValues: { chatModel: "", + chatApiStyle: "openai-compatible" as ChatApiStyle, publicShareChatModel: "", publicShareAssistantRoleId: "", embeddingModel: "", @@ -330,6 +334,7 @@ export default function AiProviderSettings() { if (!settings) return; form.setValues({ chatModel: settings.chatModel ?? "", + chatApiStyle: settings.chatApiStyle ?? "openai-compatible", publicShareChatModel: settings.publicShareChatModel ?? "", publicShareAssistantRoleId: settings.publicShareAssistantRoleId ?? "", embeddingModel: settings.embeddingModel ?? "", @@ -359,6 +364,7 @@ export default function AiProviderSettings() { // Everything is OpenAI-compatible. driver: "openai", chatModel: values.chatModel, + chatApiStyle: values.chatApiStyle, // Cheap model id for the anonymous public-share assistant; empty falls // back to chatModel server-side. publicShareChatModel: values.publicShareChatModel, @@ -761,6 +767,24 @@ export default function AiProviderSettings() { {t("Resolves to {{url}}", { url: chatResolved })} +