fix(ai): fixed CCA schema stripping for properties named properties

- Updated `normalizeSchemaNode` to keep `insideProperties` active only when entering an outer `properties` map, not when the key appears within an existing properties object.
- Added a regression test for `google-tool-schema` ensuring `propertyNames` and `additionalProperties` are removed from a schema property literally named `properties`.
This commit is contained in:
can1357
2026-06-04 02:23:43 +02:00
parent 542ea6c930
commit debd90656c
3 changed files with 34 additions and 2 deletions
+1
View File
@@ -4,6 +4,7 @@
### Fixed
- Fixed Cloud Code Assist (Gemini / Antigravity) rejecting tool schemas with `Invalid JSON payload received. Unknown name "propertyNames"` (HTTP 400) when a tool exposed a property literally named `properties` (e.g. the Resend MCP `create_contact` tool). The schema normalizer's `insideProperties` flag was re-asserted when descending into such a property's value schema, so Google-unsupported keywords (`propertyNames`, `additionalProperties`, …) nested inside it were never stripped. The flag is now only set when entering a real `properties` map from a schema node, not from within another `properties` map.
- Fixed local/self-hosted providers leaking machine-specific endpoints into the bundled `models.json`. A `generate-models` run on a machine with a LiteLLM proxy baked 1202 `litellm` models pinned to `http://localhost:4000/v1` into the committed catalog. `litellm` (and `lm-studio`) now join `ollama`/`vllm` in the generator's discovery-only exclusion set, so local providers are never fetched during generation nor written to `models.json` — they are discovered dynamically at runtime instead. LiteLLM model discovery now enriches metadata against models.dev (the same reference source the other gateway providers use) rather than a bundled reference map. Added a regression test pinning the invariant (no local provider blocks, no loopback/private-network `baseUrl`s in the bundled catalog).
## [15.8.2] - 2026-06-03
+2 -2
View File
@@ -280,7 +280,7 @@ function normalizeSchemaNode(value: unknown, options: NormalizeSchemaWalkOptions
if (options.stripNullableKeyword && key === "nullable") continue;
result[key] = normalizeSchemaNode(entry, {
...options,
insideProperties: key === "properties",
insideProperties: !options.insideProperties && key === "properties",
});
}
applyDescriptionSpill(result, spill, options);
@@ -302,7 +302,7 @@ function normalizeSchemaNode(value: unknown, options: NormalizeSchemaWalkOptions
}
result[key] = normalizeSchemaNode(entry, {
...options,
insideProperties: key === "properties",
insideProperties: !options.insideProperties && key === "properties",
});
}
@@ -70,6 +70,37 @@ describe("Cloud Code Assist Claude tool schema conversion", () => {
});
});
it("strips schema keywords inside a property literally named properties", () => {
// Regression: the Resend MCP `create_contact` tool exposes a property
// literally named `properties`. The walker must not treat that property's
// value schema as a properties map — otherwise nested `propertyNames` /
// `additionalProperties` keywords leak to the CCA wire and get rejected
// with `Unknown name "propertyNames"` (HTTP 400).
const schema = {
type: "object",
properties: {
properties: {
description: "Custom property key-value pairs",
type: "object",
propertyNames: { type: "string" },
additionalProperties: { type: "string" },
properties: {},
},
},
} as unknown;
expect(normalizeSchemaForCCA(schema)).toEqual({
type: "object",
properties: {
properties: {
description: "Custom property key-value pairs",
type: "object",
properties: {},
},
},
});
});
it("uses sanitized parameters for claude models with deterministic output", () => {
const parameters = {
type: "object",