Commit Graph

38 Commits

Author SHA1 Message Date
can1357 668cb2115f fix(ai): scoped exclusive-required flattening to xAI 2026-08-16 02:43:35 +02:00
David Andrews 7c5ee37227 fix(ai): scoped xAI root-union flatten and quarantine 2026-08-16 02:43:35 +02:00
David Andrews cb96258405 fix(ai): flattened xAI exclusive-required anyOf at tool root only 2026-08-16 02:43:35 +02:00
David Andrews 96922bd5c9 fix(ai): flattened xAI MCP exclusive-required anyOf 2026-08-16 02:43:35 +02:00
can1357 6b4823181b test: cleaned test suites and documented filtering guidelines
- Remove redundant definedness, null, and type checks across test suites in multiple packages.
- Clean up unused assertions, metadata tests, and obsolete test cases.
- Add good versus bad test filter guidelines and requirements to project documentation.
2026-08-13 08:28:42 +02:00
can1357 e9888367d1 refactor: migrated packages to internal utility modules and removed external dependencies
- Implemented in-house, zero-dependency utility modules in `pi-utils` covering DOM manipulation, markdown parsing, templating, browser automation helpers, and terminal buffers.
- Migrated packages across the repository to consume the new internal utilities and `omptype` schema validators instead of external dependencies.
- Removed multiple external runtime and development dependencies including Zod, Marked, LRU cache, Turndown, and Puppeteer browser packages.
2026-08-05 13:39:09 +02:00
usr-bin-roygbiv 2ee5a10923 fix(ai): preserve CCA literal payloads
(cherry picked from commit b026a96326e3d7df89771f3224476dc37eeeaa9c)
2026-07-30 01:27:35 +02:00
usr-bin-roygbiv 34069920a6 fix(ai): normalize map value schemas
(cherry picked from commit 836951121076394b775771b29070f1022d7591c7)
2026-07-30 01:27:34 +02:00
usr-bin-roygbiv 2f579e1ac1 fix(ai): preserve literal schema payloads
(cherry picked from commit 3631bc5bd0a27eabb774bf800e0144523d25a55b)
2026-07-30 01:27:34 +02:00
usr-bin-roygbiv d17ae32b1d fix(ai): preserve enum keys in Google schema defaults
(cherry picked from commit 226f00efb3c330f5ed6b0583c4b65e2fa75b9f5b)
2026-07-30 01:27:34 +02:00
Roy 16e03728f0 fix(ai): omit unsupported Google enum values
(cherry picked from commit 6cc7916f9ff508ee0864229fe83a3c31a585f832)
2026-07-30 01:27:34 +02:00
roboomp d4a9d50a5b fix(ai): normalized boolean schemas for moonshot
Coerced boolean subschemas into MFJS-compatible object forms while preserving boolean keyword values.

Fixes #5952
2026-07-18 03:52:16 +00:00
can1357 8932acb6f3 fix(schema): scope boolean coercion to google transports 2026-07-16 03:31:58 +02:00
roboomp cd41719757 fix(schema): stripped conditional keywords for google/cca
Added dependencies, dependentSchemas, and dependentRequired to UNSUPPORTED_SCHEMA_FIELDS so both the Google and CCA normalizers drop them before serializing to the OpenAPI-style Schema wire, which cannot model draft-2019 conditional keywords.

Kept them in the MCP subschema-map path (still coercing boolean entries) and documented the additions in CONSTRAINTS.md.

Fixes #5604
2026-07-15 19:47:02 +00:00
roboomp c6c063ee00 fix(schema): rejected not schemas on cca transport
Added not to the CCA residual incompatibility gate so false boolean subschemas fall back before reaching the legacy object-shaped parameters wire.

Made residual scanning schema-map aware to avoid treating a property literally named not as the unsupported keyword, and added root, property, and dependentSchemas regressions.

Fixes #5604
2026-07-15 19:34:49 +00:00
roboomp da3e500637 fix(schema): handled boolean schema-map entries
Generalized the schema-map walk context beyond properties to include patternProperties, dependencies, dependentSchemas, $defs, and definitions. Each arbitrary map entry is now treated as a subschema, so bare booleans coerce before reaching Google/CCA.

Reused the shared map/array keyword tables in the Ollama sanitizer and added a dependentSchemas regression for both Google and CCA normalizers.

Fixes #5604
2026-07-15 19:27:00 +00:00
roboomp 508dbbbc5a fix(schema): coerce boolean subschemas for google/cca transport
Boolean JSON Schema subschemas (`true`/`false`, draft 6+) in MCP tool
inputs passed through normalizeSchemaForGoogle/normalizeSchemaForCCA
untouched. The Cloud Code Assist / Gemini protobuf Schema type has no
representation for a bare boolean, so requests bounced with a 400
INVALID_ARGUMENT before reaching the model.

Coerce booleans to their object equivalents (`true` -> `{}`,
`false` -> `{ not: {} }`) at the single normalizeSchemaNode choke point,
but only in genuine subschema slots (root, combiner branches,
subschema-valued keywords, property values). Keyword-slot booleans
(`nullable`, `enum` entries, `additionalProperties`) stay untouched so
Moonshot/MCP open-record markers survive.

Fixes #5604
2026-07-15 19:15:07 +00:00
lycaon 3f52e26a73 fix(ai): preserve CCA schemas with annotation conflicts 2026-07-11 00:10:47 -06:00
can1357 291b3c74c2 feat: enhanced model reasoning, schema normalization, and loop guarding
- Integrated comprehensive loop guard support for DeepSeek and assistant prose patterns, including configurable stream checks.
- Implemented Moonshot Flavored JSON Schema (MFJS) normalization for improved tool compatibility and enum type inference.
- Added support for Ollama reasoning effort backfilling and Grok-specific service tier cost tracking across providers.
- Expanded model catalog with new entries and unified compatibility logic for improved OpenRouter API integration.
2026-06-18 04:51:43 +02:00
roboomp d35d1c1883 fix(ai): loosened openai pattern property fallback
Rewrote unsupported lookaround patternProperties keys to a supported catch-all pattern instead of dropping their value schemas, preserving dynamic-key tool arguments when additionalProperties is false.

Extended sanitizer and Codex conversion regression coverage for the closed dynamic-key case.

Fixes #2784
2026-06-17 00:23:37 +02:00
roboomp e4444a0fe7 fix(ai): normalized stripped openai schemas
Converted schema nodes emptied by OpenAI Responses lookaround stripping to boolean true so pattern-only nodes keep the existing empty-schema semantics.

Extended sanitizer and Codex regression coverage for pattern-only property and propertyNames schemas.

Fixes #2784
2026-06-16 15:54:50 +00:00
roboomp 965afbe377 fix(ai): stripped openai pattern property lookarounds
Dropped unsupported lookaround regex keys from OpenAI Responses patternProperties maps while preserving ordinary property names and supported regex keys.

Extended sanitizer and Codex tool conversion coverage for patternProperties.

Fixes #2784
2026-06-16 15:42:32 +00:00
roboomp a93a6c3908 fix(ai): stripped openai responses regex lookarounds
Removed JSON Schema pattern values containing regex lookaround from OpenAI Responses/Codex tool schemas so incompatible MCP tools do not poison the request.

Added schema-normalization and Codex conversion regression coverage for Figma-style fileKey patterns.

Fixes #2784
2026-06-16 15:24:54 +00:00
can1357 ae415199dc feat: added build-time compatibility in ModelSpec/buildModel pipeline
- Centralized catalog and registry handling on `ModelSpec` and `buildModel`, resolving compatibility at model build time.
- Removed runtime compatibility detectors and switched provider request flows to direct `model.compat` reads.
- Added compat fields (`supportsReasoningParams`, `alwaysSendMaxTokens`, `strictResponsesPairing`, `whenThinking`).
- Persisted explicit compatibility overrides through `compatConfig` in discovery and cache merge paths.
2026-06-10 06:20:51 +02:00
can1357 8a66c8786b fix(ai): surfaced Gemini stream errors and fixed Bedrock/AWS credential handling
in-band Gemini errors, promptFeedback blocks, and missing finishReason no longer report success; toolUse override stops masking SAFETY/MALFORMED finishes; schema normalization keeps DAG-shared subtrees while detecting true cycles; Google/AWS shared credential resolution detached from first caller's signal and bounded by own timeout; Bedrock keeps toolConfig under toolChoice none; eventstream cancels body on abnormal exit.
2026-06-10 01:26:31 +02:00
basedcorp99 7c8fb4d8f6 fix(ai): also strip sibling type-specific keys during CCA mixed-type collapse
Address review feedback:
- Replace `as string` assertion with typed `chosenType` local
- Strip sibling keys from nextSchema that were copied via
  copySchemaWithout but belong to a type other than the chosen one
  (e.g. sibling `items` on a now-string-typed schema)
- Export ALL_CCA_TYPE_SPECIFIC_KEYS from fields.ts for sibling filtering
- Add regression test for the sibling-key edge case
2026-06-06 20:42:20 +02:00
basedcorp99 2623bd75a2 test(ai): add stripResidualCombiners regression for mixed-type string|array collapse 2026-06-06 20:42:20 +02:00
basedcorp99 f3210ab862 fix(ai): strip type-specific keys when CCA mixed-type collapse picks non-matching type
When collapseMixedTypeCombinerVariants collapses an anyOf with mixed
types (e.g. string | array), it previously picked the first non-null
type but indiscriminately copied ALL mergedVariantFields — including
type-specific keys like "items" that only belong to array. This
produced schemas like {type: "string", items: {...}} which Google
Cloud Code Assist API rejects with 400.

Fix: filter mergedVariantFields against the chosen types allowed keys
(CLOUD_CODE_ASSIST_TYPE_SPECIFIC_KEYS) before copying, so array-only
keys are dropped when the winner is string (and vice versa).

Fixes 400 error on github tools "pr" parameter (anyOf string/array).
2026-06-06 20:42:20 +02:00
roboomp 09ea361331 fix(schema): normalize empty JSON schema {} to true for grammar-constrained models
z.unknown() emits {} (empty JSON Schema) as the value for additionalProperties,
items, and other schema-valued positions. This is semantically equivalent to
boolean true per JSON Schema draft 2020-12 §4.3.1, but grammar-constrained
samplers (llama.cpp, etc.) interpret the object form as "generate an empty
object" rather than "any JSON value". Models using such samplers therefore
emit {} for every open-typed field, including extra.title in plan-mode resolve
calls (issue #1179). This affected all tools with open schemas, not just the
resolve tool -- MCP tools and any tool using z.unknown() in value positions
have the same problem.

Fix: normalize any {} in schema-valued positions to true in two places:
- zodToWireSchema postProcess/walk: covers Zod-based tools across all providers
- normalizeOpenAIResponsesSchemaNode: covers all tools (Zod, TypeBox, MCP)
  going to openai-responses-compatible endpoints (llama.cpp, Azure Responses)

Adds isJsonObjectEmpty() helper to schema/types.ts (for...in based, no allocation).

Fixes #1179
2026-05-19 04:39:27 +00:00
Can Bölük 4024fbe7e2 fix(ai): decontaminate leaked Zod schema instances to valid JSON Schema
Rewrites JSON-roundtripped Zod 4 schema objects that leak Zod internals as
JSON Schema keywords (e.g., `type:"enum"`, `enum:{...}`) into valid
JSON Schema 2020-12. This prevents validation failures when such schemas
are used as tool input schemas (e.g., from MCP servers).

Updates `isZodSchema` to reject deserialized Zod impostors that retain
`_zod` but lose their prototype.

Wires `toJSON` methods onto TypeBox shim schemas to ensure `JSON.stringify`
produces clean JSON Schema, preventing future leaks.

Fixes #1101
2026-05-19 10:16:40 +09:00
roboomp 74461e6f53 fix(ai): broadened openai schema sanitization coverage
Added dependencies and contentSchema to the OpenAI Responses schema-position sets so draft-04..07 dependencies maps and draft 2019-09 contentSchema nodes also get the properties-on-object normalization. Recognized array-form type declarations that include object. Preserved malformed non-array oneOf payloads instead of dropping them. Documented the cycle-safe cache seed and added a self-referential regression test.

Refs #1147
2026-05-17 10:55:29 +00:00
roboomp 03623bdf5e fix(ai): normalized openai object tool schemas
Normalized OpenAI Responses schema sanitization so object schema nodes always include properties while only traversing schema-valued positions. Wired the same sanitizer into the OpenAI Codex Responses tool conversion path and added regression coverage for no-argument MCP-style schemas and literal payload preservation.

Fixes #1147
2026-05-17 09:28:59 +00:00
can1357 54a60a7702 fix(ai/schema): hoisted description to anyOf wrapper in strict-mode unions
- Extracted `description` from type-array and nullable branches so it lives on the wrapper, not duplicated onto each variant.
- Replaced inline enum-type inference with `inferStrictPrimitiveTypeFromEnumOrConst`, covering both `enum` and `const` in sanitize and enforce paths.
- Mixed-primitive enums and non-primitive consts now fall back to non-strict instead of producing a typeless schema that OpenAI rejects on the wire.
2026-05-16 20:22:39 +02:00
can1357 e7200c2e4a feat(ai): added unified normalize flow for Google/CCA schema handling
- Implemented a unified normalization flow by switching Google/CCA handling to normalizeSchemaForGoogle/CCA.
- Added normalize.ts with recursive node normalization, nullable-union checks, and combiner collapsing.
- Removed sanitize-google.ts and normalize-cca.ts, replacing them with normalize exports in schema indexes.
- Added spill-to-description utilities with spill/paren modes and `$defs` exclusion for unsupported fields.
- Updated MCP bridge and schema tests to use normalizeSchemaFor* APIs with expanded compatibility checks.
- Documented normalization behavior changes and breaking rename in constraints and package changelog files.
2026-05-16 19:04:09 +02:00
can1357 9bd4d0099b fix(ai): resolved strict-mode local-ref inlining and single-item allOf
- Added strict-mode ref preprocessing to resolve local `#/` refs with sibling-key precedence.
- Added single-item allOf handling that inlines the sole schema entry and retains multi-item allOf.
- Added Anthropic schema normalization to retain whitelisted metadata and enforce stricter key handling.
- Added Google schema sanitizer options for snake_case renaming, null-collapse behavior, and ordering.
- Expanded schema tests for Anthropic, Google, and strict-mode parity across refs, arrays, and recursion.
2026-05-16 18:33:25 +02:00
can1357 0d00f015ec feat(ai): added 2020-12 schema migration to ai strict validation
- Added draft-07-to-2020-12 schema upgrade logic for `$schema`, `definitions`, `$ref`, tuple, and nullable mapping.
- Integrated `upgradeJsonSchemaTo202012` into strict adaptation, validation, strict-mode, sanitizer, and wire/dereference flows.
- Replaced set-based traversal helpers with record maps, `for...in` loops, and epoch/`once` cycle guards.
- Added unreleased changelog entries and tests for schema normalization, `oneOf` to `anyOf`, and tuple validation edge cases.
2026-05-15 23:46:23 +02:00
can1357 5c7c5eccb8 fix(ai): corrected AI schema normalization to draft-2020-12 prefixItems
- Adopted draft-2020-12 tuple validation with `prefixItems`, rejecting array-valued `items`.
- Expanded strict-mode handling to recurse `prefixItems` entries and infer `array` when tuple prefixes exist.
- Normalized Anthropic schemas through `prefixItems`, keeping supported tuple constraints and dropping unsupported fields.
- Updated coding-agent schema metadata and tests to draft-2020-12 `$schema` targets, including MCP/theme fixtures.
- Added `trimTrailingWhitespace()` to strip trailing spaces/tabs and keep the original line when none exist.
2026-05-15 23:46:23 +02:00
can1357 cba80c79c3 fix(schema): harden all provider schema normalizers with cycle detection, fixpoint iteration, and correctness fixes
## New: schema compatibility validation API

Add `validateSchemaCompatibility(schema, provider)` in
`packages/ai/src/utils/schema/compatibility.ts` that performs a static
audit of a JSON Schema against three provider targets:

- `openai-strict`: checks forbidden keys, required/properties symmetry,
  additionalProperties constraint, and that every node declares a type,
  combinator, or $ref
- `google`: checks unsupported keyword set and array-valued type
- `cloud-code-assist-claude`: checks forbidden keywords, array type,
  null type, nullable keyword, and combiner presence; also validates via
  AJV 2020 draft

Add `validateStrictSchemaEnforcement(original, result)` to assert the
fail-open contract: when strict enforcement succeeds the output must pass
openai-strict validation; when it fails the output must be the original
schema object (same reference).

Export both functions and their types from `./utils/schema/index.ts`.

## New: shared constants in fields.ts

Extract `COMBINATOR_KEYS` (`anyOf`, `allOf`, `oneOf`) and add
`CCA_UNSUPPORTED_SCHEMA_FIELDS` as exported constants, eliminating the
local duplicate in `strict-mode.ts` and providing a canonical field set
for Cloud Code Assist (much narrower than the Google set — CCA supports
validation keywords like `additionalProperties`, `minLength`,
`pattern`, etc.).

## Fix: cycle detection in all recursive schema traversals

All recursive walkers now carry a `WeakSet<object>` guard. Previously any
schema with a reference cycle (or a schema object that appears at two
nodes in the tree) would cause an infinite loop or a stack overflow:

- `sanitizeSchemaForStrictMode` / `enforceStrictSchema`
- `normalizeSchemaForCloudCodeAssistClaude`
- `normalizeNullablePropertiesForCloudCodeAssist`
- `stripResidualCombiners`
- `sanitizeSchemaImpl` (Google sanitizer)
- `hasResidualCloudCodeAssistIncompatibilities`

`hasResidualCloudCodeAssistIncompatibilities` previously returned `true`
for already-visited nodes, producing false positives that forced the CCA
fallback schema on valid (but multiply-referenced) schemas. It now
correctly returns `false`.

## Fix: stripResidualCombiners iterates to fixpoint

The previous single-pass approach missed chained combiner reductions
where one collapsed variant exposed another reducible combiner. The
rewriter now loops until no further reduction occurs.

## Fix: mergeObjectCombinerVariants required-field computation

The merged object schema now takes the intersection of all variants'
`required` arrays, then unions in own-level required properties that
exist in the merged schema. Previously the `required` field was silently
dropped from the flattened schema, making all properties effectively
optional.

## Fix: sanitizeSchemaForGoogle improvements

- Type inference for const-collapsed enums: type is derived from all
  variants (must unanimously agree), falling back to inference from enum
  values; mixed null/non-null infers the non-null scalar type and sets
  `nullable: true`
- Const→enum deduplication now uses deep structural equality instead of
  `Object.is`
- Recursion spreads the full options object so new fields (`unsupportedFields`,
  `seen`) are not silently dropped when descending into sub-schemas
- Array-valued `type` is filtered to strings before processing
- Removed incorrect stripping of `additionalProperties: false` (the
  field is valid and should be preserved)
- Parameterized `unsupportedFields` in `SanitizeSchemaOptions` enables
  code reuse between the Google and CCA sanitizers

## Fix: sanitizeSchemaForStrictMode / enforceStrictSchema

- `nullable: true` is now stripped during sanitization and expanded into
  `anyOf: [schema, {type: "null"}]` in the enforcer output, matching
  what OpenAI strict mode requires
- Type inference: `type: "array"` is inferred when `items` is present;
  a scalar type is inferred from uniform `enum` values
- Const→enum merge uses deep equality to avoid duplicate entries when
  both `const` and `enum` exist with the same value
- `additionalProperties` is now dropped unconditionally in sanitization
  (previously only object-valued `additionalProperties` was recursed;
  non-object values were passed through)
- `enforceStrictSchema` recurses into `$defs` and `definitions` blocks
- `enforceStrictSchema` handles tuple-style `items` arrays
- `enforceStrictSchema` skips double-wrapping: optional properties
  already expressed as `anyOf: [..., {type: "null"}]` are not wrapped again
- `tryEnforceStrictSchema` now caches results in a `WeakMap` keyed on
  the input schema object to avoid redundant work on repeated calls

## Fix: mergeCompatibleEnumSchemas deep equality

Uses `areJsonValuesEqual` instead of `Object.is` when deduplicating
enum members, so structurally equal objects are not duplicated.

## New: test coverage

- `packages/ai/test/schema-normalization.test.ts`: comprehensive unit
  tests for strict mode, Google, and Cloud Code Assist normalization
- `packages/ai/test/schema-compatibility.test.ts`: unit tests for all
  three provider targets in the new compatibility validator
- `packages/coding-agent/test/tools/provider-schema-compatibility.test.ts`:
  integration test that instantiates every builtin and hidden tool, runs
  their parameter schemas through all three provider pipelines, and
  asserts zero compatibility violations
2026-02-28 18:41:10 +01:00