fix(ai): normalize map value schemas

(cherry picked from commit 836951121076394b775771b29070f1022d7591c7)
This commit is contained in:
usr-bin-roygbiv
2026-07-28 10:04:42 +00:00
committed by can1357
parent 2f579e1ac1
commit 34069920a6
3 changed files with 35 additions and 7 deletions
+1 -3
View File
@@ -33,6 +33,7 @@
- Fixed an HTTP 400 error when resuming or replaying OpenAI history after an interrupted native Computer Use turn.
- Fixed connection 404 errors when using Google Vertex AI in multi-region locations (eu and us) by correctly resolving regional endpoint (REP) hosts.
- Fixed a resource leak in SqliteAuthCredentialStore.close() where unclosed prepared statements kept the SQLite connection alive, preventing database file cleanup (especially on Windows where files remained locked).
- Fixed Google Gemini and Vertex tool declarations carrying numeric, boolean, object-valued, or mixed `enum` arrays that the Google Schema wire type cannot represent. Unsupported enums are omitted while valid string enums remain constrained.
## [17.1.7] - 2026-07-27
@@ -58,9 +59,6 @@
- Kimi Code now sends its session-stable prompt cache key on both supported transports: `prompt_cache_key` for OpenAI-compatible requests and `metadata.user_id` for Anthropic-compatible requests. Explicit keys survive side-channel session IDs, while `cacheRetention: "none"` still disables automatic affinity ([#6049](https://github.com/can1357/oh-my-pi/issues/6049)).
- Fresh encrypted auth-broker snapshot caches are revalidated within a short startup budget, so one-shot clients see newly imported or revoked credentials immediately when the broker is reachable while retaining cache fallback for transport and server failures.
- Fixed custom `anthropic-messages` endpoints dropping native web-search call/result blocks in the leaked-thinking wrapper, preserving signed continuation history in source order without carrying a preceding text signature onto later unsigned blocks ([#6703](https://github.com/can1357/oh-my-pi/issues/6703)).
### Fixed
- Fixed Google Gemini and Vertex tool declarations carrying numeric, boolean, object-valued, or mixed `enum` arrays that the Google Schema wire type cannot represent. Unsupported enums are omitted while valid string enums remain constrained.
## [17.1.4] - 2026-07-26
+19 -4
View File
@@ -107,6 +107,15 @@ const SUBSCHEMA_VALUE_KEYS: Record<string, true> = {
contentSchema: true,
};
/**
* Keywords whose value is either a boolean keyword value or an object
* subschema. Object values must be walked, while bare booleans stay literal.
*/
const BOOLEAN_OR_SCHEMA_VALUE_KEYS: Record<string, true> = {
additionalProperties: true,
unevaluatedProperties: true,
};
/** Keywords whose value is an array of subschemas. */
const SUBSCHEMA_ARRAY_KEYS: Record<string, true> = {
anyOf: true,
@@ -367,12 +376,15 @@ function normalizeSchemaObjectNode(value: JsonObject, options: NormalizeSchemaWa
options.insideSchemaMap ||
Object.hasOwn(SUBSCHEMA_VALUE_KEYS, key) ||
Object.hasOwn(SUBSCHEMA_ARRAY_KEYS, key);
const childIsSubschema =
childBooleanIsSubschema ||
(Object.hasOwn(BOOLEAN_OR_SCHEMA_VALUE_KEYS, key) && isJsonObject(entry));
result[key] =
childInsideSchemaMap || childBooleanIsSubschema
childInsideSchemaMap || childIsSubschema
? normalizeSchemaNode(entry, {
...options,
insideSchemaMap: childInsideSchemaMap,
booleanIsSubschema: childBooleanIsSubschema,
booleanIsSubschema: childIsSubschema,
})
: entry;
}
@@ -398,12 +410,15 @@ function normalizeSchemaObjectNode(value: JsonObject, options: NormalizeSchemaWa
options.insideSchemaMap ||
Object.hasOwn(SUBSCHEMA_VALUE_KEYS, key) ||
Object.hasOwn(SUBSCHEMA_ARRAY_KEYS, key);
const childIsSubschema =
childBooleanIsSubschema ||
(Object.hasOwn(BOOLEAN_OR_SCHEMA_VALUE_KEYS, key) && isJsonObject(entry));
result[key] =
childInsideSchemaMap || childBooleanIsSubschema
childInsideSchemaMap || childIsSubschema
? normalizeSchemaNode(entry, {
...options,
insideSchemaMap: childInsideSchemaMap,
booleanIsSubschema: childBooleanIsSubschema,
booleanIsSubschema: childIsSubschema,
})
: entry;
}
@@ -1305,6 +1305,21 @@ describe("normalizeSchemaForMoonshot", () => {
expect(props.limit).toEqual({ type: "integer", default: 10 });
});
it("normalizes schema-valued additionalProperties without walking literal payload objects", () => {
const literal = { oneOf: [{ const: "literal-a" }, { const: "literal-b" }] };
const normalized = normalizeSchemaForMoonshot({
type: "object",
additionalProperties: { oneOf: [{ const: 1 }, { const: 2 }] },
default: literal,
});
expect(normalized).toEqual({
type: "object",
additionalProperties: { type: "number", enum: [1, 2] },
default: literal,
});
});
it("coerces boolean subschemas to MFJS object forms without changing boolean keywords", () => {
expect(
normalizeSchemaForMoonshot({