fix(ai): normalize map value schemas
(cherry picked from commit 836951121076394b775771b29070f1022d7591c7)
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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({
|
||||
|
||||
Reference in New Issue
Block a user