* fix(ai/gemini): coerce numeric/boolean enum values to strings Gemini Function Calling only accepts string enum values (see https://ai.google.dev/gemini-api/docs/function-calling). Tool schemas containing enum: [1,2,3] or enum: [true,false] were passed through unchanged, causing Gemini to reject the entire request with 400 TYPE_STRING errors at 'function_declarations[X].parameters...enum[N]'. Extend cleanSchemaForGeminiWithDefs to coerce enum and const values via a shared helper (number/boolean/bigint -> string, drop null and non-coercible entries, de-duplicate), and retype the containing schema as 'string' since Gemini's validator only accepts enum on string-typed schemas. Adds seven vitest cases covering numeric/boolean enum, const, nested schemas, and dedup/empty-after-coercion edge cases. Fixes #104566 Co-Authored-By: Claude <noreply@anthropic.com> * fix(ai/gemini): make enum retyping property-order independent Address @clawsweeper review on #104567: The initial patch set cleaned.type = 'string' inline while visiting the 'enum' or 'const' key. For schemas where 'type' appears AFTER 'enum' / 'const' in the input object — a valid ordering since JSON Schema property order is not semantic — a later 'type' pass would overwrite the coercion via the tail 'cleaned[key] = value' branch, and Gemini would still receive an invalid declaration. Move the type override out of the loop: track whether any enum/const was coerced via a boolean flag, and force cleaned.type = 'string' after the loop finishes. This makes the fix independent of input property order. Also add curly braces around single-line ifs to satisfy check-lint (eslint(curly)) which failed on the previous commit. New reversed-order regression tests added. Co-Authored-By: Claude <noreply@anthropic.com> * fix(ai): preserve Gemini enum schema types --------- Co-authored-by: leonme <leonme@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Peter Steinberger <steipete@gmail.com>
@openclaw/ai
Reusable model API contracts, provider adapters, and streaming primitives from OpenClaw. The package supports isolated runtime instances; importing it does not register providers globally.
import { createLlmRuntime } from "@openclaw/ai";
import { registerBuiltInApiProviders } from "@openclaw/ai/providers";
const runtime = createLlmRuntime();
registerBuiltInApiProviders(runtime.registry);
Provider-neutral contracts, validation, diagnostics, and event streams are
available from the package root and focused subpaths such as
@openclaw/ai/event-stream and @openclaw/ai/validation. No second OpenClaw
runtime package is required.
Provider ids, credentials, model catalogs, retries, and failover remain
application concerns. OpenClaw supplies those policies around this package.
Host policy (request fetch guarding, secret redaction, strict-tool defaults,
diagnostics logging) can be injected with configureAiTransportHost; the
defaults are inert.
@openclaw/ai/internal/* subpaths exist for the OpenClaw application itself.
They carry no semver guarantee and can change or disappear in any release; do
not depend on them outside OpenClaw.