mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
feat: remove ant-ling thinking format and update model
This commit is contained in:
parent
676af1d777
commit
7a6284b095
12 changed files with 102 additions and 96 deletions
|
|
@ -2,11 +2,19 @@
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- Removed the `thinkingFormat: \`"ant-ling"\`` compat value. Use `thinkingFormat: \`"deepseek"\`` for Ant Ling models ([#10943](https://github.com/earendil-works/pi/pull/10943) by [@lvisei](https://github.com/lvisei))
|
||||
|
||||
### Added
|
||||
|
||||
- Anthropic requests with a `sessionId` (and `cacheRetention` not `"none"`) now use message threads (`message-threads-2026-08-12` beta): the server continues from the previous reply and pi sends only the new messages instead of the whole conversation. When anything earlier in the request changed, or the server can't continue the thread, the full request is sent. Token counts and prompt caching are unchanged. On by default only for the `anthropic` provider on `api.anthropic.com`; set `compat.supportsMessageThreads` to change that, for example for gateways that forward the `thread` field. Call `cleanupSessionResources(sessionId)` when a session ends to free the per-session state ([#11545](https://github.com/earendil-works/pi/pull/11545))
|
||||
- Added `StreamOptions.disableContinuation`, which keeps a request from using or replacing server-side continuation state such as Anthropic message threads. Set it on requests that repeat an earlier one, such as cache warming ([#11545](https://github.com/earendil-works/pi/pull/11545))
|
||||
|
||||
### Changed
|
||||
|
||||
- Replaced the Ant Ling Ling 2.6 and Ring 2.6 models with Ling 3.1 Flash, Ling 3.0 Flash, and Ling 3.0 Flash VL. Ant Ling reasoning requests now use the DeepSeek-compatible `thinking` field instead of nested `reasoning`, with thinking either off or high and no reasoning effort parameter ([#10943](https://github.com/earendil-works/pi/pull/10943) by [@lvisei](https://github.com/lvisei))
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed OpenCode Go Claude Haiku 5.5 failing with a 400 (`Invalid signature in thinking block ... bound to a different conversation`) after the tool list, system prompt, or earlier history changed, which left the session failing on every retry. OpenCode Go and Zen Claude 5.5 models, Opus 5, and Fable 5.1 now use per-message effort and send `thinking.block_binding: drop_block`, like the Anthropic provider ([#10954](https://github.com/earendil-works/pi/issues/10954))
|
||||
|
|
|
|||
|
|
@ -1461,7 +1461,7 @@ interface OpenAICompletionsCompat {
|
|||
requiresAssistantAfterToolResult?: boolean; // Whether tool results must be followed by an assistant message (default: false)
|
||||
requiresThinkingAsText?: boolean; // Whether thinking blocks must be converted to text (default: false)
|
||||
requiresReasoningContentOnAssistantMessages?: boolean; // Whether all replayed assistant messages must include empty reasoning_content when reasoning is enabled (default: auto-detected for DeepSeek)
|
||||
thinkingFormat?: 'openai' | 'openrouter' | 'deepseek' | 'together' | 'baseten' | 'zai' | 'qwen' | 'chat-template' | 'qwen-chat-template' | 'string-thinking' | 'ant-ling'; // Format for reasoning param: 'openai' uses reasoning_effort, 'openrouter' uses reasoning: { effort }, 'deepseek' uses thinking: { type } plus reasoning_effort when supported, 'together' uses reasoning: { enabled } plus reasoning_effort when supported, 'baseten' uses configurable chat_template_args plus reasoning_effort when supported, 'zai' uses thinking: { type }, 'qwen' uses enable_thinking, 'chat-template' uses configurable chat_template_kwargs, 'qwen-chat-template' uses chat_template_kwargs.enable_thinking and preserve_thinking, 'string-thinking' uses top-level thinking, 'ant-ling' uses reasoning: { effort } only for mapped efforts (default: openai)
|
||||
thinkingFormat?: 'openai' | 'openrouter' | 'deepseek' | 'together' | 'baseten' | 'zai' | 'qwen' | 'chat-template' | 'qwen-chat-template' | 'string-thinking'; // Format for reasoning param: 'openai' uses reasoning_effort, 'openrouter' uses reasoning: { effort }, 'deepseek' uses thinking: { type } plus reasoning_effort when supported, 'together' uses reasoning: { enabled } plus reasoning_effort when supported, 'baseten' uses configurable chat_template_args plus reasoning_effort when supported, 'zai' uses thinking: { type }, 'qwen' uses enable_thinking, 'chat-template' uses configurable chat_template_kwargs, 'qwen-chat-template' uses chat_template_kwargs.enable_thinking and preserve_thinking, 'string-thinking' uses top-level thinking (default: openai)
|
||||
chatTemplateKwargs?: Record<string, string | number | boolean | null | { '$var': 'thinking.enabled' | 'thinking.effort' | 'thinking.budget'; omitWhenOff?: boolean }>; // chat_template_kwargs values; use $var for pi-controlled thinking values
|
||||
chatTemplateArgs?: Record<string, string | number | boolean | null | { '$var': 'thinking.enabled' | 'thinking.effort' | 'thinking.budget'; omitWhenOff?: boolean }>; // chat_template_args values for thinkingFormat: 'baseten'; use $var for pi-controlled thinking values
|
||||
thinkingTokenBudgetField?: 'thinking_token_budget' | 'thinking_budget' | 'thinking_budget_tokens'; // Top-level field that caps reasoning tokens from thinkingBudgets (vLLM / Qwen / llama.cpp). Off by default.
|
||||
|
|
|
|||
|
|
@ -1,52 +1,69 @@
|
|||
import type { Model, OpenAICompletionsCompat } from "../../src/types.ts";
|
||||
import { defineProvider, mergeThinking } from "../define.ts";
|
||||
import { defineProvider } from "../define.ts";
|
||||
|
||||
const COMPAT: OpenAICompletionsCompat = {
|
||||
supportsStore: false,
|
||||
supportsDeveloperRole: false,
|
||||
supportsReasoningEffort: false,
|
||||
maxTokensField: "max_tokens",
|
||||
thinkingFormat: "deepseek",
|
||||
supportsStrictMode: true,
|
||||
supportsLongCacheRetention: false,
|
||||
};
|
||||
|
||||
function model(id: string, name: string, reasoning: boolean, cost: Model<"openai-completions">["cost"]) {
|
||||
// Thinking is either off or high. Hiding the lower levels makes pi clamp them to
|
||||
// high; off is unmapped, so a request without reasoning sends thinking disabled.
|
||||
const ANT_LING_THINKING_LEVEL_MAP = {
|
||||
minimal: null,
|
||||
low: null,
|
||||
medium: null,
|
||||
} as const;
|
||||
|
||||
function model(
|
||||
id: string,
|
||||
name: string,
|
||||
input: ["text"] | ["text", "image"],
|
||||
contextWindow: number,
|
||||
cost: Model<"openai-completions">["cost"],
|
||||
) {
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
api: "openai-completions",
|
||||
baseUrl: "https://api.ant-ling.com/v1",
|
||||
provider: "ant-ling",
|
||||
reasoning,
|
||||
input: ["text"],
|
||||
reasoning: true,
|
||||
thinkingLevelMap: ANT_LING_THINKING_LEVEL_MAP,
|
||||
input,
|
||||
cost,
|
||||
contextWindow: 262144,
|
||||
maxTokens: 65536,
|
||||
compat: reasoning ? { ...COMPAT, thinkingFormat: "ant-ling" } : COMPAT,
|
||||
contextWindow,
|
||||
maxTokens: 262144,
|
||||
} satisfies Model<"openai-completions">;
|
||||
}
|
||||
|
||||
export default defineProvider({
|
||||
id: "ant-ling",
|
||||
models: () => [
|
||||
model("Ling-2.6-flash", "Ling 2.6 Flash", false, { input: 0.01, output: 0.02, cacheRead: 0, cacheWrite: 0 }),
|
||||
model("Ling-2.6-1T", "Ling 2.6 1T", false, { input: 0.06, output: 0.25, cacheRead: 0, cacheWrite: 0 }),
|
||||
model("Ring-2.6-1T", "Ring 2.6 1T", true, { input: 0.06, output: 0.25, cacheRead: 0, cacheWrite: 0 }),
|
||||
model("Ling-3.1-flash", "Ling 3.1 Flash", ["text"], 1000000, {
|
||||
input: 0.075,
|
||||
output: 0.225,
|
||||
cacheRead: 0.015,
|
||||
cacheWrite: 0,
|
||||
}),
|
||||
model("Ling-3.0-flash-VL", "Ling 3.0 Flash VL", ["text", "image"], 262144, {
|
||||
input: 0.021,
|
||||
output: 0.062,
|
||||
cacheRead: 0.0042,
|
||||
cacheWrite: 0,
|
||||
}),
|
||||
model("Ling-3.0-flash", "Ling 3.0 Flash", ["text"], 262144, {
|
||||
input: 0.0168,
|
||||
output: 0.0504,
|
||||
cacheRead: 0.0034,
|
||||
cacheWrite: 0,
|
||||
}),
|
||||
],
|
||||
compat: {
|
||||
"openai-completions": {
|
||||
supportsStore: false,
|
||||
supportsDeveloperRole: false,
|
||||
supportsReasoningEffort: false,
|
||||
maxTokensField: "max_tokens",
|
||||
thinkingFormat: "ant-ling",
|
||||
supportsStrictMode: true,
|
||||
supportsLongCacheRetention: false,
|
||||
},
|
||||
},
|
||||
finalize: (model) => {
|
||||
// Ring reasons by default. Only high/xhigh have documented explicit effort controls.
|
||||
if (model.reasoning) {
|
||||
mergeThinking(model, { off: null, minimal: null, low: null, medium: null, high: "high", xhigh: "xhigh" });
|
||||
}
|
||||
"openai-completions": COMPAT,
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -930,11 +930,6 @@ function buildParams(
|
|||
} else if (model.thinkingLevelMap?.off !== null) {
|
||||
openRouterParams.reasoning = { effort: model.thinkingLevelMap?.off ?? "none" };
|
||||
}
|
||||
} else if (compat.thinkingFormat === "ant-ling" && model.reasoning && options?.reasoningEffort) {
|
||||
const effort = model.thinkingLevelMap?.[options.reasoningEffort];
|
||||
if (typeof effort === "string") {
|
||||
(params as typeof params & { reasoning?: { effort: string } }).reasoning = { effort };
|
||||
}
|
||||
} else if (compat.thinkingFormat === "together" && model.reasoning) {
|
||||
const togetherParams = params as Omit<typeof params, "reasoning_effort"> & {
|
||||
reasoning?: { enabled: boolean };
|
||||
|
|
@ -1638,8 +1633,7 @@ function detectCompat(model: Model<"openai-completions">): ResolvedOpenAIComplet
|
|||
return {
|
||||
supportsStore: !isNonStandard,
|
||||
supportsDeveloperRole: isOpenRouterDeveloperRoleModel || (!isNonStandard && !isOpenRouter),
|
||||
supportsReasoningEffort:
|
||||
!isGrok && !isZai && !isMoonshot && !isTogether && !isCloudflareAiGateway && !isNvidia && !isAntLing,
|
||||
supportsReasoningEffort: !isGrok && !isZai && !isMoonshot && !isTogether && !isCloudflareAiGateway && !isNvidia,
|
||||
supportsUsageInStreaming: true,
|
||||
supportsFinishReason: true,
|
||||
maxTokensField: useMaxTokens ? "max_tokens" : "max_completion_tokens",
|
||||
|
|
@ -1647,14 +1641,13 @@ function detectCompat(model: Model<"openai-completions">): ResolvedOpenAIComplet
|
|||
requiresAssistantAfterToolResult: false,
|
||||
requiresThinkingAsText: false,
|
||||
requiresReasoningContentOnAssistantMessages: isDeepSeek,
|
||||
thinkingFormat: isDeepSeek
|
||||
? "deepseek"
|
||||
: isZai
|
||||
? "zai"
|
||||
: isTogether
|
||||
? "together"
|
||||
: isAntLing
|
||||
? "ant-ling"
|
||||
thinkingFormat:
|
||||
isDeepSeek || isAntLing
|
||||
? "deepseek"
|
||||
: isZai
|
||||
? "zai"
|
||||
: isTogether
|
||||
? "together"
|
||||
: isOpenRouter
|
||||
? "openrouter"
|
||||
: "openai",
|
||||
|
|
|
|||
|
|
@ -257,11 +257,10 @@ const OpenAICompletionsCompatProperties = {
|
|||
stringLiteral("chat-template"),
|
||||
stringLiteral("qwen-chat-template"),
|
||||
stringLiteral("string-thinking"),
|
||||
stringLiteral("ant-ling"),
|
||||
],
|
||||
{
|
||||
description:
|
||||
'Format for reasoning or thinking parameters. When omitted, Pi auto-detects the format from the provider URL. "openai" uses reasoning_effort, "openrouter" uses reasoning.effort, "deepseek" uses thinking.type plus reasoning_effort when supported, "together" uses reasoning.enabled plus reasoning_effort when supported, "baseten" uses configurable chat_template_args plus reasoning_effort when supported, "zai" uses thinking.type, "qwen" uses top-level enable_thinking, "qwen-chat-template" uses chat_template_kwargs.enable_thinking and preserve_thinking, "chat-template" uses configurable chat_template_kwargs, "string-thinking" uses top-level thinking, and "ant-ling" uses reasoning.effort only when the mapped effort is non-null.',
|
||||
'Format for reasoning or thinking parameters. When omitted, Pi auto-detects the format from the provider URL. "openai" uses reasoning_effort, "openrouter" uses reasoning.effort, "deepseek" uses thinking.type plus reasoning_effort when supported, "together" uses reasoning.enabled plus reasoning_effort when supported, "baseten" uses configurable chat_template_args plus reasoning_effort when supported, "zai" uses thinking.type, "qwen" uses top-level enable_thinking, "qwen-chat-template" uses chat_template_kwargs.enable_thinking and preserve_thinking, "chat-template" uses configurable chat_template_kwargs, and "string-thinking" uses top-level thinking.',
|
||||
},
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import { Type } from "typebox";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { convertMessages } from "../src/api/openai-completions.ts";
|
||||
import { getModel, normalizeContext, stream, streamSimple } from "../src/compat.ts";
|
||||
import { getModel, normalizeContext, streamSimple } from "../src/compat.ts";
|
||||
import { getSupportedThinkingLevels } from "../src/models.ts";
|
||||
import type { AssistantMessage, Model, SimpleStreamOptions, Tool, ToolResultMessage } from "../src/types.ts";
|
||||
|
||||
const mockState = vi.hoisted(() => ({
|
||||
|
|
@ -1399,7 +1400,7 @@ describe("openai-completions tool_choice", () => {
|
|||
...model.compat,
|
||||
supportsStore: false,
|
||||
supportsDeveloperRole: false,
|
||||
supportsReasoningEffort: true,
|
||||
supportsReasoningEffort: false,
|
||||
supportsUsageInStreaming: true,
|
||||
supportsFinishReason: true,
|
||||
maxTokensField: "max_completion_tokens",
|
||||
|
|
@ -1863,8 +1864,8 @@ describe("openai-completions tool_choice", () => {
|
|||
expect(params.reasoning_effort).toBeUndefined();
|
||||
});
|
||||
|
||||
it("uses Ant Ling compatibility metadata", async () => {
|
||||
const model = getModel("ant-ling", "Ring-2.6-1T")!;
|
||||
it("uses DeepSeek-compatible Ant Ling metadata", async () => {
|
||||
const model = getModel("ant-ling", "Ling-3.1-flash")!;
|
||||
let payload: unknown;
|
||||
|
||||
expect(model.compat).toMatchObject({
|
||||
|
|
@ -1872,7 +1873,7 @@ describe("openai-completions tool_choice", () => {
|
|||
supportsDeveloperRole: false,
|
||||
supportsReasoningEffort: false,
|
||||
maxTokensField: "max_tokens",
|
||||
thinkingFormat: "ant-ling",
|
||||
thinkingFormat: "deepseek",
|
||||
supportsLongCacheRetention: false,
|
||||
});
|
||||
expect(model.compat?.supportsStrictMode).toBe(true);
|
||||
|
|
@ -1900,7 +1901,7 @@ describe("openai-completions tool_choice", () => {
|
|||
max_tokens?: number;
|
||||
max_completion_tokens?: number;
|
||||
messages?: Array<{ role?: string }>;
|
||||
reasoning?: { effort?: string };
|
||||
thinking?: { type?: string };
|
||||
reasoning_effort?: string;
|
||||
store?: boolean;
|
||||
prompt_cache_key?: string;
|
||||
|
|
@ -1909,48 +1910,36 @@ describe("openai-completions tool_choice", () => {
|
|||
expect(params.max_tokens).toBe(123);
|
||||
expect(params.max_completion_tokens).toBeUndefined();
|
||||
expect(params.messages?.[0]?.role).toBe("system");
|
||||
expect(params.reasoning).toEqual({ effort: "high" });
|
||||
expect(params.thinking).toEqual({ type: "enabled" });
|
||||
expect(params.reasoning_effort).toBeUndefined();
|
||||
expect(params).not.toHaveProperty("reasoning");
|
||||
expect(params.store).toBeUndefined();
|
||||
expect(params.prompt_cache_key).toBeUndefined();
|
||||
expect(params.prompt_cache_retention).toBeUndefined();
|
||||
});
|
||||
|
||||
it("omits Ant Ling reasoning for unmapped direct reasoning efforts and non-reasoning models", async () => {
|
||||
const ring = getModel("ant-ling", "Ring-2.6-1T")!;
|
||||
let payload: unknown;
|
||||
it("exposes only off and high for Ant Ling models", () => {
|
||||
for (const id of ["Ling-3.1-flash", "Ling-3.0-flash", "Ling-3.0-flash-VL"] as const) {
|
||||
expect(getSupportedThinkingLevels(getModel("ant-ling", id)!)).toEqual(["off", "high"]);
|
||||
}
|
||||
expect(getModel("ant-ling", "Ling-3.1-flash")!.contextWindow).toBe(1000000);
|
||||
expect(getModel("ant-ling", "Ling-3.0-flash")!.contextWindow).toBe(262144);
|
||||
expect(getModel("ant-ling", "Ling-3.0-flash-VL")!.contextWindow).toBe(262144);
|
||||
});
|
||||
|
||||
await stream(
|
||||
ring,
|
||||
{
|
||||
messages: [{ role: "user", content: "Hi", timestamp: Date.now() }],
|
||||
},
|
||||
{
|
||||
apiKey: "test",
|
||||
reasoningEffort: "medium",
|
||||
onPayload: (params: unknown) => {
|
||||
payload = params;
|
||||
},
|
||||
},
|
||||
).result();
|
||||
it("clamps every Ant Ling reasoning level to high", async () => {
|
||||
const model = getModel("ant-ling", "Ling-3.0-flash")!;
|
||||
for (const reasoning of ["minimal", "low", "medium", "high", "xhigh"] as const) {
|
||||
const params = await captureSimpleParams(model, reasoning);
|
||||
expect(params.thinking).toEqual({ type: "enabled" });
|
||||
expect(params.reasoning_effort).toBeUndefined();
|
||||
}
|
||||
});
|
||||
|
||||
expect((payload ?? mockState.lastParams) as { reasoning?: unknown }).not.toHaveProperty("reasoning");
|
||||
|
||||
const ling = getModel("ant-ling", "Ling-2.6-flash")!;
|
||||
await streamSimple(
|
||||
ling,
|
||||
{
|
||||
messages: [{ role: "user", content: "Hi", timestamp: Date.now() }],
|
||||
},
|
||||
{
|
||||
apiKey: "test",
|
||||
reasoning: "high",
|
||||
onPayload: (params: unknown) => {
|
||||
payload = params;
|
||||
},
|
||||
},
|
||||
).result();
|
||||
|
||||
expect((payload ?? mockState.lastParams) as { reasoning?: unknown }).not.toHaveProperty("reasoning");
|
||||
it("disables Ant Ling reasoning when no reasoning level is requested", async () => {
|
||||
const model = getModel("ant-ling", "Ling-3.0-flash-VL")!;
|
||||
const params = await captureSimpleParams(model, undefined);
|
||||
expect(params.thinking).toEqual({ type: "disabled" });
|
||||
expect(params.reasoning_effort).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1305,8 +1305,8 @@ describe("Generate E2E Tests", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe.skipIf(!process.env.ANT_LING_API_KEY)("Ant Ling Provider (Ling 2.6 Flash via OpenAI Completions)", () => {
|
||||
const llm = getModel("ant-ling", "Ling-2.6-flash");
|
||||
describe.skipIf(!process.env.ANT_LING_API_KEY)("Ant Ling Provider (Ling 3.1 Flash via OpenAI Completions)", () => {
|
||||
const llm = getModel("ant-ling", "Ling-3.1-flash");
|
||||
|
||||
it("should complete basic text generation", { retry: 3 }, async () => {
|
||||
await basicTextGeneration(llm);
|
||||
|
|
@ -1321,8 +1321,8 @@ describe("Generate E2E Tests", () => {
|
|||
});
|
||||
|
||||
it("should handle thinking mode", { retry: 3 }, async () => {
|
||||
const ringModel = getModel("ant-ling", "Ring-2.6-1T");
|
||||
await handleThinking(ringModel, { reasoningEffort: "high" });
|
||||
const model = getModel("ant-ling", "Ling-3.1-flash");
|
||||
await handleThinking(model, { reasoningEffort: "high" });
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@
|
|||
- Anthropic sessions now use message threads: each request sends only the new messages and the server continues from the previous reply, falling back to the full request when the conversation changed (for example after compaction or a tool list change). On by default for the `anthropic` provider on `api.anthropic.com`; set `compat.supportsMessageThreads` in `models.json` to enable it for gateways that forward the `thread` field, or to turn it off. Cache warming does not touch the session's thread ([#11545](https://github.com/earendil-works/pi/pull/11545))
|
||||
- `pi.registerMarkdownTransformer()` takes an optional `{ messageTypes }` that selects the Markdown surfaces a transformer runs on. Besides user, assistant, and thinking Markdown, transformers can now opt into `custom` (custom messages and skill blocks), `summary` (branch and compaction summaries), and `changelog` (What's New, `/changelog`, the Extension Updates notice, and the Update Available note). Without options a transformer runs on user, assistant, and thinking Markdown as before. The built-in Mermaid renderer now also draws diagrams in expanded branch and compaction summaries
|
||||
|
||||
### Changed
|
||||
|
||||
- Changed the `ant-ling` default model to `Ling-3.1-flash`, replacing the removed Ling 2.6 and Ring 2.6 models ([#10943](https://github.com/earendil-works/pi/pull/10943) by [@lvisei](https://github.com/lvisei))
|
||||
|
||||
### Fixed
|
||||
|
||||
- A failed token refresh of an MCP connection no longer registers an OAuth client or replaces the PKCE verifier of a sign-in in progress, which made that sign-in fail. MCP sign-in now refreshes the stored tokens with the stored client even when the loopback callback port changed, instead of registering a new client and opening the browser. Ctrl+C in `/mcp` and the `--timeout` of `pi mcp login` now also stop a sign-in while it waits up to 25 seconds for another pi process's token refresh, and a refresh lock that fails for another reason than that wait now fails the sign-in instead of opening the browser.
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ See [Describe model input and caching](models.md#describe-model-input-and-cachin
|
|||
| `requiresAssistantAfterToolResult` | boolean | | Whether a user message after tool results requires an assistant message in between. Default: auto-detected from URL. |
|
||||
| `requiresThinkingAsText` | boolean | | Whether thinking blocks must be converted to text blocks with <thinking> delimiters. Default: auto-detected from URL. |
|
||||
| `requiresReasoningContentOnAssistantMessages` | boolean | | Whether all replayed assistant messages must include an empty reasoning_content field when reasoning is enabled. Default: auto-detected from URL. |
|
||||
| `thinkingFormat` | `"openai" \| "openrouter" \| "deepseek" \| "together" \| "baseten" \| "zai" \| "qwen" \| "chat-template" \| "qwen-chat-template" \| "string-thinking" \| "ant-ling"` | | Format for reasoning or thinking parameters. When omitted, Pi auto-detects the format from the provider URL. "openai" uses reasoning_effort, "openrouter" uses reasoning.effort, "deepseek" uses thinking.type plus reasoning_effort when supported, "together" uses reasoning.enabled plus reasoning_effort when supported, "baseten" uses configurable chat_template_args plus reasoning_effort when supported, "zai" uses thinking.type, "qwen" uses top-level enable_thinking, "qwen-chat-template" uses chat_template_kwargs.enable_thinking and preserve_thinking, "chat-template" uses configurable chat_template_kwargs, "string-thinking" uses top-level thinking, and "ant-ling" uses reasoning.effort only when the mapped effort is non-null. |
|
||||
| `thinkingFormat` | `"openai" \| "openrouter" \| "deepseek" \| "together" \| "baseten" \| "zai" \| "qwen" \| "chat-template" \| "qwen-chat-template" \| "string-thinking"` | | Format for reasoning or thinking parameters. When omitted, Pi auto-detects the format from the provider URL. "openai" uses reasoning_effort, "openrouter" uses reasoning.effort, "deepseek" uses thinking.type plus reasoning_effort when supported, "together" uses reasoning.enabled plus reasoning_effort when supported, "baseten" uses configurable chat_template_args plus reasoning_effort when supported, "zai" uses thinking.type, "qwen" uses top-level enable_thinking, "qwen-chat-template" uses chat_template_kwargs.enable_thinking and preserve_thinking, "chat-template" uses configurable chat_template_kwargs, and "string-thinking" uses top-level thinking. |
|
||||
| `chatTemplateKwargs` | object | | Kwargs sent as chat_template_kwargs when thinkingFormat is "chat-template". Use $var with "thinking.enabled", "thinking.effort", or "thinking.budget" for pi-controlled values. |
|
||||
| `chatTemplateArgs` | object | | Arguments sent as chat_template_args when thinkingFormat is "baseten". Use $var with "thinking.enabled", "thinking.effort", or "thinking.budget" for pi-controlled values. |
|
||||
| `openRouterRouting` | object | | OpenRouter provider routing preferences. Controls which upstream providers OpenRouter routes requests to. Sent as the provider field in the OpenRouter API request body. See https://openrouter.ai/docs/guides/routing/provider-selection. |
|
||||
|
|
|
|||
|
|
@ -601,13 +601,9 @@
|
|||
{
|
||||
"type": "string",
|
||||
"const": "string-thinking"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"const": "ant-ling"
|
||||
}
|
||||
],
|
||||
"description": "Format for reasoning or thinking parameters. When omitted, Pi auto-detects the format from the provider URL. \"openai\" uses reasoning_effort, \"openrouter\" uses reasoning.effort, \"deepseek\" uses thinking.type plus reasoning_effort when supported, \"together\" uses reasoning.enabled plus reasoning_effort when supported, \"baseten\" uses configurable chat_template_args plus reasoning_effort when supported, \"zai\" uses thinking.type, \"qwen\" uses top-level enable_thinking, \"qwen-chat-template\" uses chat_template_kwargs.enable_thinking and preserve_thinking, \"chat-template\" uses configurable chat_template_kwargs, \"string-thinking\" uses top-level thinking, and \"ant-ling\" uses reasoning.effort only when the mapped effort is non-null."
|
||||
"description": "Format for reasoning or thinking parameters. When omitted, Pi auto-detects the format from the provider URL. \"openai\" uses reasoning_effort, \"openrouter\" uses reasoning.effort, \"deepseek\" uses thinking.type plus reasoning_effort when supported, \"together\" uses reasoning.enabled plus reasoning_effort when supported, \"baseten\" uses configurable chat_template_args plus reasoning_effort when supported, \"zai\" uses thinking.type, \"qwen\" uses top-level enable_thinking, \"qwen-chat-template\" uses chat_template_kwargs.enable_thinking and preserve_thinking, \"chat-template\" uses configurable chat_template_kwargs, and \"string-thinking\" uses top-level thinking."
|
||||
},
|
||||
"chatTemplateKwargs": {
|
||||
"type": "object",
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import type { ModelRuntime } from "./model-runtime.ts";
|
|||
/** Default chat model IDs for providers with built-in chat models. */
|
||||
export const defaultModelPerProvider: Partial<Record<KnownProvider, string>> = {
|
||||
"amazon-bedrock": "us.anthropic.claude-opus-4-6-v1",
|
||||
"ant-ling": "Ring-2.6-1T",
|
||||
"ant-ling": "Ling-3.1-flash",
|
||||
anthropic: "claude-opus-4-8",
|
||||
openai: "gpt-6.1-sol",
|
||||
azure: "gpt-5.4",
|
||||
|
|
|
|||
|
|
@ -708,7 +708,7 @@ describe("default model selection", () => {
|
|||
expect(defaultModelPerProvider.minimax).toBe("MiniMax-M2.7");
|
||||
expect(defaultModelPerProvider["minimax-cn"]).toBe("MiniMax-M2.7");
|
||||
expect(defaultModelPerProvider.cerebras).toBe("gpt-oss-120b");
|
||||
expect(defaultModelPerProvider["ant-ling"]).toBe("Ring-2.6-1T");
|
||||
expect(defaultModelPerProvider["ant-ling"]).toBe("Ling-3.1-flash");
|
||||
});
|
||||
|
||||
test("built-in chat providers have defaults in their generated catalogs", () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue