@oh-my-pi/pi-catalog 16.0.8 → 16.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/dist/types/types.d.ts +4 -1
- package/package.json +3 -3
- package/src/compat/anthropic.ts +10 -1
- package/src/compat/openai.ts +7 -0
- package/src/types.ts +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [16.0.9] - 2026-06-18
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Fixed GitHub Copilot's `anthropic-messages` proxy being misclassified as a non-signing reasoning endpoint (`replayUnsignedThinking: true`). It forwards to signature-enforcing Anthropic, so replaying a stripped/unsigned historical `thinking` block as `signature: ""` — most visibly an end_turn-bound checkpoint/branch-return turn whose signature the transform must strip — caused a `400 Invalid signature` that corrupted the session and re-tripped on every full history re-send (e.g. after toggling MCP servers). Copilot now degrades such blocks to text like the official API. ([#2851](https://github.com/can1357/oh-my-pi/issues/2851))
|
|
10
|
+
- Added a `supportsImageDetailOriginal` compat flag that resolves to `false` for GitHub Copilot, whose Responses endpoint rejects the `detail: "original"` image hint with a 400, and `true` for every other host. ([#2822](https://github.com/can1357/oh-my-pi/issues/2822))
|
|
11
|
+
|
|
5
12
|
## [16.0.8] - 2026-06-18
|
|
6
13
|
|
|
7
14
|
### Changed
|
package/dist/types/types.d.ts
CHANGED
|
@@ -247,6 +247,8 @@ export interface OpenAICompat {
|
|
|
247
247
|
alwaysSendMaxTokens?: boolean;
|
|
248
248
|
/** Whether Responses-API tool-call/result history must be strictly paired. Default: auto-detected (Azure OpenAI, GitHub Copilot). */
|
|
249
249
|
strictResponsesPairing?: boolean;
|
|
250
|
+
/** Whether the Responses API accepts the `detail: "original"` image hint. Default: auto-detected (false for GitHub Copilot, which rejects it with a 400). */
|
|
251
|
+
supportsImageDetailOriginal?: boolean;
|
|
250
252
|
/**
|
|
251
253
|
* Append a trailing `# Juice: 0 !important` developer item when the caller
|
|
252
254
|
* did not request reasoning, suppressing default reasoning on models that
|
|
@@ -416,7 +418,7 @@ export interface ResolvedOpenAISharedCompat {
|
|
|
416
418
|
* `buildModel`; request handlers read fields and never detect, resolve, or
|
|
417
419
|
* allocate.
|
|
418
420
|
*/
|
|
419
|
-
export type ResolvedOpenAICompat = ResolvedOpenAISharedCompat & Required<Omit<OpenAICompat, "supportsDeveloperRole" | "supportsReasoningEffort" | "reasoningEffortMap" | "supportsReasoningParams" | "thinkingFormat" | "reasoningDisableMode" | "omitReasoningEffort" | "includeEncryptedReasoning" | "filterReasoningHistory" | "disableReasoningOnForcedToolChoice" | "disableReasoningOnToolChoice" | "supportsToolChoice" | "supportsForcedToolChoice" | "reasoningContentField" | "requiresReasoningContentForToolCalls" | "requiresReasoningContentForAllAssistantTurns" | "allowsSyntheticReasoningContentForToolCalls" | "requiresThinkingAsText" | "requiresMistralToolIds" | "requiresToolResultName" | "requiresAssistantAfterToolResult" | "requiresAssistantContentForToolCalls" | "stripDeepseekSpecialTokens" | "streamMarkupHealingPattern" | "reasoningDeltasMayBeCumulative" | "emptyLengthFinishIsContextError" | "usesOpenAIToolCallIdLimit" | "promptCacheSessionHeader" | "openRouterRouting" | "isOpenRouterHost" | "supportsStrictMode" | "supportsLongPromptCacheRetention" | "alwaysSendMaxTokens" | "wireModelIdMode" | "vercelGatewayRouting" | "extraBody" | "toolStrictMode" | "toolSchemaFlavor" | "streamIdleTimeoutMs" | "cacheControlFormat" | "thinkingKeep" | "strictResponsesPairing" | "requiresJuiceZeroHack" | "enableGeminiThinkingLoopGuard" | "whenThinking">> & {
|
|
421
|
+
export type ResolvedOpenAICompat = ResolvedOpenAISharedCompat & Required<Omit<OpenAICompat, "supportsDeveloperRole" | "supportsReasoningEffort" | "reasoningEffortMap" | "supportsReasoningParams" | "thinkingFormat" | "reasoningDisableMode" | "omitReasoningEffort" | "includeEncryptedReasoning" | "filterReasoningHistory" | "disableReasoningOnForcedToolChoice" | "disableReasoningOnToolChoice" | "supportsToolChoice" | "supportsForcedToolChoice" | "reasoningContentField" | "requiresReasoningContentForToolCalls" | "requiresReasoningContentForAllAssistantTurns" | "allowsSyntheticReasoningContentForToolCalls" | "requiresThinkingAsText" | "requiresMistralToolIds" | "requiresToolResultName" | "requiresAssistantAfterToolResult" | "requiresAssistantContentForToolCalls" | "stripDeepseekSpecialTokens" | "streamMarkupHealingPattern" | "reasoningDeltasMayBeCumulative" | "emptyLengthFinishIsContextError" | "usesOpenAIToolCallIdLimit" | "promptCacheSessionHeader" | "openRouterRouting" | "isOpenRouterHost" | "supportsStrictMode" | "supportsLongPromptCacheRetention" | "alwaysSendMaxTokens" | "wireModelIdMode" | "vercelGatewayRouting" | "extraBody" | "toolStrictMode" | "toolSchemaFlavor" | "streamIdleTimeoutMs" | "cacheControlFormat" | "thinkingKeep" | "strictResponsesPairing" | "supportsImageDetailOriginal" | "requiresJuiceZeroHack" | "enableGeminiThinkingLoopGuard" | "whenThinking">> & {
|
|
420
422
|
vercelGatewayRouting?: OpenAICompat["vercelGatewayRouting"];
|
|
421
423
|
extraBody?: OpenAICompat["extraBody"];
|
|
422
424
|
cacheControlFormat?: OpenAICompat["cacheControlFormat"];
|
|
@@ -434,6 +436,7 @@ export type ResolvedOpenAICompat = ResolvedOpenAISharedCompat & Required<Omit<Op
|
|
|
434
436
|
export interface ResolvedOpenAIResponsesCompat extends ResolvedOpenAISharedCompat {
|
|
435
437
|
supportsLongPromptCacheRetention: boolean;
|
|
436
438
|
strictResponsesPairing: boolean;
|
|
439
|
+
supportsImageDetailOriginal: boolean;
|
|
437
440
|
requiresJuiceZeroHack: boolean;
|
|
438
441
|
supportsObfuscationOptOut: boolean;
|
|
439
442
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-catalog",
|
|
4
|
-
"version": "16.0.
|
|
4
|
+
"version": "16.0.10",
|
|
5
5
|
"description": "Model catalog for omp: bundled model database, provider discovery descriptors, model identity, classification, and equivalence",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@bufbuild/protobuf": "^2.12.0",
|
|
37
|
-
"@oh-my-pi/pi-utils": "16.0.
|
|
37
|
+
"@oh-my-pi/pi-utils": "16.0.10",
|
|
38
38
|
"arktype": "^2.2.0",
|
|
39
39
|
"zod": "^4"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@oh-my-pi/pi-ai": "16.0.
|
|
42
|
+
"@oh-my-pi/pi-ai": "16.0.10",
|
|
43
43
|
"@types/bun": "^1.3.14"
|
|
44
44
|
},
|
|
45
45
|
"engines": {
|
package/src/compat/anthropic.ts
CHANGED
|
@@ -66,7 +66,16 @@ export function buildAnthropicCompat(spec: ModelSpec<"anthropic-messages">): Res
|
|
|
66
66
|
// loses the reasoning chain and can destabilize the next tool-call
|
|
67
67
|
// arguments (#2005). Known non-signing hosts (Z.AI, DeepSeek) are also
|
|
68
68
|
// preserved for compatibility.
|
|
69
|
-
|
|
69
|
+
//
|
|
70
|
+
// GitHub Copilot's `anthropic-messages` proxy is excluded: it forwards to
|
|
71
|
+
// signature-enforcing Anthropic and returns full thinking signatures, so it
|
|
72
|
+
// is a SIGNING endpoint. Replaying a stripped/unsigned thinking block as
|
|
73
|
+
// `signature: ""` there 400s the whole request ("Invalid signature") — most
|
|
74
|
+
// visibly when a checkpoint/branch-return turn's end_turn-bound signature is
|
|
75
|
+
// stripped on replay (issue #2851). Treating it like official Anthropic
|
|
76
|
+
// degrades such blocks to text instead, which the API accepts.
|
|
77
|
+
replayUnsignedThinking:
|
|
78
|
+
!isCopilot && (isZai || modelMatchesHost(spec, "deepseekFamily") || (spec.reasoning && !official)),
|
|
70
79
|
escapeBuiltinToolNames: modelMatchesHost(spec, "umans"),
|
|
71
80
|
};
|
|
72
81
|
applyCompatOverrides(compat, spec.compat);
|
package/src/compat/openai.ts
CHANGED
|
@@ -459,6 +459,12 @@ export function buildOpenAIResponsesCompat(spec: OpenAIResponsesSpecLike): Resol
|
|
|
459
459
|
// Azure OpenAI and GitHub Copilot Responses paths require tool results
|
|
460
460
|
// to strictly match prior tool calls when building Responses inputs.
|
|
461
461
|
strictResponsesPairing: isAzure || spec.provider === "github-copilot",
|
|
462
|
+
// GitHub Copilot's Responses endpoint rejects the `detail: "original"`
|
|
463
|
+
// image hint with a 400; every other host preserves native-resolution
|
|
464
|
+
// frames (snapcompact relies on `original`). Detect Copilot by provider id
|
|
465
|
+
// or base-URL host (mirroring the Anthropic compat builder) so a model
|
|
466
|
+
// pointed at the Copilot host under a different provider id still clamps.
|
|
467
|
+
supportsImageDetailOriginal: !modelMatchesHost({ provider: spec.provider, baseUrl }, "githubCopilot"),
|
|
462
468
|
requiresJuiceZeroHack: spec.name.toLowerCase().startsWith("gpt-5"),
|
|
463
469
|
reasoningEffortMap: {},
|
|
464
470
|
supportsReasoningParams: true,
|
|
@@ -514,6 +520,7 @@ function pickResponsesOnly(compat: ResolvedOpenAIResponsesCompat): ResponsesOnly
|
|
|
514
520
|
return {
|
|
515
521
|
supportsLongPromptCacheRetention: compat.supportsLongPromptCacheRetention,
|
|
516
522
|
strictResponsesPairing: compat.strictResponsesPairing,
|
|
523
|
+
supportsImageDetailOriginal: compat.supportsImageDetailOriginal,
|
|
517
524
|
requiresJuiceZeroHack: compat.requiresJuiceZeroHack,
|
|
518
525
|
supportsObfuscationOptOut: compat.supportsObfuscationOptOut,
|
|
519
526
|
} satisfies ResponsesOnlyCompat;
|
package/src/types.ts
CHANGED
|
@@ -283,6 +283,8 @@ export interface OpenAICompat {
|
|
|
283
283
|
alwaysSendMaxTokens?: boolean;
|
|
284
284
|
/** Whether Responses-API tool-call/result history must be strictly paired. Default: auto-detected (Azure OpenAI, GitHub Copilot). */
|
|
285
285
|
strictResponsesPairing?: boolean;
|
|
286
|
+
/** Whether the Responses API accepts the `detail: "original"` image hint. Default: auto-detected (false for GitHub Copilot, which rejects it with a 400). */
|
|
287
|
+
supportsImageDetailOriginal?: boolean;
|
|
286
288
|
/**
|
|
287
289
|
* Append a trailing `# Juice: 0 !important` developer item when the caller
|
|
288
290
|
* did not request reasoning, suppressing default reasoning on models that
|
|
@@ -504,6 +506,7 @@ export type ResolvedOpenAICompat = ResolvedOpenAISharedCompat &
|
|
|
504
506
|
| "cacheControlFormat"
|
|
505
507
|
| "thinkingKeep"
|
|
506
508
|
| "strictResponsesPairing"
|
|
509
|
+
| "supportsImageDetailOriginal"
|
|
507
510
|
| "requiresJuiceZeroHack"
|
|
508
511
|
| "enableGeminiThinkingLoopGuard"
|
|
509
512
|
| "whenThinking"
|
|
@@ -527,6 +530,7 @@ export type ResolvedOpenAICompat = ResolvedOpenAISharedCompat &
|
|
|
527
530
|
export interface ResolvedOpenAIResponsesCompat extends ResolvedOpenAISharedCompat {
|
|
528
531
|
supportsLongPromptCacheRetention: boolean;
|
|
529
532
|
strictResponsesPairing: boolean;
|
|
533
|
+
supportsImageDetailOriginal: boolean;
|
|
530
534
|
requiresJuiceZeroHack: boolean;
|
|
531
535
|
supportsObfuscationOptOut: boolean;
|
|
532
536
|
}
|