fix(providers): enabled append-only auto for xiaomi

Centralized append-only context auto-mode resolution so SDK sessions, interactive sessions, and the status display use the same provider checks. Auto mode now enables for Xiaomi/SGLang hosts and explicit stored-request compat signals while preserving DeepSeek behavior.

Added focused regression coverage for Xiaomi Token Plan SGLang HiCache endpoints and explicit on/off behavior.

Fixes #1851
This commit is contained in:
roboomp
2026-06-04 11:59:47 +00:00
parent f6fca1f5cd
commit 15d4d7fcf9
7 changed files with 95 additions and 25 deletions
+4
View File
@@ -2,6 +2,10 @@
## [Unreleased]
### Fixed
- Fixed `provider.appendOnlyContext: "auto"` staying inactive for Xiaomi Token Plan/SGLang endpoints, preserving prefix-cache hits without forcing append-only mode globally ([#1851](https://github.com/can1357/oh-my-pi/issues/1851)).
## [15.9.0] - 2026-06-04
### Breaking Changes
@@ -0,0 +1,37 @@
/** Provider metadata needed to resolve append-only context mode. */
export interface AppendOnlyContextModel {
provider: string;
baseUrl: string;
compat?: object;
}
function isXiaomiHost(baseUrl: string): boolean {
try {
const host = new URL(baseUrl).hostname;
return host === "xiaomimimo.com" || host.endsWith(".xiaomimimo.com");
} catch {
return false;
}
}
function shouldAutoEnableAppendOnlyContext(model: AppendOnlyContextModel | null | undefined): boolean {
if (!model) return false;
if (model.provider === "deepseek") return true;
if (isXiaomiHost(model.baseUrl)) return true;
return !!model.compat && "supportsStore" in model.compat && model.compat.supportsStore === true;
}
/** Resolves whether append-only context should be active for a model and setting. */
export function shouldEnableAppendOnlyContext(
setting: "auto" | "on" | "off" | undefined,
model: AppendOnlyContextModel | null | undefined,
): boolean {
switch (setting ?? "auto") {
case "on":
return true;
case "off":
return false;
default:
return shouldAutoEnableAppendOnlyContext(model);
}
}
@@ -3057,9 +3057,9 @@ export const SETTINGS_SCHEMA = {
tab: "providers",
label: "Append-Only Context",
description:
"Cache system prompt + tool specs and keep an append-only message log so provider prefix caches (DeepSeek, Anthropic) hit at maximum rate. Auto enables for DeepSeek.",
"Cache system prompt + tool specs and keep an append-only message log so provider prefix caches (DeepSeek, Xiaomi/SGLang, Anthropic) hit at maximum rate. Auto enables for known prefix-cache providers.",
options: [
{ value: "auto", label: "Auto", description: "Enable for DeepSeek (recommended)" },
{ value: "auto", label: "Auto", description: "Enable for known prefix-cache providers (recommended)" },
{ value: "on", label: "On", description: "Always enable append-only context" },
{ value: "off", label: "Off", description: "Disable append-only context" },
],
@@ -13,6 +13,7 @@ import {
import { Loader, Markdown, padding, Spacer, Text, visibleWidth } from "@oh-my-pi/pi-tui";
import { formatDuration, Snowflake } from "@oh-my-pi/pi-utils";
import { $ } from "bun";
import { shouldEnableAppendOnlyContext } from "../../config/append-only-context-mode";
import { loadCustomShare } from "../../export/custom-share";
import type { CompactOptions } from "../../extensibility/extensions/types";
import {
@@ -397,10 +398,10 @@ export class CommandController {
// Append-only context
{
const setting = this.ctx.settings.get("provider.appendOnlyContext") ?? "auto";
const provider = this.ctx.session.model?.provider;
const mode = setting === "on" ? true : setting === "off" ? false : provider === "deepseek";
const model = this.ctx.session.model;
const mode = shouldEnableAppendOnlyContext(setting, model);
const activeLabel = mode ? theme.fg("success", "active") : theme.fg("dim", "inactive");
const settingLabel = setting === "auto" ? `${setting} (${provider ?? "?"})` : setting;
const settingLabel = setting === "auto" ? `${setting} (${model?.provider ?? "?"})` : setting;
info += `${theme.fg("dim", "Append-Only:")} ${activeLabel} (setting: ${settingLabel})\n`;
}
info += `${theme.bold("Tokens")}\n`;
+2 -19
View File
@@ -39,6 +39,7 @@ import { createAutoresearchExtension } from "./autoresearch";
import { loadCapability } from "./capability";
import { type Rule, ruleCapability, setActiveRules } from "./capability/rule";
import { bucketRules } from "./capability/rule-buckets";
import { shouldEnableAppendOnlyContext } from "./config/append-only-context-mode";
import { ModelRegistry } from "./config/model-registry";
import {
formatModelString,
@@ -646,24 +647,6 @@ function registerPythonCleanup(): void {
postmortem.register("python-cleanup", disposeAllKernelSessions);
}
/**
* Resolve whether to enable append-only context mode based on the setting and provider.
*
* - `"on"` → always enable
* - `"off"` → never enable
* - `"auto"` → enable for DeepSeek (prefix-caching provider)
*/
function resolveAppendOnlyMode(setting: "auto" | "on" | "off" | undefined, provider: string): boolean {
switch (setting ?? "auto") {
case "on":
return true;
case "off":
return false;
default:
return provider === "deepseek";
}
}
function customToolToDefinition(tool: CustomTool): ToolDefinition {
const definition: ToolDefinition & { [TOOL_DEFINITION_MARKER]: true } = {
name: tool.name,
@@ -2028,7 +2011,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
getToolChoice: () => session?.nextToolChoice(),
telemetry: options.telemetry,
appendOnlyContext: model
? resolveAppendOnlyMode(settings.get("provider.appendOnlyContext"), model.provider)
? shouldEnableAppendOnlyContext(settings.get("provider.appendOnlyContext"), model)
? new AppendOnlyContextManager()
: undefined
: undefined,
@@ -100,6 +100,7 @@ import { type AsyncJob, type AsyncJobDeliveryState, AsyncJobManager } from "../a
import { classifyDifficulty } from "../auto-thinking/classifier";
import { reset as resetCapabilities } from "../capability";
import type { Rule } from "../capability/rule";
import { shouldEnableAppendOnlyContext } from "../config/append-only-context-mode";
import { MODEL_ROLE_IDS, type ModelRegistry } from "../config/model-registry";
import {
extractExplicitThinkingSelector,
@@ -6735,8 +6736,8 @@ export class AgentSession {
*/
#syncAppendOnlyContext(model: Model | null | undefined): void {
const setting = this.settings.get("provider.appendOnlyContext") ?? "auto";
const enable = shouldEnableAppendOnlyContext(setting, model);
const providerId = model?.provider;
const enable = setting === "on" || (setting === "auto" && providerId === "deepseek");
const prev = this.#lastAppendOnlyResolution;
if (prev && prev.enable === enable && prev.providerId === providerId) return;
this.#lastAppendOnlyResolution = { enable, providerId };
@@ -0,0 +1,44 @@
import { describe, expect, test } from "bun:test";
import { shouldEnableAppendOnlyContext } from "@oh-my-pi/pi-coding-agent/config/append-only-context-mode";
const XIAOMI_TOKEN_PLAN_ANTHROPIC = {
provider: "xiaomi-token-plan-sgp",
baseUrl: "https://token-plan-sgp.xiaomimimo.com/anthropic",
};
const GENERIC_PROXY = {
provider: "generic-proxy",
baseUrl: "https://llm.example.com/v1",
};
describe("shouldEnableAppendOnlyContext", () => {
test("honors explicit on and off settings", () => {
expect(shouldEnableAppendOnlyContext("on", GENERIC_PROXY)).toBe(true);
expect(shouldEnableAppendOnlyContext("off", { provider: "deepseek", baseUrl: "https://api.deepseek.com" })).toBe(
false,
);
});
test("auto enables for DeepSeek", () => {
expect(shouldEnableAppendOnlyContext("auto", { provider: "deepseek", baseUrl: "https://api.deepseek.com" })).toBe(
true,
);
});
test("auto enables for Xiaomi Token Plan SGLang HiCache endpoints", () => {
expect(shouldEnableAppendOnlyContext("auto", XIAOMI_TOKEN_PLAN_ANTHROPIC)).toBe(true);
});
test("auto enables when model compat explicitly supports stored requests", () => {
expect(
shouldEnableAppendOnlyContext("auto", {
...GENERIC_PROXY,
compat: { supportsStore: true },
}),
).toBe(true);
});
test("auto remains off for unknown providers without prefix-cache signals", () => {
expect(shouldEnableAppendOnlyContext("auto", GENERIC_PROXY)).toBe(false);
});
});