@@ -24,6 +24,7 @@
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed `models.json` provider compatibility to accept `compat.supportsLongCacheRetention`, allowing proxies to opt out of long-retention cache fields when needed while long retention is enabled by default when requested ([#3543](https://github.com/badlogic/pi-mono/issues/3543))
|
||||
- Fixed `--thinking xhigh` for `openai-codex` `gpt-5.5` so it is no longer downgraded to `high`.
|
||||
- Fixed git package installs with custom `npmCommand` values such as `pnpm` by avoiding npm-specific production flags in that compatibility path ([#3604](https://github.com/badlogic/pi-mono/issues/3604))
|
||||
- Fixed first user messages rendering without spacing after existing notices such as compaction summaries or status messages ([#3613](https://github.com/badlogic/pi-mono/issues/3613))
|
||||
|
||||
@@ -284,7 +284,8 @@ By default pi sends per-tool `eager_input_streaming: true`. If a proxy or Anthro
|
||||
"api": "anthropic-messages",
|
||||
"apiKey": "ANTHROPIC_PROXY_KEY",
|
||||
"compat": {
|
||||
"supportsEagerToolInputStreaming": false
|
||||
"supportsEagerToolInputStreaming": false,
|
||||
"supportsLongCacheRetention": true
|
||||
},
|
||||
"models": [
|
||||
{
|
||||
@@ -301,6 +302,7 @@ By default pi sends per-tool `eager_input_streaming: true`. If a proxy or Anthro
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `supportsEagerToolInputStreaming` | Whether the provider accepts per-tool `eager_input_streaming`. Default: `true`. Set to `false` to omit that field and use the legacy fine-grained tool streaming beta header on tool-enabled requests. |
|
||||
| `supportsLongCacheRetention` | Whether the provider accepts Anthropic long cache retention (`cache_control.ttl: "1h"`) when cache retention is `long`. Default: `true`. |
|
||||
|
||||
## OpenAI Compatibility
|
||||
|
||||
@@ -339,6 +341,7 @@ For providers with partial OpenAI compatibility, use the `compat` field.
|
||||
| `thinkingFormat` | Use `reasoning_effort`, `zai`, `qwen`, or `qwen-chat-template` thinking parameters |
|
||||
| `cacheControlFormat` | Use Anthropic-style `cache_control` markers on the system prompt, last tool definition, and last user/assistant text content. Currently only `anthropic` is supported. |
|
||||
| `supportsStrictMode` | Include the `strict` field in tool definitions |
|
||||
| `supportsLongCacheRetention` | Whether the provider accepts long cache retention when cache retention is `long`: `prompt_cache_retention: "24h"` for OpenAI prompt caching, or `cache_control.ttl: "1h"` when `cacheControlFormat` is `anthropic`. Default: `true`. |
|
||||
| `openRouterRouting` | OpenRouter provider routing preferences. This object is sent as-is in the `provider` field of the [OpenRouter API request](https://openrouter.ai/docs/guides/routing/provider-selection). |
|
||||
| `vercelGatewayRouting` | Vercel AI Gateway routing config for provider selection (`only`, `order`) |
|
||||
|
||||
|
||||
@@ -111,14 +111,17 @@ const OpenAICompletionsCompatSchema = Type.Object({
|
||||
openRouterRouting: Type.Optional(OpenRouterRoutingSchema),
|
||||
vercelGatewayRouting: Type.Optional(VercelGatewayRoutingSchema),
|
||||
supportsStrictMode: Type.Optional(Type.Boolean()),
|
||||
supportsLongCacheRetention: Type.Optional(Type.Boolean()),
|
||||
});
|
||||
|
||||
const OpenAIResponsesCompatSchema = Type.Object({
|
||||
// Reserved for future use
|
||||
sendSessionIdHeader: Type.Optional(Type.Boolean()),
|
||||
supportsLongCacheRetention: Type.Optional(Type.Boolean()),
|
||||
});
|
||||
|
||||
const AnthropicMessagesCompatSchema = Type.Object({
|
||||
supportsEagerToolInputStreaming: Type.Optional(Type.Boolean()),
|
||||
supportsLongCacheRetention: Type.Optional(Type.Boolean()),
|
||||
});
|
||||
|
||||
const ProviderCompatSchema = Type.Union([
|
||||
|
||||
@@ -461,6 +461,35 @@ describe("ModelRegistry", () => {
|
||||
expect(compat?.supportsEagerToolInputStreaming).toBe(false);
|
||||
});
|
||||
|
||||
test("compat schema accepts long cache retention flag", () => {
|
||||
writeRawModelsJson({
|
||||
demo: {
|
||||
baseUrl: "https://example.com",
|
||||
apiKey: "DEMO_KEY",
|
||||
api: "anthropic-messages",
|
||||
compat: {
|
||||
supportsLongCacheRetention: false,
|
||||
},
|
||||
models: [
|
||||
{
|
||||
id: "demo-model",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 1000,
|
||||
maxTokens: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const registry = ModelRegistry.create(authStorage, modelsJsonPath);
|
||||
const compat = registry.find("demo", "demo-model")?.compat as AnthropicMessagesCompat | undefined;
|
||||
|
||||
expect(registry.getError()).toBeUndefined();
|
||||
expect(compat?.supportsLongCacheRetention).toBe(false);
|
||||
});
|
||||
|
||||
test("model-level baseUrl overrides provider-level baseUrl for custom models", () => {
|
||||
writeRawModelsJson({
|
||||
"opencode-go": {
|
||||
|
||||
Reference in New Issue
Block a user